diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index 308cf9e905..d1d28c20be 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -52,7 +52,7 @@ import {computed, onMounted, onUnmounted, ref} from 'vue' import NotificationService from '@/services/notification' import BaseButton from '@/components/base/BaseButton.vue' import User from '@/components/misc/user.vue' -import { NOTIFICATION_NAMES as names, type INotification} from '@/models/notification' +import { NOTIFICATION_NAMES as names, type INotification} from '@/modelTypes/INotification' import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside' import {useStore} from '@/store' import {useRouter} from 'vue-router' diff --git a/src/components/tasks/partials/attachments.vue b/src/components/tasks/partials/attachments.vue index b5043eee95..70d6e5b1e3 100644 --- a/src/components/tasks/partials/attachments.vue +++ b/src/components/tasks/partials/attachments.vue @@ -49,7 +49,7 @@ /> - {{ a.file.getHumanSize() }} + {{ getHumanSize(a.file.size) }} {{ a.file.mime }} @@ -157,6 +157,7 @@ import {formatDate, formatDateSince, formatDateLong} from '@/helpers/time/format import BaseButton from '@/components/base/BaseButton' import type { IFile } from '@/models/file' +import { getHumanSize } from '@/helpers/getHumanSize' export default defineComponent({ name: 'attachments', @@ -231,6 +232,7 @@ export default defineComponent({ }) }, methods: { + getHumanSize, formatDate, formatDateSince, formatDateLong, diff --git a/src/components/tasks/partials/relatedTasks.vue b/src/components/tasks/partials/relatedTasks.vue index a46c4f6352..2e717fd952 100644 --- a/src/components/tasks/partials/relatedTasks.vue +++ b/src/components/tasks/partials/relatedTasks.vue @@ -144,7 +144,8 @@ import {defineComponent} from 'vue' import TaskService from '../../../services/task' import TaskModel from '../../../models/task' import TaskRelationService from '../../../services/taskRelation' -import TaskRelationModel, {RELATION_KINDS} from '@/models/taskRelation' +import TaskRelationModel from '@/models/taskRelation' +import { RELATION_KIND, RELATION_KINDS } from '@/types/IRelationKind' import BaseButton from '@/components/base/BaseButton.vue' import Multiselect from '@/components/input/multiselect.vue' @@ -158,7 +159,7 @@ export default defineComponent({ foundTasks: [], relationKinds: RELATION_KINDS, newTaskRelationTask: new TaskModel(), - newTaskRelationKind: 'related', + newTaskRelationKind: RELATION_KIND.RELATED, taskRelationService: new TaskRelationService(), showDeleteModal: false, relationToDelete: {}, diff --git a/src/components/tasks/partials/repeatAfter.vue b/src/components/tasks/partials/repeatAfter.vue index 4cb246276d..bf50384dcd 100644 --- a/src/components/tasks/partials/repeatAfter.vue +++ b/src/components/tasks/partials/repeatAfter.vue @@ -66,7 +66,10 @@ import {ref, reactive, watch, type PropType} from 'vue' import {useI18n} from 'vue-i18n' import {error} from '@/message' -import {TASK_REPEAT_MODES, type ITask, type RepeatAfter} from '@/models/task' + +import {TASK_REPEAT_MODES} from '@/types/IRepeatMode' +import type {IRepeatAfter} from '@/types/IRepeatAfter' +import type {ITask} from '@/modelTypes/ITask' const props = defineProps({ modelValue: { @@ -116,7 +119,7 @@ function updateData() { emit('change') } -function setRepeatAfter(amount: number, type: RepeatAfter['type']) { +function setRepeatAfter(amount: number, type: IRepeatAfter['type']) { Object.assign(repeatAfter, { amount, type}) updateData() } diff --git a/src/helpers/color/colorIsDark.ts b/src/helpers/color/colorIsDark.ts index 3ae8ff286c..5548dab99f 100644 --- a/src/helpers/color/colorIsDark.ts +++ b/src/helpers/color/colorIsDark.ts @@ -1,4 +1,4 @@ -export function colorIsDark(color) { +export function colorIsDark(color: string | undefined) { if (typeof color === 'undefined') { return true // Defaults to dark } diff --git a/src/helpers/getHumanSize.ts b/src/helpers/getHumanSize.ts new file mode 100644 index 0000000000..2744e1eb06 --- /dev/null +++ b/src/helpers/getHumanSize.ts @@ -0,0 +1,18 @@ +const SIZES = [ + 'B', + 'KB', + 'MB', + 'GB', + 'TB', + ] as const + +export function getHumanSize(inputSize: number) { + let iterator = 0 + let size = inputSize + while (size > 1024) { + size /= 1024 + iterator++ + } + + return Number(Math.round(Number(size + 'e2')) + 'e-2') + ' ' + SIZES[iterator] +} \ No newline at end of file diff --git a/src/modelSchema/common/repeats.ts b/src/modelSchema/common/repeats.ts new file mode 100644 index 0000000000..175b0c7277 --- /dev/null +++ b/src/modelSchema/common/repeats.ts @@ -0,0 +1,43 @@ +import { REPEAT_TYPES, type IRepeatAfter } from '@/types/IRepeatAfter' +import { nativeEnum, number, object, preprocess } from 'zod' + +export const RepeatsSchema = preprocess( + (repeats: unknown) => { + // Parses the "repeat after x seconds" from the task into a usable js object inside the task. + + if (typeof repeats !== 'number') { + return repeats + } + + const repeatAfterHours = (repeats / 60) / 60 + + const repeatAfter : IRepeatAfter = { + type: 'hours', + amount: repeatAfterHours, + } + + // if its dividable by 24, its something with days, otherwise hours + if (repeatAfterHours % 24 === 0) { + const repeatAfterDays = repeatAfterHours / 24 + if (repeatAfterDays % 7 === 0) { + repeatAfter.type = 'weeks' + repeatAfter.amount = repeatAfterDays / 7 + } else if (repeatAfterDays % 30 === 0) { + repeatAfter.type = 'months' + repeatAfter.amount = repeatAfterDays / 30 + } else if (repeatAfterDays % 365 === 0) { + repeatAfter.type = 'years' + repeatAfter.amount = repeatAfterDays / 365 + } else { + repeatAfter.type = 'days' + repeatAfter.amount = repeatAfterDays + } + } + + return repeatAfter + }, + object({ + type: nativeEnum(REPEAT_TYPES), + amount: number().int(), + }), +) \ No newline at end of file diff --git a/src/modelTypes/IAbstract.ts b/src/modelTypes/IAbstract.ts new file mode 100644 index 0000000000..7ca1142d61 --- /dev/null +++ b/src/modelTypes/IAbstract.ts @@ -0,0 +1,5 @@ +import type {Right} from '@/constants/rights' + +export interface IAbstract { + maxRight: Right | null // FIXME: should this be readonly? +} \ No newline at end of file diff --git a/src/modelTypes/IAttachment.ts b/src/modelTypes/IAttachment.ts new file mode 100644 index 0000000000..b1b279b611 --- /dev/null +++ b/src/modelTypes/IAttachment.ts @@ -0,0 +1,11 @@ +import type {IAbstract} from './IAbstract' +import type {IFile} from './IFile' +import type {IUser} from './IUser' + +export interface IAttachment extends IAbstract { + id: number + taskId: number + createdBy: IUser + file: IFile + created: Date +} \ No newline at end of file diff --git a/src/modelTypes/IAvatar.ts b/src/modelTypes/IAvatar.ts new file mode 100644 index 0000000000..ab681996a0 --- /dev/null +++ b/src/modelTypes/IAvatar.ts @@ -0,0 +1,7 @@ +import type {IAbstract} from './IAbstract' + +export type AvatarProvider = 'default' | 'initials' | 'gravatar' | 'marble' | 'upload' + +export interface IAvatar extends IAbstract { + avatarProvider: AvatarProvider +} \ No newline at end of file diff --git a/src/modelTypes/IBackgroundImage.ts b/src/modelTypes/IBackgroundImage.ts new file mode 100644 index 0000000000..311d7bc726 --- /dev/null +++ b/src/modelTypes/IBackgroundImage.ts @@ -0,0 +1,12 @@ +import type {IAbstract} from './IAbstract' + +export interface IBackgroundImage extends IAbstract { + id: number + url: string + thumb: string + info: { + author: string + authorName: string + } + blurHash: string +} \ No newline at end of file diff --git a/src/modelTypes/IBucket.ts b/src/modelTypes/IBucket.ts new file mode 100644 index 0000000000..e4c2c56856 --- /dev/null +++ b/src/modelTypes/IBucket.ts @@ -0,0 +1,17 @@ +import type {IAbstract} from './IAbstract' +import type {IUser} from './IUser' +import type {ITask} from './ITask' + +export interface IBucket extends IAbstract { + id: number + title: string + listId: number + limit: number + tasks: ITask[] + isDoneBucket: boolean + position: number + + createdBy: IUser + created: Date + updated: Date +} \ No newline at end of file diff --git a/src/modelTypes/ICaldavToken.ts b/src/modelTypes/ICaldavToken.ts new file mode 100644 index 0000000000..d7e1e68d59 --- /dev/null +++ b/src/modelTypes/ICaldavToken.ts @@ -0,0 +1,7 @@ +import type {IAbstract} from './IAbstract' + +export interface ICaldavToken extends IAbstract { + id: number; + + created: Date; +} \ No newline at end of file diff --git a/src/modelTypes/IEmailUpdate.ts b/src/modelTypes/IEmailUpdate.ts new file mode 100644 index 0000000000..fbb39c1b93 --- /dev/null +++ b/src/modelTypes/IEmailUpdate.ts @@ -0,0 +1,6 @@ +import type {IAbstract} from './IAbstract' + +export interface IEmailUpdate extends IAbstract { + newEmail: string + password: string +} \ No newline at end of file diff --git a/src/modelTypes/IFile.ts b/src/modelTypes/IFile.ts new file mode 100644 index 0000000000..70ae387395 --- /dev/null +++ b/src/modelTypes/IFile.ts @@ -0,0 +1,10 @@ +import type {IAbstract} from './IAbstract' + +export interface IFile extends IAbstract { + id: number + mime: string + name: string + size: number + + created: Date +} \ No newline at end of file diff --git a/src/modelTypes/ILabel.ts b/src/modelTypes/ILabel.ts new file mode 100644 index 0000000000..c7cbe778b6 --- /dev/null +++ b/src/modelTypes/ILabel.ts @@ -0,0 +1,15 @@ +import type {IAbstract} from './IAbstract' +import type {IUser} from './IUser' + +export interface ILabel extends IAbstract { + id: number + title: string + hexColor: string + description: string + createdBy: IUser + listId: number + textColor: string + + created: Date + updated: Date +} \ No newline at end of file diff --git a/src/modelTypes/ILabelTask.ts b/src/modelTypes/ILabelTask.ts new file mode 100644 index 0000000000..dcc2acefed --- /dev/null +++ b/src/modelTypes/ILabelTask.ts @@ -0,0 +1,7 @@ +import type {IAbstract} from './IAbstract' + +export interface ILabelTask extends IAbstract { + id: number + taskId: number + labelId: number +} \ No newline at end of file diff --git a/src/modelTypes/ILinkShare.ts b/src/modelTypes/ILinkShare.ts new file mode 100644 index 0000000000..d5eacb2412 --- /dev/null +++ b/src/modelTypes/ILinkShare.ts @@ -0,0 +1,17 @@ +import type {IAbstract} from './IAbstract' +import type {IUser} from './IUser' +import type { Right } from '@/constants/rights' + +export interface ILinkShare extends IAbstract { + id: number + hash: string + right: Right + sharedBy: IUser + sharingType: number // FIXME: use correct numbers + listId: number + name: string + password: string + + created: Date + updated: Date +} \ No newline at end of file diff --git a/src/modelTypes/IList.ts b/src/modelTypes/IList.ts new file mode 100644 index 0000000000..c51633b527 --- /dev/null +++ b/src/modelTypes/IList.ts @@ -0,0 +1,26 @@ +import type {IAbstract} from './IAbstract' +import type {ITask} from './ITask' +import type {IUser} from './IUser' +import type {ISubscription} from './ISubscription' +import type {INamespace} from './INamespace' + + +export interface IList extends IAbstract { + id: number + title: string + description: string + owner: IUser + tasks: ITask[] + namespaceId: INamespace['id'] + isArchived: boolean + hexColor: string + identifier: string + backgroundInformation: any // FIXME: improve type + isFavorite: boolean + subscription: ISubscription + position: number + backgroundBlurHash: string + + created: Date + updated: Date +} \ No newline at end of file diff --git a/src/modelTypes/IListDuplicate.ts b/src/modelTypes/IListDuplicate.ts new file mode 100644 index 0000000000..bdd924e345 --- /dev/null +++ b/src/modelTypes/IListDuplicate.ts @@ -0,0 +1,9 @@ +import type {IAbstract} from './IAbstract' +import type {IList} from './IList' +import type {INamespace} from './INamespace' + +export interface IListDuplicate extends IAbstract { + listId: number + namespaceId: INamespace['id'] + list: IList +} \ No newline at end of file diff --git a/src/modelTypes/INamespace.ts b/src/modelTypes/INamespace.ts new file mode 100644 index 0000000000..95ee4700a6 --- /dev/null +++ b/src/modelTypes/INamespace.ts @@ -0,0 +1,18 @@ +import type {IAbstract} from './IAbstract' +import type {IList} from './IList' +import type {IUser} from './IUser' +import type {ISubscription} from './ISubscription' + +export interface INamespace extends IAbstract { + id: number + title: string + description: string + owner: IUser + lists: IList[] + isArchived: boolean + hexColor: string + subscription: ISubscription + + created: Date + updated: Date +} \ No newline at end of file diff --git a/src/modelTypes/INotification.ts b/src/modelTypes/INotification.ts new file mode 100644 index 0000000000..52d6dc2a9a --- /dev/null +++ b/src/modelTypes/INotification.ts @@ -0,0 +1,51 @@ +import type {IAbstract} from './IAbstract' +import type {IUser} from './IUser' +import type {ITask} from './ITask' +import type {ITaskComment} from './ITaskComment' +import type {ITeam} from './ITeam' +import type { IList } from './IList' + +export const NOTIFICATION_NAMES = { + 'TASK_COMMENT': 'task.comment', + 'TASK_ASSIGNED': 'task.assigned', + 'TASK_DELETED': 'task.deleted', + 'LIST_CREATED': 'list.created', + 'TEAM_MEMBER_ADDED': 'team.member.added', +} as const + +interface Notification { + doer: IUser +} +interface NotificationTask extends Notification { + task: ITask + comment: ITaskComment +} + +interface NotificationAssigned extends Notification { + task: ITask + assignee: IUser +} + +interface NotificationDeleted extends Notification { + task: ITask +} + +interface NotificationCreated extends Notification { + task: ITask + list: IList +} + +interface NotificationMemberAdded extends Notification { + member: IUser + team: ITeam +} + +export interface INotification extends IAbstract { + id: number + name: string + notification: NotificationTask | NotificationAssigned | NotificationDeleted | NotificationCreated | NotificationMemberAdded + read: boolean + readAt: Date | null + + created: Date +} \ No newline at end of file diff --git a/src/modelTypes/IPasswordReset.ts b/src/modelTypes/IPasswordReset.ts new file mode 100644 index 0000000000..0b3d679ad4 --- /dev/null +++ b/src/modelTypes/IPasswordReset.ts @@ -0,0 +1,7 @@ +import type {IAbstract} from './IAbstract' + +export interface IPasswordReset extends IAbstract { + token: string + newPassword: string + email: string +} \ No newline at end of file diff --git a/src/modelTypes/IPasswordUpdate.ts b/src/modelTypes/IPasswordUpdate.ts new file mode 100644 index 0000000000..003b43b8d4 --- /dev/null +++ b/src/modelTypes/IPasswordUpdate.ts @@ -0,0 +1,6 @@ +import type {IAbstract} from './IAbstract' + +export interface IPasswordUpdate extends IAbstract { + newPassword: string + oldPassword: string +} \ No newline at end of file diff --git a/src/modelTypes/ISavedFilter.ts b/src/modelTypes/ISavedFilter.ts new file mode 100644 index 0000000000..5f206efa9d --- /dev/null +++ b/src/modelTypes/ISavedFilter.ts @@ -0,0 +1,14 @@ +import type {IAbstract} from './IAbstract' +import type {IUser} from './IUser' +import type {IFilter} from '@/types/IFilter' + +export interface ISavedFilter extends IAbstract { + id: number + title: string + description: string + filters: IFilter + + owner: IUser + created: Date + updated: Date +} \ No newline at end of file diff --git a/src/modelTypes/ISubscription.ts b/src/modelTypes/ISubscription.ts new file mode 100644 index 0000000000..51dbfbcfbe --- /dev/null +++ b/src/modelTypes/ISubscription.ts @@ -0,0 +1,11 @@ +import type {IAbstract} from './IAbstract' +import type {IUser} from './IUser' + +export interface ISubscription extends IAbstract { + id: number + entity: string // FIXME: correct type? + entityId: number // FIXME: correct type? + user: IUser + + created: Date +} \ No newline at end of file diff --git a/src/modelTypes/ITask.ts b/src/modelTypes/ITask.ts new file mode 100644 index 0000000000..86bae8c2a3 --- /dev/null +++ b/src/modelTypes/ITask.ts @@ -0,0 +1,50 @@ +import type { Priority } from '@/constants/priorities' + +import type {IAbstract} from './IAbstract' +import type {IUser} from './IUser' +import type {ILabel} from './ILabel' +import type {IAttachment} from './IAttachment' +import type {ISubscription} from './ISubscription' +import type {IList} from './IList' +import type {IBucket} from './IBucket' + +import type {IRelationKind} from '@/types/IRelationKind' +import type {IRepeatAfter} from '@/types/IRepeatAfter' +import type {IRepeatMode} from '@/types/IRepeatMode' +export interface ITask extends IAbstract { + id: number + title: string + description: string + done: boolean + doneAt: Date | null + priority: Priority + labels: ILabel[] + assignees: IUser[] + + dueDate: Date | null + startDate: Date | null + endDate: Date | null + repeatAfter: number | IRepeatAfter + repeatFromCurrentDate: boolean + repeatMode: IRepeatMode + reminderDates: Date[] + parentTaskId: ITask['id'] + hexColor: string + percentDone: number + relatedTasks: Partial>, + attachments: IAttachment[] + identifier: string + index: number + isFavorite: boolean + subscription: ISubscription + + position: number + kanbanPosition: number + + createdBy: IUser + created: Date + updated: Date + + listId: IList['id'] // Meta, only used when creating a new task + bucketId: IBucket['id'] +} \ No newline at end of file diff --git a/src/modelTypes/ITaskAssignee.ts b/src/modelTypes/ITaskAssignee.ts new file mode 100644 index 0000000000..a508e4b866 --- /dev/null +++ b/src/modelTypes/ITaskAssignee.ts @@ -0,0 +1,9 @@ +import type {IAbstract} from './IAbstract' +import type {ITask} from './ITask' +import type {IUser} from './IUser' + +export interface ITaskAssignee extends IAbstract { + created: Date + userId: IUser['id'] + taskId: ITask['id'] +} \ No newline at end of file diff --git a/src/modelTypes/ITaskComment.ts b/src/modelTypes/ITaskComment.ts new file mode 100644 index 0000000000..4246ab13dc --- /dev/null +++ b/src/modelTypes/ITaskComment.ts @@ -0,0 +1,13 @@ +import type {IAbstract} from './IAbstract' +import type {IUser} from './IUser' +import type {ITask} from './ITask' + +export interface ITaskComment extends IAbstract { + id: number + taskId: ITask['id'] + comment: string + author: IUser + + created: Date + updated: Date +} \ No newline at end of file diff --git a/src/modelTypes/ITaskRelation.ts b/src/modelTypes/ITaskRelation.ts new file mode 100644 index 0000000000..df286f5c00 --- /dev/null +++ b/src/modelTypes/ITaskRelation.ts @@ -0,0 +1,15 @@ +import type {IAbstract} from './IAbstract' +import type {IUser} from './IUser' +import type {ITask} from './ITask' + +import type {IRelationKind} from '@/types/IRelationKind' + +export interface ITaskRelation extends IAbstract { + id: number + otherTaskId: ITask['id'] + taskId: ITask['id'] + relationKind: IRelationKind + + createdBy: IUser + created: Date +} \ No newline at end of file diff --git a/src/modelTypes/ITeam.ts b/src/modelTypes/ITeam.ts new file mode 100644 index 0000000000..cd5a7dc731 --- /dev/null +++ b/src/modelTypes/ITeam.ts @@ -0,0 +1,16 @@ +import type {IAbstract} from './IAbstract' +import type {IUser} from './IUser' +import type {ITeamMember} from './ITeamMember' +import type {Right} from '@/constants/rights' + +export interface ITeam extends IAbstract { + id: number + name: string + description: string + members: ITeamMember[] + right: Right + + createdBy: IUser + created: Date + updated: Date +} \ No newline at end of file diff --git a/src/modelTypes/ITeamList.ts b/src/modelTypes/ITeamList.ts new file mode 100644 index 0000000000..a1abd692d0 --- /dev/null +++ b/src/modelTypes/ITeamList.ts @@ -0,0 +1,6 @@ +import type {ITeamShareBase} from './ITeamShareBase' +import type {IList} from './IList' + +export interface ITeamList extends ITeamShareBase { + listId: IList['id'] +} \ No newline at end of file diff --git a/src/modelTypes/ITeamMember.ts b/src/modelTypes/ITeamMember.ts new file mode 100644 index 0000000000..62a1d91ba2 --- /dev/null +++ b/src/modelTypes/ITeamMember.ts @@ -0,0 +1,7 @@ +import type {IUser} from './IUser' +import type {IList} from './IList' + +export interface ITeamMember extends IUser { + admin: boolean + teamId: IList['id'] +} diff --git a/src/modelTypes/ITeamNamespace.ts b/src/modelTypes/ITeamNamespace.ts new file mode 100644 index 0000000000..e66a98bb68 --- /dev/null +++ b/src/modelTypes/ITeamNamespace.ts @@ -0,0 +1,6 @@ +import type {ITeamShareBase} from './ITeamShareBase' +import type {INamespace} from './INamespace' + +export interface ITeamNamespace extends ITeamShareBase { + namespaceId: INamespace['id'] +} \ No newline at end of file diff --git a/src/modelTypes/ITeamShareBase.ts b/src/modelTypes/ITeamShareBase.ts new file mode 100644 index 0000000000..793b88945f --- /dev/null +++ b/src/modelTypes/ITeamShareBase.ts @@ -0,0 +1,11 @@ +import type {IAbstract} from './IAbstract' +import type {ITeam} from './ITeam' +import type {Right} from '@/constants/rights' + +export interface ITeamShareBase extends IAbstract { + teamId: ITeam['id'] + right: Right + + created: Date + updated: Date +} \ No newline at end of file diff --git a/src/modelTypes/ITotp.ts b/src/modelTypes/ITotp.ts new file mode 100644 index 0000000000..8c2147bba1 --- /dev/null +++ b/src/modelTypes/ITotp.ts @@ -0,0 +1,7 @@ +import type {IAbstract} from './IAbstract' + +export interface ITotp extends IAbstract { + secret: string + enabled: boolean + url: string +} \ No newline at end of file diff --git a/src/modelTypes/IUser.ts b/src/modelTypes/IUser.ts new file mode 100644 index 0000000000..d2ee19ea82 --- /dev/null +++ b/src/modelTypes/IUser.ts @@ -0,0 +1,13 @@ +import type {IAbstract} from './IAbstract' +import type {IUserSettings} from './IUserSettings' + +export interface IUser extends IAbstract { + id: number + email: string + username: string + name: string + + created: Date + updated: Date + settings: IUserSettings +} \ No newline at end of file diff --git a/src/modelTypes/IUserList.ts b/src/modelTypes/IUserList.ts new file mode 100644 index 0000000000..20787db7ff --- /dev/null +++ b/src/modelTypes/IUserList.ts @@ -0,0 +1,6 @@ +import type {IUserShareBase} from './IUserShareBase' +import type {IList} from './IList' + +export interface IUserList extends IUserShareBase { + listId: IList['id'] +} \ No newline at end of file diff --git a/src/modelTypes/IUserNamespace.ts b/src/modelTypes/IUserNamespace.ts new file mode 100644 index 0000000000..e2bd1b468e --- /dev/null +++ b/src/modelTypes/IUserNamespace.ts @@ -0,0 +1,6 @@ +import type {IUserShareBase} from './IUserShareBase' +import type {INamespace} from './INamespace' + +export interface IUserNamespace extends IUserShareBase { + namespaceId: INamespace['id'] +} \ No newline at end of file diff --git a/src/modelTypes/IUserSettings.ts b/src/modelTypes/IUserSettings.ts new file mode 100644 index 0000000000..9550e1e676 --- /dev/null +++ b/src/modelTypes/IUserSettings.ts @@ -0,0 +1,14 @@ + +import type {IAbstract} from './IAbstract' +import type {IList} from './IList' + +export interface IUserSettings extends IAbstract { + name: string + emailRemindersEnabled: boolean + discoverableByName: boolean + discoverableByEmail: boolean + overdueTasksRemindersEnabled: boolean + defaultListId: undefined | IList['id'] + weekStart: 0 | 1 | 2 | 3 | 4 | 5 | 6 + timezone: string +} \ No newline at end of file diff --git a/src/modelTypes/IUserShareBase.ts b/src/modelTypes/IUserShareBase.ts new file mode 100644 index 0000000000..cc23a2be00 --- /dev/null +++ b/src/modelTypes/IUserShareBase.ts @@ -0,0 +1,11 @@ +import type {IAbstract} from './IAbstract' +import type {IUser} from './IUser' +import type {Right} from '@/constants/rights' + +export interface IUserShareBase extends IAbstract { + userId: IUser['id'] + right: Right + + created: Date + updated: Date +} \ No newline at end of file diff --git a/src/models/abstractModel.ts b/src/models/abstractModel.ts index f859c361da..8e0605e525 100644 --- a/src/models/abstractModel.ts +++ b/src/models/abstractModel.ts @@ -1,13 +1,11 @@ import {objectToCamelCase} from '@/helpers/case' import {omitBy, isNil} from '@/helpers/utils' import type {Right} from '@/constants/rights' - -export interface IAbstract { - maxRight: Right | null // FIXME: should this be readonly? -} +import type {IAbstract} from '@/modelTypes/IAbstract' export default abstract class AbstractModel implements IAbstract { + /** * The max right the user has on this object, as returned by the x-max-right header from the api. */ diff --git a/src/models/attachment.ts b/src/models/attachment.ts index 074d61b658..694609725b 100644 --- a/src/models/attachment.ts +++ b/src/models/attachment.ts @@ -1,14 +1,9 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import UserModel, {type IUser} from './user' -import FileModel, {type IFile} from './file' - -export interface IAttachment extends IAbstract { - id: number - taskId: number - createdBy: IUser - file: IFile - created: Date -} +import AbstractModel from './abstractModel' +import UserModel from './user' +import FileModel from './file' +import type { IUser } from '@/modelTypes/IUser' +import type { IFile } from '@/modelTypes/IFile' +import type { IAttachment } from '@/modelTypes/IAttachment' export default class AttachmentModel extends AbstractModel implements IAttachment { id = 0 diff --git a/src/models/avatar.ts b/src/models/avatar.ts index daf221c0af..06f484fce3 100644 --- a/src/models/avatar.ts +++ b/src/models/avatar.ts @@ -1,13 +1,8 @@ -import AbstractModel, { type IAbstract } from './abstractModel' - -export type AvatarProvider = 'default' | 'initials' | 'gravatar' | 'marble' | 'upload' - -export interface IAvatar extends IAbstract { - avatarProvider: AvatarProvider -} +import AbstractModel from './abstractModel' +import type { IAvatar } from '@/modelTypes/IAvatar' export default class AvatarModel extends AbstractModel implements IAvatar { - avatarProvider: AvatarProvider = 'default' + avatarProvider: IAvatar['avatarProvider'] = 'default' constructor(data: Partial) { super() diff --git a/src/models/backgroundImage.ts b/src/models/backgroundImage.ts index 137c83836e..8c1a213411 100644 --- a/src/models/backgroundImage.ts +++ b/src/models/backgroundImage.ts @@ -1,15 +1,5 @@ -import AbstractModel, { type IAbstract } from './abstractModel' - -export interface IBackgroundImage extends IAbstract { - id: number - url: string - thumb: string - info: { - author: string - authorName: string - } - blurHash: string -} +import AbstractModel from './abstractModel' +import type {IBackgroundImage} from '@/modelTypes/IBackgroundImage' export default class BackgroundImageModel extends AbstractModel implements IBackgroundImage { id = 0 diff --git a/src/models/bucket.ts b/src/models/bucket.ts index 94f6c2d08d..3394583c40 100644 --- a/src/models/bucket.ts +++ b/src/models/bucket.ts @@ -1,20 +1,10 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import UserModel, { type IUser } from './user' -import TaskModel, { type ITask } from './task' +import AbstractModel from './abstractModel' +import UserModel from './user' +import TaskModel from './task' -export interface IBucket extends IAbstract { - id: number - title: string - listId: number - limit: number - tasks: ITask[] - isDoneBucket: boolean - position: number - - createdBy: IUser - created: Date - updated: Date -} +import type {IBucket} from '@/modelTypes/IBucket' +import type {ITask} from '@/modelTypes/ITask' +import type {IUser} from '@/modelTypes/IUser' export default class BucketModel extends AbstractModel implements IBucket { id = 0 diff --git a/src/models/caldavToken.ts b/src/models/caldavToken.ts index 4a4d4c4daf..bc904c4772 100644 --- a/src/models/caldavToken.ts +++ b/src/models/caldavToken.ts @@ -1,15 +1,12 @@ -import AbstractModel, { type IAbstract } from './abstractModel' +import AbstractModel from './abstractModel' -export interface ICaldavToken extends IAbstract { - id: number; - created: Date; -} +import type {ICaldavToken} from '@/modelTypes/ICaldavToken' export default class CaldavTokenModel extends AbstractModel implements ICaldavToken { id: number created: Date - constructor(data? : Partial) { + constructor(data: Partial) { super() this.assignData(data) diff --git a/src/models/emailUpdate.ts b/src/models/emailUpdate.ts index 2f8c9a853c..aece407f11 100644 --- a/src/models/emailUpdate.ts +++ b/src/models/emailUpdate.ts @@ -1,9 +1,6 @@ -import AbstractModel, { type IAbstract } from './abstractModel' +import AbstractModel from './abstractModel' -interface IEmailUpdate extends IAbstract { - newEmail: string - password: string -} +import type {IEmailUpdate} from '@/modelTypes/IEmailUpdate' export default class EmailUpdateModel extends AbstractModel implements IEmailUpdate { newEmail = '' diff --git a/src/models/file.ts b/src/models/file.ts index ba5950c7b2..cb17d51514 100644 --- a/src/models/file.ts +++ b/src/models/file.ts @@ -1,12 +1,5 @@ -import AbstractModel, { type IAbstract } from './abstractModel' - -export interface IFile extends IAbstract { - id: number - mime: string - name: string - size: number - created: Date -} +import AbstractModel from './abstractModel' +import type {IFile} from '@/modelTypes/IFile' export default class FileModel extends AbstractModel implements IFile { id = 0 @@ -21,23 +14,4 @@ export default class FileModel extends AbstractModel implements IFile { this.created = new Date(this.created) } - - getHumanSize() { - const sizes = { - 0: 'B', - 1: 'KB', - 2: 'MB', - 3: 'GB', - 4: 'TB', - } - - let it = 0 - let size = this.size - while (size > 1024) { - size /= 1024 - it++ - } - - return Number(Math.round(size + 'e2') + 'e-2') + ' ' + sizes[it] - } } diff --git a/src/models/label.ts b/src/models/label.ts index 5b3659b70b..1e14cf8209 100644 --- a/src/models/label.ts +++ b/src/models/label.ts @@ -1,22 +1,13 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import UserModel, { type IUser } from './user' +import AbstractModel from './abstractModel' +import UserModel from './user' + +import type {ILabel} from '@/modelTypes/ILabel' +import type {IUser} from '@/modelTypes/IUser' + import {colorIsDark} from '@/helpers/color/colorIsDark' const DEFAULT_LABEL_BACKGROUND_COLOR = 'e8e8e8' -export interface ILabel extends IAbstract { - id: number - title: string - hexColor: string - description: string - createdBy: IUser - listId: number - textColor: string - - created: Date - updated: Date -} - export default class LabelModel extends AbstractModel implements ILabel { id = 0 title = '' diff --git a/src/models/labelTask.ts b/src/models/labelTask.ts index 8223edb4f2..b1e068224a 100644 --- a/src/models/labelTask.ts +++ b/src/models/labelTask.ts @@ -1,10 +1,6 @@ -import AbstractModel, { type IAbstract } from './abstractModel' +import AbstractModel from './abstractModel' -export interface ILabelTask extends IAbstract { - id: number - taskId: number - labelId: number -} +import type { ILabelTask } from '@/modelTypes/ILabelTask' export default class LabelTask extends AbstractModel implements ILabelTask { id = 0 diff --git a/src/models/linkShare.ts b/src/models/linkShare.ts index c7df693b0d..24aa8779cc 100644 --- a/src/models/linkShare.ts +++ b/src/models/linkShare.ts @@ -1,19 +1,9 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import UserModel, { type IUser } from './user' -import {RIGHTS, type Right} from '@/constants/rights' +import AbstractModel from './abstractModel' +import UserModel from './user' -export interface ILinkShare extends IAbstract { - id: number - hash: string - right: Right - sharedBy: IUser - sharingType: number // FIXME: use correct numbers - listId: number - name: string - password: string - created: Date - updated: Date -} +import {RIGHTS, type Right} from '@/constants/rights' +import type {ILinkShare} from '@/modelTypes/ILinkShare' +import type {IUser} from '@/modelTypes/IUser' export default class LinkShareModel extends AbstractModel implements ILinkShare { id = 0 diff --git a/src/models/list.ts b/src/models/list.ts index 7ef058c452..02387f18e9 100644 --- a/src/models/list.ts +++ b/src/models/list.ts @@ -1,31 +1,16 @@ -import AbstractModel, { type IAbstract } from '@/models/abstractModel' -import TaskModel, { type ITask } from '@/models/task' -import UserModel, { type IUser } from '@/models/user' -import SubscriptionModel, { type ISubscription } from '@/models/subscription' -import type { INamespace } from '@/models/namespace' +import AbstractModel from './abstractModel' +import TaskModel from '@/models/task' +import UserModel from '@/models/user' +import SubscriptionModel from '@/models/subscription' + +import type {IList} from '@/modelTypes/IList' +import type {IUser} from '@/modelTypes/IUser' +import type {ITask} from '@/modelTypes/ITask' +import type {INamespace} from '@/modelTypes/INamespace' +import type {ISubscription} from '@/modelTypes/ISubscription' import {getSavedFilterIdFromListId} from '@/helpers/savedFilter' -export interface IList extends IAbstract { - id: number - title: string - description: string - owner: IUser - tasks: ITask[] - namespaceId: INamespace['id'] - isArchived: boolean - hexColor: string - identifier: string - backgroundInformation: any // FIXME: improve type - isFavorite: boolean - subscription: ISubscription - position: number - backgroundBlurHash: string - - created: Date - updated: Date -} - export default class ListModel extends AbstractModel implements IList { id = 0 title = '' diff --git a/src/models/listDuplicateModel.ts b/src/models/listDuplicateModel.ts index 4d8faf1f4c..8ed2ae74d5 100644 --- a/src/models/listDuplicateModel.ts +++ b/src/models/listDuplicateModel.ts @@ -1,12 +1,9 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import ListModel, { type IList } from './list' -import type { INamespace } from './namespace' +import AbstractModel from './abstractModel' +import ListModel from './list' -export interface IListDuplicate extends IAbstract { - listId: number - namespaceId: INamespace['id'] - list: IList -} +import type {IListDuplicate} from '@/modelTypes/IListDuplicate' +import type {INamespace} from '@/modelTypes/INamespace' +import type {IList} from '@/modelTypes/IList' export default class ListDuplicateModel extends AbstractModel implements IListDuplicate { listId = 0 diff --git a/src/models/namespace.ts b/src/models/namespace.ts index f1962f1aff..dade605e8a 100644 --- a/src/models/namespace.ts +++ b/src/models/namespace.ts @@ -1,21 +1,12 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import ListModel, { type IList } from './list' -import UserModel, { type IUser } from './user' -import SubscriptionModel, { type ISubscription } from '@/models/subscription' +import AbstractModel from './abstractModel' +import ListModel from './list' +import UserModel from './user' +import SubscriptionModel from '@/models/subscription' -export interface INamespace extends IAbstract { - id: number - title: string - description: string - owner: IUser - lists: IList[] - isArchived: boolean - hexColor: string - subscription: ISubscription - - created: Date - updated: Date -} +import type {INamespace} from '@/modelTypes/INamespace' +import type {IUser} from '@/modelTypes/IUser' +import type {IList} from '@/modelTypes/IList' +import type {ISubscription} from '@/modelTypes/ISubscription' export default class NamespaceModel extends AbstractModel implements INamespace { id = 0 diff --git a/src/models/notification.ts b/src/models/notification.ts index bd9c872761..a1fc44ad57 100644 --- a/src/models/notification.ts +++ b/src/models/notification.ts @@ -1,60 +1,17 @@ -import AbstractModel, { type IAbstract } from '@/models/abstractModel' +import AbstractModel from './abstractModel' import {parseDateOrNull} from '@/helpers/parseDateOrNull' -import UserModel, { type IUser } from '@/models/user' -import TaskModel, { type ITask } from '@/models/task' -import TaskCommentModel, { type ITaskComment } from '@/models/taskComment' -import ListModel, { type IList } from '@/models/list' -import TeamModel, { type ITeam } from '@/models/team' +import UserModel from '@/models/user' +import TaskModel from '@/models/task' +import TaskCommentModel from '@/models/taskComment' +import ListModel from '@/models/list' +import TeamModel from '@/models/team' -export const NOTIFICATION_NAMES = { - 'TASK_COMMENT': 'task.comment', - 'TASK_ASSIGNED': 'task.assigned', - 'TASK_DELETED': 'task.deleted', - 'LIST_CREATED': 'list.created', - 'TEAM_MEMBER_ADDED': 'team.member.added', -} as const - -interface Notification { - doer: IUser -} -interface NotificationTask extends Notification { - task: ITask - comment: ITaskComment -} - -interface NotificationAssigned extends Notification { - task: ITask - assignee: IUser -} - -interface NotificationDeleted extends Notification { - task: ITask -} - -interface NotificationCreated extends Notification { - task: ITask - list: IList -} - -interface NotificationMemberAdded extends Notification { - member: IUser - team: ITeam -} - -export interface INotification extends IAbstract { - id: number - name: string - notification: NotificationTask | NotificationAssigned | NotificationDeleted | NotificationCreated | NotificationMemberAdded - read: boolean - readAt: Date | null - - created: Date -} +import {NOTIFICATION_NAMES, type INotification} from '@/modelTypes/INotification' export default class NotificationModel extends AbstractModel implements INotification { id = 0 name = '' - notification: NotificationTask | NotificationAssigned | NotificationDeleted | NotificationCreated | NotificationMemberAdded = null + notification: INotification['notification'] = null read = false readAt: Date | null = null diff --git a/src/models/passwordReset.ts b/src/models/passwordReset.ts index e982f7cd73..5140063f81 100644 --- a/src/models/passwordReset.ts +++ b/src/models/passwordReset.ts @@ -1,10 +1,6 @@ -import AbstractModel, { type IAbstract } from './abstractModel' +import AbstractModel from './abstractModel' -export interface IPasswordReset extends IAbstract { - token: string - newPassword: string - email: string -} +import type {IPasswordReset} from '@/modelTypes/IPasswordReset' export default class PasswordResetModel extends AbstractModel implements IPasswordReset { token = '' diff --git a/src/models/passwordUpdate.ts b/src/models/passwordUpdate.ts index 1548ccb9b0..702fcd50fd 100644 --- a/src/models/passwordUpdate.ts +++ b/src/models/passwordUpdate.ts @@ -1,9 +1,6 @@ -import AbstractModel, { type IAbstract } from '@/models/abstractModel' +import AbstractModel from './abstractModel' -export interface IPasswordUpdate extends IAbstract { - newPassword: string - oldPassword: string -} +import type {IPasswordUpdate} from '@/modelTypes/IPasswordUpdate' export default class PasswordUpdateModel extends AbstractModel implements IPasswordUpdate { newPassword = '' diff --git a/src/models/savedFilter.ts b/src/models/savedFilter.ts index 8749d03594..c432014ffe 100644 --- a/src/models/savedFilter.ts +++ b/src/models/savedFilter.ts @@ -1,38 +1,14 @@ -import AbstractModel, { type IAbstract } from '@/models/abstractModel' -import UserModel, { type IUser } from '@/models/user' +import AbstractModel from './abstractModel' +import UserModel from '@/models/user' -export interface ISavedFilter extends IAbstract { - id: number - title: string - description: string - filters: { - sortBy: ('done' | 'id')[] - orderBy: ('asc' | 'desc')[] - filterBy: 'done'[] - filterValue: 'false'[] - filterComparator: 'equals'[] - filterConcat: 'and' - filterIncludeNulls: boolean - } - - owner: IUser - created: Date - updated: Date -} +import type {ISavedFilter} from '@/modelTypes/ISavedFilter' +import type {IUser} from '@/modelTypes/IUser' export default class SavedFilterModel extends AbstractModel implements ISavedFilter { id = 0 title = '' description = '' - filters: { - sortBy: ('done' | 'id')[] - orderBy: ('asc' | 'desc')[] - filterBy: 'done'[] - filterValue: 'false'[] - filterComparator: 'equals'[] - filterConcat: 'and' - filterIncludeNulls: boolean - } = { + filters: ISavedFilter['filters'] = { sortBy: ['done', 'id'], orderBy: ['asc', 'desc'], filterBy: ['done'], diff --git a/src/models/subscription.ts b/src/models/subscription.ts index 3ae79dd2e2..77ae3dec81 100644 --- a/src/models/subscription.ts +++ b/src/models/subscription.ts @@ -1,14 +1,8 @@ -import AbstractModel, { type IAbstract } from '@/models/abstractModel' -import UserModel, { type IUser } from '@/models/user' +import AbstractModel from './abstractModel' +import UserModel from '@/models/user' -export interface ISubscription extends IAbstract { - id: number - entity: string // FIXME: correct type? - entityId: number // FIXME: correct type? - user: IUser - - created: Date -} +import type {ISubscription} from '@/modelTypes/ISubscription' +import type {IUser} from '@/modelTypes/IUser' export default class SubscriptionModel extends AbstractModel implements ISubscription { id = 0 diff --git a/src/models/task.ts b/src/models/task.ts index e3c03b13d5..e8dafdf1c2 100644 --- a/src/models/task.ts +++ b/src/models/task.ts @@ -1,63 +1,35 @@ + import { PRIORITIES, type Priority } from '@/constants/priorities' -import AbstractModel, { type IAbstract } from '@/models/abstractModel' -import UserModel, { type IUser } from '@/models/user' -import LabelModel, { type ILabel } from '@/models/label' -import AttachmentModel, {type IAttachment} from '@/models/attachment' -import SubscriptionModel, { type ISubscription } from '@/models/subscription' -import type { IList } from '@/models/list' -import type {IRepeats} from '@/types/IRepeats' +import type {ITask} from '@/modelTypes/ITask' +import type {ILabel} from '@/modelTypes/ILabel' +import type {IUser} from '@/modelTypes/IUser' +import type {IAttachment} from '@/modelTypes/IAttachment' +import type {IList} from '@/modelTypes/IList' +import type {ISubscription} from '@/modelTypes/ISubscription' +import type {IBucket} from '@/modelTypes/IBucket' + +import type {IRepeatAfter} from '@/types/IRepeatAfter' +import {TASK_REPEAT_MODES, type IRepeatMode} from '@/types/IRepeatMode' import {parseDateOrNull} from '@/helpers/parseDateOrNull' -import type { IBucket } from './bucket' +import type { IRelationKind } from '@/types/IRelationKind' + +import AbstractModel from './abstractModel' +import LabelModel from './label' +import UserModel from './user' +import AttachmentModel from './attachment' +import SubscriptionModel from './subscription' const SUPPORTS_TRIGGERED_NOTIFICATION = 'Notification' in window && 'showTrigger' in Notification.prototype export const TASK_DEFAULT_COLOR = '#1973ff' -export const TASK_REPEAT_MODES = { - 'REPEAT_MODE_DEFAULT': 0, - 'REPEAT_MODE_MONTH': 1, - 'REPEAT_MODE_FROM_CURRENT_DATE': 2, -} as const +export function getHexColor(hexColor: string) { + if (hexColor === '' || hexColor === '#') { + return TASK_DEFAULT_COLOR + } -export type TaskRepeatMode = typeof TASK_REPEAT_MODES[keyof typeof TASK_REPEAT_MODES] - -export interface ITask extends IAbstract { - id: number - title: string - description: string - done: boolean - doneAt: Date | null - priority: Priority - labels: ILabel[] - assignees: IUser[] - - dueDate: Date | null - startDate: Date | null - endDate: Date | null - repeatAfter: number | IRepeats - repeatFromCurrentDate: boolean - repeatMode: TaskRepeatMode - reminderDates: Date[] - parentTaskId: ITask['id'] - hexColor: string - percentDone: number - relatedTasks: { [relationKind: string]: ITask } // FIXME: use relationKinds - attachments: IAttachment[] - identifier: string - index: number - isFavorite: boolean - subscription: ISubscription - - position: number - kanbanPosition: number - - createdBy: IUser - created: Date - updated: Date - - listId: IList['id'] // Meta, only used when creating a new task - bucketId: IBucket['id'] + return hexColor } export default class TaskModel extends AbstractModel implements ITask { @@ -73,14 +45,14 @@ export default class TaskModel extends AbstractModel implements ITask { dueDate: Date | null = 0 startDate: Date | null = 0 endDate: Date | null = 0 - repeatAfter: number | IRepeats = 0 + repeatAfter: number | IRepeatAfter = 0 repeatFromCurrentDate = false - repeatMode: TaskRepeatMode = TASK_REPEAT_MODES.REPEAT_MODE_DEFAULT + repeatMode: IRepeatMode = TASK_REPEAT_MODES.REPEAT_MODE_DEFAULT reminderDates: Date[] = [] parentTaskId: ITask['id'] = 0 hexColor = '' percentDone = 0 - relatedTasks: { [relationKind: string]: ITask } = {} + relatedTasks: Partial> = {} attachments: IAttachment[] = [] identifier = '' index = 0 @@ -168,11 +140,7 @@ export default class TaskModel extends AbstractModel implements ITask { } getHexColor() { - if (this.hexColor === '' || this.hexColor === '#') { - return TASK_DEFAULT_COLOR - } - - return this.hexColor + return getHexColor(this.hexColor) } ///////////////// diff --git a/src/models/taskAssignee.ts b/src/models/taskAssignee.ts index 29a8db271d..5777e5b209 100644 --- a/src/models/taskAssignee.ts +++ b/src/models/taskAssignee.ts @@ -1,12 +1,8 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import type { ITask } from './task' -import type { IUser } from './user' +import AbstractModel from './abstractModel' -export interface ITaskAssignee extends IAbstract { - created: Date - userId: IUser['id'] - taskId: ITask['id'] -} +import type {ITaskAssignee} from '@/modelTypes/ITaskAssignee' +import type {IUser} from '@/modelTypes/IUser' +import type {ITask} from '@/modelTypes/ITask' export default class TaskAssigneeModel extends AbstractModel implements ITaskAssignee { created: Date = null diff --git a/src/models/taskComment.ts b/src/models/taskComment.ts index bb5ceb101c..6c76e822ff 100644 --- a/src/models/taskComment.ts +++ b/src/models/taskComment.ts @@ -1,16 +1,9 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import UserModel, { type IUser } from './user' -import type { ITask } from './task' +import AbstractModel from './abstractModel' +import UserModel from './user' -export interface ITaskComment extends IAbstract { - id: number - taskId: ITask['id'] - comment: string - author: IUser - - created: Date - updated: Date -} +import type {ITaskComment} from '@/modelTypes/ITaskComment' +import type {ITask} from '@/modelTypes/ITask' +import type {IUser} from '@/modelTypes/IUser' export default class TaskCommentModel extends AbstractModel implements ITaskComment { id = 0 diff --git a/src/models/taskRelation.ts b/src/models/taskRelation.ts index db375faba4..e22eddb912 100644 --- a/src/models/taskRelation.ts +++ b/src/models/taskRelation.ts @@ -1,39 +1,16 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import UserModel, { type IUser } from './user' -import type { ITask } from './task' +import AbstractModel from './abstractModel' +import UserModel from './user' -export const RELATION_KIND = { - 'SUBTASK': 'subtask', - 'PARENTTASK': 'parenttask', - 'RELATED': 'related', - 'DUPLICATES': 'duplicates', - 'BLOCKING': 'blocking', - 'BLOCKED': 'blocked', - 'PROCEDES': 'precedes', - 'FOLLOWS': 'follows', - 'COPIEDFROM': 'copiedfrom', - 'COPIEDTO': 'copiedto', - } as const - -export const RELATION_KINDS = [...Object.values(RELATION_KIND)] as const - -export type RelationKind = typeof RELATION_KINDS[number] - -export interface ITaskRelation extends IAbstract { - id: number - otherTaskId: ITask['id'] - taskId: ITask['id'] - relationKind: RelationKind - - createdBy: IUser - created: Date -} +import type {ITaskRelation} from '@/modelTypes/ITaskRelation' +import type {ITask} from '@/modelTypes/ITask' +import type {IUser} from '@/modelTypes/IUser' +import type {IRelationKind} from '@/types/IRelationKind' export default class TaskRelationModel extends AbstractModel implements ITaskRelation { id = 0 otherTaskId: ITask['id'] = 0 taskId: ITask['id'] = 0 - relationKind: RelationKind = '' + relationKind: IRelationKind = '' createdBy: IUser = UserModel created: Date = null diff --git a/src/models/team.ts b/src/models/team.ts index 56e13dee51..5e3bd27e5c 100644 --- a/src/models/team.ts +++ b/src/models/team.ts @@ -1,19 +1,11 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import UserModel, { type IUser } from './user' -import TeamMemberModel, { type ITeamMember } from './teamMember' +import AbstractModel from './abstractModel' +import UserModel from './user' +import TeamMemberModel from './teamMember' + import {RIGHTS, type Right} from '@/constants/rights' - -export interface ITeam extends IAbstract { - id: number - name: string - description: string - members: ITeamMember[] - right: Right - - createdBy: IUser - created: Date - updated: Date -} +import type {ITeam} from '@/modelTypes/ITeam' +import type {ITeamMember} from '@/modelTypes/ITeamMember' +import type {IUser} from '@/modelTypes/IUser' export default class TeamModel extends AbstractModel implements ITeam { id = 0 diff --git a/src/models/teamList.ts b/src/models/teamList.ts index bb55b1cc20..eab202cf05 100644 --- a/src/models/teamList.ts +++ b/src/models/teamList.ts @@ -1,9 +1,7 @@ import TeamShareBaseModel from './teamShareBase' -import type { IList } from './list' -export interface ITeamList extends TeamShareBaseModel { - listId: IList['id'] -} +import type {ITeamList} from '@/modelTypes/ITeamList' +import type {IList} from '@/modelTypes/IList' export default class TeamListModel extends TeamShareBaseModel implements ITeamList { listId: IList['id'] = 0 diff --git a/src/models/teamMember.ts b/src/models/teamMember.ts index 6caf49328e..ee8768f020 100644 --- a/src/models/teamMember.ts +++ b/src/models/teamMember.ts @@ -1,10 +1,7 @@ import UserModel from './user' -import type { IList } from './list' -export interface ITeamMember extends UserModel { - admin: boolean - teamId: IList['id'] -} +import type {ITeamMember} from '@/modelTypes/ITeamMember' +import type {IList} from '@/modelTypes/IList' export default class TeamMemberModel extends UserModel implements ITeamMember { admin = false diff --git a/src/models/teamNamespace.ts b/src/models/teamNamespace.ts index 104d7a77d0..3d583ae801 100644 --- a/src/models/teamNamespace.ts +++ b/src/models/teamNamespace.ts @@ -1,9 +1,7 @@ import TeamShareBaseModel from './teamShareBase' -import type { INamespace } from './namespace' -export interface ITeamNamespace extends TeamShareBaseModel { - namespaceId: INamespace['id'] -} +import type {ITeamNamespace} from '@/modelTypes/ITeamNamespace' +import type {INamespace} from '@/modelTypes/INamespace' export default class TeamNamespaceModel extends TeamShareBaseModel implements ITeamNamespace { namespaceId: INamespace['id'] = 0 diff --git a/src/models/teamShareBase.ts b/src/models/teamShareBase.ts index 02495d1cd2..c7eb23c7ef 100644 --- a/src/models/teamShareBase.ts +++ b/src/models/teamShareBase.ts @@ -1,14 +1,8 @@ -import AbstractModel, { type IAbstract } from './abstractModel' +import AbstractModel from './abstractModel' + import {RIGHTS, type Right} from '@/constants/rights' -import type { ITeam } from './team' - -export interface ITeamShareBase extends IAbstract { - teamId: ITeam['id'] - right: Right - - created: Date - updated: Date -} +import type {ITeamShareBase} from '@/modelTypes/ITeamShareBase' +import type {ITeam} from '@/modelTypes/ITeam' /** * This class is a base class for common team sharing model. diff --git a/src/models/totp.ts b/src/models/totp.ts index 42242cf01c..5e094392df 100644 --- a/src/models/totp.ts +++ b/src/models/totp.ts @@ -1,10 +1,6 @@ -import AbstractModel, { type IAbstract } from './abstractModel' +import AbstractModel from './abstractModel' -export interface ITotp extends IAbstract { - secret: string - enabled: boolean - url: string -} +import type {ITotp} from '@/modelTypes/ITotp' export default class TotpModel extends AbstractModel implements ITotp { secret = '' diff --git a/src/models/user.ts b/src/models/user.ts index cd6423b76c..41509c1711 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -1,16 +1,8 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import UserSettingsModel, { type IUserSettings } from '@/models/userSettings' +import AbstractModel from './abstractModel' +import UserSettingsModel from '@/models/userSettings' -export interface IUser extends IAbstract { - id: number - email: string - username: string - name: string - - created: Date - updated: Date - settings: IUserSettings -} +import type { IUser } from '@/modelTypes/IUser' +import type { IUserSettings } from '@/modelTypes/IUserSettings' export default class UserModel extends AbstractModel implements IUser { id = 0 diff --git a/src/models/userList.ts b/src/models/userList.ts index ae5f881124..ed264d9b83 100644 --- a/src/models/userList.ts +++ b/src/models/userList.ts @@ -1,9 +1,7 @@ import UserShareBaseModel from './userShareBase' -import type { IList } from './list' -export interface IUserList extends UserShareBaseModel { - listId: IList['id'] -} +import type {IUserList} from '@/modelTypes/IUserList' +import type {IList} from '@/modelTypes/IList' // This class extends the user share model with a 'rights' parameter which is used in sharing export default class UserListModel extends UserShareBaseModel implements IUserList { diff --git a/src/models/userNamespace.ts b/src/models/userNamespace.ts index 4795b87377..326373837e 100644 --- a/src/models/userNamespace.ts +++ b/src/models/userNamespace.ts @@ -1,9 +1,7 @@ import UserShareBaseModel from './userShareBase' -import type { INamespace } from './namespace' -export interface IUserNamespace extends UserShareBaseModel { - namespaceId: INamespace['id'] -} +import type {INamespace} from '@/modelTypes/INamespace' +import type {IUserNamespace} from '@/modelTypes/IUserNamespace' // This class extends the user share model with a 'rights' parameter which is used in sharing export default class UserNamespaceModel extends UserShareBaseModel implements IUserNamespace { diff --git a/src/models/userSettings.ts b/src/models/userSettings.ts index 382e71590c..6b5bd7ca48 100644 --- a/src/models/userSettings.ts +++ b/src/models/userSettings.ts @@ -1,17 +1,8 @@ -import AbstractModel, { type IAbstract } from './abstractModel' -import type { IList } from './list' +import AbstractModel from './abstractModel' -export interface IUserSettings extends IAbstract { - name: string - emailRemindersEnabled: boolean - discoverableByName: boolean - discoverableByEmail: boolean - overdueTasksRemindersEnabled: boolean - defaultListId: undefined | IList['id'] - weekStart: 0 | 1 | 2 | 3 | 4 | 5 | 6 - timezone: string -} +import type {IUserSettings} from '@/modelTypes/IUserSettings' +import type {IList} from '@/modelTypes/IList' export default class UserSettingsModel extends AbstractModel implements IUserSettings { name = '' @@ -20,7 +11,7 @@ export default class UserSettingsModel extends AbstractModel implements IUserSet discoverableByEmail = false overdueTasksRemindersEnabled = true defaultListId: undefined | IList['id'] = undefined - weekStart: 0 | 1 | 2 | 3 | 4 | 5 | 6 = 0 + weekStart: IUserSettings['weekStart'] = 0 timezone = '' constructor(data: Partial) { diff --git a/src/models/userShareBase.ts b/src/models/userShareBase.ts index 82ab543272..e21998d94f 100644 --- a/src/models/userShareBase.ts +++ b/src/models/userShareBase.ts @@ -1,14 +1,8 @@ -import AbstractModel, { type IAbstract } from './abstractModel' +import AbstractModel from './abstractModel' + import {RIGHTS, type Right} from '@/constants/rights' -import type { IUser } from './user' - -export interface IUserShareBase extends IAbstract { - userId: IUser['id'] - right: Right - - created: Date - updated: Date -} +import type {IUserShareBase} from '@/modelTypes/IUserShareBase' +import type {IUser} from '@/modelTypes/IUser' export default class UserShareBaseModel extends AbstractModel implements IUserShareBase { userId: IUser['id'] = '' diff --git a/src/modules/parseTaskText.ts b/src/modules/parseTaskText.ts index 5be6d2ab00..319bada8f6 100644 --- a/src/modules/parseTaskText.ts +++ b/src/modules/parseTaskText.ts @@ -1,6 +1,6 @@ import {parseDate} from '../helpers/time/parseDate' import {PRIORITIES} from '@/constants/priorities' -import {REPEAT_TYPES, type IRepeats, type RepeatType} from '@/types/IRepeats' +import {REPEAT_TYPES, type IRepeatAfter, type IRepeatType} from '@/types/IRepeatAfter' const VIKUNJA_PREFIXES: Prefixes = { label: '*', @@ -30,7 +30,7 @@ export const PREFIXES = { interface repeatParsedResult { textWithoutMatched: string, - repeats: IRepeats | null, + repeats: IRepeatAfter | null, } export interface ParsedTaskText { @@ -40,7 +40,7 @@ export interface ParsedTaskText { list: string | null, priority: number | null, assignees: string[], - repeats: IRepeats | null, + repeats: IRepeatAfter | null, } interface Prefixes { @@ -185,7 +185,7 @@ const getRepeats = (text: string): repeatParsedResult => { default: amount = results[3] ? parseInt(results[3]) : 1 } - let type: RepeatType = REPEAT_TYPES.Hours + let type: IRepeatType = REPEAT_TYPES.Hours switch (results[0]) { case 'biennially': diff --git a/src/store/index.ts b/src/store/index.ts index 0033e07e10..34dc7c049a 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,7 +1,6 @@ import type {InjectionKey} from 'vue' import {createStore, useStore as baseUseStore, Store} from 'vuex' - import {getBlobFromBlurHash} from '../helpers/getBlobFromBlurHash' import { BACKGROUND, diff --git a/src/store/modules/attachments.ts b/src/store/modules/attachments.ts index 208ab4cef6..172696e41f 100644 --- a/src/store/modules/attachments.ts +++ b/src/store/modules/attachments.ts @@ -2,7 +2,7 @@ import type { Module } from 'vuex' import {findIndexById} from '@/helpers/utils' import type { AttachmentState, RootStoreState } from '@/store/types' -import type { IAttachment } from '@/models/attachment' +import type { IAttachment } from '@/modelTypes/IAttachment' const store : Module = { namespaced: true, diff --git a/src/store/modules/auth.ts b/src/store/modules/auth.ts index a66b656b6c..c101381ca3 100644 --- a/src/store/modules/auth.ts +++ b/src/store/modules/auth.ts @@ -12,7 +12,7 @@ import {success} from '@/message' import {redirectToProvider} from '@/helpers/redirectToProvider' import type { RootStoreState, AuthState, Info} from '@/store/types' import {AUTH_TYPES} from '@/store/types' -import type { IUserSettings } from '@/models/userSettings' +import type { IUserSettings } from '@/modelTypes/IUserSettings' const defaultSettings = settings => { diff --git a/src/store/modules/kanban.ts b/src/store/modules/kanban.ts index c6e46d58aa..194121309c 100644 --- a/src/store/modules/kanban.ts +++ b/src/store/modules/kanban.ts @@ -9,9 +9,9 @@ import BucketService from '../../services/bucket' import {setLoading} from '../helper' import TaskCollectionService from '@/services/taskCollection' import type { RootStoreState, KanbanState } from '@/store/types' -import type { ITask } from '@/models/task' -import type { IList } from '@/models/list' -import type { IBucket } from '@/models/bucket' +import type { ITask } from '@/modelTypes/ITask' +import type { IList } from '@/modelTypes/IList' +import type { IBucket } from '@/modelTypes/IBucket' const TASKS_PER_BUCKET = 25 diff --git a/src/store/modules/labels.ts b/src/store/modules/labels.ts index ce32db6d09..928b6b1e4c 100644 --- a/src/store/modules/labels.ts +++ b/src/store/modules/labels.ts @@ -7,7 +7,7 @@ import {setLoading} from '@/store/helper' import type { LabelState, RootStoreState } from '@/store/types' import {getLabelsByIds, filterLabelsByQuery} from '@/helpers/labels' import {createNewIndexer} from '@/indexes' -import type { ILabel } from '@/models/label' +import type { ILabel } from '@/modelTypes/ILabel' const {add, remove, update} = createNewIndexer('labels', ['title', 'description']) diff --git a/src/store/modules/lists.ts b/src/store/modules/lists.ts index 0d18a2c04f..be2e3fcfe0 100644 --- a/src/store/modules/lists.ts +++ b/src/store/modules/lists.ts @@ -5,7 +5,7 @@ import {setLoading} from '@/store/helper' import {removeListFromHistory} from '@/modules/listHistory' import {createNewIndexer} from '@/indexes' import type {ListState, RootStoreState} from '@/store/types' -import type {IList} from '@/models/list' +import type {IList} from '@/modelTypes/IList' const {add, remove, search, update} = createNewIndexer('lists', ['title', 'description']) diff --git a/src/store/modules/namespaces.ts b/src/store/modules/namespaces.ts index 0eccc99bbc..d835c7095d 100644 --- a/src/store/modules/namespaces.ts +++ b/src/store/modules/namespaces.ts @@ -4,8 +4,8 @@ import NamespaceService from '../../services/namespace' import {setLoading} from '@/store/helper' import {createNewIndexer} from '@/indexes' import type {NamespaceState, RootStoreState} from '@/store/types' -import type {INamespace} from '@/models/namespace' -import type {IList} from '@/models/list' +import type {INamespace} from '@/modelTypes/INamespace' +import type {IList} from '@/modelTypes/IList' const {add, remove, search, update} = createNewIndexer('namespaces', ['title', 'description']) diff --git a/src/store/modules/tasks.ts b/src/store/modules/tasks.ts index 6588c51f76..332286917e 100644 --- a/src/store/modules/tasks.ts +++ b/src/store/modules/tasks.ts @@ -4,22 +4,27 @@ import {formatISO} from 'date-fns' import TaskService from '@/services/task' import TaskAssigneeService from '@/services/taskAssignee' -import TaskAssigneeModel from '@/models/taskAssignee' -import LabelTaskModel from '@/models/labelTask' import LabelTaskService from '@/services/labelTask' +import UserService from '@/services/user' + import {HAS_TASKS} from '../mutation-types' import {setLoading} from '../helper' import {getQuickAddMagicMode} from '@/helpers/quickAddMagicMode' - import {parseTaskText} from '@/modules/parseTaskText' -import TaskModel, { type ITask } from '@/models/task' + +import TaskAssigneeModel from '@/models/taskAssignee' +import LabelTaskModel from '@/models/labelTask' +import TaskModel from '@/models/task' import LabelTask from '@/models/labelTask' -import LabelModel, { type ILabel } from '@/models/label' -import UserService from '@/services/user' +import LabelModel from '@/models/label' + +import type {ILabel} from '@/modelTypes/ILabel' +import type {ITask} from '@/modelTypes/ITask' +import type { IUser } from '@/modelTypes/IUser' +import type { IAttachment } from '@/modelTypes/IAttachment' +import type { IList } from '@/modelTypes/IList' + import type { RootStoreState, TaskState } from '@/store/types' -import type { IUser } from '@/models/user' -import type { IAttachment } from '@/models/attachment' -import type { IList } from '@/models/list' // IDEA: maybe use a small fuzzy search here to prevent errors function findPropertyByValue(object, key, value) { diff --git a/src/store/types.ts b/src/store/types.ts index 96f061dca7..2cc467a1e7 100644 --- a/src/store/types.ts +++ b/src/store/types.ts @@ -1,9 +1,9 @@ -import type { IBucket } from '@/models/bucket' -import type { IUserSettings } from '@/models/userSettings' -import type { IList } from '@/models/list' -import type { IAttachment } from '@/models/attachment' -import type { ILabel } from '@/models/label' -import type { INamespace } from '@/models/namespace' +import type { IBucket } from '@/modelTypes/IBucket' +import type { IUserSettings } from '@/modelTypes/IUserSettings' +import type { IList } from '@/modelTypes/IList' +import type { IAttachment } from '@/modelTypes/IAttachment' +import type { ILabel } from '@/modelTypes/ILabel' +import type { INamespace } from '@/modelTypes/INamespace' export interface RootStoreState { loading: boolean, diff --git a/src/types/IFilter.ts b/src/types/IFilter.ts new file mode 100644 index 0000000000..aca000ab69 --- /dev/null +++ b/src/types/IFilter.ts @@ -0,0 +1,9 @@ +export interface IFilter { + sortBy: ('done' | 'id')[] + orderBy: ('asc' | 'desc')[] + filterBy: 'done'[] + filterValue: 'false'[] + filterComparator: 'equals'[] + filterConcat: 'and' + filterIncludeNulls: boolean +} \ No newline at end of file diff --git a/src/types/IRelationKind.ts b/src/types/IRelationKind.ts new file mode 100644 index 0000000000..a9ffb3d672 --- /dev/null +++ b/src/types/IRelationKind.ts @@ -0,0 +1,16 @@ +export enum RELATION_KIND { + 'SUBTASK' = 'subtask', + 'PARENTTASK' = 'parenttask', + 'RELATED' = 'related', + 'DUPLICATES' = 'duplicates', + 'BLOCKING' = 'blocking', + 'BLOCKED' = 'blocked', + 'PROCEDES' = 'precedes', + 'FOLLOWS' = 'follows', + 'COPIEDFROM' = 'copiedfrom', + 'COPIEDTO' = 'copiedto', +} + +export type IRelationKind = typeof RELATION_KIND[keyof typeof RELATION_KIND] + +export const RELATION_KINDS = [...Object.values(RELATION_KIND)] as const \ No newline at end of file diff --git a/src/types/IRepeats.ts b/src/types/IRepeatAfter.ts similarity index 53% rename from src/types/IRepeats.ts rename to src/types/IRepeatAfter.ts index e2ab90777f..0b132a2f7b 100644 --- a/src/types/IRepeats.ts +++ b/src/types/IRepeatAfter.ts @@ -6,9 +6,9 @@ export const REPEAT_TYPES = { Years: 'years', } as const -export type RepeatType = typeof REPEAT_TYPES[keyof typeof REPEAT_TYPES] +export type IRepeatType = typeof REPEAT_TYPES[keyof typeof REPEAT_TYPES] -export interface IRepeats { - type: RepeatType, +export interface IRepeatAfter { + type: IRepeatType, amount: number, } \ No newline at end of file diff --git a/src/types/IRepeatMode.ts b/src/types/IRepeatMode.ts new file mode 100644 index 0000000000..46297ff722 --- /dev/null +++ b/src/types/IRepeatMode.ts @@ -0,0 +1,7 @@ +export const TASK_REPEAT_MODES = { + 'REPEAT_MODE_DEFAULT': 0, + 'REPEAT_MODE_MONTH': 1, + 'REPEAT_MODE_FROM_CURRENT_DATE': 2, +} as const + +export type IRepeatMode = typeof TASK_REPEAT_MODES[keyof typeof TASK_REPEAT_MODES] diff --git a/src/views/list/ListList.vue b/src/views/list/ListList.vue index 6c018fe13a..b5ef4aa5fd 100644 --- a/src/views/list/ListList.vue +++ b/src/views/list/ListList.vue @@ -156,7 +156,7 @@ import {calculateItemPosition} from '../../helpers/calculateItemPosition' import type { ITask } from '@/models/task' function sortTasks(tasks: ITask[]) { - if (tasks === null || tasks === []) { + if (tasks === null || Array.isArray(tasks) && tasks.length === 0) { return } return tasks.sort((a, b) => { diff --git a/src/views/teams/EditTeam.vue b/src/views/teams/EditTeam.vue index 5497ba3478..08a6c4025f 100644 --- a/src/views/teams/EditTeam.vue +++ b/src/views/teams/EditTeam.vue @@ -170,6 +170,7 @@ import {useStore} from '@/store' import TeamService from '@/services/team' import TeamMemberService from '@/services/teamMember' import UserService from '@/services/user' + import {RIGHTS as Rights} from '@/constants/rights' import Multiselect from '@/components/input/multiselect.vue'