refactor(dav): migrate Settings frontend to Vue 3

- migrate deprecated props
- use direct import of t rather than the mixin

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
Ferdinand Thiessen
2025-10-22 23:07:55 +02:00
parent e04597d8a1
commit 97b91027da
21 changed files with 197 additions and 151 deletions
@@ -56,6 +56,8 @@ class AvailabilitySettings implements ISettings {
}
}
\OCP\Util::addStyle(Application::APP_ID, 'settings-personal-availability');
\OCP\Util::addScript(Application::APP_ID, 'settings-personal-availability');
return new TemplateResponse(Application::APP_ID, 'settings-personal-availability');
}
+3
View File
@@ -44,6 +44,9 @@ class CalDAVSettings implements IDelegatedSettings {
$value = $this->config->getAppValue(Application::APP_ID, $key, $default);
$this->initialState->provideInitialState($key, $value === 'yes');
}
\OCP\Util::addScript(Application::APP_ID, 'settings-admin-caldav');
\OCP\Util::addStyle(Application::APP_ID, 'settings-admin-caldav');
return new TemplateResponse(Application::APP_ID, 'settings-admin-caldav');
}
@@ -53,7 +53,9 @@ class ExampleContentSettings implements ISettings {
);
}
return new TemplateResponse(Application::APP_ID, 'settings-example-content');
\OCP\Util::addStyle(Application::APP_ID, 'settings-admin-example-content');
\OCP\Util::addScript(Application::APP_ID, 'settings-admin-example-content');
return new TemplateResponse(Application::APP_ID, 'settings-admin-example-content');
}
public function getSection(): ?string {
+22 -25
View File
@@ -9,46 +9,39 @@
<NcDateTimePickerNative
id="absence-first-day"
v-model="firstDay"
:label="$t('dav', 'First day')"
:label="t('dav', 'First day')"
class="absence__dates__picker"
:required="true" />
<NcDateTimePickerNative
id="absence-last-day"
v-model="lastDay"
:label="$t('dav', 'Last day (inclusive)')"
:label="t('dav', 'Last day (inclusive)')"
class="absence__dates__picker"
:required="true" />
</div>
<label for="replacement-search-input">{{ $t('dav', 'Out of office replacement (optional)') }}</label>
<NcSelect
ref="select"
<label for="replacement-search-input">{{ t('dav', 'Out of office replacement (optional)') }}</label>
<NcSelectUsers
v-model="replacementUser"
input-id="replacement-search-input"
:loading="searchLoading"
:placeholder="$t('dav', 'Name of the replacement')"
:clear-search-on-blur="() => false"
user-select
:placeholder="t('dav', 'Name of the replacement')"
:options="options"
@search="asyncFind">
<template #no-options="{ search }">
{{ search ? $t('dav', 'No results.') : $t('dav', 'Start typing.') }}
</template>
</NcSelect>
<NcTextField :value.sync="status" :label="$t('dav', 'Short absence status')" :required="true" />
<NcTextArea :value.sync="message" :label="$t('dav', 'Long absence Message')" :required="true" />
@search="asyncFind" />
<NcTextField v-model="status" :label="t('dav', 'Short absence status')" :required="true" />
<NcTextArea v-model="message" :label="t('dav', 'Long absence Message')" :required="true" />
<div class="absence__buttons">
<NcButton
:disabled="loading || !valid"
variant="primary"
type="submit">
{{ $t('dav', 'Save') }}
{{ t('dav', 'Save') }}
</NcButton>
<NcButton
:disabled="loading || !valid"
variant="error"
@click="clearAbsence">
{{ $t('dav', 'Disable absence') }}
{{ t('dav', 'Disable absence') }}
</NcButton>
</div>
</form>
@@ -59,18 +52,18 @@ import { getCurrentUser } from '@nextcloud/auth'
import axios from '@nextcloud/axios'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { generateOcsUrl } from '@nextcloud/router'
import { ShareType } from '@nextcloud/sharing'
import debounce from 'debounce'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcDateTimePickerNative from '@nextcloud/vue/components/NcDateTimePickerNative'
import NcSelect from '@nextcloud/vue/components/NcSelect'
import NcSelectUsers from '@nextcloud/vue/components/NcSelectUsers'
import NcTextArea from '@nextcloud/vue/components/NcTextArea'
import NcTextField from '@nextcloud/vue/components/NcTextField'
import { logger } from '../service/logger.ts'
import { formatDateAsYMD } from '../utils/date.js'
import { formatDateAsYMD } from '../utils/date.ts'
/* eslint @nextcloud/vue/no-deprecated-props: "warn" */
export default {
name: 'AbsenceForm',
components: {
@@ -78,7 +71,11 @@ export default {
NcTextField,
NcTextArea,
NcDateTimePickerNative,
NcSelect,
NcSelectUsers,
},
setup() {
return { t }
},
data() {
@@ -228,9 +225,9 @@ export default {
message: this.message,
replacementUserId: this.replacementUser?.user ?? null,
})
showSuccess(this.$t('dav', 'Absence saved'))
showSuccess(t('dav', 'Absence saved'))
} catch (error) {
showError(this.$t('dav', 'Failed to save your absence settings'))
showError(t('dav', 'Failed to save your absence settings'))
logger.error('Could not save absence', { error })
} finally {
this.loading = false
@@ -242,9 +239,9 @@ export default {
try {
await axios.delete(generateOcsUrl('/apps/dav/api/v1/outOfOffice/{userId}', { userId: getCurrentUser().uid }))
this.resetForm()
showSuccess(this.$t('dav', 'Absence cleared'))
showSuccess(t('dav', 'Absence cleared'))
} catch (error) {
showError(this.$t('dav', 'Failed to clear your absence settings'))
showError(t('dav', 'Failed to clear your absence settings'))
logger.error('Could not clear absence', { error })
} finally {
this.loading = false
@@ -9,7 +9,7 @@
:checked="enableDefaultContact"
type="switch"
@update:model-value="updateEnableDefaultContact">
{{ $t('dav', "Add example contact to user's address book when they first log in") }}
{{ t('dav', "Add example contact to user's address book when they first log in") }}
</NcCheckboxRadioSwitch>
<div v-if="enableDefaultContact" class="example-contact-settings__buttons">
<ExampleContentDownloadButton :href="downloadUrl">
@@ -24,7 +24,7 @@
<template #icon>
<IconUpload :size="20" />
</template>
{{ $t('dav', 'Import contact') }}
{{ t('dav', 'Import contact') }}
</NcButton>
<NcButton
v-if="hasCustomDefaultContact"
@@ -33,15 +33,15 @@
<template #icon>
<IconRestore :size="20" />
</template>
{{ $t('dav', 'Reset to default') }}
{{ t('dav', 'Reset to default') }}
</NcButton>
</div>
<NcDialog
:open.sync="isModalOpen"
:name="$t('dav', 'Import contacts')"
v-model:open="isModalOpen"
:name="t('dav', 'Import contacts')"
:buttons="buttons">
<div>
<p>{{ $t('dav', 'Importing a new .vcf file will delete the existing default contact and replace it with the new one. Do you want to continue?') }}</p>
<p>{{ t('dav', 'Importing a new .vcf file will delete the existing default contact and replace it with the new one. Do you want to continue?') }}</p>
</div>
</NcDialog>
<input
@@ -61,6 +61,7 @@ import IconCheck from '@mdi/svg/svg/check.svg?raw'
import axios from '@nextcloud/axios'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { generateUrl } from '@nextcloud/router'
import { NcButton, NcCheckboxRadioSwitch, NcDialog } from '@nextcloud/vue'
import IconAccount from 'vue-material-design-icons/Account.vue'
@@ -69,8 +70,8 @@ import IconUpload from 'vue-material-design-icons/TrayArrowUp.vue'
import ExampleContentDownloadButton from './ExampleContentDownloadButton.vue'
import { logger } from '../service/logger.ts'
const enableDefaultContact = loadState('dav', 'enableDefaultContact')
const hasCustomDefaultContact = loadState('dav', 'hasCustomDefaultContact')
const enableDefaultContact = loadState('dav', 'enableDefaultContact', false)
const hasCustomDefaultContact = loadState('dav', 'hasCustomDefaultContact', false)
export default {
name: 'ExampleContactSettings',
@@ -84,6 +85,10 @@ export default {
ExampleContentDownloadButton,
},
setup() {
return { t }
},
data() {
return {
enableDefaultContact,
@@ -92,12 +97,12 @@ export default {
loading: false,
buttons: [
{
label: this.$t('dav', 'Cancel'),
label: t('dav', 'Cancel'),
icon: IconCancel,
callback: () => { this.isModalOpen = false },
},
{
label: this.$t('dav', 'Import'),
label: t('dav', 'Import'),
icon: IconCheck,
variant: 'primary',
callback: () => { this.clickImportInput() },
@@ -119,7 +124,7 @@ export default {
}).then(() => {
this.enableDefaultContact = !this.enableDefaultContact
}).catch(() => {
showError(this.$t('dav', 'Error while saving settings'))
showError(t('dav', 'Error while saving settings'))
})
},
@@ -136,11 +141,11 @@ export default {
axios.put(generateUrl('/apps/dav/api/defaultcontact/contact'))
.then(() => {
this.hasCustomDefaultContact = false
showSuccess(this.$t('dav', 'Contact reset successfully'))
showSuccess(t('dav', 'Contact reset successfully'))
})
.catch((error) => {
logger.error('Error importing contact:', { error })
showError(this.$t('dav', 'Error while resetting contact'))
showError(t('dav', 'Error while resetting contact'))
})
.finally(() => {
this.loading = false
@@ -158,10 +163,10 @@ export default {
try {
await axios.put(generateUrl('/apps/dav/api/defaultcontact/contact'), { contactData: reader.result })
this.hasCustomDefaultContact = true
showSuccess(this.$t('dav', 'Contact imported successfully'))
showSuccess(t('dav', 'Contact imported successfully'))
} catch (error) {
logger.error('Error importing contact:', { error })
showError(this.$t('dav', 'Error while importing contact'))
showError(t('dav', 'Error while importing contact'))
} finally {
this.loading = false
event.target.value = ''
@@ -41,7 +41,7 @@
</NcButton>
</div>
<NcDialog
:open.sync="showImportModal"
v-model:open="showImportModal"
:name="t('dav', 'Import calendar event')">
<div class="import-event-modal">
<p>
@@ -73,6 +73,7 @@
<script>
import { showError, showSuccess } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { generateUrl } from '@nextcloud/router'
import { NcButton, NcCheckboxRadioSwitch, NcDialog } from '@nextcloud/vue'
import IconCalendarBlank from 'vue-material-design-icons/CalendarBlank.vue'
@@ -94,6 +95,10 @@ export default {
ExampleContentDownloadButton,
},
setup() {
return { t }
},
data() {
return {
createExampleEvent: loadState('dav', 'create_example_event', false),
@@ -3,17 +3,8 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { t } from '@nextcloud/l10n'
import Vue from 'vue'
import { createApp } from 'vue'
import ExampleContentSettingsSection from './views/ExampleContentSettingsSection.vue'
Vue.mixin({
methods: {
t,
$t: t,
},
})
const View = Vue.extend(ExampleContentSettingsSection);
(new View({})).$mount('#settings-example-content')
const app = createApp(ExampleContentSettingsSection)
app.mount('#settings-example-content')
+10
View File
@@ -0,0 +1,10 @@
/**
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { createApp } from 'vue'
import CalDavSettings from './views/CalDavSettings.vue'
const app = createApp(CalDavSettings)
app.mount('#settings-admin-caldav')
@@ -1,14 +0,0 @@
/**
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { t } from '@nextcloud/l10n'
import Vue from 'vue'
import Availability from './views/UserAvailability.vue'
Vue.prototype.$t = t
const View = Vue.extend(Availability);
(new View({})).$mount('#settings-personal-availability')
@@ -0,0 +1,10 @@
/**
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { createApp } from 'vue'
import UserAvailability from './views/UserAvailability.vue'
const app = createApp(UserAvailability)
app.mount('#settings-personal-availability')
-33
View File
@@ -1,33 +0,0 @@
/**
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import Vue from 'vue'
import CalDavSettings from './views/CalDavSettings.vue'
Vue.prototype.$t = t
const View = Vue.extend(CalDavSettings)
const CalDavSettingsView = new View({
name: 'CalDavSettingsView',
data() {
return {
sendInvitations: loadState('dav', 'sendInvitations'),
generateBirthdayCalendar: loadState(
'dav',
'generateBirthdayCalendar',
),
sendEventReminders: loadState('dav', 'sendEventReminders'),
sendEventRemindersToSharedUsers: loadState(
'dav',
'sendEventRemindersToSharedUsers',
),
sendEventRemindersPush: loadState('dav', 'sendEventRemindersPush'),
}
},
})
CalDavSettingsView.$mount('#settings-admin-caldav')
+11 -18
View File
@@ -7,6 +7,15 @@ import { render } from '@testing-library/vue'
import { beforeEach, describe, expect, test, vi } from 'vitest'
import CalDavSettings from './CalDavSettings.vue'
const initialState = vi.hoisted(() => ({
userSyncCalendarsDocUrl: 'https://docs.nextcloud.com/server/23/go.php?to=user-sync-calendars',
sendInvitations: true,
generateBirthdayCalendar: true,
sendEventReminders: true,
sendEventRemindersToSharedUsers: true,
sendEventRemindersPush: true,
}))
vi.mock('@nextcloud/axios')
vi.mock('@nextcloud/router', () => {
return {
@@ -17,7 +26,7 @@ vi.mock('@nextcloud/router', () => {
})
vi.mock('@nextcloud/initial-state', () => {
return {
loadState: vi.fn(() => 'https://docs.nextcloud.com/server/23/go.php?to=user-sync-calendars'),
loadState: vi.fn((app, key) => app === 'dav' && initialState[key]),
}
})
@@ -32,23 +41,7 @@ describe('CalDavSettings', () => {
})
test('interactions', async () => {
const TLUtils = render(
CalDavSettings,
{
data() {
return {
sendInvitations: true,
generateBirthdayCalendar: true,
sendEventReminders: true,
sendEventRemindersToSharedUsers: true,
sendEventRemindersPush: true,
}
},
},
(Vue) => {
Vue.prototype.$t = vi.fn((app, text) => text)
},
)
const TLUtils = render(CalDavSettings)
const sendInvitations = TLUtils.getByLabelText('Send invitations to attendees')
expect(sendInvitations).toBeChecked()
const generateBirthdayCalendar = TLUtils.getByLabelText('Automatically generate a birthday calendar')
+39 -21
View File
@@ -4,22 +4,22 @@
-->
<template>
<NcSettingsSection
:name="$t('dav', 'Calendar server')"
:name="t('dav', 'Calendar server')"
:doc-url="userSyncCalendarsDocUrl">
<!-- Can use v-html as:
- $t passes the translated string through DOMPurify.sanitize,
- t passes the translated string through DOMPurify.sanitize,
- replacement strings are not user-controlled. -->
<!-- eslint-disable-next-line vue/no-v-html -->
<p class="settings-hint" v-html="hint" />
<p>
<NcCheckboxRadioSwitch
id="caldavSendInvitations"
:checked.sync="sendInvitations"
v-model="sendInvitations"
type="switch">
{{ $t('dav', 'Send invitations to attendees') }}
{{ t('dav', 'Send invitations to attendees') }}
</NcCheckboxRadioSwitch>
<!-- Can use v-html as:
- $t passes the translated string through DOMPurify.sanitize,
- t passes the translated string through DOMPurify.sanitize,
- replacement strings are not user-controlled. -->
<!-- eslint-disable-next-line vue/no-v-html -->
<em v-html="sendInvitationsHelpText" />
@@ -27,55 +27,55 @@
<p>
<NcCheckboxRadioSwitch
id="caldavGenerateBirthdayCalendar"
:checked.sync="generateBirthdayCalendar"
v-model="generateBirthdayCalendar"
type="switch"
class="checkbox">
{{ $t('dav', 'Automatically generate a birthday calendar') }}
{{ t('dav', 'Automatically generate a birthday calendar') }}
</NcCheckboxRadioSwitch>
<em>
{{ $t('dav', 'Birthday calendars will be generated by a background job.') }}
{{ t('dav', 'Birthday calendars will be generated by a background job.') }}
</em>
<br>
<em>
{{ $t('dav', 'Hence they will not be available immediately after enabling but will show up after some time.') }}
{{ t('dav', 'Hence they will not be available immediately after enabling but will show up after some time.') }}
</em>
</p>
<p>
<NcCheckboxRadioSwitch
id="caldavSendEventReminders"
:checked.sync="sendEventReminders"
v-model="sendEventReminders"
type="switch">
{{ $t('dav', 'Send notifications for events') }}
{{ t('dav', 'Send notifications for events') }}
</NcCheckboxRadioSwitch>
<!-- Can use v-html as:
- $t passes the translated string through DOMPurify.sanitize,
- t passes the translated string through DOMPurify.sanitize,
- replacement strings are not user-controlled. -->
<!-- eslint-disable-next-line vue/no-v-html -->
<em v-html="sendEventRemindersHelpText" />
<br>
<em>
{{ $t('dav', 'Notifications are sent via background jobs, so these must occur often enough.') }}
{{ t('dav', 'Notifications are sent via background jobs, so these must occur often enough.') }}
</em>
</p>
<p class="indented">
<NcCheckboxRadioSwitch
id="caldavSendEventRemindersToSharedGroupMembers"
:checked.sync="sendEventRemindersToSharedUsers"
v-model="sendEventRemindersToSharedUsers"
type="switch"
:disabled="!sendEventReminders">
{{ $t('dav', 'Send reminder notifications to calendar sharees as well') }}
{{ t('dav', 'Send reminder notifications to calendar sharees as well') }}
</NcCheckboxRadioSwitch>
<em>
{{ $t('dav', 'Reminders are always sent to organizers and attendees.') }}
{{ t('dav', 'Reminders are always sent to organizers and attendees.') }}
</em>
</p>
<p class="indented">
<NcCheckboxRadioSwitch
id="caldavSendEventRemindersPush"
:checked.sync="sendEventRemindersPush"
v-model="sendEventRemindersPush"
type="switch"
:disabled="!sendEventReminders">
{{ $t('dav', 'Enable notifications for events via push') }}
{{ t('dav', 'Enable notifications for events via push') }}
</NcCheckboxRadioSwitch>
</p>
</NcSettingsSection>
@@ -84,6 +84,7 @@
<script>
import axios from '@nextcloud/axios'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { generateUrl } from '@nextcloud/router'
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
@@ -97,15 +98,32 @@ export default {
NcSettingsSection,
},
setup() {
return { t }
},
data() {
return {
userSyncCalendarsDocUrl,
sendInvitations: loadState('dav', 'sendInvitations'),
generateBirthdayCalendar: loadState(
'dav',
'generateBirthdayCalendar',
),
sendEventReminders: loadState('dav', 'sendEventReminders'),
sendEventRemindersToSharedUsers: loadState(
'dav',
'sendEventRemindersToSharedUsers',
),
sendEventRemindersPush: loadState('dav', 'sendEventRemindersPush'),
}
},
computed: {
hint() {
const translated = this.$t(
const translated = t(
'dav',
'Also install the {calendarappstoreopen}Calendar app{linkclose}, or {calendardocopen}connect your desktop & mobile for syncing ↗{linkclose}.',
)
@@ -116,14 +134,14 @@ export default {
},
sendInvitationsHelpText() {
const translated = this.$t('dav', 'Please make sure to properly set up {emailopen}the email server{linkclose}.')
const translated = t('dav', 'Please make sure to properly set up {emailopen}the email server{linkclose}.')
return translated
.replace('{emailopen}', '<a href="../admin#mail_general_settings">')
.replace('{linkclose}', '</a>')
},
sendEventRemindersHelpText() {
const translated = this.$t('dav', 'Please make sure to properly set up {emailopen}the email server{linkclose}.')
const translated = t('dav', 'Please make sure to properly set up {emailopen}the email server{linkclose}.')
return translated
.replace('{emailopen}', '<a href="../admin#mail_general_settings">')
.replace('{linkclose}', '</a>')
@@ -4,8 +4,6 @@
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
\OCP\Util::addScript('dav', 'settings-admin-caldav', 'core');
?>
<div id="settings-admin-caldav"></div>
@@ -4,8 +4,6 @@
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
\OCP\Util::addScript('dav', 'settings-example-content', 'core');
?>
<div id="settings-example-content"></div>
@@ -4,8 +4,6 @@
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
\OCP\Util::addScript('dav', 'settings-personal-availability', 'core');
?>
<div id="settings-personal-availability"></div>
@@ -31,11 +31,6 @@ module.exports = {
dashboard: {
main: path.join(__dirname, 'apps/dashboard/src', 'main.js'),
},
dav: {
'settings-admin-caldav': path.join(__dirname, 'apps/dav/src', 'settings.js'),
'settings-personal-availability': path.join(__dirname, 'apps/dav/src', 'settings-personal-availability.js'),
'settings-example-content': path.join(__dirname, 'apps/dav/src', 'settings-example-content.js'),
},
files: {
sidebar: path.join(__dirname, 'apps/files/src', 'sidebar.ts'),
main: path.join(__dirname, 'apps/files/src', 'main.ts'),
+5
View File
@@ -7,6 +7,11 @@ import { createAppConfig } from '@nextcloud/vite-config'
import { resolve } from 'node:path'
const modules = {
dav: {
'settings-admin-caldav': resolve(import.meta.dirname, 'apps/dav/src', 'settings-admin.ts'),
'settings-admin-example-content': resolve(import.meta.dirname, 'apps/dav/src', 'settings-admin-example-content.ts'),
'settings-personal-availability': resolve(import.meta.dirname, 'apps/dav/src', 'settings-personal-availability.ts'),
},
sharebymail: {
'admin-settings': resolve(import.meta.dirname, 'apps/sharebymail/src', 'settings-admin.ts'),
},
+61
View File
@@ -10,7 +10,9 @@
"hasInstallScript": true,
"license": "AGPL-3.0-or-later",
"dependencies": {
"@mdi/svg": "^7.4.47",
"@nextcloud/axios": "^2.5.2",
"@nextcloud/calendar-availability-vue": "^3.0.0",
"@nextcloud/dialogs": "^7.1.0",
"@nextcloud/password-confirmation": "^6.0.1",
"@nextcloud/paths": "^2.2.1",
@@ -1951,6 +1953,12 @@
"integrity": "sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==",
"license": "Apache-2.0"
},
"node_modules/@mdi/svg": {
"version": "7.4.47",
"resolved": "https://registry.npmjs.org/@mdi/svg/-/svg-7.4.47.tgz",
"integrity": "sha512-WQ2gDll12T9WD34fdRFgQVgO8bag3gavrAgJ0frN4phlwdJARpE6gO1YvLEMJR0KKgoc+/Ea/A0Pp11I00xBvw==",
"license": "Apache-2.0"
},
"node_modules/@microsoft/api-extractor": {
"version": "7.53.2",
"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.53.2.tgz",
@@ -2148,6 +2156,41 @@
"browserslist": "^4.26.3"
}
},
"node_modules/@nextcloud/calendar-availability-vue": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@nextcloud/calendar-availability-vue/-/calendar-availability-vue-3.0.0.tgz",
"integrity": "sha512-6B4oWgVcvoYvdM8G3avD/XcpWbuEIEu5bXkfvH+rM8R12s7NpIvKmwNSyXOwXjzIeJQRIkcimEn9Am4pVfM1lg==",
"license": "MIT",
"dependencies": {
"@nextcloud/logger": "^3.0.2",
"ical.js": "^2.2.1",
"icalzone": "^0.0.1",
"uuid": "^12.0.0",
"vue-material-design-icons": "^5.3.1"
},
"engines": {
"node": "^22.0.0",
"npm": "^10.5.0"
},
"peerDependencies": {
"@nextcloud/l10n": "^1.4 || ^2.0 || ^3.0.0",
"@nextcloud/vue": "^9",
"vue": "^3.5.17"
}
},
"node_modules/@nextcloud/calendar-availability-vue/node_modules/uuid": {
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-12.0.0.tgz",
"integrity": "sha512-USe1zesMYh4fjCA8ZH5+X5WIVD0J4V1Jksm1bFTVBX2F/cwSXt0RO5w/3UXbdLKmZX65MiWV+hwhSS8p6oBTGA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@nextcloud/capabilities": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@nextcloud/capabilities/-/capabilities-1.2.0.tgz",
@@ -9330,6 +9373,18 @@
"url": "https://github.com/sponsors/EvanHahn"
}
},
"node_modules/ical.js": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ical.js/-/ical.js-2.2.1.tgz",
"integrity": "sha512-yK/UlPbEs316igb/tjRgbFA8ZV75rCsBJp/hWOatpyaPNlgw0dGDmU+FoicOcwX4xXkeXOkYiOmCqNPFpNPkQg==",
"license": "MPL-2.0"
},
"node_modules/icalzone": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/icalzone/-/icalzone-0.0.1.tgz",
"integrity": "sha512-ln0AM3fMSLLuJijuWuRzwrN0Tg+BG8ADi7ha6slmC7ZqOijagif5I6b4Nl4/vPSXWexnxyrHiEof8VxDOllXVQ==",
"license": "ISC"
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -16576,6 +16631,12 @@
"eslint": "^8.57.0 || ^9.0.0"
}
},
"node_modules/vue-material-design-icons": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/vue-material-design-icons/-/vue-material-design-icons-5.3.1.tgz",
"integrity": "sha512-6UNEyhlTzlCeT8ZeX5WbpUGFTTPSbOoTQeoASTv7X4Ylh0pe8vltj+36VMK56KM0gG8EQVoMK/Qw/6evalg8lA==",
"license": "MIT"
},
"node_modules/vue-resize": {
"version": "2.0.0-alpha.1",
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz",
+2
View File
@@ -39,7 +39,9 @@
"extends @nextcloud/browserslist-config"
],
"dependencies": {
"@mdi/svg": "^7.4.47",
"@nextcloud/axios": "^2.5.2",
"@nextcloud/calendar-availability-vue": "^3.0.0",
"@nextcloud/dialogs": "^7.1.0",
"@nextcloud/password-confirmation": "^6.0.1",
"@nextcloud/paths": "^2.2.1",