diff --git a/common/helpers/endpoints.d.ts b/common/helpers/endpoints.d.ts new file mode 100644 index 00000000000..213a8943691 --- /dev/null +++ b/common/helpers/endpoints.d.ts @@ -0,0 +1,402 @@ +import type { + CollectionReference, + ResourceInterface, + ResourceReference, + HalJsonVuex, +} from 'hal-json-vuex' + +interface UserEntity extends ResourceInterface { + id: string + displayName: string + + profile: ResourceReference +} + +interface ProfileEntity extends ResourceInterface { + id: string + firstname: string + surname: string + nickname: string + legalName: string + + email: string + + language: string + + user: ResourceReference +} + +interface CampEntity extends ResourceInterface { + id: string + name: string + title: string + motto: string + + isPrototype: boolean + creator: ResourceReference + + addressName: string | null + addressStreet: string | null + addressZipcode: string | null + addressCity: string | null + + coachName: string | null + courseKind: string | null + courseNumber: string | null + organizer: string | null + kind: string | null + printYSLogoOnPicasso: boolean | null + trainingAdvisorName: string | null + + activities: CollectionReference + periods: CollectionReference + categories: CollectionReference + profiles: CollectionReference + progressLabels: CollectionReference +} + +interface PeriodEntity extends ResourceInterface { + id: string + start: string + end: string + + camp: ResourceReference +} + +interface ActivityEntity extends ResourceInterface { + id: string + title: string + location: string + + camp: ResourceReference + category: ResourceReference + period: ResourceReference + scheduleEntries: CollectionReference + activityResponsibles: CollectionReference + activityProgressLabel: ResourceReference +} + +interface ActivityProgressLabelEntity + extends ResourceInterface { + id: string + title: string + position: number + camp: ResourceReference +} + +interface ActivityResponsibleEntity extends ResourceInterface { + id: string + activity: ResourceReference + campCollaboration: ResourceReference +} + +interface ScheduleEntryEntity extends ResourceInterface { + id: string + start: string + end: string + + dayNumber: number + scheduleEntryNumber: number + number: string + + left: number + width: number + + period: ResourceReference + day: ResourceReference +} + +interface DayEntity extends ResourceInterface { + id: string + start: string + end: string + + number: number + dayOffset: number + + period: ResourceReference + scheduleEntries: CollectionReference + dayResponsibles: CollectionReference +} + +interface DayResponsibleEntity extends ResourceInterface { + id: string + day: ResourceReference + campCollaboration: ResourceReference +} + +interface CategoryEntity extends ResourceInterface { + id: string + short: string + name: string + + numberingStyle: 'a' | 'A' | 'i' | 'I' | '1' + color: string + + camp: ResourceReference + contentNodes: CollectionReference + rootContentNode: ResourceReference + preferredContentNodes: CollectionReference +} + +type ContentNode = + | ColumnLayoutNodeEntity + | MultiSelectNodeEntity + | SingleTextNodeEntity + | StoryboardNodeEntity + +interface ContentNodesBase { + id: string + contentTypeName: string + instanceName: string | null + slot: string + position: number + data: Data + + contentType: ResourceReference + + children: CollectionReference + parent: ResourceReference + root: ResourceReference +} + +interface ColumnLayoutNodeData { + columns: { + slot: string + width: number + }[] +} + +interface ColumnLayoutNodeEntity + extends ContentNodesBase, + ResourceInterface {} + +interface MultiSelectNodeData { + options: { + [key: string]: { + checked: boolean + } + } +} + +interface MultiSelectNodeEntity + extends ContentNodesBase, + ResourceInterface {} + +interface SingleTextNodeData { + html: string +} + +interface SingleTextNodeEntity + extends ContentNodesBase, + ResourceInterface {} + +interface StoryboardNodeData { + sections: { + [key: string]: { + column1: string + column2Html: string + column3: string + position: number + } + } +} + +interface StoryboardNodeEntity + extends ContentNodesBase, + ResourceInterface {} + +interface MaterialNodeEntity + extends ContentNodesBase, + ResourceInterface { + materialItems: CollectionReference +} + +interface ContentTypeEntity extends ResourceInterface { + id: string + name: string + + contentNodes: CollectionReference +} + +interface CampCollaborationEntity extends ResourceInterface { + id: string + role: 'member' | 'manager' | 'guest' + status: 'invited' | 'established' | 'inactive' + camp: ResourceReference + + inviteEmail: string | null + user: ResourceReference | null +} + +interface MaterialListEntity extends ResourceInterface { + id: string + name: string + + itemCount: number + camp: ResourceReference + campCollaboration: ResourceReference +} + +interface MaterialItemBase { + id: string + article: string + quantity: number + unit: string + materialList: ResourceReference +} + +type MaterialItemEntity = MaterialItemNodeEntity | MaterialItemPeriodEntity + +interface MaterialItemNodeEntity + extends MaterialItemBase, + ResourceInterface { + materialNode: ResourceReference + period: null +} + +interface MaterialItemPeriodEntity + extends MaterialItemBase, + ResourceInterface { + materialNode: null + period: ResourceReference +} + +interface InvitationDTO extends ResourceInterface { + campId: string + campTitle: string + userDisplayName: string | null + userAlreadyInCamp: boolean | null +} + +interface InvitationDTOParams { + action: 'find' | 'accept' | 'reject' + id: string +} + +type CampParam = { camp?: string | string[] } +type ActivityParam = { activity?: string | string[] } +type PeriodParam = { period?: string | string[] } +type ActivityResponsiblesParams = ActivityParam & { + activity?: { camp: string | string[] } +} +type ActivityResponsibleParams = { + activityResponsibles?: ActivityParam +} +type CampPrototypeQueryParam = { isPrototype: boolean } +type ContentNodeParam = { + contentType?: string | string[] + root?: string | string[] + period?: string +} +type CategoryParam = { categories?: string | string[] } +type DayParam = { day?: string | string[] } +type DayResponsibleParams = DayParam & { + day?: { period: string | string[] } +} +type MaterialListParam = { materialList?: string | string[] } +type MaterialNodeParam = { materialNode?: string | string[] } +type MaterialItemParams = MaterialListParam & MaterialNodeParam & { period?: string } +type ProfileParams = { + user: { collaborations: { camp: string | string[] } } +} +type TimeParam = { + before?: string + strictly_before?: string + after?: string + strictly_after?: string +} +type ScheduleEntryParams = PeriodParam & + ActivityParam & { + start?: TimeParam + end?: TimeParam +} + +type SingleResource> = ResourceReference +type QueryResources< + T extends ResourceInterface, + Params = undefined, +> = CollectionReference + +export interface RootEndpoint extends ResourceInterface { + activities: QueryResources & SingleResource + + activityProgressLabels: QueryResources & + SingleResource + + activityResponsibles: QueryResources< + ActivityResponsibleEntity, + ActivityResponsiblesParams + > & + SingleResource + + campCollaborations: QueryResources< + CampCollaborationEntity, + CampParam & ActivityResponsibleParams + > & + SingleResource + + camps: QueryResources & SingleResource + + categories: QueryResources & SingleResource + + columnLayouts: QueryResources & + SingleResource + + contentNodes: CollectionReference + + contentTypes: QueryResources & + SingleResource + + days: CollectionReference | SingleResource + + dayResponsibles: QueryResources & + SingleResource + + invitations: ResourceReference + + login: ResourceReference + + materialItems: QueryResources & + SingleResource + + materialLists: QueryResources & + SingleResource + + materialNodes: QueryResources & + SingleResource + + multiSelects: QueryResources & + SingleResource + + oauthCevidb: ResourceReference + + oauthGoogle: ResourceReference + + oauthJubladb: ResourceReference + + oauthPbsmidata: ResourceReference + + periods: QueryResources & SingleResource + + profiles: QueryResources & SingleResource + + resetPassword: ResourceReference + + scheduleEntries: QueryResources & + SingleResource + + singleTexts: QueryResources & + SingleResource + + storyboards: QueryResources & + SingleResource + + users: CollectionReference & SingleResource +} + +declare module 'vue/types/vue' { + interface Vue { + api: HalJsonVuex + } +} diff --git a/frontend/components.d.ts b/frontend/components.d.ts new file mode 100644 index 00000000000..c9d0fbc2a85 --- /dev/null +++ b/frontend/components.d.ts @@ -0,0 +1,211 @@ +/* eslint-disable */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +export {} + +/* prettier-ignore */ +declare module 'vue' { + export interface GlobalComponents { + ActivityConfig: typeof import('./src/components/print/config/ActivityConfig.vue')['default'] + ActivityResponsibles: typeof import('./src/components/activity/ActivityResponsibles.vue')['default'] + ActivityRow: typeof import('./src/components/dashboard/ActivityRow.vue')['default'] + ApiCheckbox: typeof import('./src/components/form/api/ApiCheckbox.vue')['default'] + ApiColorField: typeof import('./src/components/form/api/ApiColorField.vue')['default'] + ApiColorPicker: typeof import('./src/components/form/api/ApiColorPicker.vue')['default'] + ApiDatePicker: typeof import('./src/components/form/api/ApiDatePicker.vue')['default'] + ApiForm: typeof import('./src/components/form/api/ApiForm.vue')['default'] + ApiNumberField: typeof import('./src/components/form/api/ApiNumberField.vue')['default'] + ApiRichtext: typeof import('./src/components/form/api/ApiRichtext.vue')['default'] + ApiSelect: typeof import('./src/components/form/api/ApiSelect.vue')['default'] + ApiSortable: typeof import('./src/components/form/api/ApiSortable.vue')['default'] + ApiSwitch: typeof import('./src/components/form/api/ApiSwitch.vue')['default'] + ApiTextarea: typeof import('./src/components/form/api/ApiTextarea.vue')['default'] + ApiTextField: typeof import('./src/components/form/api/ApiTextField.vue')['default'] + ApiTimePicker: typeof import('./src/components/form/api/ApiTimePicker.vue')['default'] + ApiWrapper: typeof import('./src/components/form/api/ApiWrapper.vue')['default'] + ApiWrapperAppend: typeof import('./src/components/form/api/ApiWrapperAppend.vue')['default'] + AuthContainer: typeof import('./src/components/layout/AuthContainer.vue')['default'] + AvatarRow: typeof import('./src/components/generic/AvatarRow.vue')['default'] + BaseComponent: typeof import('./src/components/form/base/BaseComponent.vue')['default'] + BasePicker: typeof import('./src/components/form/base/BasePicker.vue')['default'] + BooleanFilter: typeof import('./src/components/dashboard/BooleanFilter.vue')['default'] + ButtonAdd: typeof import('./src/components/buttons/ButtonAdd.vue')['default'] + ButtonBack: typeof import('./src/components/buttons/ButtonBack.vue')['default'] + ButtonCancel: typeof import('./src/components/buttons/ButtonCancel.vue')['default'] + ButtonContinue: typeof import('./src/components/buttons/ButtonContinue.vue')['default'] + ButtonDelete: typeof import('./src/components/buttons/ButtonDelete.vue')['default'] + ButtonEdit: typeof import('./src/components/buttons/ButtonEdit.vue')['default'] + ButtonNestedContentNodeAdd: typeof import('./src/components/activity/ButtonNestedContentNodeAdd.vue')['default'] + ButtonRetry: typeof import('./src/components/buttons/ButtonRetry.vue')['default'] + CampActivityProgressLabels: typeof import('./src/components/campAdmin/CampActivityProgressLabels.vue')['default'] + CampAddress: typeof import('./src/components/campAdmin/CampAddress.vue')['default'] + CampCategories: typeof import('./src/components/campAdmin/CampCategories.vue')['default'] + CampConditionalFields: typeof import('./src/components/campAdmin/CampConditionalFields.vue')['default'] + CampCreate: typeof import('./src/components/campCreate/CampCreate.vue')['default'] + CampCreateStep1: typeof import('./src/components/campCreate/CampCreateStep1.vue')['default'] + CampCreateStep2: typeof import('./src/components/campCreate/CampCreateStep2.vue')['default'] + CampDangerZone: typeof import('./src/components/campAdmin/CampDangerZone.vue')['default'] + CampListItem: typeof import('./src/components/camp/CampListItem.vue')['default'] + CampMaterialLists: typeof import('./src/components/campAdmin/CampMaterialLists.vue')['default'] + CampMaterialListsItem: typeof import('./src/components/campAdmin/CampMaterialListsItem.vue')['default'] + CampPeriods: typeof import('./src/components/campAdmin/CampPeriods.vue')['default'] + CampPeriodsListItem: typeof import('./src/components/campAdmin/CampPeriodsListItem.vue')['default'] + CampSettings: typeof import('./src/components/campAdmin/CampSettings.vue')['default'] + CategoryChip: typeof import('./src/components/generic/CategoryChip.vue')['default'] + CategoryProperties: typeof import('./src/components/category/CategoryProperties.vue')['default'] + CategoryTemplate: typeof import('./src/components/category/CategoryTemplate.vue')['default'] + Checklist: typeof import('./src/components/activity/content/Checklist.vue')['default'] + ChecklistCreate: typeof import('./src/components/checklist/ChecklistCreate.vue')['default'] + ChecklistDetail: typeof import('./src/components/checklist/ChecklistDetail.vue')['default'] + ChecklistItem: typeof import('./src/components/activity/content/checklist/ChecklistItem.vue')['default'] + ChecklistItemCreate: typeof import('./src/components/checklist/ChecklistItemCreate.vue')['default'] + ChecklistItemEdit: typeof import('./src/components/checklist/ChecklistItemEdit.vue')['default'] + ChecklistOverview: typeof import('./src/components/checklist/ChecklistOverview.vue')['default'] + CollaboratorCreate: typeof import('./src/components/collaborator/CollaboratorCreate.vue')['default'] + CollaboratorEdit: typeof import('./src/components/collaborator/CollaboratorEdit.vue')['default'] + CollaboratorForm: typeof import('./src/components/collaborator/CollaboratorForm.vue')['default'] + CollaboratorList: typeof import('./src/components/collaborator/CollaboratorList.vue')['default'] + CollaboratorListItem: typeof import('./src/components/collaborator/CollaboratorListItem.vue')['default'] + ColorSwatch: typeof import('./src/components/form/base/ColorPicker/ColorSwatch.vue')['default'] + ColumnIndicator: typeof import('./src/components/activity/content/columnLayout/ColumnIndicator.vue')['default'] + ColumnLayout: typeof import('./src/components/activity/content/ColumnLayout.vue')['default'] + ColumnOperations: typeof import('./src/components/activity/content/columnLayout/ColumnOperations.vue')['default'] + ContentActions: typeof import('./src/components/layout/ContentActions.vue')['default'] + ContentCard: typeof import('./src/components/layout/ContentCard.vue')['default'] + ContentGroup: typeof import('./src/components/layout/ContentGroup.vue')['default'] + ContentNode: typeof import('./src/components/activity/ContentNode.vue')['default'] + ContentNodeCard: typeof import('./src/components/activity/content/layout/ContentNodeCard.vue')['default'] + CopyActivityInfoDialog: typeof import('./src/components/activity/CopyActivityInfoDialog.vue')['default'] + CopyCategoryInfoDialog: typeof import('./src/components/category/CopyCategoryInfoDialog.vue')['default'] + CoverConfig: typeof import('./src/components/print/config/CoverConfig.vue')['default'] + CreateCampPeriods: typeof import('./src/components/campAdmin/CreateCampPeriods.vue')['default'] + DayResponsibles: typeof import('./src/components/program/picasso/DayResponsibles.vue')['default'] + DaySwitcher: typeof import('./src/components/activity/DaySwitcher.vue')['default'] + DetailPane: typeof import('./src/components/generic/DetailPane.vue')['default'] + DialogActivityCreate: typeof import('./src/components/program/DialogActivityCreate.vue')['default'] + DialogActivityEdit: typeof import('./src/components/program/DialogActivityEdit.vue')['default'] + DialogActivityForm: typeof import('./src/components/program/DialogActivityForm.vue')['default'] + DialogActivityProgressLabelCreate: typeof import('./src/components/campAdmin/DialogActivityProgressLabelCreate.vue')['default'] + DialogActivityProgressLabelEdit: typeof import('./src/components/campAdmin/DialogActivityProgressLabelEdit.vue')['default'] + DialogActivityProgressLabelForm: typeof import('./src/components/campAdmin/DialogActivityProgressLabelForm.vue')['default'] + DialogBase: typeof import('./src/components/dialog/DialogBase.vue')['default'] + DialogBottomSheet: typeof import('./src/components/dialog/DialogBottomSheet.vue')['default'] + DialogCategoryCreate: typeof import('./src/components/campAdmin/DialogCategoryCreate.vue')['default'] + DialogCategoryForm: typeof import('./src/components/campAdmin/DialogCategoryForm.vue')['default'] + DialogChangeMail: typeof import('./src/components/user/DialogChangeMail.vue')['default'] + DialogChangeMailRunning: typeof import('./src/components/user/DialogChangeMailRunning.vue')['default'] + DialogEntityDelete: typeof import('./src/components/dialog/DialogEntityDelete.vue')['default'] + DialogForm: typeof import('./src/components/dialog/DialogForm.vue')['default'] + DialogMaterialItemCreate: typeof import('./src/components/material/DialogMaterialItemCreate.vue')['default'] + DialogMaterialItemEdit: typeof import('./src/components/material/DialogMaterialItemEdit.vue')['default'] + DialogMaterialItemForm: typeof import('./src/components/material/DialogMaterialItemForm.vue')['default'] + DialogMaterialListCreate: typeof import('./src/components/campAdmin/DialogMaterialListCreate.vue')['default'] + DialogMaterialListEdit: typeof import('./src/components/campAdmin/DialogMaterialListEdit.vue')['default'] + DialogMaterialListForm: typeof import('./src/components/campAdmin/DialogMaterialListForm.vue')['default'] + DialogPeriodCreate: typeof import('./src/components/campAdmin/DialogPeriodCreate.vue')['default'] + DialogPeriodDateEdit: typeof import('./src/components/campAdmin/DialogPeriodDateEdit.vue')['default'] + DialogPeriodDescriptionEdit: typeof import('./src/components/campAdmin/DialogPeriodDescriptionEdit.vue')['default'] + DialogPeriodForm: typeof import('./src/components/campAdmin/DialogPeriodForm.vue')['default'] + DialogPersonalInvitationReject: typeof import('./src/components/personal_invitations/DialogPersonalInvitationReject.vue')['default'] + DialogUiBase: typeof import('./src/components/dialog/DialogUiBase.vue')['default'] + DownloadClientPdfButton: typeof import('./src/components/print/print-client/DownloadClientPdfButton.vue')['default'] + DownloadClientPdfListItem: typeof import('./src/components/print/print-client/DownloadClientPdfListItem.vue')['default'] + DownloadNuxtPdfButton: typeof import('./src/components/print/print-nuxt/DownloadNuxtPdfButton.vue')['default'] + DownloadNuxtPdfListItem: typeof import('./src/components/print/print-nuxt/DownloadNuxtPdfListItem.vue')['default'] + DraggableContentNodes: typeof import('./src/components/activity/DraggableContentNodes.vue')['default'] + ECheckbox: typeof import('./src/components/form/base/ECheckbox.vue')['default'] + EColorField: typeof import('./src/components/form/base/EColorField.vue')['default'] + EColorPicker: typeof import('./src/components/form/base/EColorPicker.vue')['default'] + EDatePicker: typeof import('./src/components/form/base/EDatePicker.vue')['default'] + EForm: typeof import('./src/components/form/base/EForm.vue')['default'] + ENumberField: typeof import('./src/components/form/base/ENumberField.vue')['default'] + EParseField: typeof import('./src/components/form/base/EParseField.vue')['default'] + ERichtext: typeof import('./src/components/form/base/ERichtext.vue')['default'] + ErrorExistingActivitiesList: typeof import('./src/components/campAdmin/ErrorExistingActivitiesList.vue')['default'] + ESelect: typeof import('./src/components/form/base/ESelect.vue')['default'] + ESwitch: typeof import('./src/components/form/base/ESwitch.vue')['default'] + ETextarea: typeof import('./src/components/form/base/ETextarea.vue')['default'] + ETextField: typeof import('./src/components/form/base/ETextField.vue')['default'] + ETimePicker: typeof import('./src/components/form/base/ETimePicker.vue')['default'] + FilterDivider: typeof import('./src/components/dashboard/FilterDivider.vue')['default'] + FormScheduleEntryItem: typeof import('./src/components/program/FormScheduleEntryItem.vue')['default'] + FormScheduleEntryList: typeof import('./src/components/program/FormScheduleEntryList.vue')['default'] + GenericChip: typeof import('./src/components/generic/GenericChip.vue')['default'] + GenericPage: typeof import('./src/components/generic/GenericPage.vue')['default'] + HorizontalRule: typeof import('./src/components/layout/HorizontalRule.vue')['default'] + IconButton: typeof import('./src/components/buttons/IconButton.vue')['default'] + IconSpacer: typeof import('./src/components/layout/IconSpacer.vue')['default'] + IconSuccess: typeof import('./src/components/form/api/IconSuccess.vue')['default'] + IconWithTooltip: typeof import('./src/components/generic/IconWithTooltip.vue')['default'] + LanguageSwitcher: typeof import('./src/components/layout/LanguageSwitcher.vue')['default'] + LAThematicArea: typeof import('./src/components/activity/content/LAThematicArea.vue')['default'] + LayoutItem: typeof import('./src/components/activity/content/layout/LayoutItem.vue')['default'] + LayoutNodeCard: typeof import('./src/components/activity/content/layout/LayoutNodeCard.vue')['default'] + LearningObjectives: typeof import('./src/components/activity/content/LearningObjectives.vue')['default'] + LearningTopics: typeof import('./src/components/activity/content/LearningTopics.vue')['default'] + LockButton: typeof import('./src/components/generic/LockButton.vue')['default'] + LockUnlockListItem: typeof import('./src/components/generic/LockUnlockListItem.vue')['default'] + Logo: typeof import('./src/components/navigation/Logo.vue')['default'] + Material: typeof import('./src/components/activity/content/Material.vue')['default'] + MaterialCreateItem: typeof import('./src/components/material/MaterialCreateItem.vue')['default'] + MaterialLists: typeof import('./src/components/material/MaterialLists.vue')['default'] + MaterialListsEdit: typeof import('./src/components/material/MaterialListsEdit.vue')['default'] + MaterialTable: typeof import('./src/components/material/MaterialTable.vue')['default'] + MenuCardlessContentNode: typeof import('./src/components/activity/MenuCardlessContentNode.vue')['default'] + MultiLineToast: typeof import('./src/components/toast/MultiLineToast.vue')['default'] + Notes: typeof import('./src/components/activity/content/Notes.vue')['default'] + PagesConfig: typeof import('./src/components/print/configurator/PagesConfig.vue')['default'] + PagesOverview: typeof import('./src/components/print/configurator/PagesOverview.vue')['default'] + PeriodMaterialLists: typeof import('./src/components/material/PeriodMaterialLists.vue')['default'] + PeriodSwitcher: typeof import('./src/components/program/PeriodSwitcher.vue')['default'] + PersonalInvitations: typeof import('./src/components/personal_invitations/PersonalInvitations.vue')['default'] + Picasso: typeof import('./src/components/program/picasso/Picasso.vue')['default'] + PicassoConfig: typeof import('./src/components/print/config/PicassoConfig.vue')['default'] + PicassoEntry: typeof import('./src/components/program/picasso/PicassoEntry.vue')['default'] + PopoverPrompt: typeof import('./src/components/prompt/PopoverPrompt.vue')['default'] + PrintConfigurator: typeof import('./src/components/print/PrintConfigurator.vue')['default'] + PrintPreviewClient: typeof import('./src/components/print/print-client/PrintPreviewClient.vue')['default'] + PrintPreviewNuxt: typeof import('./src/components/print/print-nuxt/PrintPreviewNuxt.vue')['default'] + ProgramConfig: typeof import('./src/components/print/config/ProgramConfig.vue')['default'] + PromptCollaboratorDeactivate: typeof import('./src/components/collaborator/PromptCollaboratorDeactivate.vue')['default'] + PromptEntityDelete: typeof import('./src/components/prompt/PromptEntityDelete.vue')['default'] + ResizableColumn: typeof import('./src/components/activity/content/columnLayout/ResizableColumn.vue')['default'] + ResizableColumnHeader: typeof import('./src/components/activity/content/columnLayout/ResizableColumnHeader.vue')['default'] + ResponsiveLayout: typeof import('./src/components/activity/content/ResponsiveLayout.vue')['default'] + RootNode: typeof import('./src/components/activity/RootNode.vue')['default'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + SafetyConsiderations: typeof import('./src/components/activity/content/SafetyConsiderations.vue')['default'] + SafetyConsiderationsConfig: typeof import('./src/components/print/config/SafetyConsiderationsConfig.vue')['default'] + ScheduleEntries: typeof import('./src/components/program/ScheduleEntries.vue')['default'] + ScheduleEntry: typeof import('./src/components/activity/ScheduleEntry.vue')['default'] + ScheduleEntryFilters: typeof import('./src/components/program/ScheduleEntryFilters.vue')['default'] + ScheduleEntryLinks: typeof import('./src/components/material/ScheduleEntryLinks.vue')['default'] + SelectFilter: typeof import('./src/components/dashboard/SelectFilter.vue')['default'] + ServerError: typeof import('./src/components/form/ServerError.vue')['default'] + ServerErrorContent: typeof import('./src/components/form/ServerErrorContent.vue')['default'] + SideBar: typeof import('./src/components/navigation/SideBar.vue')['default'] + SidebarListItem: typeof import('./src/components/layout/SidebarListItem.vue')['default'] + SortableChecklist: typeof import('./src/components/checklist/SortableChecklist.vue')['default'] + SortableChecklistItem: typeof import('./src/components/checklist/SortableChecklistItem.vue')['default'] + Storyboard: typeof import('./src/components/activity/content/Storyboard.vue')['default'] + StoryboardDialogRemoveSection: typeof import('./src/components/activity/content/storyboard/StoryboardDialogRemoveSection.vue')['default'] + StoryboardRowDefault: typeof import('./src/components/activity/content/storyboard/StoryboardRowDefault.vue')['default'] + StoryboardRowDense: typeof import('./src/components/activity/content/storyboard/StoryboardRowDense.vue')['default'] + StoryboardSortable: typeof import('./src/components/activity/content/storyboard/StoryboardSortable.vue')['default'] + StoryConfig: typeof import('./src/components/print/config/StoryConfig.vue')['default'] + Storycontext: typeof import('./src/components/activity/content/Storycontext.vue')['default'] + StoryDay: typeof import('./src/components/story/StoryDay.vue')['default'] + StoryPeriod: typeof import('./src/components/story/StoryPeriod.vue')['default'] + SummaryConfig: typeof import('./src/components/print/config/SummaryConfig.vue')['default'] + TextAlignBaseline: typeof import('./src/components/layout/TextAlignBaseline.vue')['default'] + TiptapEditor: typeof import('./src/components/form/tiptap/TiptapEditor.vue')['default'] + TiptapToolbarButton: typeof import('./src/components/form/tiptap/TiptapToolbarButton.vue')['default'] + TocConfig: typeof import('./src/components/print/config/TocConfig.vue')['default'] + TogglePaperSize: typeof import('./src/components/activity/TogglePaperSize.vue')['default'] + UserAvatar: typeof import('./src/components/user/UserAvatar.vue')['default'] + UserMeta: typeof import('./src/components/navigation/UserMeta.vue')['default'] + VTiptapEditor: typeof import('./src/components/form/tiptap/VTiptapEditor.vue')['default'] + } +} diff --git a/frontend/env.d.ts b/frontend/env.d.ts new file mode 100644 index 00000000000..11f02fe2a00 --- /dev/null +++ b/frontend/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f8b243da519..2b3eff24c67 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -47,7 +47,7 @@ "deepmerge": "4.3.1", "emoji-regex": "10.4.0", "file-saver": "2.0.5", - "hal-json-vuex": "2.0.0-alpha.16", + "hal-json-vuex": "3.0.0-alpha.2", "inter-ui": "3.19.3", "js-cookie": "3.0.5", "linkify-it": "5.0.0", @@ -83,7 +83,9 @@ "@vitest/coverage-v8": "2.1.1", "@vue/babel-preset-app": "5.0.8", "@vue/eslint-config-prettier": "9.0.0", + "@vue/eslint-config-typescript": "^14.0.0-rc.1", "@vue/test-utils": "1.3.6", + "@vue/tsconfig": "^0.1.3", "autoprefixer": "10.4.20", "babel-plugin-require-context-hook": "1.0.0", "eslint": "9.11.1", @@ -101,13 +103,15 @@ "lint-staged": "15.2.10", "prettier": "3.3.3", "sass": "1.32.13", + "typescript": "5.6.2", "unplugin-vue-components": "0.27.4", "vite": "5.4.8", "vite-plugin-comlink": "5.0.1", "vite-plugin-vue2-svg": "0.4.0", "vitest": "2.1.1", "vitest-canvas-mock": "0.3.3", - "vue-template-compiler": "2.7.15" + "vue-template-compiler": "2.7.15", + "vue-tsc": "^0.38.8" } }, "node_modules/@adobe/css-tools": { @@ -4296,6 +4300,236 @@ "dev": true, "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz", + "integrity": "sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/type-utils": "8.7.0", + "@typescript-eslint/utils": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.7.0.tgz", + "integrity": "sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/typescript-estree": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", + "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz", + "integrity": "sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "8.7.0", + "@typescript-eslint/utils": "8.7.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", + "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz", + "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", + "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/typescript-estree": "8.7.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", + "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@vitejs/plugin-vue2": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue2/-/plugin-vue2-2.3.1.tgz", @@ -4497,6 +4731,49 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@volar/code-gen": { + "version": "0.38.9", + "resolved": "https://registry.npmjs.org/@volar/code-gen/-/code-gen-0.38.9.tgz", + "integrity": "sha512-n6LClucfA+37rQeskvh9vDoZV1VvCVNy++MAPKj2dT4FT+Fbmty/SDQqnsEBtdEe6E3OQctFvA/IcKsx3Mns0A==", + "dev": true, + "dependencies": { + "@volar/source-map": "0.38.9" + } + }, + "node_modules/@volar/source-map": { + "version": "0.38.9", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-0.38.9.tgz", + "integrity": "sha512-ba0UFoHDYry+vwKdgkWJ6xlQT+8TFtZg1zj9tSjj4PykW1JZDuM0xplMotLun4h3YOoYfY9K1huY5gvxmrNLIw==", + "dev": true + }, + "node_modules/@volar/vue-code-gen": { + "version": "0.38.9", + "resolved": "https://registry.npmjs.org/@volar/vue-code-gen/-/vue-code-gen-0.38.9.tgz", + "integrity": "sha512-tzj7AoarFBKl7e41MR006ncrEmNPHALuk8aG4WdDIaG387X5//5KhWC5Ff3ZfB2InGSeNT+CVUd74M0gS20rjA==", + "deprecated": "WARNING: This project has been renamed to @vue/language-core. Install using @vue/language-core instead.", + "dev": true, + "dependencies": { + "@volar/code-gen": "0.38.9", + "@volar/source-map": "0.38.9", + "@vue/compiler-core": "^3.2.37", + "@vue/compiler-dom": "^3.2.37", + "@vue/shared": "^3.2.37" + } + }, + "node_modules/@volar/vue-typescript": { + "version": "0.38.9", + "resolved": "https://registry.npmjs.org/@volar/vue-typescript/-/vue-typescript-0.38.9.tgz", + "integrity": "sha512-iJMQGU91ADi98u8V1vXd2UBmELDAaeSP0ZJaFjwosClQdKlJQYc6MlxxKfXBZisHqfbhdtrGRyaryulnYtliZw==", + "deprecated": "WARNING: This project has been renamed to @vue/typescript. Install using @vue/typescript instead.", + "dev": true, + "dependencies": { + "@volar/code-gen": "0.38.9", + "@volar/source-map": "0.38.9", + "@volar/vue-code-gen": "0.38.9", + "@vue/compiler-sfc": "^3.2.37", + "@vue/reactivity": "^3.2.37" + } + }, "node_modules/@vue/babel-helper-vue-jsx-merge-props": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", @@ -4924,6 +5201,46 @@ "prettier": ">= 3.0.0" } }, + "node_modules/@vue/eslint-config-typescript": { + "version": "14.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-14.0.0-rc.1.tgz", + "integrity": "sha512-RMSEN2DuVvZa3W0ySN7aUm9xxCTGfCUIxDcqj9OnMkG9l1ugoKbf+a+yhazUzzUX4P96Z+l67uaFRYwV0eDXUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^8.6.0", + "@typescript-eslint/parser": "^8.6.0", + "typescript-eslint": "^8.6.0", + "vue-eslint-parser": "^9.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.10.0", + "eslint-plugin-vue": "^9.28.0", + "typescript": ">=4.8.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.10.tgz", + "integrity": "sha512-kW08v06F6xPSHhid9DJ9YjOGmwNDOsJJQk0ax21wKaUYzzuJGEuoKNU2Ujux8FLMrP7CFJJKsHhXN9l2WOVi2g==", + "dev": true, + "dependencies": { + "@vue/shared": "3.5.10" + } + }, + "node_modules/@vue/reactivity/node_modules/@vue/shared": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.10.tgz", + "integrity": "sha512-VkkBhU97Ki+XJ0xvl4C9YJsIZ2uIlQ7HqPpZOS3m9VCvmROPaChZU6DexdMJqvz9tbgG+4EtFVrSuailUq5KGQ==", + "dev": true + }, "node_modules/@vue/shared": { "version": "3.5.8", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.8.tgz", @@ -4947,6 +5264,20 @@ "vue-template-compiler": "^2.x" } }, + "node_modules/@vue/tsconfig": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.1.3.tgz", + "integrity": "sha512-kQVsh8yyWPvHpb8gIc9l/HIDiiVUy1amynLNpCy8p+FoCiZXCo6fQos5/097MmnNZc9AtseDsCrfkhqCrJ8Olg==", + "dev": true, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/@zxcvbn-ts/core": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@zxcvbn-ts/core/-/core-3.0.4.tgz", @@ -7595,6 +7926,12 @@ "dev": true, "license": "ISC" }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/hal-json-normalizer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/hal-json-normalizer/-/hal-json-normalizer-4.2.0.tgz", @@ -7608,23 +7945,51 @@ } }, "node_modules/hal-json-vuex": { - "version": "2.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/hal-json-vuex/-/hal-json-vuex-2.0.0-alpha.16.tgz", - "integrity": "sha512-7OtQtJLr9Od4giw27ryINOYlM/6dvNZlcQiiseINq8qKrpc5dV9hLo4QOvKy8YGgnQOXYnCMSJ55/7XM+qiPGg==", - "license": "MIT", + "version": "3.0.0-alpha.2", + "resolved": "https://registry.npmjs.org/hal-json-vuex/-/hal-json-vuex-3.0.0-alpha.2.tgz", + "integrity": "sha512-YJZYQlr32fN/WJme1JuxqqmkiWpXUd4dvXpcl8dT5yIcglQSRkJWIFmJSz9lP6F/eKkUjHlJI4Nso3la1vqkdg==", "dependencies": { "hal-json-normalizer": "^4.2.0", - "url-template": "^2.0.8" + "url-template": "^3.1.1", + "vue-demi": "^0.14.10" }, "engines": { - "node": ">=14.0.0 <19.0.0" + "node": ">=18.0.0 <23.0.0" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^2.0.0 || >=3.0.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } } }, - "node_modules/hal-json-vuex/node_modules/url-template": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==", - "license": "BSD" + "node_modules/hal-json-vuex/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } }, "node_modules/has-bigints": { "version": "1.0.2", @@ -11471,6 +11836,18 @@ "node": ">=18" } }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/tslib": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", @@ -11503,6 +11880,42 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.7.0.tgz", + "integrity": "sha512-nEHbEYJyHwsuf7c3V3RS7Saq+1+la3i0ieR3qP0yjqWSzVmh8Drp47uOl9LjbPANac4S7EFSqvcYIKXUUwIfIQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.7.0", + "@typescript-eslint/parser": "8.7.0", + "@typescript-eslint/utils": "8.7.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", @@ -12247,6 +12660,21 @@ "vue": "^2.6 || ^3.2" } }, + "node_modules/vue-tsc": { + "version": "0.38.9", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-0.38.9.tgz", + "integrity": "sha512-Yoy5phgvGqyF98Fb4mYqboR4Q149jrdcGv5kSmufXJUq++RZJ2iMVG0g6zl+v3t4ORVWkQmRpsV4x2szufZ0LQ==", + "dev": true, + "dependencies": { + "@volar/vue-typescript": "0.38.9" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + }, "node_modules/vue/node_modules/@vue/compiler-sfc": { "version": "2.7.15", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.15.tgz", diff --git a/frontend/package.json b/frontend/package.json index a198e966e86..e80fce8648b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -59,7 +59,7 @@ "deepmerge": "4.3.1", "emoji-regex": "10.4.0", "file-saver": "2.0.5", - "hal-json-vuex": "2.0.0-alpha.16", + "hal-json-vuex": "3.0.0-alpha.2", "inter-ui": "3.19.3", "js-cookie": "3.0.5", "linkify-it": "5.0.0", @@ -95,7 +95,9 @@ "@vitest/coverage-v8": "2.1.1", "@vue/babel-preset-app": "5.0.8", "@vue/eslint-config-prettier": "9.0.0", + "@vue/eslint-config-typescript": "^14.0.0-rc.1", "@vue/test-utils": "1.3.6", + "@vue/tsconfig": "^0.1.3", "autoprefixer": "10.4.20", "babel-plugin-require-context-hook": "1.0.0", "eslint": "9.11.1", @@ -113,13 +115,15 @@ "lint-staged": "15.2.10", "prettier": "3.3.3", "sass": "1.32.13", + "typescript": "5.6.2", "unplugin-vue-components": "0.27.4", "vite": "5.4.8", "vite-plugin-comlink": "5.0.1", "vite-plugin-vue2-svg": "0.4.0", "vitest": "2.1.1", "vitest-canvas-mock": "0.3.3", - "vue-template-compiler": "2.7.15" + "vue-template-compiler": "2.7.15", + "vue-tsc": "^0.38.8" }, "overrides": { "uri-js": "npm:uri-js-replace" diff --git a/frontend/src/plugins/store/index.js b/frontend/src/plugins/store/index.js index cc7c66358db..993281bf562 100644 --- a/frontend/src/plugins/store/index.js +++ b/frontend/src/plugins/store/index.js @@ -1,7 +1,7 @@ import Vuex from 'vuex' import axios from 'axios' import VueAxios from 'vue-axios/dist/vue-axios.common.min' -import HalJsonVuex from 'hal-json-vuex' +import { HalJsonVuexPlugin } from 'hal-json-vuex' import lang from './lang' import auth from './auth' import preferences from './preferences' @@ -32,11 +32,10 @@ class StorePlugin { Vue.use(VueAxios, axios) - let halJsonVuex = HalJsonVuex - if (typeof halJsonVuex !== 'function') { - halJsonVuex = HalJsonVuex.default - } - apiStore = halJsonVuex(store, axios, { forceRequestedSelfLink: true }) + /** + * @type apiStore {import('hal-json-vuex').HalJsonVuex} + */ + apiStore = HalJsonVuexPlugin(store, axios, { forceRequestedSelfLink: true }) Vue.use(apiStore) } } diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json new file mode 100644 index 00000000000..cdbea1d76e5 --- /dev/null +++ b/frontend/tsconfig.app.json @@ -0,0 +1,12 @@ +{ + "extends": "@vue/tsconfig/tsconfig.web.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/frontend/tsconfig.config.json b/frontend/tsconfig.config.json new file mode 100644 index 00000000000..c2d3a309ef1 --- /dev/null +++ b/frontend/tsconfig.config.json @@ -0,0 +1,8 @@ +{ + "extends": "@vue/tsconfig/tsconfig.node.json", + "include": ["vite.config.*", "vitest.config.*", "cypress.config.*"], + "compilerOptions": { + "composite": true, + "types": ["node"] + } +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 00000000000..31f90037cb7 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,14 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.config.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.vitest.json" + } + ] +} diff --git a/frontend/tsconfig.vitest.json b/frontend/tsconfig.vitest.json new file mode 100644 index 00000000000..d080d611e38 --- /dev/null +++ b/frontend/tsconfig.vitest.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.app.json", + "exclude": [], + "compilerOptions": { + "composite": true, + "lib": [], + "types": ["node", "jsdom"] + } +} diff --git a/print/nuxt.config.js b/print/nuxt.config.js index 38aa28a265b..bd50f26da24 100644 --- a/print/nuxt.config.js +++ b/print/nuxt.config.js @@ -11,7 +11,7 @@ export default defineNuxtConfig({ '~/assets/calendar/CalendarDaily.sass', '~/assets/calendar/CalendarWithEvents.sass', ], - plugins: [{ src: '~/plugins/hal-json-vuex.js' }, { src: '~/plugins/dayjs.js' }], + plugins: [{ src: '~/plugins/hal-json-vuex.ts' }, { src: '~/plugins/dayjs.js' }], components: [ { path: '~/components/config', prefix: 'Config', global: 'true' }, diff --git a/print/package-lock.json b/print/package-lock.json index 062d137dceb..52bce334d45 100644 --- a/print/package-lock.json +++ b/print/package-lock.json @@ -13,7 +13,7 @@ "colorjs.io": "0.5.2", "dayjs": "1.11.13", "deepmerge": "4.3.1", - "hal-json-vuex": "3.0.0-alpha.1", + "hal-json-vuex": "3.0.0-alpha.2", "isomorphic-dompurify": "2.15.0", "lodash": "4.17.21", "puppeteer-core": "23.4.1", @@ -9178,16 +9178,50 @@ } }, "node_modules/hal-json-vuex": { - "version": "3.0.0-alpha.1", - "resolved": "https://registry.npmjs.org/hal-json-vuex/-/hal-json-vuex-3.0.0-alpha.1.tgz", - "integrity": "sha512-9aLwBtdNGxNGmJrDu/aEDTaCNgHMhiPTKE40iL7R08kYiVrf2VfV+jfu89GyJKYDgZiBjm46naQ9FmW0fnAAPQ==", - "license": "MIT", + "version": "3.0.0-alpha.2", + "resolved": "https://registry.npmjs.org/hal-json-vuex/-/hal-json-vuex-3.0.0-alpha.2.tgz", + "integrity": "sha512-YJZYQlr32fN/WJme1JuxqqmkiWpXUd4dvXpcl8dT5yIcglQSRkJWIFmJSz9lP6F/eKkUjHlJI4Nso3la1vqkdg==", "dependencies": { "hal-json-normalizer": "^4.2.0", - "url-template": "^2.0.8" + "url-template": "^3.1.1", + "vue-demi": "^0.14.10" }, "engines": { - "node": ">=16.0.0 <21.0.0" + "node": ">=18.0.0 <23.0.0" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^2.0.0 || >=3.0.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/hal-json-vuex/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } } }, "node_modules/has-flag": { @@ -16873,10 +16907,12 @@ "license": "MIT" }, "node_modules/url-template": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==", - "license": "BSD" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-3.1.1.tgz", + "integrity": "sha512-4oszoaEKE/mQOtAmdMWqIRHmkxWkUZMnXFnjQ5i01CuRSK3uluxcH1MRVVVWmhlnzT1SCDfKxxficm2G37qzCA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } }, "node_modules/urlpattern-polyfill": { "version": "8.0.2", diff --git a/print/package.json b/print/package.json index 0789c5e937a..18983e0dee0 100644 --- a/print/package.json +++ b/print/package.json @@ -22,7 +22,7 @@ "colorjs.io": "0.5.2", "dayjs": "1.11.13", "deepmerge": "4.3.1", - "hal-json-vuex": "3.0.0-alpha.1", + "hal-json-vuex": "3.0.0-alpha.2", "isomorphic-dompurify": "2.15.0", "lodash": "4.17.21", "puppeteer-core": "23.4.1", diff --git a/print/plugins/hal-json-vuex.ts b/print/plugins/hal-json-vuex.ts new file mode 100644 index 00000000000..2f617e5d5b0 --- /dev/null +++ b/print/plugins/hal-json-vuex.ts @@ -0,0 +1,41 @@ +import { HalJsonVuexPlugin } from 'hal-json-vuex' +import axios from 'axios' +import { createStore } from 'vuex' +import { + addAuthorizationInterceptor, + addDebugInterceptor, + addErrorLogInterceptor, +} from '~/plugins/hal-json-vuex/axios' +import type { RootEndpoint } from '~/common/helpers/endpoints' + +export default defineNuxtPlugin((nuxtApp) => { + // create store + const store = createStore({ + state() { + return {} + }, + }) + nuxtApp.vueApp.use(store) + + // create axios instance + const { internalApiRootUrl } = useRuntimeConfig() + const axiosInstance = axios.create({ + withCredentials: true, + baseURL: internalApiRootUrl, + headers: { common: { Accept: 'application/hal+json' } }, + }) + addAuthorizationInterceptor(axiosInstance) + addDebugInterceptor(axiosInstance) + addErrorLogInterceptor(axiosInstance) + + // create and inject API + const api = HalJsonVuexPlugin(store, axiosInstance, { + forceRequestedSelfLink: true, + }) + + return { + provide: { + api, + }, + } +}) diff --git a/print/plugins/hal-json-vuex.js b/print/plugins/hal-json-vuex/axios.js similarity index 59% rename from print/plugins/hal-json-vuex.js rename to print/plugins/hal-json-vuex/axios.js index cc28e385756..0d5586bff58 100644 --- a/print/plugins/hal-json-vuex.js +++ b/print/plugins/hal-json-vuex/axios.js @@ -1,40 +1,4 @@ -import HalJsonVuex from 'hal-json-vuex' -import axios from 'axios' -import { createStore } from 'vuex' - -export default defineNuxtPlugin((nuxtApp) => { - // create store - const store = createStore({ - state() { - return {} - }, - }) - nuxtApp.vueApp.use(store) - - // create axios instance - const { internalApiRootUrl } = useRuntimeConfig() - const axiosInstance = axios.create({ - withCredentials: true, - baseURL: internalApiRootUrl, - headers: { common: { Accept: 'application/hal+json' } }, - }) - addAuthorizationInterceptor(axiosInstance) - addDebugInterceptor(axiosInstance) - addErrorLogInterceptor(axiosInstance) - - // create and inject API - const api = new HalJsonVuex(store, axiosInstance, { - forceRequestedSelfLink: true, - }) - - return { - provide: { - api, - }, - } -}) - -function addAuthorizationInterceptor(axios) { +export function addAuthorizationInterceptor(axios) { const { basicAuthToken } = useRuntimeConfig() const requestHeaders = useRequestHeaders(['cookie']) @@ -58,7 +22,7 @@ function addAuthorizationInterceptor(axios) { }) } -function addDebugInterceptor(axios) { +export function addDebugInterceptor(axios) { if (!import.meta.env.DEV) { return } @@ -81,7 +45,7 @@ function addDebugInterceptor(axios) { }) } -function addErrorLogInterceptor(axios) { +export function addErrorLogInterceptor(axios) { axios.interceptors.response.use( (response) => response, (error) => {