mirror of
https://github.com/go-vikunja/vikunja.git
synced 2026-04-24 22:25:15 +00:00
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:
@@ -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>
|
||||
|
||||
|
||||
@@ -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>(() => {
|
||||
|
||||
@@ -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() || ''
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user