@conduction/nextcloud-vue 2.143.0 → 2.144.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +7 -2
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
- package/dist/esm/components/CnEventsCard/CnEventsCard.vue.js +1 -1
- package/dist/esm/components/CnEventsCard/CnEventsCard.vue2.js +9 -0
- package/dist/esm/components/CnEventsCard/CnEventsCard.vue2.js.map +1 -1
- package/dist/esm/components/CnEventsCard/CnEventsCard.vue3.js +24 -13
- package/dist/esm/components/CnEventsCard/CnEventsCard.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +2 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +3 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +3 -0
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js +19 -14
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js +30 -0
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js +158 -102
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js +12 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue.js +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +110 -2
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +146 -80
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js +45 -0
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue3.js +67 -34
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js +3 -22
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/eventStatus.js +67 -0
- package/dist/esm/integrations/builtin/calendar/eventStatus.js.map +1 -0
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +39 -0
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js +81 -32
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +5 -6
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/deckCardParts.js +59 -0
- package/dist/esm/integrations/builtin/deck/deckCardParts.js.map +1 -0
- package/dist/esm/l10n/en.json.js +6 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +6 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +815 -363
- package/dist/esm/utils/fetchFilterCounts.js +5 -2
- package/dist/esm/utils/fetchFilterCounts.js.map +1 -1
- package/dist/esm/utils/nextcloudDirectory.js +19 -6
- package/dist/esm/utils/nextcloudDirectory.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +1347 -758
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +815 -363
- package/l10n/en.json +6 -0
- package/l10n/nl.json +6 -0
- package/package.json +1 -1
- package/src/components/CnActionDialog/CnActionDialog.vue +28 -3
- package/src/components/CnConversationThread/CnConversationThread.vue +5 -2
- package/src/components/CnEventsCard/CnEventsCard.vue +27 -5
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +15 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +3 -1
- package/src/components/CnNotesCard/CnNotesCard.vue +8 -0
- package/src/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue +114 -46
- package/src/components/CnRetentionWidget/CnRetentionWidget.vue +26 -1
- package/src/components/CnTasksWidget/CnTasksWidget.vue +170 -13
- package/src/css/dialog.css +7 -1
- package/src/css/kpi-card.css +3 -0
- package/src/css/look-board-detail.css +317 -0
- package/src/css/look-board-index.css +14 -0
- package/src/css/look-board.css +25 -0
- package/src/integrations/builtin/calendar/CnCalendarCard.vue +76 -11
- package/src/integrations/builtin/calendar/CnCalendarTab.vue +3 -22
- package/src/integrations/builtin/calendar/__tests__/CnCalendarCardBoardRows.spec.js +52 -0
- package/src/integrations/builtin/calendar/eventStatus.js +63 -0
- package/src/integrations/builtin/deck/CnDeckCard.vue +66 -0
- package/src/integrations/builtin/deck/CnDeckTab.vue +5 -6
- package/src/integrations/builtin/deck/__tests__/CnDeckCardBoardRows.spec.js +49 -0
- package/src/integrations/builtin/deck/deckCardParts.js +56 -0
- package/src/utils/fetchFilterCounts.js +5 -2
- package/src/utils/nextcloudDirectory.js +19 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnCalendarCard.vue2.js","sources":["../../../../../src/integrations/builtin/calendar/CnCalendarCard.vue"],"sourcesContent":["<!--\n CnCalendarCard — bespoke widget for the `calendar` integration.\n\n Surface-aware (AD-19) widget that renders linked VEVENTs across the\n four pluggable-integration-registry surfaces with one component:\n\n - `user-dashboard` : compact list, \"next 5 upcoming meetings\" across\n the user's objects (one row per VEVENT). Falls\n back to a list scoped by the optional\n register/schema/objectId when given (registry\n dashboards pass the full triple) so it still\n works without a global \"across all my objects\"\n query — see AD-22.\n - `app-dashboard` : same compact list scoped to the current app's\n register/schema/objectId, when given.\n - `detail-page` : full per-object meeting list with a quick\n \"Open in Calendar\" CTA — the inline create\n form lives in CnCalendarTab, not here, to keep\n the detail card compact (design.md AD-3).\n - `single-entity` : a single VEVENT rendered as a chip with date +\n summary + status icon. Accepts `entityId`\n (composite \"calendarId/eventUri\") for the\n referenceType auto-rendering path.\n\n Loading / empty / error states follow ADR-017 component composition.\n All strings pass through t('nextcloud-vue', ...) for nl + en\n translation (ADR-007). Theming uses Nextcloud CSS variables only so\n the nldesign app's overrides apply transparently (ADR-010).\n-->\n<template>\n\t<CnDetailCard :title=\"resolvedTitle\" :icon=\"Calendar\" :collapsible=\"collapsible\">\n\t\t<!-- `headerActions`: the calendar tab's create and link-existing flows in the title row (detail page). -->\n\t\t<template v-if=\"shownHeaderActions.length > 0\" #actions>\n\t\t\t<NcButton\n\t\t\t\tv-for=\"action in shownHeaderActions\"\n\t\t\t\t:key=\"action\"\n\t\t\t\t:variant=\"action === 'create' && createVariant !== 'secondary' ? 'primary' : 'secondary'\"\n\t\t\t\t:data-testid=\"`cn-calendar-card-${action}`\"\n\t\t\t\t@click=\"action === 'create' ? (showCreate = true) : (showPicker = true)\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<CnIcon v-if=\"action === 'create' && createIcon\"\n\t\t\t\t\t\t:name=\"createIcon\"\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\tdata-testid=\"cn-calendar-card-create-icon\" />\n\t\t\t\t\t<Plus v-else-if=\"action === 'create'\" :size=\"20\" />\n\t\t\t\t\t<LinkVariant v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ action === 'create' ? createLabel : linkLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\n\t\t<!-- Loading -->\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- Error -->\n\t\t<div v-else-if=\"error\" class=\"cn-calendar-card__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\n\t\t<!-- Empty -->\n\t\t<div v-else-if=\"displayedEvents.length === 0\" class=\"cn-calendar-card__empty\">\n\t\t\t{{ noEventsLabel }}\n\t\t</div>\n\n\t\t<!-- single-entity surface: one compact chip -->\n\t\t<div v-else-if=\"surface === 'single-entity'\" class=\"cn-calendar-card__chip\">\n\t\t\t<CalendarClock :size=\"18\" class=\"cn-calendar-card__chip-icon\" />\n\t\t\t<span class=\"cn-calendar-card__chip-title\">{{ displayedEvents[0].summary || untitledLabel }}</span>\n\t\t\t<span v-if=\"displayedEvents[0].dtstart\" class=\"cn-calendar-card__chip-when\">\n\t\t\t\t{{ formatShort(displayedEvents[0].dtstart) }}\n\t\t\t</span>\n\t\t\t<span\n\t\t\t\tv-if=\"displayedEvents[0].status\"\n\t\t\t\tclass=\"cn-calendar-card__chip-status\"\n\t\t\t\t:class=\"`cn-calendar-card__chip-status--${displayedEvents[0].status}`\">\n\t\t\t\t{{ displayedEvents[0].status }}\n\t\t\t</span>\n\t\t</div>\n\n\t\t<!-- list surfaces: user/app/detail share the row template -->\n\t\t<div v-else class=\"cn-calendar-card__list\">\n\t\t\t<div\n\t\t\t\tv-for=\"ev in displayedEvents\"\n\t\t\t\t:key=\"rowKey(ev)\"\n\t\t\t\tclass=\"cn-calendar-card__row\">\n\t\t\t\t<div class=\"cn-calendar-card__row-icon\">\n\t\t\t\t\t<CalendarClock v-if=\"isUpcoming(ev)\" :size=\"20\" class=\"cn-calendar-card__icon--upcoming\" />\n\t\t\t\t\t<CalendarCheck v-else :size=\"20\" class=\"cn-calendar-card__icon--past\" />\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-calendar-card__row-main\">\n\t\t\t\t\t<span class=\"cn-calendar-card__title\">{{ ev.summary || untitledLabel }}</span>\n\t\t\t\t\t<div class=\"cn-calendar-card__meta\">\n\t\t\t\t\t\t<span v-if=\"ev.dtstart\" class=\"cn-calendar-card__when\">{{ formatShort(ev.dtstart) }}</span>\n\t\t\t\t\t\t<span v-if=\"ev.location\" class=\"cn-calendar-card__location\">· {{ ev.location }}</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Footer: detail surface gets \"Open in NC Calendar\" CTA -->\n\t\t<template v-if=\"surface === 'detail-page'\" #footer>\n\t\t\t<a\n\t\t\t\tclass=\"cn-calendar-card__cta\"\n\t\t\t\t:href=\"calendarAppUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener\">\n\t\t\t\t{{ openInCalendarLabel }}\n\t\t\t</a>\n\t\t</template>\n\n\t\t<!-- Footer: dashboard surfaces get \"Show all\" when truncated -->\n\t\t<template v-else-if=\"allEvents.length > maxDisplay && surface !== 'single-entity'\" #footer>\n\t\t\t<button class=\"cn-calendar-card__show-all\" @click=\"$emit('show-all')\">\n\t\t\t\t{{ showAllLabel }} ({{ allEvents.length }})\n\t\t\t</button>\n\t\t</template>\n\t\t<CnCalendarEventPicker\n\t\t\tv-if=\"showPicker\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@link=\"onPickerLink\"\n\t\t\t@close=\"showPicker = false\" />\n\t\t<CnCalendarEventCreate\n\t\t\tv-if=\"showCreate\"\n\t\t\t:register=\"register\"\n\t\t\t:schema=\"schema\"\n\t\t\t:objectId=\"objectId\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@created=\"onEventCreated\"\n\t\t\t@close=\"showCreate = false\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport Calendar from 'vue-material-design-icons/Calendar.vue'\nimport CalendarCheck from 'vue-material-design-icons/CalendarCheck.vue'\nimport CalendarClock from 'vue-material-design-icons/CalendarClock.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnCalendarEventCreate from '../../../components/CnCalendarEventCreate/CnCalendarEventCreate.vue'\nimport CnCalendarEventPicker from '../../../components/CnCalendarEventPicker/CnCalendarEventPicker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport CnIcon from '../../../components/CnIcon/CnIcon.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { userLocale } from '../../../utils/userLocale.js'\nimport { linkCalendarEvent } from './calendarEventLink.js'\n\n/**\n * CnCalendarCard — surface-aware compact widget for the calendar\n * integration. Renders linked VEVENTs across all four widget surfaces\n * (AD-19) with the same component.\n */\nexport default {\n\tname: 'CnCalendarCard',\n\n\tcomponents: { CnCalendarEventCreate, CnCalendarEventPicker, CnDetailCard, CnIcon, LinkVariant, NcButton, NcLoadingIcon, Plus, CalendarClock, CalendarCheck },\n\n\tprops: {\n\t\t/** OpenRegister register id (slug or uuid). Optional for user-dashboard. */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). Optional for user-dashboard. */\n\t\tschema: { type: String, default: '' },\n\t\t/** Parent object id. Optional for user-dashboard. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** Stable integration id (matches PHP-side provider id). */\n\t\tintegrationId: { type: String, default: 'calendar' },\n\t\t/**\n\t\t * Composite entity id \"calendarId/eventUri\" for the\n\t\t * single-entity surface. Ignored on other surfaces.\n\t\t */\n\t\tentityId: { type: String, default: '' },\n\t\t/** Rendering surface per ADR-019 AD-19. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (v) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(v),\n\t\t},\n\n\t\t/** Base API URL for OpenRegister. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Maximum rows on list surfaces (ignored on single-entity). */\n\t\tmaxDisplay: { type: Number, default: 5 },\n\t\t/** Whether the CnDetailCard collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\n\t\t// --- Pre-translated labels (ADR-007) ---\n\t\t/** Empty-state label. */\n\t\tnoEventsLabel: { type: String, default: () => t('nextcloud-vue', 'No meetings') },\n\t\t/** Fallback when a VEVENT has no summary. */\n\t\tuntitledLabel: { type: String, default: () => t('nextcloud-vue', '(no title)') },\n\t\t/** detail-page footer CTA label. */\n\t\topenInCalendarLabel: { type: String, default: () => t('nextcloud-vue', 'Open in Calendar') },\n\t\t/** dashboard \"show all\" footer label. */\n\t\tshowAllLabel: { type: String, default: () => t('nextcloud-vue', 'Show all') },\n\t\t/**\n\t\t * Buttons in the card's title row on a detail page: `create` makes a\n\t\t * meeting linked to the object, `link` links an existing one from the\n\t\t * user's calendar. In the order given; none by default.\n\t\t */\n\t\theaderActions: { type: Array, default: () => [] },\n\t\t/** Label of the `create` button. */\n\t\tcreateLabel: { type: String, default: () => t('nextcloud-vue', 'Make an appointment') },\n\t\t/** `secondary` draws the `create` button outlined instead of primary. */\n\t\tcreateVariant: { type: String, default: 'primary' },\n\t\t/** Icon name of the `create` button; a plus without it. */\n\t\tcreateIcon: { type: String, default: '' },\n\t\t/** Label of the `link` button. */\n\t\tlinkLabel: { type: String, default: () => t('nextcloud-vue', 'Link an existing one') },\n\t},\n\n\temits: ['show-all'],\n\n\tdata() {\n\t\treturn {\n\t\t\tCalendar: markRaw(Calendar),\n\t\t\tallEvents: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tshowCreate: false,\n\t\t\tshowPicker: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The title-row buttons to draw: only on a detail page with an\n\t\t * object, only the known ones, in the order given.\n\t\t *\n\t\t * @return {Array<string>}\n\t\t */\n\t\tshownHeaderActions() {\n\t\t\tif (this.surface !== 'detail-page' || !this.objectId || !Array.isArray(this.headerActions)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.headerActions.filter((action, index, all) => ['create', 'link'].includes(action) && all.indexOf(action) === index)\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Meetings')\n\t\t},\n\n\t\tcalendarAppUrl() {\n\t\t\ttry {\n\t\t\t\treturn generateUrl('/apps/calendar')\n\t\t\t} catch {\n\t\t\t\treturn '/apps/calendar'\n\t\t\t}\n\t\t},\n\n\t\tdisplayedEvents() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\treturn this.allEvents.slice(0, 1)\n\t\t\t}\n\t\t\t// list surfaces sort by dtstart ascending, then cap at maxDisplay.\n\t\t\tconst sorted = [...this.allEvents].sort((a, b) => {\n\t\t\t\tconst ta = a.dtstart ? new Date(a.dtstart).getTime() : Number.POSITIVE_INFINITY\n\t\t\t\tconst tb = b.dtstart ? new Date(b.dtstart).getTime() : Number.POSITIVE_INFINITY\n\t\t\t\treturn ta - tb\n\t\t\t})\n\t\t\t// On dashboard surfaces, surface upcoming meetings first.\n\t\t\tif (this.surface === 'user-dashboard' || this.surface === 'app-dashboard') {\n\t\t\t\tconst now = Date.now()\n\t\t\t\tconst upcoming = sorted.filter((ev) => {\n\t\t\t\t\tif (!ev.dtstart) {\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t\treturn new Date(ev.dtstart).getTime() >= now\n\t\t\t\t})\n\t\t\t\treturn upcoming.slice(0, this.maxDisplay)\n\t\t\t}\n\t\t\treturn sorted.slice(0, this.maxDisplay)\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.refresh()\n\t\t} },\n\n\t\tentityId() {\n\t\t\tthis.refresh()\n\t\t},\n\n\t\tsurface() {\n\t\t\tthis.refresh()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A meeting was made on this object: close the form, read the list again.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonEventCreated() {\n\t\t\tthis.showCreate = false\n\t\t\tthis.refresh()\n\t\t},\n\n\t\t/**\n\t\t * Link the picked meeting, then read the list again, or say why not.\n\t\t *\n\t\t * @param {{calendarUri: string, eventUid: string}} payload The picked event.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onPickerLink(payload) {\n\t\t\tthis.showPicker = false\n\t\t\tconst result = await linkCalendarEvent(prefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/events`), payload)\n\t\t\tif (result.ok) {\n\t\t\t\tthis.error = ''\n\t\t\t\tthis.refresh()\n\t\t\t} else {\n\t\t\t\tthis.error = result.error\n\t\t\t}\n\t\t},\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\trowKey(ev) {\n\t\t\tif (ev.calendarId && ev.id) {\n\t\t\t\treturn `${ev.calendarId}/${ev.id}`\n\t\t\t}\n\t\t\treturn ev.id || ev.uid || ''\n\t\t},\n\n\t\tisUpcoming(ev) {\n\t\t\tif (!ev.dtstart) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(ev.dtstart).getTime() >= Date.now()\n\t\t\t} catch {\n\t\t\t\treturn true\n\t\t\t}\n\t\t},\n\n\t\trefresh() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingleEntity()\n\t\t\t} else {\n\t\t\t\tthis.fetchList()\n\t\t\t}\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.allEvents = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.allEvents = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Calendar is currently unavailable.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meetings.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCalendarCard] failed to fetch events', err)\n\t\t\t\tthis.allEvents = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meetings.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingleEntity() {\n\t\t\tif (!this.entityId || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.allEvents = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst url = `${this.baseUrl()}/${encodeURI(this.entityId)}`\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.allEvents = data && (data.id || data.uid) ? [data] : []\n\t\t\t\t} else {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tif (response.status !== 404) {\n\t\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meeting.')\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCalendarCard] failed to fetch single entity', err)\n\t\t\t\tthis.allEvents = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meeting.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tformatShort(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst d = new Date(value)\n\t\t\t\tif (Number.isNaN(d.getTime())) {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t\tconst opts = this.surface === 'single-entity'\n\t\t\t\t\t? { dateStyle: 'medium' }\n\t\t\t\t\t: { dateStyle: 'medium', timeStyle: 'short' }\n\t\t\t\treturn d.toLocaleString(userLocale(), opts)\n\t\t\t} catch {\n\t\t\t\treturn String(value)\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-calendar-card__empty {\n\ttext-align: center;\n\tpadding: 16px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-calendar-card__error {\n\tcolor: var(--color-error);\n\tpadding: 8px 0;\n\tfont-size: 13px;\n}\n\n.cn-calendar-card__list {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-calendar-card__row {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-calendar-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-calendar-card__row-icon {\n\tflex-shrink: 0;\n\tpadding-top: 1px;\n}\n\n.cn-calendar-card__icon--upcoming { color: var(--color-primary-element); }\n\n.cn-calendar-card__icon--past { color: var(--color-text-maxcontrast); }\n\n.cn-calendar-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.cn-calendar-card__title {\n\tdisplay: block;\n\tfont-size: 13px;\n\tfont-weight: 500;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.cn-calendar-card__meta {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tmargin-top: 2px;\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-calendar-card__when {\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__location {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 10px;\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: var(--color-background-hover);\n\tfont-size: 13px;\n\tmax-width: 100%;\n}\n\n.cn-calendar-card__chip-icon {\n\tcolor: var(--color-primary-element);\n\tflex-shrink: 0;\n}\n\n.cn-calendar-card__chip-title {\n\tfont-weight: 500;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip-when {\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip-status {\n\tfont-size: 11px;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tpadding: 1px 6px;\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: var(--color-background-darker);\n}\n\n.cn-calendar-card__chip-status--confirmed { background: var(--color-success); color: var(--color-main-background); }\n\n.cn-calendar-card__chip-status--tentative { background: var(--color-warning, #e9a40f); color: var(--color-main-background); }\n\n.cn-calendar-card__chip-status--cancelled { background: var(--color-error); color: var(--color-main-background); }\n\n.cn-calendar-card__cta,\n.cn-calendar-card__show-all {\n\tbackground: none;\n\tborder: none;\n\tcolor: var(--color-primary-element);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\tpadding: 0;\n\twidth: 100%;\n\ttext-align: center;\n\ttext-decoration: none;\n\tdisplay: inline-block;\n}\n\n.cn-calendar-card__cta:hover,\n.cn-calendar-card__show-all:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnCalendarEventCreate","CnCalendarEventPicker","CnDetailCard","CnIcon","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnCalendarCard.vue2.js","sources":["../../../../../src/integrations/builtin/calendar/CnCalendarCard.vue"],"sourcesContent":["<!--\n CnCalendarCard — bespoke widget for the `calendar` integration.\n\n Surface-aware (AD-19) widget that renders linked VEVENTs across the\n four pluggable-integration-registry surfaces with one component:\n\n - `user-dashboard` : compact list, \"next 5 upcoming meetings\" across\n the user's objects (one row per VEVENT). Falls\n back to a list scoped by the optional\n register/schema/objectId when given (registry\n dashboards pass the full triple) so it still\n works without a global \"across all my objects\"\n query — see AD-22.\n - `app-dashboard` : same compact list scoped to the current app's\n register/schema/objectId, when given.\n - `detail-page` : full per-object meeting list with a quick\n \"Open in Calendar\" CTA — the inline create\n form lives in CnCalendarTab, not here, to keep\n the detail card compact (design.md AD-3).\n - `single-entity` : a single VEVENT rendered as a chip with date +\n summary + status icon. Accepts `entityId`\n (composite \"calendarId/eventUri\") for the\n referenceType auto-rendering path.\n\n Loading / empty / error states follow ADR-017 component composition.\n All strings pass through t('nextcloud-vue', ...) for nl + en\n translation (ADR-007). Theming uses Nextcloud CSS variables only so\n the nldesign app's overrides apply transparently (ADR-010).\n-->\n<template>\n\t<CnDetailCard :title=\"resolvedTitle\" :icon=\"Calendar\" :collapsible=\"collapsible\">\n\t\t<!-- `headerActions`: the calendar tab's create and link-existing flows in the title row (detail page). -->\n\t\t<template v-if=\"shownHeaderActions.length > 0\" #actions>\n\t\t\t<NcButton\n\t\t\t\tv-for=\"action in shownHeaderActions\"\n\t\t\t\t:key=\"action\"\n\t\t\t\t:variant=\"action === 'create' && createVariant !== 'secondary' ? 'primary' : 'secondary'\"\n\t\t\t\t:data-testid=\"`cn-calendar-card-${action}`\"\n\t\t\t\t@click=\"action === 'create' ? (showCreate = true) : (showPicker = true)\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<CnIcon v-if=\"action === 'create' && createIcon\"\n\t\t\t\t\t\t:name=\"createIcon\"\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\tdata-testid=\"cn-calendar-card-create-icon\" />\n\t\t\t\t\t<Plus v-else-if=\"action === 'create'\" :size=\"20\" />\n\t\t\t\t\t<LinkVariant v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ action === 'create' ? createLabel : linkLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\n\t\t<!-- Loading -->\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- Error -->\n\t\t<div v-else-if=\"error\" class=\"cn-calendar-card__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\n\t\t<!-- Empty -->\n\t\t<div v-else-if=\"displayedEvents.length === 0\" class=\"cn-calendar-card__empty\">\n\t\t\t{{ noEventsLabel }}\n\t\t</div>\n\n\t\t<!-- single-entity surface: one compact chip -->\n\t\t<div v-else-if=\"surface === 'single-entity'\" class=\"cn-calendar-card__chip\">\n\t\t\t<CalendarClock :size=\"18\" class=\"cn-calendar-card__chip-icon\" />\n\t\t\t<span class=\"cn-calendar-card__chip-title\">{{ displayedEvents[0].summary || untitledLabel }}</span>\n\t\t\t<span v-if=\"displayedEvents[0].dtstart\" class=\"cn-calendar-card__chip-when\">\n\t\t\t\t{{ formatShort(displayedEvents[0].dtstart) }}\n\t\t\t</span>\n\t\t\t<span\n\t\t\t\tv-if=\"displayedEvents[0].status\"\n\t\t\t\tclass=\"cn-calendar-card__chip-status\"\n\t\t\t\t:class=\"`cn-calendar-card__chip-status--${displayedEvents[0].status}`\">\n\t\t\t\t{{ displayedEvents[0].status }}\n\t\t\t</span>\n\t\t</div>\n\n\t\t<!-- list surfaces: user/app/detail share the row template -->\n\t\t<div v-else class=\"cn-calendar-card__list\">\n\t\t\t<div\n\t\t\t\tv-for=\"ev in displayedEvents\"\n\t\t\t\t:key=\"rowKey(ev)\"\n\t\t\t\tclass=\"cn-calendar-card__row\">\n\t\t\t\t<!-- The board look draws a meeting as a ruled row: its title, one\n\t\t\t\t meta line (when, where, who) and its status at the end. -->\n\t\t\t\t<template v-if=\"boardRows\">\n\t\t\t\t\t<div class=\"cn-calendar-card__row-main\">\n\t\t\t\t\t\t<span class=\"cn-calendar-card__title\">{{ ev.summary || untitledLabel }}</span>\n\t\t\t\t\t\t<span class=\"cn-calendar-card__meta\" data-testid=\"cn-calendar-card-meta\">{{ boardMetaOf(ev) }}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span v-if=\"statusOf(ev)\"\n\t\t\t\t\t\tclass=\"cn-status-badge\"\n\t\t\t\t\t\t:class=\"`cn-status-badge--${statusVariantOf(ev)}`\"\n\t\t\t\t\t\tdata-testid=\"cn-calendar-card-status\">{{ statusOf(ev) }}</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-else>\n\t\t\t\t\t<div class=\"cn-calendar-card__row-icon\">\n\t\t\t\t\t\t<CalendarClock v-if=\"isUpcoming(ev)\" :size=\"20\" class=\"cn-calendar-card__icon--upcoming\" />\n\t\t\t\t\t\t<CalendarCheck v-else :size=\"20\" class=\"cn-calendar-card__icon--past\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"cn-calendar-card__row-main\">\n\t\t\t\t\t\t<span class=\"cn-calendar-card__title\">{{ ev.summary || untitledLabel }}</span>\n\t\t\t\t\t\t<div class=\"cn-calendar-card__meta\">\n\t\t\t\t\t\t\t<span v-if=\"ev.dtstart\" class=\"cn-calendar-card__when\">{{ formatShort(ev.dtstart) }}</span>\n\t\t\t\t\t\t\t<span v-if=\"ev.location\" class=\"cn-calendar-card__location\">· {{ ev.location }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</template>\n\t\t\t</div>\n\t\t\t<a v-if=\"boardRows\"\n\t\t\t\tclass=\"cn-calendar-card__open\"\n\t\t\t\t:href=\"calendarAppUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener\"\n\t\t\t\tdata-testid=\"cn-calendar-card-open\">{{ openInCalendarLabel }}</a>\n\t\t</div>\n\n\t\t<!-- Footer: detail surface gets \"Open in NC Calendar\" CTA -->\n\t\t<template v-if=\"surface === 'detail-page' && !isBoard\" #footer>\n\t\t\t<a\n\t\t\t\tclass=\"cn-calendar-card__cta\"\n\t\t\t\t:href=\"calendarAppUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener\">\n\t\t\t\t{{ openInCalendarLabel }}\n\t\t\t</a>\n\t\t</template>\n\n\t\t<!-- Footer: dashboard surfaces get \"Show all\" when truncated -->\n\t\t<template v-else-if=\"allEvents.length > maxDisplay && surface !== 'single-entity'\" #footer>\n\t\t\t<button class=\"cn-calendar-card__show-all\" @click=\"$emit('show-all')\">\n\t\t\t\t{{ showAllLabel }} ({{ allEvents.length }})\n\t\t\t</button>\n\t\t</template>\n\t\t<CnCalendarEventPicker\n\t\t\tv-if=\"showPicker\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@link=\"onPickerLink\"\n\t\t\t@close=\"showPicker = false\" />\n\t\t<CnCalendarEventCreate\n\t\t\tv-if=\"showCreate\"\n\t\t\t:register=\"register\"\n\t\t\t:schema=\"schema\"\n\t\t\t:objectId=\"objectId\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@created=\"onEventCreated\"\n\t\t\t@close=\"showCreate = false\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport Calendar from 'vue-material-design-icons/Calendar.vue'\nimport CalendarCheck from 'vue-material-design-icons/CalendarCheck.vue'\nimport CalendarClock from 'vue-material-design-icons/CalendarClock.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnCalendarEventCreate from '../../../components/CnCalendarEventCreate/CnCalendarEventCreate.vue'\nimport CnCalendarEventPicker from '../../../components/CnCalendarEventPicker/CnCalendarEventPicker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport CnIcon from '../../../components/CnIcon/CnIcon.vue'\nimport { normalizeLook } from '../../../composables/useLook.js'\nimport { formatBoardDate, formatTimeOfDay } from '../../../utils/boardDate.js'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { userLocale } from '../../../utils/userLocale.js'\nimport { linkCalendarEvent } from './calendarEventLink.js'\nimport { eventAttendeeNames, eventStatusLabel, eventStatusVariant } from './eventStatus.js'\n\n/**\n * CnCalendarCard — surface-aware compact widget for the calendar\n * integration. Renders linked VEVENTs across all four widget surfaces\n * (AD-19) with the same component.\n */\nexport default {\n\tname: 'CnCalendarCard',\n\n\tcomponents: { CnCalendarEventCreate, CnCalendarEventPicker, CnDetailCard, CnIcon, LinkVariant, NcButton, NcLoadingIcon, Plus, CalendarClock, CalendarCheck },\n\n\tinject: {\n\t\tcnLook: { default: 'nextcloud' },\n\t},\n\n\tprops: {\n\t\t/** OpenRegister register id (slug or uuid). Optional for user-dashboard. */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). Optional for user-dashboard. */\n\t\tschema: { type: String, default: '' },\n\t\t/** Parent object id. Optional for user-dashboard. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** Stable integration id (matches PHP-side provider id). */\n\t\tintegrationId: { type: String, default: 'calendar' },\n\t\t/**\n\t\t * Composite entity id \"calendarId/eventUri\" for the\n\t\t * single-entity surface. Ignored on other surfaces.\n\t\t */\n\t\tentityId: { type: String, default: '' },\n\t\t/** Rendering surface per ADR-019 AD-19. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (v) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(v),\n\t\t},\n\n\t\t/** Base API URL for OpenRegister. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Maximum rows on list surfaces (ignored on single-entity). */\n\t\tmaxDisplay: { type: Number, default: 5 },\n\t\t/** Whether the CnDetailCard collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\n\t\t// --- Pre-translated labels (ADR-007) ---\n\t\t/** Empty-state label. */\n\t\tnoEventsLabel: { type: String, default: () => t('nextcloud-vue', 'No meetings') },\n\t\t/** Fallback when a VEVENT has no summary. */\n\t\tuntitledLabel: { type: String, default: () => t('nextcloud-vue', '(no title)') },\n\t\t/** detail-page footer CTA label. */\n\t\topenInCalendarLabel: { type: String, default: () => t('nextcloud-vue', 'Open in Calendar') },\n\t\t/** dashboard \"show all\" footer label. */\n\t\tshowAllLabel: { type: String, default: () => t('nextcloud-vue', 'Show all') },\n\t\t/**\n\t\t * Buttons in the card's title row on a detail page: `create` makes a\n\t\t * meeting linked to the object, `link` links an existing one from the\n\t\t * user's calendar. In the order given; none by default.\n\t\t */\n\t\theaderActions: { type: Array, default: () => [] },\n\t\t/** Label of the `create` button. */\n\t\tcreateLabel: { type: String, default: () => t('nextcloud-vue', 'Make an appointment') },\n\t\t/** `secondary` draws the `create` button outlined instead of primary. */\n\t\tcreateVariant: { type: String, default: 'primary' },\n\t\t/** Icon name of the `create` button; a plus without it. */\n\t\tcreateIcon: { type: String, default: '' },\n\t\t/** Label of the `link` button. */\n\t\tlinkLabel: { type: String, default: () => t('nextcloud-vue', 'Link an existing one') },\n\t},\n\n\temits: ['show-all'],\n\n\tdata() {\n\t\treturn {\n\t\t\tCalendar: markRaw(Calendar),\n\t\t\tallEvents: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tshowCreate: false,\n\t\t\tshowPicker: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The title-row buttons to draw: only on a detail page with an\n\t\t * object, only the known ones, in the order given.\n\t\t *\n\t\t * @return {Array<string>}\n\t\t */\n\t\t/** @return {boolean} The board look draws ruled rows. */\n\t\tisBoard() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\t/** @return {boolean} The meetings are ruled rows: the board look on a detail page. */\n\t\tboardRows() {\n\t\t\treturn this.isBoard && this.surface === 'detail-page'\n\t\t},\n\n\t\tshownHeaderActions() {\n\t\t\tif (this.surface !== 'detail-page' || !this.objectId || !Array.isArray(this.headerActions)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.headerActions.filter((action, index, all) => ['create', 'link'].includes(action) && all.indexOf(action) === index)\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Meetings')\n\t\t},\n\n\t\tcalendarAppUrl() {\n\t\t\ttry {\n\t\t\t\treturn generateUrl('/apps/calendar')\n\t\t\t} catch {\n\t\t\t\treturn '/apps/calendar'\n\t\t\t}\n\t\t},\n\n\t\tdisplayedEvents() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\treturn this.allEvents.slice(0, 1)\n\t\t\t}\n\t\t\t// list surfaces sort by dtstart ascending, then cap at maxDisplay.\n\t\t\tconst sorted = [...this.allEvents].sort((a, b) => {\n\t\t\t\tconst ta = a.dtstart ? new Date(a.dtstart).getTime() : Number.POSITIVE_INFINITY\n\t\t\t\tconst tb = b.dtstart ? new Date(b.dtstart).getTime() : Number.POSITIVE_INFINITY\n\t\t\t\treturn ta - tb\n\t\t\t})\n\t\t\t// On dashboard surfaces, surface upcoming meetings first.\n\t\t\tif (this.surface === 'user-dashboard' || this.surface === 'app-dashboard') {\n\t\t\t\tconst now = Date.now()\n\t\t\t\tconst upcoming = sorted.filter((ev) => {\n\t\t\t\t\tif (!ev.dtstart) {\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t\treturn new Date(ev.dtstart).getTime() >= now\n\t\t\t\t})\n\t\t\t\treturn upcoming.slice(0, this.maxDisplay)\n\t\t\t}\n\t\t\treturn sorted.slice(0, this.maxDisplay)\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.refresh()\n\t\t} },\n\n\t\tentityId() {\n\t\t\tthis.refresh()\n\t\t},\n\n\t\tsurface() {\n\t\t\tthis.refresh()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A meeting's meta line in the board look: \"14 okt, 10:00 tot 10:30\",\n\t\t * its place and its attendees, separated by middots.\n\t\t *\n\t\t * @param {object} ev The event.\n\t\t * @return {string}\n\t\t */\n\t\tboardMetaOf(ev) {\n\t\t\tconst start = ev.dtstart ? new Date(ev.dtstart) : null\n\t\t\tconst end = ev.dtend ? new Date(ev.dtend) : null\n\t\t\tlet when = ''\n\t\t\tif (start && !Number.isNaN(start.getTime())) {\n\t\t\t\twhen = `${formatBoardDate(start)}, ${formatTimeOfDay(start)}`\n\t\t\t\tif (end && !Number.isNaN(end.getTime())) {\n\t\t\t\t\twhen = t('nextcloud-vue', '{start} until {end}', { start: when, end: formatTimeOfDay(end) })\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn [when, ev.location, ...eventAttendeeNames(ev)].filter(Boolean).join(' · ')\n\t\t},\n\n\t\tstatusOf(ev) {\n\t\t\treturn eventStatusLabel(ev)\n\t\t},\n\n\t\tstatusVariantOf(ev) {\n\t\t\treturn eventStatusVariant(ev)\n\t\t},\n\n\t\t/**\n\t\t * A meeting was made on this object: close the form, read the list again.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonEventCreated() {\n\t\t\tthis.showCreate = false\n\t\t\tthis.refresh()\n\t\t},\n\n\t\t/**\n\t\t * Link the picked meeting, then read the list again, or say why not.\n\t\t *\n\t\t * @param {{calendarUri: string, eventUid: string}} payload The picked event.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onPickerLink(payload) {\n\t\t\tthis.showPicker = false\n\t\t\tconst result = await linkCalendarEvent(prefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/events`), payload)\n\t\t\tif (result.ok) {\n\t\t\t\tthis.error = ''\n\t\t\t\tthis.refresh()\n\t\t\t} else {\n\t\t\t\tthis.error = result.error\n\t\t\t}\n\t\t},\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\trowKey(ev) {\n\t\t\tif (ev.calendarId && ev.id) {\n\t\t\t\treturn `${ev.calendarId}/${ev.id}`\n\t\t\t}\n\t\t\treturn ev.id || ev.uid || ''\n\t\t},\n\n\t\tisUpcoming(ev) {\n\t\t\tif (!ev.dtstart) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(ev.dtstart).getTime() >= Date.now()\n\t\t\t} catch {\n\t\t\t\treturn true\n\t\t\t}\n\t\t},\n\n\t\trefresh() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingleEntity()\n\t\t\t} else {\n\t\t\t\tthis.fetchList()\n\t\t\t}\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.allEvents = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.allEvents = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Calendar is currently unavailable.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meetings.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCalendarCard] failed to fetch events', err)\n\t\t\t\tthis.allEvents = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meetings.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingleEntity() {\n\t\t\tif (!this.entityId || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.allEvents = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst url = `${this.baseUrl()}/${encodeURI(this.entityId)}`\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.allEvents = data && (data.id || data.uid) ? [data] : []\n\t\t\t\t} else {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tif (response.status !== 404) {\n\t\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meeting.')\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCalendarCard] failed to fetch single entity', err)\n\t\t\t\tthis.allEvents = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meeting.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tformatShort(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst d = new Date(value)\n\t\t\t\tif (Number.isNaN(d.getTime())) {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t\tconst opts = this.surface === 'single-entity'\n\t\t\t\t\t? { dateStyle: 'medium' }\n\t\t\t\t\t: { dateStyle: 'medium', timeStyle: 'short' }\n\t\t\t\treturn d.toLocaleString(userLocale(), opts)\n\t\t\t} catch {\n\t\t\t\treturn String(value)\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-calendar-card__empty {\n\ttext-align: center;\n\tpadding: 16px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-calendar-card__error {\n\tcolor: var(--color-error);\n\tpadding: 8px 0;\n\tfont-size: 13px;\n}\n\n.cn-calendar-card__list {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-calendar-card__row {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-calendar-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-calendar-card__row-icon {\n\tflex-shrink: 0;\n\tpadding-top: 1px;\n}\n\n.cn-calendar-card__icon--upcoming { color: var(--color-primary-element); }\n\n.cn-calendar-card__icon--past { color: var(--color-text-maxcontrast); }\n\n.cn-calendar-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.cn-calendar-card__title {\n\tdisplay: block;\n\tfont-size: 13px;\n\tfont-weight: 500;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.cn-calendar-card__meta {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tmargin-top: 2px;\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-calendar-card__when {\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__location {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 10px;\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: var(--color-background-hover);\n\tfont-size: 13px;\n\tmax-width: 100%;\n}\n\n.cn-calendar-card__chip-icon {\n\tcolor: var(--color-primary-element);\n\tflex-shrink: 0;\n}\n\n.cn-calendar-card__chip-title {\n\tfont-weight: 500;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip-when {\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip-status {\n\tfont-size: 11px;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tpadding: 1px 6px;\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: var(--color-background-darker);\n}\n\n.cn-calendar-card__chip-status--confirmed { background: var(--color-success); color: var(--color-main-background); }\n\n.cn-calendar-card__chip-status--tentative { background: var(--color-warning, #e9a40f); color: var(--color-main-background); }\n\n.cn-calendar-card__chip-status--cancelled { background: var(--color-error); color: var(--color-main-background); }\n\n.cn-calendar-card__cta,\n.cn-calendar-card__show-all {\n\tbackground: none;\n\tborder: none;\n\tcolor: var(--color-primary-element);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\tpadding: 0;\n\twidth: 100%;\n\ttext-align: center;\n\ttext-decoration: none;\n\tdisplay: inline-block;\n}\n\n.cn-calendar-card__cta:hover,\n.cn-calendar-card__show-all:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnCalendarEventCreate","CnCalendarEventPicker","CnDetailCard","CnIcon","t"],"mappings":"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"}
|
|
@@ -22,19 +22,26 @@ const _hoisted_6 = {
|
|
|
22
22
|
key: 4,
|
|
23
23
|
class: "cn-calendar-card__list"
|
|
24
24
|
};
|
|
25
|
-
const _hoisted_7 = { class: "cn-calendar-card__row-
|
|
26
|
-
const _hoisted_8 = { class: "cn-calendar-
|
|
27
|
-
const _hoisted_9 = {
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
const _hoisted_7 = { class: "cn-calendar-card__row-main" };
|
|
26
|
+
const _hoisted_8 = { class: "cn-calendar-card__title" };
|
|
27
|
+
const _hoisted_9 = {
|
|
28
|
+
class: "cn-calendar-card__meta",
|
|
29
|
+
"data-testid": "cn-calendar-card-meta"
|
|
30
|
+
};
|
|
31
|
+
const _hoisted_10 = { class: "cn-calendar-card__row-icon" };
|
|
32
|
+
const _hoisted_11 = { class: "cn-calendar-card__row-main" };
|
|
33
|
+
const _hoisted_12 = { class: "cn-calendar-card__title" };
|
|
34
|
+
const _hoisted_13 = { class: "cn-calendar-card__meta" };
|
|
35
|
+
const _hoisted_14 = {
|
|
30
36
|
key: 0,
|
|
31
37
|
class: "cn-calendar-card__when"
|
|
32
38
|
};
|
|
33
|
-
const
|
|
39
|
+
const _hoisted_15 = {
|
|
34
40
|
key: 1,
|
|
35
41
|
class: "cn-calendar-card__location"
|
|
36
42
|
};
|
|
37
|
-
const
|
|
43
|
+
const _hoisted_16 = ["href"];
|
|
44
|
+
const _hoisted_17 = ["href"];
|
|
38
45
|
|
|
39
46
|
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
40
47
|
const _component_CnIcon = resolveComponent("CnIcon");
|
|
@@ -83,32 +90,58 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
83
90
|
key: $options.rowKey(ev),
|
|
84
91
|
class: "cn-calendar-card__row"
|
|
85
92
|
}, [
|
|
86
|
-
|
|
87
|
-
(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
93
|
+
($options.boardRows)
|
|
94
|
+
? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
|
|
95
|
+
createElementVNode("div", _hoisted_7, [
|
|
96
|
+
createElementVNode("span", _hoisted_8, toDisplayString(ev.summary || $props.untitledLabel), 1 /* TEXT */),
|
|
97
|
+
createElementVNode("span", _hoisted_9, toDisplayString($options.boardMetaOf(ev)), 1 /* TEXT */)
|
|
98
|
+
]),
|
|
99
|
+
($options.statusOf(ev))
|
|
100
|
+
? (openBlock(), createElementBlock("span", {
|
|
101
|
+
key: 0,
|
|
102
|
+
class: normalizeClass(["cn-status-badge", `cn-status-badge--${$options.statusVariantOf(ev)}`]),
|
|
103
|
+
"data-testid": "cn-calendar-card-status"
|
|
104
|
+
}, toDisplayString($options.statusOf(ev)), 3 /* TEXT, CLASS */))
|
|
105
|
+
: createCommentVNode("v-if", true)
|
|
106
|
+
], 64 /* STABLE_FRAGMENT */))
|
|
107
|
+
: (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
108
|
+
createElementVNode("div", _hoisted_10, [
|
|
109
|
+
($options.isUpcoming(ev))
|
|
110
|
+
? (openBlock(), createBlock(_component_CalendarClock, {
|
|
111
|
+
key: 0,
|
|
112
|
+
size: 20,
|
|
113
|
+
class: "cn-calendar-card__icon--upcoming"
|
|
114
|
+
}))
|
|
115
|
+
: (openBlock(), createBlock(_component_CalendarCheck, {
|
|
116
|
+
key: 1,
|
|
117
|
+
size: 20,
|
|
118
|
+
class: "cn-calendar-card__icon--past"
|
|
119
|
+
}))
|
|
120
|
+
]),
|
|
121
|
+
createElementVNode("div", _hoisted_11, [
|
|
122
|
+
createElementVNode("span", _hoisted_12, toDisplayString(ev.summary || $props.untitledLabel), 1 /* TEXT */),
|
|
123
|
+
createElementVNode("div", _hoisted_13, [
|
|
124
|
+
(ev.dtstart)
|
|
125
|
+
? (openBlock(), createElementBlock("span", _hoisted_14, toDisplayString($options.formatShort(ev.dtstart)), 1 /* TEXT */))
|
|
126
|
+
: createCommentVNode("v-if", true),
|
|
127
|
+
(ev.location)
|
|
128
|
+
? (openBlock(), createElementBlock("span", _hoisted_15, "· " + toDisplayString(ev.location), 1 /* TEXT */))
|
|
129
|
+
: createCommentVNode("v-if", true)
|
|
130
|
+
])
|
|
131
|
+
])
|
|
132
|
+
], 64 /* STABLE_FRAGMENT */))
|
|
110
133
|
]))
|
|
111
|
-
}), 128 /* KEYED_FRAGMENT */))
|
|
134
|
+
}), 128 /* KEYED_FRAGMENT */)),
|
|
135
|
+
($options.boardRows)
|
|
136
|
+
? (openBlock(), createElementBlock("a", {
|
|
137
|
+
key: 0,
|
|
138
|
+
class: "cn-calendar-card__open",
|
|
139
|
+
href: $options.calendarAppUrl,
|
|
140
|
+
target: "_blank",
|
|
141
|
+
rel: "noopener",
|
|
142
|
+
"data-testid": "cn-calendar-card-open"
|
|
143
|
+
}, toDisplayString($props.openInCalendarLabel), 9 /* TEXT, PROPS */, _hoisted_16))
|
|
144
|
+
: createCommentVNode("v-if", true)
|
|
112
145
|
])),
|
|
113
146
|
($data.showPicker)
|
|
114
147
|
? (openBlock(), createBlock(_component_CnCalendarEventPicker, {
|
|
@@ -171,7 +204,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
171
204
|
key: "0"
|
|
172
205
|
}
|
|
173
206
|
: undefined,
|
|
174
|
-
($props.surface === 'detail-page')
|
|
207
|
+
($props.surface === 'detail-page' && !$options.isBoard)
|
|
175
208
|
? {
|
|
176
209
|
name: "footer",
|
|
177
210
|
fn: withCtx(() => [
|
|
@@ -180,7 +213,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
180
213
|
href: $options.calendarAppUrl,
|
|
181
214
|
target: "_blank",
|
|
182
215
|
rel: "noopener"
|
|
183
|
-
}, toDisplayString($props.openInCalendarLabel), 9 /* TEXT, PROPS */,
|
|
216
|
+
}, toDisplayString($props.openInCalendarLabel), 9 /* TEXT, PROPS */, _hoisted_17)
|
|
184
217
|
]),
|
|
185
218
|
key: "1"
|
|
186
219
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnCalendarCard.vue3.js","sources":["../../../../../src/integrations/builtin/calendar/CnCalendarCard.vue?vue&type=template&id=25d68a70&lang.js"],"sourcesContent":["<!--\n CnCalendarCard — bespoke widget for the `calendar` integration.\n\n Surface-aware (AD-19) widget that renders linked VEVENTs across the\n four pluggable-integration-registry surfaces with one component:\n\n - `user-dashboard` : compact list, \"next 5 upcoming meetings\" across\n the user's objects (one row per VEVENT). Falls\n back to a list scoped by the optional\n register/schema/objectId when given (registry\n dashboards pass the full triple) so it still\n works without a global \"across all my objects\"\n query — see AD-22.\n - `app-dashboard` : same compact list scoped to the current app's\n register/schema/objectId, when given.\n - `detail-page` : full per-object meeting list with a quick\n \"Open in Calendar\" CTA — the inline create\n form lives in CnCalendarTab, not here, to keep\n the detail card compact (design.md AD-3).\n - `single-entity` : a single VEVENT rendered as a chip with date +\n summary + status icon. Accepts `entityId`\n (composite \"calendarId/eventUri\") for the\n referenceType auto-rendering path.\n\n Loading / empty / error states follow ADR-017 component composition.\n All strings pass through t('nextcloud-vue', ...) for nl + en\n translation (ADR-007). Theming uses Nextcloud CSS variables only so\n the nldesign app's overrides apply transparently (ADR-010).\n-->\n<template>\n\t<CnDetailCard :title=\"resolvedTitle\" :icon=\"Calendar\" :collapsible=\"collapsible\">\n\t\t<!-- `headerActions`: the calendar tab's create and link-existing flows in the title row (detail page). -->\n\t\t<template v-if=\"shownHeaderActions.length > 0\" #actions>\n\t\t\t<NcButton\n\t\t\t\tv-for=\"action in shownHeaderActions\"\n\t\t\t\t:key=\"action\"\n\t\t\t\t:variant=\"action === 'create' && createVariant !== 'secondary' ? 'primary' : 'secondary'\"\n\t\t\t\t:data-testid=\"`cn-calendar-card-${action}`\"\n\t\t\t\t@click=\"action === 'create' ? (showCreate = true) : (showPicker = true)\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<CnIcon v-if=\"action === 'create' && createIcon\"\n\t\t\t\t\t\t:name=\"createIcon\"\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\tdata-testid=\"cn-calendar-card-create-icon\" />\n\t\t\t\t\t<Plus v-else-if=\"action === 'create'\" :size=\"20\" />\n\t\t\t\t\t<LinkVariant v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ action === 'create' ? createLabel : linkLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\n\t\t<!-- Loading -->\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- Error -->\n\t\t<div v-else-if=\"error\" class=\"cn-calendar-card__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\n\t\t<!-- Empty -->\n\t\t<div v-else-if=\"displayedEvents.length === 0\" class=\"cn-calendar-card__empty\">\n\t\t\t{{ noEventsLabel }}\n\t\t</div>\n\n\t\t<!-- single-entity surface: one compact chip -->\n\t\t<div v-else-if=\"surface === 'single-entity'\" class=\"cn-calendar-card__chip\">\n\t\t\t<CalendarClock :size=\"18\" class=\"cn-calendar-card__chip-icon\" />\n\t\t\t<span class=\"cn-calendar-card__chip-title\">{{ displayedEvents[0].summary || untitledLabel }}</span>\n\t\t\t<span v-if=\"displayedEvents[0].dtstart\" class=\"cn-calendar-card__chip-when\">\n\t\t\t\t{{ formatShort(displayedEvents[0].dtstart) }}\n\t\t\t</span>\n\t\t\t<span\n\t\t\t\tv-if=\"displayedEvents[0].status\"\n\t\t\t\tclass=\"cn-calendar-card__chip-status\"\n\t\t\t\t:class=\"`cn-calendar-card__chip-status--${displayedEvents[0].status}`\">\n\t\t\t\t{{ displayedEvents[0].status }}\n\t\t\t</span>\n\t\t</div>\n\n\t\t<!-- list surfaces: user/app/detail share the row template -->\n\t\t<div v-else class=\"cn-calendar-card__list\">\n\t\t\t<div\n\t\t\t\tv-for=\"ev in displayedEvents\"\n\t\t\t\t:key=\"rowKey(ev)\"\n\t\t\t\tclass=\"cn-calendar-card__row\">\n\t\t\t\t<div class=\"cn-calendar-card__row-icon\">\n\t\t\t\t\t<CalendarClock v-if=\"isUpcoming(ev)\" :size=\"20\" class=\"cn-calendar-card__icon--upcoming\" />\n\t\t\t\t\t<CalendarCheck v-else :size=\"20\" class=\"cn-calendar-card__icon--past\" />\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-calendar-card__row-main\">\n\t\t\t\t\t<span class=\"cn-calendar-card__title\">{{ ev.summary || untitledLabel }}</span>\n\t\t\t\t\t<div class=\"cn-calendar-card__meta\">\n\t\t\t\t\t\t<span v-if=\"ev.dtstart\" class=\"cn-calendar-card__when\">{{ formatShort(ev.dtstart) }}</span>\n\t\t\t\t\t\t<span v-if=\"ev.location\" class=\"cn-calendar-card__location\">· {{ ev.location }}</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Footer: detail surface gets \"Open in NC Calendar\" CTA -->\n\t\t<template v-if=\"surface === 'detail-page'\" #footer>\n\t\t\t<a\n\t\t\t\tclass=\"cn-calendar-card__cta\"\n\t\t\t\t:href=\"calendarAppUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener\">\n\t\t\t\t{{ openInCalendarLabel }}\n\t\t\t</a>\n\t\t</template>\n\n\t\t<!-- Footer: dashboard surfaces get \"Show all\" when truncated -->\n\t\t<template v-else-if=\"allEvents.length > maxDisplay && surface !== 'single-entity'\" #footer>\n\t\t\t<button class=\"cn-calendar-card__show-all\" @click=\"$emit('show-all')\">\n\t\t\t\t{{ showAllLabel }} ({{ allEvents.length }})\n\t\t\t</button>\n\t\t</template>\n\t\t<CnCalendarEventPicker\n\t\t\tv-if=\"showPicker\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@link=\"onPickerLink\"\n\t\t\t@close=\"showPicker = false\" />\n\t\t<CnCalendarEventCreate\n\t\t\tv-if=\"showCreate\"\n\t\t\t:register=\"register\"\n\t\t\t:schema=\"schema\"\n\t\t\t:objectId=\"objectId\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@created=\"onEventCreated\"\n\t\t\t@close=\"showCreate = false\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport Calendar from 'vue-material-design-icons/Calendar.vue'\nimport CalendarCheck from 'vue-material-design-icons/CalendarCheck.vue'\nimport CalendarClock from 'vue-material-design-icons/CalendarClock.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnCalendarEventCreate from '../../../components/CnCalendarEventCreate/CnCalendarEventCreate.vue'\nimport CnCalendarEventPicker from '../../../components/CnCalendarEventPicker/CnCalendarEventPicker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport CnIcon from '../../../components/CnIcon/CnIcon.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { userLocale } from '../../../utils/userLocale.js'\nimport { linkCalendarEvent } from './calendarEventLink.js'\n\n/**\n * CnCalendarCard — surface-aware compact widget for the calendar\n * integration. Renders linked VEVENTs across all four widget surfaces\n * (AD-19) with the same component.\n */\nexport default {\n\tname: 'CnCalendarCard',\n\n\tcomponents: { CnCalendarEventCreate, CnCalendarEventPicker, CnDetailCard, CnIcon, LinkVariant, NcButton, NcLoadingIcon, Plus, CalendarClock, CalendarCheck },\n\n\tprops: {\n\t\t/** OpenRegister register id (slug or uuid). Optional for user-dashboard. */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). Optional for user-dashboard. */\n\t\tschema: { type: String, default: '' },\n\t\t/** Parent object id. Optional for user-dashboard. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** Stable integration id (matches PHP-side provider id). */\n\t\tintegrationId: { type: String, default: 'calendar' },\n\t\t/**\n\t\t * Composite entity id \"calendarId/eventUri\" for the\n\t\t * single-entity surface. Ignored on other surfaces.\n\t\t */\n\t\tentityId: { type: String, default: '' },\n\t\t/** Rendering surface per ADR-019 AD-19. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (v) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(v),\n\t\t},\n\n\t\t/** Base API URL for OpenRegister. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Maximum rows on list surfaces (ignored on single-entity). */\n\t\tmaxDisplay: { type: Number, default: 5 },\n\t\t/** Whether the CnDetailCard collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\n\t\t// --- Pre-translated labels (ADR-007) ---\n\t\t/** Empty-state label. */\n\t\tnoEventsLabel: { type: String, default: () => t('nextcloud-vue', 'No meetings') },\n\t\t/** Fallback when a VEVENT has no summary. */\n\t\tuntitledLabel: { type: String, default: () => t('nextcloud-vue', '(no title)') },\n\t\t/** detail-page footer CTA label. */\n\t\topenInCalendarLabel: { type: String, default: () => t('nextcloud-vue', 'Open in Calendar') },\n\t\t/** dashboard \"show all\" footer label. */\n\t\tshowAllLabel: { type: String, default: () => t('nextcloud-vue', 'Show all') },\n\t\t/**\n\t\t * Buttons in the card's title row on a detail page: `create` makes a\n\t\t * meeting linked to the object, `link` links an existing one from the\n\t\t * user's calendar. In the order given; none by default.\n\t\t */\n\t\theaderActions: { type: Array, default: () => [] },\n\t\t/** Label of the `create` button. */\n\t\tcreateLabel: { type: String, default: () => t('nextcloud-vue', 'Make an appointment') },\n\t\t/** `secondary` draws the `create` button outlined instead of primary. */\n\t\tcreateVariant: { type: String, default: 'primary' },\n\t\t/** Icon name of the `create` button; a plus without it. */\n\t\tcreateIcon: { type: String, default: '' },\n\t\t/** Label of the `link` button. */\n\t\tlinkLabel: { type: String, default: () => t('nextcloud-vue', 'Link an existing one') },\n\t},\n\n\temits: ['show-all'],\n\n\tdata() {\n\t\treturn {\n\t\t\tCalendar: markRaw(Calendar),\n\t\t\tallEvents: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tshowCreate: false,\n\t\t\tshowPicker: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The title-row buttons to draw: only on a detail page with an\n\t\t * object, only the known ones, in the order given.\n\t\t *\n\t\t * @return {Array<string>}\n\t\t */\n\t\tshownHeaderActions() {\n\t\t\tif (this.surface !== 'detail-page' || !this.objectId || !Array.isArray(this.headerActions)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.headerActions.filter((action, index, all) => ['create', 'link'].includes(action) && all.indexOf(action) === index)\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Meetings')\n\t\t},\n\n\t\tcalendarAppUrl() {\n\t\t\ttry {\n\t\t\t\treturn generateUrl('/apps/calendar')\n\t\t\t} catch {\n\t\t\t\treturn '/apps/calendar'\n\t\t\t}\n\t\t},\n\n\t\tdisplayedEvents() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\treturn this.allEvents.slice(0, 1)\n\t\t\t}\n\t\t\t// list surfaces sort by dtstart ascending, then cap at maxDisplay.\n\t\t\tconst sorted = [...this.allEvents].sort((a, b) => {\n\t\t\t\tconst ta = a.dtstart ? new Date(a.dtstart).getTime() : Number.POSITIVE_INFINITY\n\t\t\t\tconst tb = b.dtstart ? new Date(b.dtstart).getTime() : Number.POSITIVE_INFINITY\n\t\t\t\treturn ta - tb\n\t\t\t})\n\t\t\t// On dashboard surfaces, surface upcoming meetings first.\n\t\t\tif (this.surface === 'user-dashboard' || this.surface === 'app-dashboard') {\n\t\t\t\tconst now = Date.now()\n\t\t\t\tconst upcoming = sorted.filter((ev) => {\n\t\t\t\t\tif (!ev.dtstart) {\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t\treturn new Date(ev.dtstart).getTime() >= now\n\t\t\t\t})\n\t\t\t\treturn upcoming.slice(0, this.maxDisplay)\n\t\t\t}\n\t\t\treturn sorted.slice(0, this.maxDisplay)\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.refresh()\n\t\t} },\n\n\t\tentityId() {\n\t\t\tthis.refresh()\n\t\t},\n\n\t\tsurface() {\n\t\t\tthis.refresh()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A meeting was made on this object: close the form, read the list again.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonEventCreated() {\n\t\t\tthis.showCreate = false\n\t\t\tthis.refresh()\n\t\t},\n\n\t\t/**\n\t\t * Link the picked meeting, then read the list again, or say why not.\n\t\t *\n\t\t * @param {{calendarUri: string, eventUid: string}} payload The picked event.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onPickerLink(payload) {\n\t\t\tthis.showPicker = false\n\t\t\tconst result = await linkCalendarEvent(prefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/events`), payload)\n\t\t\tif (result.ok) {\n\t\t\t\tthis.error = ''\n\t\t\t\tthis.refresh()\n\t\t\t} else {\n\t\t\t\tthis.error = result.error\n\t\t\t}\n\t\t},\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\trowKey(ev) {\n\t\t\tif (ev.calendarId && ev.id) {\n\t\t\t\treturn `${ev.calendarId}/${ev.id}`\n\t\t\t}\n\t\t\treturn ev.id || ev.uid || ''\n\t\t},\n\n\t\tisUpcoming(ev) {\n\t\t\tif (!ev.dtstart) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(ev.dtstart).getTime() >= Date.now()\n\t\t\t} catch {\n\t\t\t\treturn true\n\t\t\t}\n\t\t},\n\n\t\trefresh() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingleEntity()\n\t\t\t} else {\n\t\t\t\tthis.fetchList()\n\t\t\t}\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.allEvents = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.allEvents = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Calendar is currently unavailable.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meetings.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCalendarCard] failed to fetch events', err)\n\t\t\t\tthis.allEvents = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meetings.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingleEntity() {\n\t\t\tif (!this.entityId || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.allEvents = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst url = `${this.baseUrl()}/${encodeURI(this.entityId)}`\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.allEvents = data && (data.id || data.uid) ? [data] : []\n\t\t\t\t} else {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tif (response.status !== 404) {\n\t\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meeting.')\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCalendarCard] failed to fetch single entity', err)\n\t\t\t\tthis.allEvents = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meeting.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tformatShort(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst d = new Date(value)\n\t\t\t\tif (Number.isNaN(d.getTime())) {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t\tconst opts = this.surface === 'single-entity'\n\t\t\t\t\t? { dateStyle: 'medium' }\n\t\t\t\t\t: { dateStyle: 'medium', timeStyle: 'short' }\n\t\t\t\treturn d.toLocaleString(userLocale(), opts)\n\t\t\t} catch {\n\t\t\t\treturn String(value)\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-calendar-card__empty {\n\ttext-align: center;\n\tpadding: 16px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-calendar-card__error {\n\tcolor: var(--color-error);\n\tpadding: 8px 0;\n\tfont-size: 13px;\n}\n\n.cn-calendar-card__list {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-calendar-card__row {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-calendar-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-calendar-card__row-icon {\n\tflex-shrink: 0;\n\tpadding-top: 1px;\n}\n\n.cn-calendar-card__icon--upcoming { color: var(--color-primary-element); }\n\n.cn-calendar-card__icon--past { color: var(--color-text-maxcontrast); }\n\n.cn-calendar-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.cn-calendar-card__title {\n\tdisplay: block;\n\tfont-size: 13px;\n\tfont-weight: 500;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.cn-calendar-card__meta {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tmargin-top: 2px;\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-calendar-card__when {\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__location {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 10px;\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: var(--color-background-hover);\n\tfont-size: 13px;\n\tmax-width: 100%;\n}\n\n.cn-calendar-card__chip-icon {\n\tcolor: var(--color-primary-element);\n\tflex-shrink: 0;\n}\n\n.cn-calendar-card__chip-title {\n\tfont-weight: 500;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip-when {\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip-status {\n\tfont-size: 11px;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tpadding: 1px 6px;\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: var(--color-background-darker);\n}\n\n.cn-calendar-card__chip-status--confirmed { background: var(--color-success); color: var(--color-main-background); }\n\n.cn-calendar-card__chip-status--tentative { background: var(--color-warning, #e9a40f); color: var(--color-main-background); }\n\n.cn-calendar-card__chip-status--cancelled { background: var(--color-error); color: var(--color-main-background); }\n\n.cn-calendar-card__cta,\n.cn-calendar-card__show-all {\n\tbackground: none;\n\tborder: none;\n\tcolor: var(--color-primary-element);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\tpadding: 0;\n\twidth: 100%;\n\ttext-align: center;\n\ttext-decoration: none;\n\tdisplay: inline-block;\n}\n\n.cn-calendar-card__cta:hover,\n.cn-calendar-card__show-all:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_toDisplayString","_createElementBlock","_createElementVNode","_openBlock","_normalizeClass","_Fragment","_renderList","_createTextVNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnCalendarCard.vue3.js","sources":["../../../../../src/integrations/builtin/calendar/CnCalendarCard.vue?vue&type=template&id=6c15c681&lang.js"],"sourcesContent":["<!--\n CnCalendarCard — bespoke widget for the `calendar` integration.\n\n Surface-aware (AD-19) widget that renders linked VEVENTs across the\n four pluggable-integration-registry surfaces with one component:\n\n - `user-dashboard` : compact list, \"next 5 upcoming meetings\" across\n the user's objects (one row per VEVENT). Falls\n back to a list scoped by the optional\n register/schema/objectId when given (registry\n dashboards pass the full triple) so it still\n works without a global \"across all my objects\"\n query — see AD-22.\n - `app-dashboard` : same compact list scoped to the current app's\n register/schema/objectId, when given.\n - `detail-page` : full per-object meeting list with a quick\n \"Open in Calendar\" CTA — the inline create\n form lives in CnCalendarTab, not here, to keep\n the detail card compact (design.md AD-3).\n - `single-entity` : a single VEVENT rendered as a chip with date +\n summary + status icon. Accepts `entityId`\n (composite \"calendarId/eventUri\") for the\n referenceType auto-rendering path.\n\n Loading / empty / error states follow ADR-017 component composition.\n All strings pass through t('nextcloud-vue', ...) for nl + en\n translation (ADR-007). Theming uses Nextcloud CSS variables only so\n the nldesign app's overrides apply transparently (ADR-010).\n-->\n<template>\n\t<CnDetailCard :title=\"resolvedTitle\" :icon=\"Calendar\" :collapsible=\"collapsible\">\n\t\t<!-- `headerActions`: the calendar tab's create and link-existing flows in the title row (detail page). -->\n\t\t<template v-if=\"shownHeaderActions.length > 0\" #actions>\n\t\t\t<NcButton\n\t\t\t\tv-for=\"action in shownHeaderActions\"\n\t\t\t\t:key=\"action\"\n\t\t\t\t:variant=\"action === 'create' && createVariant !== 'secondary' ? 'primary' : 'secondary'\"\n\t\t\t\t:data-testid=\"`cn-calendar-card-${action}`\"\n\t\t\t\t@click=\"action === 'create' ? (showCreate = true) : (showPicker = true)\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<CnIcon v-if=\"action === 'create' && createIcon\"\n\t\t\t\t\t\t:name=\"createIcon\"\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\tdata-testid=\"cn-calendar-card-create-icon\" />\n\t\t\t\t\t<Plus v-else-if=\"action === 'create'\" :size=\"20\" />\n\t\t\t\t\t<LinkVariant v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ action === 'create' ? createLabel : linkLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\n\t\t<!-- Loading -->\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- Error -->\n\t\t<div v-else-if=\"error\" class=\"cn-calendar-card__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\n\t\t<!-- Empty -->\n\t\t<div v-else-if=\"displayedEvents.length === 0\" class=\"cn-calendar-card__empty\">\n\t\t\t{{ noEventsLabel }}\n\t\t</div>\n\n\t\t<!-- single-entity surface: one compact chip -->\n\t\t<div v-else-if=\"surface === 'single-entity'\" class=\"cn-calendar-card__chip\">\n\t\t\t<CalendarClock :size=\"18\" class=\"cn-calendar-card__chip-icon\" />\n\t\t\t<span class=\"cn-calendar-card__chip-title\">{{ displayedEvents[0].summary || untitledLabel }}</span>\n\t\t\t<span v-if=\"displayedEvents[0].dtstart\" class=\"cn-calendar-card__chip-when\">\n\t\t\t\t{{ formatShort(displayedEvents[0].dtstart) }}\n\t\t\t</span>\n\t\t\t<span\n\t\t\t\tv-if=\"displayedEvents[0].status\"\n\t\t\t\tclass=\"cn-calendar-card__chip-status\"\n\t\t\t\t:class=\"`cn-calendar-card__chip-status--${displayedEvents[0].status}`\">\n\t\t\t\t{{ displayedEvents[0].status }}\n\t\t\t</span>\n\t\t</div>\n\n\t\t<!-- list surfaces: user/app/detail share the row template -->\n\t\t<div v-else class=\"cn-calendar-card__list\">\n\t\t\t<div\n\t\t\t\tv-for=\"ev in displayedEvents\"\n\t\t\t\t:key=\"rowKey(ev)\"\n\t\t\t\tclass=\"cn-calendar-card__row\">\n\t\t\t\t<!-- The board look draws a meeting as a ruled row: its title, one\n\t\t\t\t meta line (when, where, who) and its status at the end. -->\n\t\t\t\t<template v-if=\"boardRows\">\n\t\t\t\t\t<div class=\"cn-calendar-card__row-main\">\n\t\t\t\t\t\t<span class=\"cn-calendar-card__title\">{{ ev.summary || untitledLabel }}</span>\n\t\t\t\t\t\t<span class=\"cn-calendar-card__meta\" data-testid=\"cn-calendar-card-meta\">{{ boardMetaOf(ev) }}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span v-if=\"statusOf(ev)\"\n\t\t\t\t\t\tclass=\"cn-status-badge\"\n\t\t\t\t\t\t:class=\"`cn-status-badge--${statusVariantOf(ev)}`\"\n\t\t\t\t\t\tdata-testid=\"cn-calendar-card-status\">{{ statusOf(ev) }}</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-else>\n\t\t\t\t\t<div class=\"cn-calendar-card__row-icon\">\n\t\t\t\t\t\t<CalendarClock v-if=\"isUpcoming(ev)\" :size=\"20\" class=\"cn-calendar-card__icon--upcoming\" />\n\t\t\t\t\t\t<CalendarCheck v-else :size=\"20\" class=\"cn-calendar-card__icon--past\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"cn-calendar-card__row-main\">\n\t\t\t\t\t\t<span class=\"cn-calendar-card__title\">{{ ev.summary || untitledLabel }}</span>\n\t\t\t\t\t\t<div class=\"cn-calendar-card__meta\">\n\t\t\t\t\t\t\t<span v-if=\"ev.dtstart\" class=\"cn-calendar-card__when\">{{ formatShort(ev.dtstart) }}</span>\n\t\t\t\t\t\t\t<span v-if=\"ev.location\" class=\"cn-calendar-card__location\">· {{ ev.location }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</template>\n\t\t\t</div>\n\t\t\t<a v-if=\"boardRows\"\n\t\t\t\tclass=\"cn-calendar-card__open\"\n\t\t\t\t:href=\"calendarAppUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener\"\n\t\t\t\tdata-testid=\"cn-calendar-card-open\">{{ openInCalendarLabel }}</a>\n\t\t</div>\n\n\t\t<!-- Footer: detail surface gets \"Open in NC Calendar\" CTA -->\n\t\t<template v-if=\"surface === 'detail-page' && !isBoard\" #footer>\n\t\t\t<a\n\t\t\t\tclass=\"cn-calendar-card__cta\"\n\t\t\t\t:href=\"calendarAppUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener\">\n\t\t\t\t{{ openInCalendarLabel }}\n\t\t\t</a>\n\t\t</template>\n\n\t\t<!-- Footer: dashboard surfaces get \"Show all\" when truncated -->\n\t\t<template v-else-if=\"allEvents.length > maxDisplay && surface !== 'single-entity'\" #footer>\n\t\t\t<button class=\"cn-calendar-card__show-all\" @click=\"$emit('show-all')\">\n\t\t\t\t{{ showAllLabel }} ({{ allEvents.length }})\n\t\t\t</button>\n\t\t</template>\n\t\t<CnCalendarEventPicker\n\t\t\tv-if=\"showPicker\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@link=\"onPickerLink\"\n\t\t\t@close=\"showPicker = false\" />\n\t\t<CnCalendarEventCreate\n\t\t\tv-if=\"showCreate\"\n\t\t\t:register=\"register\"\n\t\t\t:schema=\"schema\"\n\t\t\t:objectId=\"objectId\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@created=\"onEventCreated\"\n\t\t\t@close=\"showCreate = false\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport Calendar from 'vue-material-design-icons/Calendar.vue'\nimport CalendarCheck from 'vue-material-design-icons/CalendarCheck.vue'\nimport CalendarClock from 'vue-material-design-icons/CalendarClock.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnCalendarEventCreate from '../../../components/CnCalendarEventCreate/CnCalendarEventCreate.vue'\nimport CnCalendarEventPicker from '../../../components/CnCalendarEventPicker/CnCalendarEventPicker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport CnIcon from '../../../components/CnIcon/CnIcon.vue'\nimport { normalizeLook } from '../../../composables/useLook.js'\nimport { formatBoardDate, formatTimeOfDay } from '../../../utils/boardDate.js'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { userLocale } from '../../../utils/userLocale.js'\nimport { linkCalendarEvent } from './calendarEventLink.js'\nimport { eventAttendeeNames, eventStatusLabel, eventStatusVariant } from './eventStatus.js'\n\n/**\n * CnCalendarCard — surface-aware compact widget for the calendar\n * integration. Renders linked VEVENTs across all four widget surfaces\n * (AD-19) with the same component.\n */\nexport default {\n\tname: 'CnCalendarCard',\n\n\tcomponents: { CnCalendarEventCreate, CnCalendarEventPicker, CnDetailCard, CnIcon, LinkVariant, NcButton, NcLoadingIcon, Plus, CalendarClock, CalendarCheck },\n\n\tinject: {\n\t\tcnLook: { default: 'nextcloud' },\n\t},\n\n\tprops: {\n\t\t/** OpenRegister register id (slug or uuid). Optional for user-dashboard. */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). Optional for user-dashboard. */\n\t\tschema: { type: String, default: '' },\n\t\t/** Parent object id. Optional for user-dashboard. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** Stable integration id (matches PHP-side provider id). */\n\t\tintegrationId: { type: String, default: 'calendar' },\n\t\t/**\n\t\t * Composite entity id \"calendarId/eventUri\" for the\n\t\t * single-entity surface. Ignored on other surfaces.\n\t\t */\n\t\tentityId: { type: String, default: '' },\n\t\t/** Rendering surface per ADR-019 AD-19. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (v) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(v),\n\t\t},\n\n\t\t/** Base API URL for OpenRegister. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Maximum rows on list surfaces (ignored on single-entity). */\n\t\tmaxDisplay: { type: Number, default: 5 },\n\t\t/** Whether the CnDetailCard collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\n\t\t// --- Pre-translated labels (ADR-007) ---\n\t\t/** Empty-state label. */\n\t\tnoEventsLabel: { type: String, default: () => t('nextcloud-vue', 'No meetings') },\n\t\t/** Fallback when a VEVENT has no summary. */\n\t\tuntitledLabel: { type: String, default: () => t('nextcloud-vue', '(no title)') },\n\t\t/** detail-page footer CTA label. */\n\t\topenInCalendarLabel: { type: String, default: () => t('nextcloud-vue', 'Open in Calendar') },\n\t\t/** dashboard \"show all\" footer label. */\n\t\tshowAllLabel: { type: String, default: () => t('nextcloud-vue', 'Show all') },\n\t\t/**\n\t\t * Buttons in the card's title row on a detail page: `create` makes a\n\t\t * meeting linked to the object, `link` links an existing one from the\n\t\t * user's calendar. In the order given; none by default.\n\t\t */\n\t\theaderActions: { type: Array, default: () => [] },\n\t\t/** Label of the `create` button. */\n\t\tcreateLabel: { type: String, default: () => t('nextcloud-vue', 'Make an appointment') },\n\t\t/** `secondary` draws the `create` button outlined instead of primary. */\n\t\tcreateVariant: { type: String, default: 'primary' },\n\t\t/** Icon name of the `create` button; a plus without it. */\n\t\tcreateIcon: { type: String, default: '' },\n\t\t/** Label of the `link` button. */\n\t\tlinkLabel: { type: String, default: () => t('nextcloud-vue', 'Link an existing one') },\n\t},\n\n\temits: ['show-all'],\n\n\tdata() {\n\t\treturn {\n\t\t\tCalendar: markRaw(Calendar),\n\t\t\tallEvents: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tshowCreate: false,\n\t\t\tshowPicker: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The title-row buttons to draw: only on a detail page with an\n\t\t * object, only the known ones, in the order given.\n\t\t *\n\t\t * @return {Array<string>}\n\t\t */\n\t\t/** @return {boolean} The board look draws ruled rows. */\n\t\tisBoard() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\t/** @return {boolean} The meetings are ruled rows: the board look on a detail page. */\n\t\tboardRows() {\n\t\t\treturn this.isBoard && this.surface === 'detail-page'\n\t\t},\n\n\t\tshownHeaderActions() {\n\t\t\tif (this.surface !== 'detail-page' || !this.objectId || !Array.isArray(this.headerActions)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.headerActions.filter((action, index, all) => ['create', 'link'].includes(action) && all.indexOf(action) === index)\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Meetings')\n\t\t},\n\n\t\tcalendarAppUrl() {\n\t\t\ttry {\n\t\t\t\treturn generateUrl('/apps/calendar')\n\t\t\t} catch {\n\t\t\t\treturn '/apps/calendar'\n\t\t\t}\n\t\t},\n\n\t\tdisplayedEvents() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\treturn this.allEvents.slice(0, 1)\n\t\t\t}\n\t\t\t// list surfaces sort by dtstart ascending, then cap at maxDisplay.\n\t\t\tconst sorted = [...this.allEvents].sort((a, b) => {\n\t\t\t\tconst ta = a.dtstart ? new Date(a.dtstart).getTime() : Number.POSITIVE_INFINITY\n\t\t\t\tconst tb = b.dtstart ? new Date(b.dtstart).getTime() : Number.POSITIVE_INFINITY\n\t\t\t\treturn ta - tb\n\t\t\t})\n\t\t\t// On dashboard surfaces, surface upcoming meetings first.\n\t\t\tif (this.surface === 'user-dashboard' || this.surface === 'app-dashboard') {\n\t\t\t\tconst now = Date.now()\n\t\t\t\tconst upcoming = sorted.filter((ev) => {\n\t\t\t\t\tif (!ev.dtstart) {\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t\treturn new Date(ev.dtstart).getTime() >= now\n\t\t\t\t})\n\t\t\t\treturn upcoming.slice(0, this.maxDisplay)\n\t\t\t}\n\t\t\treturn sorted.slice(0, this.maxDisplay)\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.refresh()\n\t\t} },\n\n\t\tentityId() {\n\t\t\tthis.refresh()\n\t\t},\n\n\t\tsurface() {\n\t\t\tthis.refresh()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A meeting's meta line in the board look: \"14 okt, 10:00 tot 10:30\",\n\t\t * its place and its attendees, separated by middots.\n\t\t *\n\t\t * @param {object} ev The event.\n\t\t * @return {string}\n\t\t */\n\t\tboardMetaOf(ev) {\n\t\t\tconst start = ev.dtstart ? new Date(ev.dtstart) : null\n\t\t\tconst end = ev.dtend ? new Date(ev.dtend) : null\n\t\t\tlet when = ''\n\t\t\tif (start && !Number.isNaN(start.getTime())) {\n\t\t\t\twhen = `${formatBoardDate(start)}, ${formatTimeOfDay(start)}`\n\t\t\t\tif (end && !Number.isNaN(end.getTime())) {\n\t\t\t\t\twhen = t('nextcloud-vue', '{start} until {end}', { start: when, end: formatTimeOfDay(end) })\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn [when, ev.location, ...eventAttendeeNames(ev)].filter(Boolean).join(' · ')\n\t\t},\n\n\t\tstatusOf(ev) {\n\t\t\treturn eventStatusLabel(ev)\n\t\t},\n\n\t\tstatusVariantOf(ev) {\n\t\t\treturn eventStatusVariant(ev)\n\t\t},\n\n\t\t/**\n\t\t * A meeting was made on this object: close the form, read the list again.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonEventCreated() {\n\t\t\tthis.showCreate = false\n\t\t\tthis.refresh()\n\t\t},\n\n\t\t/**\n\t\t * Link the picked meeting, then read the list again, or say why not.\n\t\t *\n\t\t * @param {{calendarUri: string, eventUid: string}} payload The picked event.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onPickerLink(payload) {\n\t\t\tthis.showPicker = false\n\t\t\tconst result = await linkCalendarEvent(prefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/events`), payload)\n\t\t\tif (result.ok) {\n\t\t\t\tthis.error = ''\n\t\t\t\tthis.refresh()\n\t\t\t} else {\n\t\t\t\tthis.error = result.error\n\t\t\t}\n\t\t},\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\trowKey(ev) {\n\t\t\tif (ev.calendarId && ev.id) {\n\t\t\t\treturn `${ev.calendarId}/${ev.id}`\n\t\t\t}\n\t\t\treturn ev.id || ev.uid || ''\n\t\t},\n\n\t\tisUpcoming(ev) {\n\t\t\tif (!ev.dtstart) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(ev.dtstart).getTime() >= Date.now()\n\t\t\t} catch {\n\t\t\t\treturn true\n\t\t\t}\n\t\t},\n\n\t\trefresh() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingleEntity()\n\t\t\t} else {\n\t\t\t\tthis.fetchList()\n\t\t\t}\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.allEvents = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.allEvents = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Calendar is currently unavailable.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meetings.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCalendarCard] failed to fetch events', err)\n\t\t\t\tthis.allEvents = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meetings.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingleEntity() {\n\t\t\tif (!this.entityId || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.allEvents = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst url = `${this.baseUrl()}/${encodeURI(this.entityId)}`\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.allEvents = data && (data.id || data.uid) ? [data] : []\n\t\t\t\t} else {\n\t\t\t\t\tthis.allEvents = []\n\t\t\t\t\tif (response.status !== 404) {\n\t\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meeting.')\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCalendarCard] failed to fetch single entity', err)\n\t\t\t\tthis.allEvents = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load meeting.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tformatShort(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst d = new Date(value)\n\t\t\t\tif (Number.isNaN(d.getTime())) {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t\tconst opts = this.surface === 'single-entity'\n\t\t\t\t\t? { dateStyle: 'medium' }\n\t\t\t\t\t: { dateStyle: 'medium', timeStyle: 'short' }\n\t\t\t\treturn d.toLocaleString(userLocale(), opts)\n\t\t\t} catch {\n\t\t\t\treturn String(value)\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-calendar-card__empty {\n\ttext-align: center;\n\tpadding: 16px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-calendar-card__error {\n\tcolor: var(--color-error);\n\tpadding: 8px 0;\n\tfont-size: 13px;\n}\n\n.cn-calendar-card__list {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-calendar-card__row {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-calendar-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-calendar-card__row-icon {\n\tflex-shrink: 0;\n\tpadding-top: 1px;\n}\n\n.cn-calendar-card__icon--upcoming { color: var(--color-primary-element); }\n\n.cn-calendar-card__icon--past { color: var(--color-text-maxcontrast); }\n\n.cn-calendar-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.cn-calendar-card__title {\n\tdisplay: block;\n\tfont-size: 13px;\n\tfont-weight: 500;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.cn-calendar-card__meta {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tmargin-top: 2px;\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-calendar-card__when {\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__location {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 10px;\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: var(--color-background-hover);\n\tfont-size: 13px;\n\tmax-width: 100%;\n}\n\n.cn-calendar-card__chip-icon {\n\tcolor: var(--color-primary-element);\n\tflex-shrink: 0;\n}\n\n.cn-calendar-card__chip-title {\n\tfont-weight: 500;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip-when {\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n\n.cn-calendar-card__chip-status {\n\tfont-size: 11px;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tpadding: 1px 6px;\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: var(--color-background-darker);\n}\n\n.cn-calendar-card__chip-status--confirmed { background: var(--color-success); color: var(--color-main-background); }\n\n.cn-calendar-card__chip-status--tentative { background: var(--color-warning, #e9a40f); color: var(--color-main-background); }\n\n.cn-calendar-card__chip-status--cancelled { background: var(--color-error); color: var(--color-main-background); }\n\n.cn-calendar-card__cta,\n.cn-calendar-card__show-all {\n\tbackground: none;\n\tborder: none;\n\tcolor: var(--color-primary-element);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\tpadding: 0;\n\twidth: 100%;\n\ttext-align: center;\n\ttext-decoration: none;\n\tdisplay: inline-block;\n}\n\n.cn-calendar-card__cta:hover,\n.cn-calendar-card__show-all:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_toDisplayString","_openBlock","_normalizeClass","_Fragment","_renderList","_createElementVNode","_createTextVNode"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnCalendarTab.vue2.js';
|
|
|
2
2
|
import { render } from './CnCalendarTab.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-44e2340e";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -12,6 +12,7 @@ import __sfc_main$1 from '../../../components/CnCalendarEventPicker/CnCalendarEv
|
|
|
12
12
|
import __sfc_main from '../../../components/CnStatusBadge/CnStatusBadge.vue.js';
|
|
13
13
|
import { userLocale } from '../../../utils/userLocale.js';
|
|
14
14
|
import { linkCalendarEvent } from './calendarEventLink.js';
|
|
15
|
+
import { eventStatusLabel, eventStatusVariant } from './eventStatus.js';
|
|
15
16
|
import { prefixUrl, buildHeaders } from '../../../utils/headers.js';
|
|
16
17
|
|
|
17
18
|
const MAX_AVATARS = 3;
|
|
@@ -313,31 +314,11 @@ var script = {
|
|
|
313
314
|
},
|
|
314
315
|
|
|
315
316
|
statusLabel(ev) {
|
|
316
|
-
|
|
317
|
-
if (status === 'confirmed') {
|
|
318
|
-
return translate('nextcloud-vue', 'Confirmed')
|
|
319
|
-
}
|
|
320
|
-
if (status === 'tentative') {
|
|
321
|
-
return translate('nextcloud-vue', 'Tentative')
|
|
322
|
-
}
|
|
323
|
-
if (status === 'cancelled') {
|
|
324
|
-
return translate('nextcloud-vue', 'Cancelled')
|
|
325
|
-
}
|
|
326
|
-
return ''
|
|
317
|
+
return eventStatusLabel(ev)
|
|
327
318
|
},
|
|
328
319
|
|
|
329
320
|
statusVariant(ev) {
|
|
330
|
-
|
|
331
|
-
if (status === 'confirmed') {
|
|
332
|
-
return 'success'
|
|
333
|
-
}
|
|
334
|
-
if (status === 'tentative') {
|
|
335
|
-
return 'warning'
|
|
336
|
-
}
|
|
337
|
-
if (status === 'cancelled') {
|
|
338
|
-
return 'error'
|
|
339
|
-
}
|
|
340
|
-
return 'default'
|
|
321
|
+
return eventStatusVariant(ev)
|
|
341
322
|
},
|
|
342
323
|
|
|
343
324
|
attendeeList(ev) {
|