diff --git a/e2e/profile.spec.ts b/e2e/profile.spec.ts
index 93d9248c..30231262 100644
--- a/e2e/profile.spec.ts
+++ b/e2e/profile.spec.ts
@@ -230,6 +230,37 @@ test('test that theme can be changed to dark and light', async ({ page }) => {
await expect(page.getByText('System default:')).toBeVisible();
});
+// =============================================
+// Group similar time entries
+// =============================================
+
+test('test that group similar time entries setting can be toggled', async ({ page }) => {
+ await goToProfilePage(page);
+
+ // Get the checkbox
+ const checkbox = page.getByLabel('Group similar time entries');
+
+ // Get initial value and verify it is checked (default is true)
+ const initialValue = await checkbox.isChecked();
+ await expect(checkbox).toBeChecked();
+
+ // Toggle the checkbox
+ await checkbox.click();
+
+ // Reload
+ await page.reload();
+
+ // Verify the value is toggled
+ const afterValue = await page.getByLabel('Group similar time entries').isChecked();
+ expect(afterValue).toBe(!initialValue);
+
+ // Verify localStorage persists the setting
+ const storedValue = await page.evaluate(() =>
+ localStorage.getItem('group-similar-time-entries')
+ );
+ expect(storedValue).toBe(String(!initialValue));
+});
+
// =============================================
// Two Factor Authentication Tests
// =============================================
diff --git a/e2e/time.spec.ts b/e2e/time.spec.ts
index 9c311b03..dfd4ba4e 100644
--- a/e2e/time.spec.ts
+++ b/e2e/time.spec.ts
@@ -39,6 +39,10 @@ function getMonthFromTimestamp(timestamp: string): number {
return new Date(timestamp).getUTCMonth() + 1;
}
+async function goToProfilePage(page: Page) {
+ await page.goto(PLAYWRIGHT_BASE_URL + '/user/profile');
+}
+
async function goToTimeOverview(page: Page) {
await page.goto(PLAYWRIGHT_BASE_URL + '/time');
}
@@ -67,6 +71,14 @@ async function createEmptyTimeEntry(page: Page) {
]);
}
+async function setTimeEntriesGrouping(page: Page, enabled: boolean) {
+ await goToProfilePage(page);
+ const checkbox = page.getByLabel('Group similar time entries');
+ const isChecked = await checkbox.isChecked();
+ if (isChecked !== enabled) await checkbox.click();
+ await goToTimeOverview(page);
+}
+
test('test that starting and stopping an empty time entry shows a new time entry in the overview', async ({
page,
}) => {
@@ -333,6 +345,30 @@ test.skip('test that load more works when the end of page is reached', async ({
await expect(page.locator('body')).toHaveText(/All time entries are loaded!/);
});
+test('test that Group similar time entries option is affected', async ({ page }) => {
+ // Enable grouping
+ await setTimeEntriesGrouping(page, true);
+
+ // Create 2 similar time entries
+ await createEmptyTimeEntry(page);
+ await page.waitForSelector('[data-testid="time_entry_row"]', { timeout: 1000 });
+ await createEmptyTimeEntry(page);
+
+ // Verify similar time entries are grouped
+ await expect(page.getByTestId('grouped_items_count_button').first()).toBeVisible({
+ timeout: 1000,
+ });
+
+ // Disable grouping
+ await setTimeEntriesGrouping(page, false);
+
+ // Verify similar time entries are not grouped
+ await expect(page.locator('[data-testid="time_entry_row"]')).toHaveCount(2, { timeout: 1000 });
+ await expect(page.locator('[data-testid="grouped_items_count_button"]')).toHaveCount(0, {
+ timeout: 1000,
+ });
+});
+
// TODO: Test that updating the time entry start / end times works while it is running
// TODO: Test for project update
diff --git a/resources/js/Pages/Profile/Partials/ThemeForm.vue b/resources/js/Pages/Profile/Partials/ThemeForm.vue
index 69de1786..022a1d70 100644
--- a/resources/js/Pages/Profile/Partials/ThemeForm.vue
+++ b/resources/js/Pages/Profile/Partials/ThemeForm.vue
@@ -2,8 +2,10 @@
import FormSection from '@/Components/FormSection.vue';
import { Field, FieldLabel, FieldDescription } from '@/packages/ui/src/field';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/packages/ui/src';
+import { Checkbox } from '@/packages/ui/src';
import { usePreferredColorScheme } from '@vueuse/core';
import { themeSetting } from '@/utils/theme';
+import { groupSimilarTimeEntriesSetting } from '@/utils/timeEntryGrouping';
const preferredColor = usePreferredColorScheme();
@@ -15,6 +17,7 @@ const preferredColor = usePreferredColorScheme();
Choose how you want solidtime to look on your device
+