From 4b4af1346958cb2020b269b0f686608ceb547b7e Mon Sep 17 00:00:00 2001 From: Christian Hartmann Date: Tue, 11 Aug 2026 22:22:14 +0200 Subject: [PATCH] chore: migrate mixins to composables Signed-off-by: Christian Hartmann --- src/Forms.vue | 12 +- src/components/AppNavigationForm.vue | 13 +- src/components/Questions/QuestionColor.vue | 15 +- src/components/Questions/QuestionDate.vue | 14 +- src/components/Questions/QuestionDropdown.vue | 22 +- src/components/Questions/QuestionFile.vue | 15 +- src/components/Questions/QuestionGrid.vue | 22 +- .../Questions/QuestionLinearScale.vue | 15 +- src/components/Questions/QuestionLong.vue | 14 +- src/components/Questions/QuestionMultiple.vue | 27 +- src/components/Questions/QuestionRanking.vue | 22 +- src/components/Questions/QuestionShort.vue | 15 +- .../SidebarTabs/SettingsSidebarTab.vue | 41 +- .../SidebarTabs/SharingSearchDiv.vue | 86 ++-- .../SidebarTabs/SharingShareDiv.vue | 25 +- .../SidebarTabs/SharingSidebarTab.vue | 28 +- .../SidebarTabs/TransferOwnership.vue | 5 +- src/components/TopBar.vue | 12 +- src/composables/useQuestion.ts | 367 +++++++++++++++ src/composables/useQuestionMultiple.ts | 383 ++++++++++++++++ src/composables/useShareLink.ts | 99 ++++ src/composables/useShareTypes.ts | 110 +++++ src/composables/useUserSearch.ts | 230 ++++++++++ src/composables/useViewForm.ts | 190 ++++++++ src/mixins/PermissionTypes.ts | 46 -- src/mixins/QuestionMixin.ts | 424 ----------------- src/mixins/QuestionMultipleMixin.ts | 431 ------------------ src/mixins/ShareLinkMixin.ts | 110 ----- src/mixins/ShareTypes.ts | 88 ---- src/mixins/UserSearchMixin.ts | 283 ------------ src/mixins/ViewsMixin.ts | 205 --------- src/models/Permissions.ts | 27 ++ src/views/Create.vue | 101 +++- src/views/Results.vue | 40 +- src/views/Sidebar.vue | 128 ++++-- src/views/Submit.vue | 46 +- 36 files changed, 1894 insertions(+), 1817 deletions(-) create mode 100644 src/composables/useQuestion.ts create mode 100644 src/composables/useQuestionMultiple.ts create mode 100644 src/composables/useShareLink.ts create mode 100644 src/composables/useShareTypes.ts create mode 100644 src/composables/useUserSearch.ts create mode 100644 src/composables/useViewForm.ts delete mode 100644 src/mixins/PermissionTypes.ts delete mode 100644 src/mixins/QuestionMixin.ts delete mode 100644 src/mixins/QuestionMultipleMixin.ts delete mode 100644 src/mixins/ShareLinkMixin.ts delete mode 100644 src/mixins/ShareTypes.ts delete mode 100644 src/mixins/UserSearchMixin.ts delete mode 100644 src/mixins/ViewsMixin.ts create mode 100644 src/models/Permissions.ts diff --git a/src/Forms.vue b/src/Forms.vue index 55f6c988e..699a739b4 100644 --- a/src/Forms.vue +++ b/src/Forms.vue @@ -174,8 +174,8 @@ import AppNavigationForm from './components/AppNavigationForm.vue' import ArchivedFormsModal from './components/ArchivedFormsModal.vue' import Sidebar from './views/Sidebar.vue' import FormsIcon from '../img/forms-dark.svg?raw' -import { PERMISSION_TYPES } from './mixins/PermissionTypes.ts' import { FormState } from './models/Constants.ts' +import { PERMISSION_TYPES } from './models/Permissions.ts' import logger from './utils/Logger.ts' import OcsResponse2Data from './utils/OcsResponse2Data.ts' @@ -273,8 +273,6 @@ export default defineComponent({ }) const updateSelectedForm = (form: FormsForm): void => { - sidebarOpened.value = false - const index = forms.value.findIndex((f) => f.hash === form.hash) if (index > -1) { forms.value[index] = form @@ -546,6 +544,14 @@ export default defineComponent({ }, ) + // Close sidebar when a different form is selected + watch( + () => selectedForm.value.hash, + () => { + sidebarOpened.value = false + }, + ) + const onLastUpdatedByEventBus = (id: number): void => { const formIndex = forms.value.findIndex((form) => form.id === id) if (formIndex !== -1) { diff --git a/src/components/AppNavigationForm.vue b/src/components/AppNavigationForm.vue index b50c71434..9e83edc02 100644 --- a/src/components/AppNavigationForm.vue +++ b/src/components/AppNavigationForm.vue @@ -123,8 +123,8 @@ import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' import NcListItem from '@nextcloud/vue/components/NcListItem' import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon' import FormsIcon from '../../img/forms-dark.svg?raw' -import PermissionTypes from '../mixins/PermissionTypes.ts' import { FormState } from '../models/Constants.ts' +import { PERMISSION_TYPES } from '../models/Permissions.ts' import logger from '../utils/Logger.ts' type NavigationTarget = 'submit' | 'formRoot' @@ -141,8 +141,6 @@ export default defineComponent({ NcLoadingIcon, }, - mixins: [PermissionTypes], - props: { form: { type: Object as PropType, @@ -186,16 +184,13 @@ export default defineComponent({ computed: { canEdit(): boolean { - return this.form.permissions.includes( - this.PERMISSION_TYPES.PERMISSION_EDIT, - ) + return this.form.permissions.includes(PERMISSION_TYPES.PERMISSION_EDIT) }, canSeeResults(): boolean { return ( - this.form.permissions.includes( - this.PERMISSION_TYPES.PERMISSION_RESULTS, - ) || (this.form.submissionCount ?? 0) > 0 + this.form.permissions.includes(PERMISSION_TYPES.PERMISSION_RESULTS) + || (this.form.submissionCount ?? 0) > 0 ) }, diff --git a/src/components/Questions/QuestionColor.vue b/src/components/Questions/QuestionColor.vue index 21755e60f..416c42370 100644 --- a/src/components/Questions/QuestionColor.vue +++ b/src/components/Questions/QuestionColor.vue @@ -53,7 +53,11 @@ import NcButton from '@nextcloud/vue/components/NcButton' import NcColorPicker from '@nextcloud/vue/components/NcColorPicker' import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' import Question from './Question.vue' -import QuestionMixin from '../../mixins/QuestionMixin.ts' +import { + QUESTION_EMITS, + QUESTION_PROPS, + useQuestion, +} from '../../composables/useQuestion.ts' export default defineComponent({ name: 'QuestionColor', @@ -65,11 +69,14 @@ export default defineComponent({ Question, }, - mixins: [QuestionMixin], - emits: ['update:values'], + props: QUESTION_PROPS, + emits: [...QUESTION_EMITS, 'update:values'], + + setup(props, { emit }) { + const question = useQuestion(props, { emit }) - setup() { return { + ...question, IconClose, t, } diff --git a/src/components/Questions/QuestionDate.vue b/src/components/Questions/QuestionDate.vue index 1207e8014..664f8437d 100644 --- a/src/components/Questions/QuestionDate.vue +++ b/src/components/Questions/QuestionDate.vue @@ -121,7 +121,11 @@ import svgClockLoader20 from '../../../img/clock_loader_20.svg?raw' import svgClockLoader80 from '../../../img/clock_loader_80.svg?raw' import svgEventIcon from '../../../img/event.svg?raw' import svgTodayIcon from '../../../img/today.svg?raw' -import QuestionMixin from '../../mixins/QuestionMixin.ts' +import { + QUESTION_EMITS, + QUESTION_PROPS, + useQuestion, +} from '../../composables/useQuestion.ts' type PickerType = 'date' | 'datetime' | 'time' | 'date-range' | 'datetime-range' | 'time-range' @@ -146,8 +150,12 @@ export default defineComponent({ Question, }, - mixins: [QuestionMixin], - emits: ['update:values'], + props: QUESTION_PROPS, + emits: [...QUESTION_EMITS, 'update:values'], + + setup(props, { emit }) { + return useQuestion(props, { emit }) + }, data() { return { diff --git a/src/components/Questions/QuestionDropdown.vue b/src/components/Questions/QuestionDropdown.vue index 2a66b2f28..cf0b306d5 100644 --- a/src/components/Questions/QuestionDropdown.vue +++ b/src/components/Questions/QuestionDropdown.vue @@ -114,8 +114,15 @@ import NcSelect from '@nextcloud/vue/components/NcSelect' import OptionInputDialog from '../OptionInputDialog.vue' import AnswerInput from './AnswerInput.vue' import Question from './Question.vue' -import QuestionMixin from '../../mixins/QuestionMixin.ts' -import QuestionMultipleMixin from '../../mixins/QuestionMultipleMixin.ts' +import { + QUESTION_EMITS, + QUESTION_PROPS, + useQuestion, +} from '../../composables/useQuestion.ts' +import { + QUESTION_MULTIPLE_EMITS, + useQuestionMultiple, +} from '../../composables/useQuestionMultiple.ts' import { OptionType } from '../../models/Constants.ts' export default defineComponent({ @@ -133,11 +140,16 @@ export default defineComponent({ Question, }, - mixins: [QuestionMixin, QuestionMultipleMixin], - emits: ['update:values'], + props: QUESTION_PROPS, + emits: [...QUESTION_EMITS, ...QUESTION_MULTIPLE_EMITS, 'update:values'], + + setup(props, { emit }) { + const question = useQuestion(props, { emit }) + const questionMultiple = useQuestionMultiple(props, { emit }) - setup() { return { + ...question, + ...questionMultiple, IconContentPaste, t, } diff --git a/src/components/Questions/QuestionFile.vue b/src/components/Questions/QuestionFile.vue index 3d2756bd1..24a9075dc 100644 --- a/src/components/Questions/QuestionFile.vue +++ b/src/components/Questions/QuestionFile.vue @@ -176,7 +176,11 @@ import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' import NcListItem from '@nextcloud/vue/components/NcListItem' import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon' import Question from './Question.vue' -import QuestionMixin from '../../mixins/QuestionMixin.ts' +import { + QUESTION_EMITS, + QUESTION_PROPS, + useQuestion, +} from '../../composables/useQuestion.ts' import fileTypes from '../../models/FileTypes.ts' import logger from '../../utils/Logger.ts' import OcsResponse2Data from '../../utils/OcsResponse2Data.ts' @@ -227,11 +231,14 @@ export default defineComponent({ Question, }, - mixins: [QuestionMixin], - emits: ['update:values'], + props: QUESTION_PROPS, + emits: [...QUESTION_EMITS, 'update:values'], + + setup(props, { emit }) { + const question = useQuestion(props, { emit }) - setup() { return { + ...question, IconChevronLeft, IconDelete, IconFile, diff --git a/src/components/Questions/QuestionGrid.vue b/src/components/Questions/QuestionGrid.vue index d931d314a..8bdcc1768 100644 --- a/src/components/Questions/QuestionGrid.vue +++ b/src/components/Questions/QuestionGrid.vue @@ -186,8 +186,15 @@ import NcInputField from '@nextcloud/vue/components/NcInputField' import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon' import AnswerInput from './AnswerInput.vue' import Question from './Question.vue' -import QuestionMixin from '../../mixins/QuestionMixin.ts' -import QuestionMultipleMixin from '../../mixins/QuestionMultipleMixin.ts' +import { + QUESTION_EMITS, + QUESTION_PROPS, + useQuestion, +} from '../../composables/useQuestion.ts' +import { + QUESTION_MULTIPLE_EMITS, + useQuestionMultiple, +} from '../../composables/useQuestionMultiple.ts' import { GridCellType, OptionType } from '../../models/Constants.ts' type GridQuestionType = GridCellType | 'text' @@ -216,11 +223,16 @@ export default defineComponent({ Question, }, - mixins: [QuestionMixin, QuestionMultipleMixin], - emits: ['update:values'], + props: QUESTION_PROPS, + emits: [...QUESTION_EMITS, ...QUESTION_MULTIPLE_EMITS, 'update:values'], + + setup(props, { emit }) { + const question = useQuestion(props, { emit }) + const questionMultiple = useQuestionMultiple(props, { emit }) - setup() { return { + ...question, + ...questionMultiple, t, } }, diff --git a/src/components/Questions/QuestionLinearScale.vue b/src/components/Questions/QuestionLinearScale.vue index 672477221..70393832a 100644 --- a/src/components/Questions/QuestionLinearScale.vue +++ b/src/components/Questions/QuestionLinearScale.vue @@ -126,7 +126,11 @@ import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwit import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' import NcTextArea from '@nextcloud/vue/components/NcTextArea' import Question from './Question.vue' -import QuestionMixin from '../../mixins/QuestionMixin.ts' +import { + QUESTION_EMITS, + QUESTION_PROPS, + useQuestion, +} from '../../composables/useQuestion.ts' type LinearScaleExtraSettings = { optionsLowest?: number | null @@ -146,11 +150,14 @@ export default defineComponent({ Question, }, - mixins: [QuestionMixin], - emits: ['update:values'], + props: QUESTION_PROPS, + emits: [...QUESTION_EMITS, 'update:values'], + + setup(props, { emit }) { + const question = useQuestion(props, { emit }) - setup() { return { + ...question, IconPencil, t, } diff --git a/src/components/Questions/QuestionLong.vue b/src/components/Questions/QuestionLong.vue index 538d1971c..cf1fa71b7 100644 --- a/src/components/Questions/QuestionLong.vue +++ b/src/components/Questions/QuestionLong.vue @@ -41,7 +41,11 @@ import { t } from '@nextcloud/l10n' import { defineComponent } from 'vue' import Question from './Question.vue' -import QuestionMixin from '../../mixins/QuestionMixin.ts' +import { + QUESTION_EMITS, + QUESTION_PROPS, + useQuestion, +} from '../../composables/useQuestion.ts' export default defineComponent({ name: 'QuestionLong', @@ -50,8 +54,12 @@ export default defineComponent({ Question, }, - mixins: [QuestionMixin], - emits: ['update:values', 'keydown'], + props: QUESTION_PROPS, + emits: [...QUESTION_EMITS, 'update:values', 'keydown'], + + setup(props, { emit }) { + return useQuestion(props, { emit }) + }, data() { return { diff --git a/src/components/Questions/QuestionMultiple.vue b/src/components/Questions/QuestionMultiple.vue index 5bdaf56dc..139b91a2f 100644 --- a/src/components/Questions/QuestionMultiple.vue +++ b/src/components/Questions/QuestionMultiple.vue @@ -204,8 +204,15 @@ import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon' import OptionInputDialog from '../OptionInputDialog.vue' import AnswerInput from './AnswerInput.vue' import Question from './Question.vue' -import QuestionMixin from '../../mixins/QuestionMixin.ts' -import QuestionMultipleMixin from '../../mixins/QuestionMultipleMixin.ts' +import { + QUESTION_EMITS, + QUESTION_PROPS, + useQuestion, +} from '../../composables/useQuestion.ts' +import { + QUESTION_MULTIPLE_EMITS, + useQuestionMultiple, +} from '../../composables/useQuestionMultiple.ts' import { OptionType, QUESTION_EXTRASETTINGS_OTHER_PREFIX, @@ -235,11 +242,21 @@ export default defineComponent({ Question, }, - mixins: [QuestionMixin, QuestionMultipleMixin], - emits: ['update:values', 'update:isRequired'], + props: QUESTION_PROPS, + emits: [ + ...QUESTION_EMITS, + ...QUESTION_MULTIPLE_EMITS, + 'update:values', + 'update:isRequired', + ], + + setup(props, { emit }) { + const question = useQuestion(props, { emit }) + const questionMultiple = useQuestionMultiple(props, { emit }) - setup() { return { + ...question, + ...questionMultiple, IconCheckboxBlankOutline, IconContentPaste, IconRadioboxBlank, diff --git a/src/components/Questions/QuestionRanking.vue b/src/components/Questions/QuestionRanking.vue index 8668fd80e..0a7d4c29b 100644 --- a/src/components/Questions/QuestionRanking.vue +++ b/src/components/Questions/QuestionRanking.vue @@ -213,8 +213,15 @@ import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon' import OptionInputDialog from '../OptionInputDialog.vue' import AnswerInput from './AnswerInput.vue' import Question from './Question.vue' -import QuestionMixin from '../../mixins/QuestionMixin.ts' -import QuestionMultipleMixin from '../../mixins/QuestionMultipleMixin.ts' +import { + QUESTION_EMITS, + QUESTION_PROPS, + useQuestion, +} from '../../composables/useQuestion.ts' +import { + QUESTION_MULTIPLE_EMITS, + useQuestionMultiple, +} from '../../composables/useQuestionMultiple.ts' import { OptionType } from '../../models/Constants.ts' export default defineComponent({ @@ -233,11 +240,16 @@ export default defineComponent({ Question, }, - mixins: [QuestionMixin, QuestionMultipleMixin], - emits: ['update:values'], + props: QUESTION_PROPS, + emits: [...QUESTION_EMITS, ...QUESTION_MULTIPLE_EMITS, 'update:values'], + + setup(props, { emit }) { + const question = useQuestion(props, { emit }) + const questionMultiple = useQuestionMultiple(props, { emit }) - setup() { return { + ...question, + ...questionMultiple, IconArrowDown, IconArrowUp, IconClose, diff --git a/src/components/Questions/QuestionShort.vue b/src/components/Questions/QuestionShort.vue index 79bbacb84..e593249bd 100644 --- a/src/components/Questions/QuestionShort.vue +++ b/src/components/Questions/QuestionShort.vue @@ -88,7 +88,11 @@ import NcActionRadio from '@nextcloud/vue/components/NcActionRadio' import NcActions from '@nextcloud/vue/components/NcActions' import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' import Question from './Question.vue' -import QuestionMixin from '../../mixins/QuestionMixin.ts' +import { + QUESTION_EMITS, + QUESTION_PROPS, + useQuestion, +} from '../../composables/useQuestion.ts' import { INPUT_DEBOUNCE_MS } from '../../models/Constants.ts' import validationTypes from '../../models/ValidationTypes.ts' import { splitRegex, validateExpression } from '../../utils/RegularExpression.ts' @@ -104,11 +108,14 @@ export default defineComponent({ Question, }, - mixins: [QuestionMixin], - emits: ['update:values'], + props: QUESTION_PROPS, + emits: [...QUESTION_EMITS, 'update:values'], + + setup(props, { emit }) { + const question = useQuestion(props, { emit }) - setup() { return { + ...question, IconRegex, t, } diff --git a/src/components/SidebarTabs/SettingsSidebarTab.vue b/src/components/SidebarTabs/SettingsSidebarTab.vue index 9ad7f1881..b16e2f85d 100644 --- a/src/components/SidebarTabs/SettingsSidebarTab.vue +++ b/src/components/SidebarTabs/SettingsSidebarTab.vue @@ -97,7 +97,7 @@ v-show="hasMaxSubmissions && !formArchived" class="settings-div--indent"> 0) { - this.$emit('update:formProp', 'maxSubmissions', value) + this.$emit('update:formProp', 'maxSubmissions', parsedValue) } }, diff --git a/src/components/SidebarTabs/SharingSearchDiv.vue b/src/components/SidebarTabs/SharingSearchDiv.vue index 6f206be9f..3a6389df1 100644 --- a/src/components/SidebarTabs/SharingSearchDiv.vue +++ b/src/components/SidebarTabs/SharingSearchDiv.vue @@ -23,28 +23,20 @@