mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-06-15 05:22:44 +01:00
Compare commits
5 Commits
db4af2bcac
...
b660486eb7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b660486eb7 | ||
|
|
61db23fc01 | ||
|
|
ab761d97f9 | ||
|
|
50d60393bc | ||
|
|
b5639e4bb2 |
@@ -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();
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -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')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user