Compare commits

...

5 Commits

Author SHA1 Message Date
Gregor Vostrak
b660486eb7 fix e2e tests 2026-05-11 19:00:37 +02:00
Gregor Vostrak
61db23fc01 fix formatting 2026-05-11 17:28:29 +02:00
Gregor Vostrak
ab761d97f9 clamp running time entry duration to min 0 for FullCalendarHeaderDuration calc 2026-05-11 17:20:28 +02:00
Gregor Vostrak
50d60393bc fix formatting 2026-05-11 17:18:57 +02:00
Gregor Vostrak
b5639e4bb2 add missing dayjs plugins for isSameOrBefore and isSameOrAfter 2026-05-11 17:08:15 +02:00
10 changed files with 22 additions and 24 deletions

View File

@@ -907,7 +907,7 @@ test.describe('Employee Sidebar Navigation', () => {
// Visible links
await expect(employee.page.getByRole('link', { name: 'Dashboard' })).toBeVisible();
await expect(employee.page.getByRole('link', { name: 'Time' })).toBeVisible();
await expect(employee.page.getByRole('link', { name: 'Time', exact: true })).toBeVisible();
await expect(employee.page.getByRole('link', { name: 'Calendar' })).toBeVisible();
await expect(employee.page.getByRole('link', { name: 'Projects' })).toBeVisible();
await expect(employee.page.getByRole('link', { name: 'Clients' })).toBeVisible();

View File

@@ -640,7 +640,7 @@ test('test that creating a project with estimated time in human-readable format
await page.getByLabel('Project Name').fill(newProjectName);
// Fill in estimated time using human-readable format
const estimatedTimeInput = page.getByPlaceholder('e.g. 2h 30m or 1.5');
const estimatedTimeInput = page.getByLabel('Time Estimated');
await estimatedTimeInput.fill('2h 30m');
await estimatedTimeInput.press('Tab');
@@ -668,7 +668,7 @@ test('test that creating a project with estimated time using decimal notation wo
await page.getByLabel('Project Name').fill(newProjectName);
// Fill in estimated time using decimal notation (1.5 hours = 1h 30m)
const estimatedTimeInput = page.getByPlaceholder('e.g. 2h 30m or 1.5');
const estimatedTimeInput = page.getByLabel('Time Estimated');
await estimatedTimeInput.fill('1.5');
await estimatedTimeInput.press('Tab');
@@ -696,7 +696,7 @@ test('test that creating a project with estimated time using comma decimal notat
await page.getByLabel('Project Name').fill(newProjectName);
// Fill in estimated time using comma decimal notation (2,5 hours = 2h 30m)
const estimatedTimeInput = page.getByPlaceholder('e.g. 2h 30m or 1.5');
const estimatedTimeInput = page.getByLabel('Time Estimated');
await estimatedTimeInput.fill('2,5');
await estimatedTimeInput.press('Tab');
@@ -727,7 +727,7 @@ test('test that updating estimated time on existing project works', async ({ pag
await page.getByRole('menuitem').getByText('Edit').first().click();
// Fill in estimated time
const estimatedTimeInput = page.getByPlaceholder('e.g. 2h 30m or 1.5');
const estimatedTimeInput = page.getByLabel('Time Estimated');
await estimatedTimeInput.fill('4h 15m');
await estimatedTimeInput.press('Tab');
@@ -748,7 +748,7 @@ test('test that estimated time input displays formatted value after blur', async
await goToProjectsOverview(page);
await page.getByRole('button', { name: 'Create Project' }).click();
const estimatedTimeInput = page.getByPlaceholder('e.g. 2h 30m or 1.5');
const estimatedTimeInput = page.getByLabel('Time Estimated');
// Enter time in various formats and check the displayed value
await estimatedTimeInput.fill('90');

View File

@@ -43,9 +43,7 @@ const emit = defineEmits<{
disabled:opacity-50 disabled:cursor-not-allowed" />
</span>
</TooltipTrigger>
<TooltipContent>
Stop the running time entry to edit the timesheet
</TooltipContent>
<TooltipContent> Stop the running time entry to edit the timesheet </TooltipContent>
</Tooltip>
</TooltipProvider>
<DurationSecondsInput

View File

@@ -26,9 +26,7 @@ defineEmits<{
<Button variant="ghost" size="sm" :disabled="busy">
<LoadingSpinner v-if="busy" class="h-3.5 w-3.5 m-0" />
Copy last week
<ChevronDownIcon
v-if="!busy"
class="h-3.5 w-3.5 ml-1 text-icon-default" />
<ChevronDownIcon v-if="!busy" class="h-3.5 w-3.5 ml-1 text-icon-default" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" class="min-w-[220px]">

View File

@@ -58,7 +58,11 @@ const emit = defineEmits<{
<div class="inline-block min-w-full align-middle">
<div
class="grid min-w-full w-max border-y border-default-background-separator"
style="grid-template-columns: minmax(420px, 1fr) repeat(7, minmax(96px, 120px)) minmax(100px, auto) 40px;">
style="
grid-template-columns:
minmax(420px, 1fr) repeat(7, minmax(96px, 120px)) minmax(100px, auto)
40px;
">
<!-- Header row -->
<div
class="bg-background dark:bg-secondary pl-7 pr-3 py-1 text-xs text-text-tertiary md:sticky md:left-0 md:z-10">

View File

@@ -170,12 +170,9 @@ async function createTag(name: string): Promise<Tag | undefined> {
@remove-row="handleRemoveRow"
@cell-update="handleCellUpdate"
@project-task-change="
(row, projectId, taskId) =>
handleRowIdentityChange(row, { projectId, taskId })
"
@billable-change="
(row, billable) => handleRowIdentityChange(row, { billable })
(row, projectId, taskId) => handleRowIdentityChange(row, { projectId, taskId })
"
@billable-change="(row, billable) => handleRowIdentityChange(row, { billable })"
@tags-change="(row, tags) => handleRowIdentityChange(row, { tags })"
@add-row="handleAddRow" />

View File

@@ -265,9 +265,9 @@ export function useCalendarEvents(params: {
'seconds'
);
} else {
durationSeconds = params.currentTime.value.diff(
getDayJsInstance()(entry.start),
'seconds'
durationSeconds = Math.max(
0,
params.currentTime.value.diff(getDayJsInstance()(entry.start), 'seconds')
);
}

View File

@@ -3,6 +3,8 @@ import duration from 'dayjs/plugin/duration';
import relativeTime from 'dayjs/plugin/relativeTime';
import isToday from 'dayjs/plugin/isToday';
import isYesterday from 'dayjs/plugin/isYesterday';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
import weekOfYear from 'dayjs/plugin/weekOfYear';
@@ -68,6 +70,8 @@ function configureParseLocale(numberFormat?: string) {
dayjs.extend(relativeTime);
dayjs.extend(isToday);
dayjs.extend(isYesterday);
dayjs.extend(isSameOrBefore);
dayjs.extend(isSameOrAfter);
dayjs.extend(duration);
dayjs.extend(utc);
dayjs.extend(timezone);

View File

@@ -88,7 +88,6 @@ export function findFreeWindowOnDay(
// Sort + merge so we can walk a clean [gap, obstacle, gap, ...] sequence.
obstacles.sort((a, b) => a.start.diff(b.start));
// merge overlaps
const merged: Interval[] = [];
for (const obs of obstacles) {

View File

@@ -19,7 +19,6 @@ import {
type FreeWindow,
} from './cellMath';
/**
* Cell-level edit dispatcher. Picks one of four strategies based on
* the diff between current and requested totals:
@@ -317,6 +316,5 @@ export function useTimesheetCellMutations(
return best;
}
return { handleCellUpdate };
}