fix: remove date-fns (#3039)
This removes date-fns and replaces it with the already used dayjs library. It does not make sense to have two libraries for the same purpose, and dayjs seems to be smaller and its translations are already integrated. Since we have to use dayjs because it is used by the gantt chart, this was the obvious way to go (instead of replacing dayjs with date-fns). Resolves https://github.com/go-vikunja/vikunja/issues/391 Reviewed-on: https://kolaente.dev/vikunja/vikunja/pulls/3039 Co-authored-by: kolaente <k@knt.li> Co-committed-by: kolaente <k@knt.li>
This commit is contained in:
parent
5cea469f8c
commit
021d71b90e
|
|
@ -1,4 +1,4 @@
|
|||
import {formatISO, format} from 'date-fns'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
import {createFakeUserAndLogin} from '../../support/authenticateUser'
|
||||
|
||||
|
|
@ -28,8 +28,8 @@ describe('Project View Gantt', () => {
|
|||
cy.visit('/projects/1/2')
|
||||
|
||||
cy.get('.g-timeunits-container')
|
||||
.should('contain', format(now, 'MMMM'))
|
||||
.should('contain', format(nextMonth, 'MMMM'))
|
||||
.should('contain', dayjs(now).format('MMMM'))
|
||||
.should('contain', dayjs(nextMonth).format('MMMM'))
|
||||
})
|
||||
|
||||
it('Shows tasks with dates', () => {
|
||||
|
|
@ -112,8 +112,8 @@ describe('Project View Gantt', () => {
|
|||
it('Should open a task when double clicked on it', () => {
|
||||
const now = new Date()
|
||||
const tasks = TaskFactory.create(1, {
|
||||
start_date: formatISO(now),
|
||||
end_date: formatISO(now.setDate(now.getDate() + 4)),
|
||||
start_date: dayjs(now).format(),
|
||||
end_date: dayjs(now.setDate(now.getDate() + 4)).format(),
|
||||
})
|
||||
cy.visit('/projects/1/2')
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {BucketFactory} from '../../factories/bucket'
|
|||
|
||||
import {TaskAttachmentFactory} from '../../factories/task_attachments'
|
||||
import {TaskReminderFactory} from '../../factories/task_reminders'
|
||||
import {createDefaultViews} from "../project/prepareProjects";
|
||||
import {createDefaultViews} from '../project/prepareProjects'
|
||||
import { TaskBucketFactory } from '../../factories/task_buckets'
|
||||
|
||||
function addLabelToTaskAndVerify(labelTitle: string) {
|
||||
|
|
@ -572,7 +572,7 @@ describe('Task', () => {
|
|||
const day = today.toLocaleString('default', {day: 'numeric'})
|
||||
const month = today.toLocaleString('default', {month: 'short'})
|
||||
const year = today.toLocaleString('default', {year: 'numeric'})
|
||||
const date = `${day} ${month} ${year}, 12:00:00`
|
||||
const date = `${month} ${day}, ${year} 12:00 PM`
|
||||
cy.get('.task-view .columns.details .column')
|
||||
.contains('Due Date')
|
||||
.get('.date-input .datepicker-popup')
|
||||
|
|
@ -615,7 +615,7 @@ describe('Task', () => {
|
|||
const day = today.toLocaleString('default', {day: 'numeric'})
|
||||
const month = today.toLocaleString('default', {month: 'short'})
|
||||
const year = today.toLocaleString('default', {year: 'numeric'})
|
||||
const date = `${day} ${month} ${year}, 12:00:00`
|
||||
const date = `${month} ${day}, ${year} 12:00 PM`
|
||||
cy.get('.task-view .columns.details .column')
|
||||
.contains('Due Date')
|
||||
.get('.date-input .datepicker-popup')
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@
|
|||
"blurhash": "2.0.5",
|
||||
"bulma-css-variables": "0.9.33",
|
||||
"change-case": "5.4.4",
|
||||
"date-fns": "4.1.0",
|
||||
"dayjs": "1.11.13",
|
||||
"dompurify": "3.2.3",
|
||||
"fast-deep-equal": "3.1.3",
|
||||
|
|
|
|||
|
|
@ -121,9 +121,6 @@ importers:
|
|||
change-case:
|
||||
specifier: 5.4.4
|
||||
version: 5.4.4
|
||||
date-fns:
|
||||
specifier: 4.1.0
|
||||
version: 4.1.0
|
||||
dayjs:
|
||||
specifier: 1.11.13
|
||||
version: 1.11.13
|
||||
|
|
@ -3430,9 +3427,6 @@ packages:
|
|||
resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
date-fns@4.1.0:
|
||||
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
||||
|
||||
dayjs@1.11.13:
|
||||
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
||||
|
||||
|
|
@ -10224,8 +10218,6 @@ snapshots:
|
|||
es-errors: 1.3.0
|
||||
is-data-view: 1.0.1
|
||||
|
||||
date-fns@4.1.0: {}
|
||||
|
||||
dayjs@1.11.13: {}
|
||||
|
||||
de-indent@1.0.2: {}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ const flatPickrDate = computed({
|
|||
}
|
||||
|
||||
if (date.value !== null) {
|
||||
const oldDate = formatDate(date.value, 'yyy-LL-dd H:mm')
|
||||
const oldDate = formatDate(date.value, 'YYYY-MM-DD h:m')
|
||||
if (oldDate === newValue) {
|
||||
return
|
||||
}
|
||||
|
|
@ -140,7 +140,7 @@ const flatPickrDate = computed({
|
|||
return ''
|
||||
}
|
||||
|
||||
return formatDate(date.value, 'yyy-LL-dd H:mm')
|
||||
return formatDate(date.value, 'YYYY-MM-DD h:m')
|
||||
},
|
||||
})
|
||||
|
||||
|
|
@ -208,7 +208,7 @@ function getWeekdayFromStringInterval(dateString: string) {
|
|||
const interval = calculateDayInterval(dateString)
|
||||
const newDate = new Date()
|
||||
newDate.setDate(newDate.getDate() + interval)
|
||||
return formatDate(newDate, 'E')
|
||||
return formatDate(newDate, 'ddd')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ import {getHexColor} from '@/models/task'
|
|||
|
||||
import {colorIsDark} from '@/helpers/color/colorIsDark'
|
||||
import {isoToKebabDate} from '@/helpers/time/isoToKebabDate'
|
||||
import {parseKebabDate} from '@/helpers/time/parseKebabDate'
|
||||
|
||||
import type {ITask, ITaskPartialWithId} from '@/modelTypes/ITask'
|
||||
import type {DateISO} from '@/types/DateISO'
|
||||
|
|
@ -181,8 +180,8 @@ async function updateGanttTask(e: {
|
|||
}) {
|
||||
emit('update:task', {
|
||||
id: Number(e.bar.ganttBarConfig.id),
|
||||
startDate: new Date(parseKebabDate(e.bar.startDate).setHours(0,0,0,0)),
|
||||
endDate: new Date(parseKebabDate(e.bar.endDate).setHours(23,59,0,0)),
|
||||
startDate: new Date((new Date(e.bar.startDate)).setHours(0,0,0,0)),
|
||||
endDate: new Date((new Date(e.bar.endDate)).setHours(23,59,0,0)),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
export const DATEFNS_DATE_FORMAT_KEBAB = 'yyyy-LL-dd' as const
|
||||
|
||||
export const SECONDS_A_MINUTE = 60
|
||||
export const SECONDS_A_HOUR = SECONDS_A_MINUTE * 60
|
||||
export const SECONDS_A_DAY = SECONDS_A_HOUR * 24
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
import {createDateFromString} from '@/helpers/time/createDateFromString'
|
||||
import {format, formatDistanceToNow} from 'date-fns'
|
||||
|
||||
// FIXME: support all locales and load dynamically
|
||||
import {enGB, de, fr, ru} from 'date-fns/locale'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
import {i18n} from '@/i18n'
|
||||
import {createSharedComposable} from '@vueuse/core'
|
||||
import {computed, toValue, type MaybeRefOrGetter} from 'vue'
|
||||
|
||||
const locales = {en: enGB, de, ch: de, fr, ru}
|
||||
|
||||
export function dateIsValid(date: Date | null) {
|
||||
if (date === null) {
|
||||
return false
|
||||
|
|
@ -18,35 +13,36 @@ export function dateIsValid(date: Date | null) {
|
|||
return date instanceof Date && !isNaN(date)
|
||||
}
|
||||
|
||||
export const formatDate = (date, f, locale = i18n.global.t('date.locale')) => {
|
||||
export const formatDate = (date: Date | string | null, f: string, locale = i18n.global.t('date.locale')) => {
|
||||
if (!dateIsValid(date)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
date = createDateFromString(date)
|
||||
|
||||
return date ? format(date, f, {locale: locales[locale]}) : ''
|
||||
return date
|
||||
? dayjs(date).locale(locale).format(f)
|
||||
: ''
|
||||
}
|
||||
|
||||
export function formatDateLong(date) {
|
||||
return formatDate(date, 'PPPPpppp')
|
||||
return formatDate(date, 'LLLL')
|
||||
}
|
||||
|
||||
export function formatDateShort(date) {
|
||||
return formatDate(date, 'PPpp')
|
||||
return formatDate(date, 'lll')
|
||||
}
|
||||
|
||||
export const formatDateSince = (date) => {
|
||||
export const formatDateSince = (date: Date | string | null, locale = i18n.global.t('date.locale')) => {
|
||||
if (!dateIsValid(date)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
date = createDateFromString(date)
|
||||
|
||||
return formatDistanceToNow(date, {
|
||||
locale: locales[i18n.global.t('date.locale')],
|
||||
addSuffix: true,
|
||||
})
|
||||
return date
|
||||
? dayjs(date).locale(locale).fromNow()
|
||||
: ''
|
||||
}
|
||||
|
||||
export function formatISO(date) {
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
import {parse} from 'date-fns'
|
||||
import {DATEFNS_DATE_FORMAT_KEBAB} from '@/constants/date'
|
||||
import type {DateKebab} from '@/types/DateKebab'
|
||||
|
||||
export function parseKebabDate(date: DateKebab): Date {
|
||||
return parse(date, DATEFNS_DATE_FORMAT_KEBAB, new Date())
|
||||
}
|
||||
|
|
@ -2,6 +2,14 @@ import {createI18n} from 'vue-i18n'
|
|||
import type {PluralizationRule} from 'vue-i18n'
|
||||
import langEN from './lang/en.json'
|
||||
|
||||
import localizedFormat from 'dayjs/plugin/localizedFormat'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import dayjs from 'dayjs'
|
||||
import {loadDayJsLocale} from '@/i18n/useDayjsLanguageSync.ts'
|
||||
|
||||
dayjs.extend(localizedFormat)
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
export const SUPPORTED_LOCALES = {
|
||||
'en': 'English',
|
||||
'de-DE': 'Deutsch',
|
||||
|
|
@ -85,6 +93,8 @@ export async function setLanguage(lang: SupportedLocale): Promise<SupportedLocal
|
|||
return setLanguage(getBrowserLanguage())
|
||||
}
|
||||
}
|
||||
|
||||
await loadDayJsLocale(lang)
|
||||
|
||||
i18n.global.locale.value = lang
|
||||
document.documentElement.lang = lang
|
||||
|
|
|
|||
|
|
@ -56,6 +56,14 @@ export const DAYJS_LANGUAGE_IMPORTS = {
|
|||
'ko-kr': () => import('dayjs/locale/ko'),
|
||||
} as Record<SupportedLocale, () => Promise<ILocale>>
|
||||
|
||||
export async function loadDayJsLocale(language: SupportedLocale) {
|
||||
if (language === 'en') {
|
||||
return
|
||||
}
|
||||
|
||||
await DAYJS_LANGUAGE_IMPORTS[language.toLowerCase()]()
|
||||
}
|
||||
|
||||
export function useDayjsLanguageSync(dayjsGlobal: typeof dayjs) {
|
||||
|
||||
const dayjsLanguageLoaded = ref(false)
|
||||
|
|
@ -70,7 +78,7 @@ export function useDayjsLanguageSync(dayjsGlobal: typeof dayjs) {
|
|||
if (dayjsLanguageLoaded.value) {
|
||||
return
|
||||
}
|
||||
await DAYJS_LANGUAGE_IMPORTS[currentLanguage.toLowerCase()]()
|
||||
await loadDayJsLocale(currentLanguage)
|
||||
dayjsGlobal.locale(dayjsLanguageCode)
|
||||
dayjsLanguageLoaded.value = true
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
/**
|
||||
* Date in Format 2022-12-10
|
||||
*/
|
||||
export type DateKebab = `${string}-${string}-${string}`
|
||||
|
|
@ -130,8 +130,8 @@ const pageTitle = computed(() => {
|
|||
return showAll.value
|
||||
? t('task.show.titleCurrent')
|
||||
: t('task.show.fromuntil', {
|
||||
from: formatDate(props.dateFrom, 'PPP'),
|
||||
until: formatDate(props.dateTo, 'PPP'),
|
||||
from: formatDate(props.dateFrom, 'LL'),
|
||||
until: formatDate(props.dateTo, 'LL'),
|
||||
})
|
||||
})
|
||||
const hasTasks = computed(() => tasks.value && tasks.value.length > 0)
|
||||
|
|
|
|||
Loading…
Reference in New Issue