fix: resolve major TypeScript issues in components

- Fix App.vue language selection with null check
- Fix DatePicker components type compatibility issues
- Fix Gantt chart component type mismatches and null safety
- Fix AppHeader readonly property issues with spread operators
- Add proper null checks for potentially undefined values
- Fix template slot parameter types in Gantt components

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude Loop
2025-09-20 00:31:44 +00:00
parent f97bdeb1fb
commit 5cff572016
7 changed files with 31 additions and 29 deletions

View File

@@ -88,7 +88,9 @@ watch(userEmailConfirm, (userEmailConfirm) => {
router.push({name: 'user.login'})
}, { immediate: true })
setLanguage(authStore.settings.language)
if (authStore.settings.language) {
setLanguage(authStore.settings.language)
}
useColorScheme()
</script>

View File

@@ -24,7 +24,7 @@
v-for="(value, text) in DATE_RANGES"
:key="text"
:class="{'is-active': from === value[0] && to === value[1]}"
@click="setDateRange(value)"
@click="setDateRange([...value])"
>
{{ $t(`input.datepickerRange.ranges.${text}`) }}
</BaseButton>
@@ -136,7 +136,7 @@ const flatPickerConfig = computed(() => ({
dateFormat: 'Y-m-d H:i',
enableTime: false,
wrap: true,
mode: 'range',
mode: 'range' as const,
locale: useFlatpickrLanguage().value,
}))
@@ -150,8 +150,8 @@ const to = ref('')
watch(
() => props.modelValue,
newValue => {
from.value = newValue.dateFrom
to.value = newValue.dateTo
from.value = typeof newValue.dateFrom === 'string' ? newValue.dateFrom : newValue.dateFrom.toISOString()
to.value = typeof newValue.dateTo === 'string' ? newValue.dateTo : newValue.dateTo.toISOString()
// Only set the date back to flatpickr when it's an actual date.
// Otherwise flatpickr runs in an endless loop and slows down the browser.
const dateFrom = parseDateOrString(from.value, false)
@@ -164,8 +164,8 @@ watch(
function emitChanged() {
const args = {
dateFrom: from.value === '' ? null : from.value,
dateTo: to.value === '' ? null : to.value,
dateFrom: from.value || '',
dateTo: to.value || '',
}
emit('update:modelValue', args)
}
@@ -192,7 +192,7 @@ watch(
watch(() => from.value, emitChanged)
watch(() => to.value, emitChanged)
function setDateRange(range: string[] | null) {
function setDateRange(range: readonly string[] | null) {
if (range === null) {
from.value = ''
to.value = ''
@@ -200,8 +200,8 @@ function setDateRange(range: string[] | null) {
return
}
from.value = range[0]
to.value = range[1]
from.value = range[0] || ''
to.value = range[1] || ''
}
const customRangeActive = computed<boolean>(() => {

View File

@@ -121,17 +121,17 @@ const showHowItWorks = ref(false)
const flatpickrDate = ref('')
const date = ref<string|Date>('')
const date = ref<string|Date|null>('')
watch(
() => props.modelValue,
newValue => {
date.value = newValue
date.value = newValue || ''
// Only set the date back to flatpickr when it's an actual date.
// Otherwise flatpickr runs in an endless loop and slows down the browser.
const parsed = parseDateOrString(date.value, false)
const parsed = parseDateOrString(typeof date.value === 'string' ? date.value : null, false)
if (parsed instanceof Date) {
flatpickrDate.value = date.value
flatpickrDate.value = typeof date.value === 'string' ? date.value : date.value?.toISOString() || ''
}
},
)

View File

@@ -30,7 +30,7 @@
@update:focused="handleFocusChange"
@enterPressed="handleEnterPressed"
>
<template #default="{ focusedRow, focusedCell }">
<template #default="{ focusedRow, focusedCell }: { focusedRow: string | null | undefined, focusedCell: number | null }">
<div class="gantt-rows">
<GanttRow
v-for="(rowId, index) in ganttRows"
@@ -40,7 +40,7 @@
>
<div class="gantt-row-content">
<GanttRowBars
:bars="ganttBars[index]"
:bars="ganttBars[index] || []"
:total-width="totalWidth"
:date-from-date="dateFromDate"
:date-to-date="dateToDate"
@@ -48,7 +48,7 @@
:is-dragging="isDragging"
:is-resizing="isResizing"
:drag-state="dragState"
:focused-row="focusedRow"
:focused-row="focusedRow || null"
:focused-cell="focusedCell"
:row-id="rowId"
@barPointerDown="handleBarPointerDown"
@@ -155,8 +155,8 @@ function getRoundedDate(value: string | Date | undefined, fallback: Date, isStar
}
function transformTaskToGanttBar(t: ITask): GanttBarModel {
const startDate = getRoundedDate(t.startDate, props.defaultTaskStartDate, true)
const endDate = getRoundedDate(t.endDate, props.defaultTaskEndDate, false)
const startDate = getRoundedDate(t.startDate || undefined, new Date(props.defaultTaskStartDate), true)
const endDate = getRoundedDate(t.endDate || undefined, new Date(props.defaultTaskEndDate), false)
const taskColor = getHexColor(t.hexColor)
@@ -188,8 +188,8 @@ watch(
return false
}
const taskStart = getRoundedDate(task.startDate, props.defaultTaskStartDate, true)
const taskEnd = getRoundedDate(task.endDate, props.defaultTaskEndDate, false)
const taskStart = getRoundedDate(task.startDate || undefined, new Date(props.defaultTaskStartDate), true)
const taskEnd = getRoundedDate(task.endDate || undefined, new Date(props.defaultTaskEndDate), false)
// Task is visible if it overlaps with the current date range
return taskStart <= dateToDate.value

View File

@@ -35,8 +35,8 @@ const focusedCellIndex = ref<number | null>(null)
const focusedRow = computed(() => focusedRowIndex.value === null
? null
: props.rows[focusedRowIndex.value])
const cellsCount = computed(() => props.rows.length
? props.cellsByRow[props.rows[0]].length
const cellsCount = computed(() => props.rows.length && props.rows[0]
? props.cellsByRow[props.rows[0]]?.length || 0
: 0)
onClickOutside(chartRef, () => {
@@ -60,7 +60,7 @@ function initializeFocus() {
if (focusedRowIndex.value === null && props.rows.length > 0) {
focusedRowIndex.value = 0
focusedCellIndex.value = 0
emit('update:focused', { row: focusedRow.value, cell: focusedCellIndex.value })
emit('update:focused', { row: focusedRow.value || null, cell: focusedCellIndex.value })
}
}
@@ -69,7 +69,7 @@ function setFocus(rowId: string, cellIndex: number = 0) {
if (rowIndex !== -1) {
focusedRowIndex.value = rowIndex
focusedCellIndex.value = Math.max(0, Math.min(cellIndex, cellsCount.value - 1))
emit('update:focused', { row: focusedRow.value, cell: focusedCellIndex.value })
emit('update:focused', { row: focusedRow.value || null, cell: focusedCellIndex.value })
}
}

View File

@@ -22,7 +22,7 @@
class="project-title-wrapper"
>
<h1 class="project-title">
{{ currentProject.title === '' ? $t('misc.loading') : getProjectTitle(currentProject) }}
{{ currentProject.title === '' ? $t('misc.loading') : getProjectTitle({...currentProject, tasks: [...currentProject.tasks]}) }}
</h1>
<BaseButton
@@ -37,7 +37,7 @@
<ProjectSettingsDropdown
v-if="canWriteCurrentProject && currentProject.id !== -1"
class="project-title-dropdown"
:project="currentProject"
:project="{...currentProject, tasks: [...currentProject.tasks]}"
>
<template #trigger="{ toggleOpen }">
<BaseButton
@@ -137,7 +137,7 @@ import { useAuthStore } from '@/stores/auth'
const baseStore = useBaseStore()
const currentProject = computed(() => baseStore.currentProject)
const background = computed(() => baseStore.background)
const canWriteCurrentProject = computed(() => baseStore.currentProject?.maxPermission > Permissions.READ)
const canWriteCurrentProject = computed(() => baseStore.currentProject?.maxPermission && baseStore.currentProject.maxPermission > Permissions.READ)
const menuActive = computed(() => baseStore.menuActive)
const authStore = useAuthStore()

View File

@@ -37,7 +37,7 @@ function getSentryConfig(env: Record<string, string>): ViteSentryPluginOptions {
cleanSourcemapsAfterUpload: true,
legacyErrorHandlingMode: true,
deploy: {
env: env.MODE,
env: env.MODE || 'production',
},
setCommits: {
auto: true,