Enable npm workspaces and update dependencies

This commit is contained in:
Gregor Vostrak
2026-02-02 03:19:22 +01:00
parent b2af9c6bf1
commit 7efb7e6071
31 changed files with 2502 additions and 7953 deletions

View File

@@ -320,8 +320,8 @@ function getSlotDuration(calendarEl: HTMLElement): number {
const secondTime = secondSlot.getAttribute('data-time');
if (firstTime && secondTime) {
const [h1, m1] = firstTime.split(':').map(Number);
const [h2, m2] = secondTime.split(':').map(Number);
const [h1 = 0, m1 = 0] = firstTime.split(':').map(Number);
const [h2 = 0, m2 = 0] = secondTime.split(':').map(Number);
const diff = h2 * 60 + m2 - (h1 * 60 + m1);
if (diff > 0) return diff;
}

View File

@@ -41,8 +41,8 @@ function updateDuration() {
const results = parseHHMM(temporaryCustomTimerEntry.value);
if (results) {
const newStartDate = getDayJsInstance()(end.value)
.subtract(parseInt(results[1]), 'h')
.subtract(parseInt(results[2]), 'm');
.subtract(parseInt(results[1]!), 'h')
.subtract(parseInt(results[2]!), 'm');
start.value = newStartDate.utc().format();
}
}

View File

@@ -25,7 +25,7 @@ function updateTime(event: Event) {
const target = event.target as HTMLInputElement;
const newValue = target.value.trim();
if (newValue.split(':').length === 2) {
const [hours, minutes] = newValue.split(':');
const [hours, minutes] = newValue.split(':') as [string, string];
if (!isNaN(parseInt(hours)) && !isNaN(parseInt(minutes))) {
const currentTime = getLocalizedDayJs(model.value);
const newHours = Math.min(parseInt(hours), 23);

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { defineProps, nextTick, ref, watch } from 'vue';
import { nextTick, ref, watch } from 'vue';
import DatePicker from '@/packages/ui/src/Input/DatePicker.vue';
import { getDayJsInstance, getLocalizedDayJs } from '@/packages/ui/src/utils/time';
import dayjs from 'dayjs';

View File

@@ -53,7 +53,7 @@ const groupedTimeEntries = computed(() => {
}
const groupedEntriesByDayAndType: Record<string, TimeEntriesGroupedByType[]> = {};
for (const dailyEntriesKey in groupedEntriesByDay) {
const dailyEntries = groupedEntriesByDay[dailyEntriesKey];
const dailyEntries = groupedEntriesByDay[dailyEntriesKey]!;
const newDailyEntries: TimeEntriesGroupedByType[] = [];
for (const entry of dailyEntries) {
@@ -66,26 +66,22 @@ const groupedTimeEntries = computed(() => {
e.description === entry.description
);
if (oldEntriesIndex !== -1 && newDailyEntries[oldEntriesIndex]) {
newDailyEntries[oldEntriesIndex].timeEntries.push(entry);
const existingEntry = newDailyEntries[oldEntriesIndex]!;
existingEntry.timeEntries.push(entry);
// Add up durations for time entries of the same type
newDailyEntries[oldEntriesIndex].duration =
(newDailyEntries[oldEntriesIndex].duration ?? 0) + (entry?.duration ?? 0);
existingEntry.duration = (existingEntry.duration ?? 0) + (entry?.duration ?? 0);
// adapt start end times so they show the earliest start and latest end time
if (
getDayJsInstance()(entry.start).isBefore(
getDayJsInstance()(newDailyEntries[oldEntriesIndex].start)
getDayJsInstance()(existingEntry.start)
)
) {
newDailyEntries[oldEntriesIndex].start = entry.start;
existingEntry.start = entry.start;
}
if (
getDayJsInstance()(entry.end).isAfter(
getDayJsInstance()(newDailyEntries[oldEntriesIndex].end)
)
) {
newDailyEntries[oldEntriesIndex].end = entry.end;
if (getDayJsInstance()(entry.end).isAfter(getDayJsInstance()(existingEntry.end))) {
existingEntry.end = entry.end;
}
} else {
newDailyEntries.push({ ...entry, timeEntries: [entry] });
@@ -204,7 +200,7 @@ function unselectAllTimeEntries(value: TimeEntriesGroupedByType[]) {
:delete-time-entry="() => deleteTimeEntries([entry])"
:duplicate-time-entry="() => createTimeEntry(entry)"
:currency="currency"
:time-entry="entry.timeEntries[0]"
:time-entry="entry.timeEntries[0]!"
@selected="selectedTimeEntries.push(entry)"
@unselected="
selectedTimeEntries = selectedTimeEntries.filter(

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import Dropdown from '@/packages/ui/src/Input/Dropdown.vue';
import { defineProps, ref, inject, type ComputedRef } from 'vue';
import { ref, inject, type ComputedRef } from 'vue';
import { formatDateLocalized, formatStartEnd } from '@/packages/ui/src/utils/time';
import TimeRangeSelector from '@/packages/ui/src/Input/TimeRangeSelector.vue';
import { twMerge } from 'tailwind-merge';

View File

@@ -4,7 +4,7 @@ import {
formatHumanReadableDuration,
parseTimeInput,
} from '@/packages/ui/src/utils/time';
import { computed, defineProps, ref, inject, type ComputedRef } from 'vue';
import { computed, ref, inject, type ComputedRef } from 'vue';
import dayjs from 'dayjs';
import type { Organization } from '@/packages/api/src';

View File

@@ -92,7 +92,7 @@ function addProjectToFilterObject(
if (projectClientIndex !== -1) {
// client already exists in filter array
tempFilteredClients[projectClientIndex].projects.push({
tempFilteredClients[projectClientIndex]!.projects.push({
...project,
expanded: expanded,
tasks: filteredTasks,
@@ -119,7 +119,7 @@ function addProjectToFilterObject(
if (noClientIndex !== -1) {
// no client group already exists in filter array
tempFilteredClients[noClientIndex].projects.push({
tempFilteredClients[noClientIndex]!.projects.push({
...project,
expanded: expanded,
tasks: filteredTasks,
@@ -253,7 +253,7 @@ function isProjectSelected(project: Project) {
function initializeHighlightedItem() {
if (filteredProjects.value.length > 0) {
highlightedItemId.value = filteredProjects.value[0].id;
highlightedItemId.value = filteredProjects.value[0]!.id;
}
}
@@ -312,27 +312,27 @@ function moveHighlightUp() {
highlightedItemId.value = currentProjectWithTasks.id;
return;
}
highlightedItemId.value = currentProjectWithTasks.tasks[taskIndex - 1].id;
highlightedItemId.value = currentProjectWithTasks.tasks[taskIndex - 1]!.id;
}
}
if (currentHighlightedIndex === 0) {
// selected project is the first project in the list
// highlight the last project or the last task of the last project
const lastProject = filteredProjects.value[filteredProjects.value.length - 1];
const lastProject = filteredProjects.value[filteredProjects.value.length - 1]!;
if (lastProject.tasks.length > 0 && lastProject.expanded) {
// highlight last task of last project
highlightedItemId.value = lastProject.tasks[lastProject.tasks.length - 1].id;
highlightedItemId.value = lastProject.tasks[lastProject.tasks.length - 1]!.id;
} else {
highlightedItemId.value = filteredProjects.value[filteredProjects.value.length - 1].id;
highlightedItemId.value = filteredProjects.value[filteredProjects.value.length - 1]!.id;
}
} else {
// selected item is a project that is not the first project in the list
const previousProject = filteredProjects.value[currentHighlightedIndex - 1];
const previousProject = filteredProjects.value[currentHighlightedIndex - 1]!;
if (previousProject.tasks.length > 0 && previousProject.expanded) {
// highlight last task of previous project
highlightedItemId.value = previousProject.tasks[previousProject.tasks.length - 1].id;
highlightedItemId.value = previousProject.tasks[previousProject.tasks.length - 1]!.id;
} else {
highlightedItemId.value = filteredProjects.value[currentHighlightedIndex - 1].id;
highlightedItemId.value = filteredProjects.value[currentHighlightedIndex - 1]!.id;
}
}
}
@@ -361,33 +361,33 @@ function moveHighlightDown() {
const projectIndex = filteredProjects.value.indexOf(currentProjectWithTasks);
if (projectIndex === filteredProjects.value.length - 1) {
// highlight the first project if it was the last project
highlightedItemId.value = filteredProjects.value[0].id;
highlightedItemId.value = filteredProjects.value[0]!.id;
} else {
highlightedItemId.value = filteredProjects.value[projectIndex + 1].id;
highlightedItemId.value = filteredProjects.value[projectIndex + 1]!.id;
}
return;
}
highlightedItemId.value = currentProjectWithTasks.tasks[taskIndex + 1].id;
highlightedItemId.value = currentProjectWithTasks.tasks[taskIndex + 1]!.id;
}
}
if (currentHighlightedIndex === filteredProjects.value.length - 1) {
// selected project is the last project in the list
// highlight the first project or the last project of the last project
const lastProject = filteredProjects.value[filteredProjects.value.length - 1];
const lastProject = filteredProjects.value[filteredProjects.value.length - 1]!;
if (lastProject.tasks.length > 0 && lastProject.expanded) {
// highlight last task of last project
highlightedItemId.value = lastProject.tasks[0].id;
highlightedItemId.value = lastProject.tasks[0]!.id;
} else {
highlightedItemId.value = filteredProjects.value[0].id;
highlightedItemId.value = filteredProjects.value[0]!.id;
}
} else {
// selected item is a project that is not the last project in the list
const currentProjectWithTasks = filteredProjects.value[currentHighlightedIndex];
const currentProjectWithTasks = filteredProjects.value[currentHighlightedIndex]!;
if (currentProjectWithTasks.tasks.length > 0 && currentProjectWithTasks.expanded) {
// highlight last task of previous project
highlightedItemId.value = currentProjectWithTasks.tasks[0].id;
highlightedItemId.value = currentProjectWithTasks.tasks[0]!.id;
} else {
highlightedItemId.value = filteredProjects.value[currentHighlightedIndex + 1].id;
highlightedItemId.value = filteredProjects.value[currentHighlightedIndex + 1]!.id;
}
}
}
@@ -423,7 +423,7 @@ function expandProject() {
if (currentHighlightedIndex === -1) {
return;
}
const currentProject = filteredProjects.value[currentHighlightedIndex];
const currentProject = filteredProjects.value[currentHighlightedIndex]!;
currentProject.expanded = true;
}
@@ -434,7 +434,7 @@ function collapseProject() {
if (currentHighlightedIndex === -1) {
return;
}
const currentProject = filteredProjects.value[currentHighlightedIndex];
const currentProject = filteredProjects.value[currentHighlightedIndex]!;
currentProject.expanded = false;
}

View File

@@ -23,11 +23,11 @@ export const colors = [
];
export function getRandomColor() {
return colors[Math.floor(Math.random() * colors.length)];
return colors[Math.floor(Math.random() * colors.length)]!;
}
export function getRandomColorWithSeed(seed: string) {
const pseudoRandom = new Prando(seed);
const index = pseudoRandom.nextInt(0, colors.length - 1);
return colors[index];
return colors[index]!;
}

View File

@@ -14,8 +14,8 @@ export type NumberFormat =
export function formatNumber(value: number, format?: string): string {
// Convert to fixed 2 decimal places first
const parts = value.toFixed(2).split('.');
const wholePart = parts[0];
const decimalPart = parts[1];
const wholePart = parts[0] ?? '0';
const decimalPart = parts[1] ?? '00';
// Format the whole number part based on the format
let formattedWhole: string;

View File

@@ -107,7 +107,7 @@ export default class Prando {
* @return An item from the array.
*/
public nextArrayItem<T>(array: T[]): T {
return array[this.nextInt(0, array.length - 1)];
return array[this.nextInt(0, array.length - 1)] as T;
}
/**

View File

@@ -12,16 +12,16 @@ export function useSelectEvents<Type>(
const currentHightlightedIndex = filteredItems.value.indexOf(highlightedItem.value);
if (currentHightlightedIndex === 0) {
highlightedItemId.value = getKeyFromItem(
filteredItems.value[filteredItems.value.length - 1]
filteredItems.value[filteredItems.value.length - 1]!
);
} else {
highlightedItemId.value = getKeyFromItem(
filteredItems.value[currentHightlightedIndex - 1]
filteredItems.value[currentHightlightedIndex - 1]!
);
}
} else {
highlightedItemId.value = getKeyFromItem(
filteredItems.value[filteredItems.value.length - 1]
filteredItems.value[filteredItems.value.length - 1]!
);
}
}
@@ -30,14 +30,14 @@ export function useSelectEvents<Type>(
if (highlightedItem.value) {
const currentHightlightedIndex = filteredItems.value.indexOf(highlightedItem.value);
if (currentHightlightedIndex === filteredItems.value.length - 1) {
highlightedItemId.value = getKeyFromItem(filteredItems.value[0]);
highlightedItemId.value = getKeyFromItem(filteredItems.value[0]!);
} else {
highlightedItemId.value = getKeyFromItem(
filteredItems.value[currentHightlightedIndex + 1]
filteredItems.value[currentHightlightedIndex + 1]!
);
}
} else {
highlightedItemId.value = getKeyFromItem(filteredItems.value[0]);
highlightedItemId.value = getKeyFromItem(filteredItems.value[0]!);
}
}

View File

@@ -227,9 +227,9 @@ export function parseTimeInput(
if (HHMMSStimeRegex.test(input)) {
const match = input.match(HHMMSStimeRegex);
if (match) {
const hours = parseInt(match[1]);
const minutes = parseInt(match[2]);
const seconds = parseInt(match[3]);
const hours = parseInt(match[1]!);
const minutes = parseInt(match[2]!);
const seconds = parseInt(match[3]!);
return hours * 3600 + minutes * 60 + seconds;
}
}
@@ -239,8 +239,8 @@ export function parseTimeInput(
if (HHMMtimeRegex.test(input)) {
const match = input.match(HHMMtimeRegex);
if (match) {
const hours = parseInt(match[1]);
const minutes = parseInt(match[2]);
const hours = parseInt(match[1]!);
const minutes = parseInt(match[2]!);
return (hours * 60 + minutes) * 60;
}
}