Files
2026-10-25 01:38:47 +00:00

1 line
141 KiB
Plaintext

{"version":3,"mappings":"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","names":["_hoisted_1","_sfc_main","defineComponent","__props","_ctx","_cache","openBlock","createElementBlock","NcAppNavigationSpacer","_export_sfc","rebuildNavigation","data","axios","generateOcsUrl","emit","logger","getLoggerBuilder","props","__emit","itemTitle","computed","_createBlock","_unref","NcListItem","t","_createTextVNode","_toDisplayString","store","useExAppsStore","_createElementBlock","_normalizeClass","$style","_openBlock","_Fragment","_renderList","daemon","DaemonSelectionDialogListEntry","$event","$emit","appApiAdminPage","generateUrl","NcDialog","NcEmptyContent","_createVNode","NcIconSvgWrapper","mdiFormatListBulleted","NcButton","DaemonSelectionDialogList","fetchApps","fetchAppStatus","appId","enableExApp","app","deployOptions","confirmPassword","forceEnableExApp","disableExApp","defineStore","isEnabled","loadState","apps","ref","updateCount","statusUpdater","daemonAccessible","defaultDaemon","dockerDaemons","initializingOrDeployingApps","getById","id","enableApp","exAppApi.enableExApp","spawnDialog","DaemonSelectionDialog","forceEnableApp","exAppApi.forceEnableExApp","initialize","disableApp","exAppApi.disableExApp","uninstallApp","updateApp","error","showError","force","fetchDockerDaemons","fetchAllApps","exAppApi.fetchApps","status","exAppApi.fetchAppStatus","e","updateAppsStatus","useAppsStore","exApps","appstoreApps","categories","bundles","readonly","isLoadingApps","isLoadingCategories","getCategoryById","categoryId","getAppById","getAppsByCategory","canInstall","needForceEnable","api.enableApp","canDisable","api.disableApp","canUninstall","api.uninstallApp","limitAppToGroups","groups","canLimitToGroups","enableBundle","bundleId","bundle","b","api.enableBundle","loadApps","loadCategories","api.getCategories","api.getApps","useUpdatesStore","internalUpdateCount","updateApps","appIds","exAppsToUpdate","appsToUpdate","results","api.updateApps","index","result","useUserSettingsStore","defaultGridSize","isGridView","showIncompatible","gridSizePx","getQuery","gridMode","useRoute","useRouter","to","updateFromQuery","query","appstoreEnabled","updateStore","userSettings","categoriesLoading","route","router","searchElement","useTemplateRef","useHotKey","search","watch","newQuery","watchDebounced","newValue","oldValue","isSubscribed","level","NcAppNavigation","NcAppNavigationSearch","NcAppNavigationItem","APPSTORE_CATEGORY_NAMES","APPSTORE_CATEGORY_ICONS","NcCounterBubble","NcLoadingIcon","category","inlineActions","action","menuActions","NcActions","NcActionButton","NcActionLink","NcActionRouter","gpuSupport","NcAppSidebarTab","mdiFileChart","_createElementVNode","mdiTextShort","MarkdownPreview","isSupported","isFeatured","badgeIcon","mdiStarShootingOutline","mdiStar","badgeText","badgeTitle","isShown","score","title","appScore","fullStars","emptyStars","hasHalfStar","mdiStarHalfFull","mdiStarOutline","queue","PQueue","useGroupsStore","fetchGroupById","groupId","internalFetchGroupById","searchGroups","url","group","getGroupById","useLimitedGroups","groupsStore","groupsAppIsLimitedTo","toValue","promises","idLimitedToGroups","useId","lastModified","release","date","appAuthors","authorName","a","appstoreUrl","externalResources","resources","appCategories","cannotLimitToGroups","xmlNode","mdiTextBoxOutline","BadgeAppLevel","BadgeAppDaemon","BadgeAppScore","NcNoteCard","dep","_hoisted_3","_hoisted_5","NcDateTime","resource","_hoisted_7","releases","values","changelog","createChangelogFromRelease","getLanguage","mdiClockFast","actionDisable","mdiClose","actionEnable","mdiCheck","canEnable","actionForceEnable","mdiAlertCircleCheckOutline","canForceEnable","actionInstall","mdiDownload","actionInstallForced","actionsInteract","mdiBugOutline","mdiForumOutline","mdiWeb","LimitToGroupDialog","defineAsyncComponent","__vitePreload","LimitToGroupDialog$1","actionLimitToGroup","mdiAccountGroup","actionRemove","mdiTrashCanOutline","actionUpdate","mdiUpdate","canUpdate","actions","useActions","useAppIcon","appIcon","categoryIcon","path","mdiCogOutline","name","icon","mdiCog","watchEffect","rawSvg","licenseText","activeTab","hideAppDetails","screenshotLoaded","hasScreenshot","loadScreenshot","image","onMounted","NcAppSidebar","AppDescriptionTab","AppReleasesTab","AppDetailsTab","AppDeployDaemonTab","AppActions","currentCategory","heading","pageTitle","showSidebar","NcContent","AppstoreNavigation","NcAppContent","_component_router_view","AppstoreSidebar","AppstoreDiscover","AppstoreManage","n","AppstoreBundles","AppstoreBrowse","AppstoreSearch","routes","createRouter","createWebHistory","pinia","createPinia","createApp","AppstoreApp","loading","g","availableGroups","onSearch","useDebounceFn","onSave","onReset","NcSelectUsers","isSvg","svgIcon","response","detailsRoute","detailsAction","mdiInformationOutline","rawActions","AppIcon","_hoisted_2","_hoisted_4","_hoisted_6","NcChip","tableElement","tableWidth","useElementSize","isNarrow","isWide","AppTableRow","appBundles","canEnableBundle","isBundleEnabled","enableAll","mdiDownloadMultiple","AppTable"],"ignoreList":[0],"sources":["../node_modules/@nextcloud/vue/dist/chunks/NcAppNavigationSpacer.mjs","../build/frontend/apps/appstore/src/service/rebuild-navigation.ts","../build/frontend/apps/appstore/src/utils/logger.ts","../build/frontend/apps/appstore/src/components/DaemonSelectionDialog/DaemonSelectionDialogListEntry.vue","../build/frontend/apps/appstore/src/components/DaemonSelectionDialog/DaemonSelectionDialogList.vue","../build/frontend/apps/appstore/src/components/DaemonSelectionDialog/DaemonSelectionDialog.vue","../build/frontend/apps/appstore/src/service/exAppApi.ts","../build/frontend/apps/appstore/src/store/exApps.ts","../build/frontend/apps/appstore/src/store/apps.ts","../build/frontend/apps/appstore/src/store/updates.ts","../build/frontend/apps/appstore/src/store/userSettings.ts","../build/frontend/apps/appstore/src/views/AppstoreNavigation.vue","../build/frontend/apps/appstore/src/components/AppActions.vue","../build/frontend/apps/appstore/src/components/AppstoreSidebar/AppDeployDaemonTab.vue","../build/frontend/apps/appstore/src/components/AppstoreSidebar/AppDescriptionTab.vue","../build/frontend/apps/appstore/src/components/BadgeAppDaemon.vue","../build/frontend/apps/appstore/src/components/BadgeAppLevel.vue","../build/frontend/apps/appstore/src/components/BadgeAppScore.vue","../build/frontend/apps/appstore/src/store/groups.ts","../build/frontend/apps/appstore/src/composables/useLimitedGroups.ts","../build/frontend/apps/appstore/src/components/AppstoreSidebar/AppDetailsTab.vue","../build/frontend/apps/appstore/src/components/AppstoreSidebar/AppReleasesTab.vue","../build/frontend/apps/appstore/src/actions/actionDisable.ts","../build/frontend/apps/appstore/src/actions/actionEnable.ts","../build/frontend/apps/appstore/src/actions/actionForceEnable.ts","../build/frontend/apps/appstore/src/actions/actionInstall.ts","../build/frontend/apps/appstore/src/actions/actionInstallForced.ts","../build/frontend/apps/appstore/src/actions/actionInteract.ts","../build/frontend/apps/appstore/src/actions/actionLimitToGroup.ts","../build/frontend/apps/appstore/src/actions/actionRemove.ts","../build/frontend/apps/appstore/src/actions/actionUpdate.ts","../build/frontend/apps/appstore/src/actions/index.ts","../build/frontend/apps/appstore/src/composables/useActions.ts","../build/frontend/apps/appstore/src/composables/useAppIcon.ts","../build/frontend/apps/appstore/src/views/AppstoreSidebar.vue","../build/frontend/apps/appstore/src/AppstoreApp.vue","../build/frontend/apps/appstore/src/router/routes.ts","../build/frontend/apps/appstore/src/router/index.ts","../build/frontend/apps/appstore/src/main.ts","../build/frontend/apps/appstore/src/components/LimitToGroupDialog.vue","../build/frontend/apps/appstore/src/components/AppIcon.vue","../build/frontend/apps/appstore/src/components/AppTable/AppTableRow.vue","../build/frontend/apps/appstore/src/components/AppTable/AppTable.vue","../build/frontend/apps/appstore/src/views/AppstoreBundles.vue"],"sourcesContent":["import '../assets/NcAppNavigationSpacer.css';\nimport { defineComponent, openBlock, createElementBlock } from \"vue\";\nimport { _ as _export_sfc } from \"./_plugin-vue_export-helper.mjs\";\nconst _hoisted_1 = { class: \"app-navigation-spacer\" };\nconst _sfc_main = /* @__PURE__ */ defineComponent({\n __name: \"NcAppNavigationSpacer\",\n setup(__props) {\n return (_ctx, _cache) => {\n return openBlock(), createElementBlock(\"li\", _hoisted_1);\n };\n }\n});\nconst NcAppNavigationSpacer = /* @__PURE__ */ _export_sfc(_sfc_main, [[\"__scopeId\", \"data-v-277fa710\"]]);\nexport {\n NcAppNavigationSpacer as N\n};\n//# sourceMappingURL=NcAppNavigationSpacer.mjs.map\n","/*!\n * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { OCSResponse } from '@nextcloud/typings/ocs'\n\nimport axios from '@nextcloud/axios'\nimport { emit } from '@nextcloud/event-bus'\nimport { generateOcsUrl } from '@nextcloud/router'\n\n/**\n * Rebuilds the app navigation menu\n */\nexport async function rebuildNavigation() {\n\tconst { data } = await axios.get<OCSResponse>(generateOcsUrl('core/navigation/apps?format=json'))\n\tif (data.ocs.meta.statuscode !== 200) {\n\t\treturn\n\t}\n\n\temit('nextcloud:app-menu.refresh', { apps: data.ocs.data })\n\twindow.dispatchEvent(new Event('resize'))\n}\n","/**\n * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { getLoggerBuilder } from '@nextcloud/logger'\n\nexport default getLoggerBuilder()\n\t.setApp('appstore')\n\t.detectUser()\n\t.build()\n","<!--\n - SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IDeployDaemon } from '../../apps.d.ts'\n\nimport { t } from '@nextcloud/l10n'\nimport { computed } from 'vue'\nimport NcListItem from '@nextcloud/vue/components/NcListItem'\n\nconst props = defineProps<{\n\t/**\n\t * The daemon to use\n\t */\n\tdaemon: IDeployDaemon\n\t/**\n\t * Whether this daemon is the default one\n\t */\n\tisDefault: boolean\n}>()\n\nconst emit = defineEmits<{\n\tselected: []\n}>()\n\nconst itemTitle = computed(() => `${props.daemon.name} - ${props.daemon.display_name}`)\n</script>\n\n<template>\n\t<NcListItem\n\t\t:active=\"isDefault\"\n\t\t:counterNumber=\"daemon.exAppsCount\"\n\t\tcounterType=\"highlighted\"\n\t\t:details=\"isDefault ? t('appstore', 'Default') : ''\"\n\t\tforceDisplayActions\n\t\t:name=\"itemTitle\"\n\t\t@click.stop=\"emit('selected')\">\n\t\t<template #subname>\n\t\t\t{{ daemon.accepts_deploy_id }}\n\t\t</template>\n\t</NcListItem>\n</template>\n","<!--\n - SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IDeployDaemon } from '../../apps.d.ts'\n\nimport { t } from '@nextcloud/l10n'\nimport DaemonSelectionDialogListEntry from './DaemonSelectionDialogListEntry.vue'\nimport { useExAppsStore } from '../../store/exApps.ts'\n\ndefineEmits<{\n\tselected: [daemon: IDeployDaemon]\n}>()\n\nconst store = useExAppsStore()\n</script>\n\n<template>\n\t<ul\n\t\t:class=\"$style.DaemonSelectionDialogList\"\n\t\t:aria-label=\"t('appstore', 'Registered Deploy daemons list')\">\n\t\t<DaemonSelectionDialogListEntry\n\t\t\tv-for=\"daemon in store.dockerDaemons\"\n\t\t\t:key=\"daemon.id\"\n\t\t\t:daemon\n\t\t\t:isDefault=\"store.defaultDaemon?.name === daemon.name\"\n\t\t\t@selected=\"$emit('selected', daemon)\" />\n\t</ul>\n</template>\n\n<style module>\n.DaemonSelectionDialogList {\n\tmax-height: 350px;\n\toverflow-y: scroll;\n\tpadding: 2rem;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IAppstoreExApp, IDeployDaemon } from '../../apps.d.ts'\n\nimport { mdiFormatListBulleted } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcDialog from '@nextcloud/vue/components/NcDialog'\nimport NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\nimport DaemonSelectionDialogList from './DaemonSelectionDialogList.vue'\nimport { useExAppsStore } from '../../store/exApps.ts'\n\ndefineProps<{\n\t/**\n\t * The app to enable\n\t */\n\tapp: IAppstoreExApp\n}>()\n\ndefineEmits<{\n\tclose: [daemon?: IDeployDaemon]\n}>()\n\nconst store = useExAppsStore()\nconst appApiAdminPage = generateUrl('/settings/admin/app_api')\n</script>\n\n<template>\n\t<NcDialog\n\t\t:name=\"t('appstore', 'Choose Deploy Daemon for {appName}', { appName: app.name })\"\n\t\tsize=\"normal\"\n\t\t@update:open=\"$event || $emit('close')\">\n\t\t<NcEmptyContent\n\t\t\tv-if=\"store.dockerDaemons.length === 0\"\n\t\t\tclass=\"daemon-selection-list__empty-content\"\n\t\t\t:name=\"t('appstore', 'No Deploy daemons configured')\"\n\t\t\t:description=\"t('appstore', 'Register a custom one or setup from available templates')\">\n\t\t\t<template #icon>\n\t\t\t\t<NcIconSvgWrapper :path=\"mdiFormatListBulleted\" />\n\t\t\t</template>\n\t\t\t<template #action>\n\t\t\t\t<NcButton :href=\"appApiAdminPage\">\n\t\t\t\t\t{{ t('appstore', 'Manage Deploy daemons') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</NcEmptyContent>\n\n\t\t<DaemonSelectionDialogList\n\t\t\tv-else\n\t\t\t:app=\"app\"\n\t\t\t@selected=\"$emit('close', $event)\" />\n\t</NcDialog>\n</template>\n","/*!\n * SPDX-License-Identifier: AGPL-3.0-or-later\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n */\n\nimport type { IAppstoreExApp, IDeployDaemon, IDeployOptions, IExAppStatus } from '../apps.d.ts'\n\nimport axios from '@nextcloud/axios'\nimport { confirmPassword } from '@nextcloud/password-confirmation'\nimport { generateUrl } from '@nextcloud/router'\n\n/**\n * Fetch all external (app_api) apps from the server.\n */\nexport async function fetchApps() {\n\tconst { data } = await axios.get(generateUrl('/apps/app_api/apps/list'))\n\treturn data.apps as IAppstoreExApp[]\n}\n\n/**\n * Get the status of an external app.\n *\n * @param appId - The app to fetch\n */\nexport async function fetchAppStatus(appId: string) {\n\tconst { data } = await axios.get<IExAppStatus>(generateUrl(`/apps/app_api/apps/status/${appId}`))\n\treturn data\n}\n\n/**\n * Enable an external app.\n *\n * @param app - The app to enable\n * @param daemon - The daemon to use for deployment\n * @param deployOptions - Additional options for deployment\n */\nexport async function enableExApp(app: IAppstoreExApp, daemon: IDeployDaemon, deployOptions?: IDeployOptions) {\n\tawait confirmPassword()\n\tawait axios.post(generateUrl(`/apps/app_api/apps/enable/${app.id}/${daemon.name}`), { deployOptions })\n}\n\n/**\n * Force enable an external app\n *\n * @param appId - The app to force-enable\n */\nexport async function forceEnableExApp(appId: string) {\n\tawait confirmPassword()\n\tawait axios.post(generateUrl('/apps/app_api/apps/force'), { appId })\n}\n\n/**\n * Disable an external app.\n *\n * @param appId - The app to disable\n */\nexport async function disableExApp(appId: string) {\n\tawait confirmPassword()\n\tawait axios.get(generateUrl(`apps/app_api/apps/disable/${appId}`))\n}\n\n/**\n * Remove an external app.\n *\n * @param appId - The app to uninstall\n * @param removeData - If all data should be removed\n */\nexport async function uninstallExApp(appId: string, removeData = false) {\n\tawait confirmPassword()\n\tawait axios.get(generateUrl(`/apps/app_api/apps/uninstall/${appId}?removeData=${removeData}`))\n}\n","/**\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppstoreExApp, IDeployDaemon, IExAppStatus } from '../apps.d.ts'\n\nimport axios from '@nextcloud/axios'\nimport { showError } from '@nextcloud/dialogs'\nimport { loadState } from '@nextcloud/initial-state'\nimport { t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { spawnDialog } from '@nextcloud/vue'\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport DaemonSelectionDialog from '../components/DaemonSelectionDialog/DaemonSelectionDialog.vue'\nimport * as exAppApi from '../service/exAppApi.ts'\nimport logger from '../utils/logger.ts'\n\nexport const useExAppsStore = defineStore('external-apps', () => {\n\t/**\n\t * Is the App API enabled\n\t */\n\tconst isEnabled = loadState('appstore', 'appApiEnabled', false)\n\n\t/**\n\t * All external apps available\n\t */\n\tconst apps = ref<IAppstoreExApp[]>([])\n\n\t/**\n\t * Number of external apps with available updates, used to show the update badge in the UI\n\t */\n\tconst updateCount = ref(loadState('appstore', 'appstoreExAppUpdateCount', 0))\n\n\t/**\n\t * The interval ID for the status updater\n\t */\n\tlet statusUpdater: number | null = null\n\n\t/**\n\t * Whether at least one of the configured daemons is accessible.\n\t */\n\tconst daemonAccessible = ref(loadState('appstore', 'defaultDaemonConfigAccessible', false))\n\n\t/**\n\t * The default daemon, used for apps that don't specify a daemon or have a daemon that is not accessible.\n\t */\n\tconst defaultDaemon = ref(loadState<IDeployDaemon | null>('appstore', 'defaultDaemonConfig', null))\n\n\t/**\n\t * The list of daemons that support docker-based deployment, used to show the daemon selection when enabling an app.\n\t */\n\tconst dockerDaemons = ref<IDeployDaemon[]>([])\n\n\tconst initializingOrDeployingApps = computed(() => apps.value\n\t\t.filter((app) => app?.status?.action\n\t\t\t&& app.status.type !== ''\n\t\t\t&& (app?.status?.action === 'deploy' || app.status.action === 'init' || app.status.action === 'healthcheck')))\n\n\t/**\n\t * Get an external app by its ID\n\t *\n\t * @param appId - The app ID\n\t */\n\tfunction getById(appId: string): IAppstoreExApp | null {\n\t\treturn apps.value.find(({ id }) => id === appId) ?? null\n\t}\n\n\t/**\n\t * Enable an exApp.\n\t *\n\t * @param appId - The app ID\n\t */\n\tasync function enableApp(appId: string) {\n\t\tconst app = getById(appId)\n\t\tif (!app) {\n\t\t\tthrow new Error(`App with id ${appId} not found`)\n\t\t}\n\n\t\tapp.loading = true\n\t\ttry {\n\t\t\tif (dockerDaemons.value.length === 1 && app.needsDownload) {\n\t\t\t\texAppApi.enableExApp(app, dockerDaemons[0])\n\t\t\t\tapp.daemon = dockerDaemons[0]\n\t\t\t} else if (app.needsDownload) {\n\t\t\t\tconst daemon = await spawnDialog(DaemonSelectionDialog, { app })\n\t\t\t\tif (!daemon) {\n\t\t\t\t\tthrow new Error('No daemon selected')\n\t\t\t\t}\n\t\t\t\tawait exAppApi.enableExApp(app, daemon)\n\t\t\t\tapp.daemon = daemon\n\t\t\t} else {\n\t\t\t\tawait exAppApi.enableExApp(app, app.daemon!)\n\t\t\t}\n\n\t\t\tif (!app.installed) {\n\t\t\t\tapp.needsDownload = false\n\t\t\t\tapp.status = {\n\t\t\t\t\ttype: 'install',\n\t\t\t\t\taction: 'deploy',\n\t\t\t\t\tinit: 0,\n\t\t\t\t\tdeploy: 0,\n\t\t\t\t} as IExAppStatus\n\t\t\t}\n\t\t\tapp.removable = true\n\t\t\tdelete app.error\n\n\t\t\tawait fetchAppStatus(appId)\n\t\t} finally {\n\t\t\tapp.loading = false\n\t\t}\n\t}\n\n\t/**\n\t * Force enable an exApp by ignoring its dependencies.\n\t *\n\t * @param appId - The app to force-enable\n\t */\n\tasync function forceEnableApp(appId: string) {\n\t\tconst app = getById(appId)\n\t\tif (!app) {\n\t\t\tthrow new Error(`App with id ${appId} not found`)\n\t\t}\n\n\t\tapp.loading = true\n\t\ttry {\n\t\t\tawait exAppApi.forceEnableExApp(appId)\n\t\t\tawait initialize(true)\n\t\t\tapp.active = false\n\t\t} finally {\n\t\t\tapp.loading = false\n\t\t}\n\t}\n\n\t/**\n\t * @param appId - The app to disable\n\t */\n\tasync function disableApp(appId: string) {\n\t\tconst app = getById(appId)\n\t\tif (!app) {\n\t\t\tthrow new Error(`App with id ${appId} not found`)\n\t\t}\n\n\t\tapp.loading = true\n\t\ttry {\n\t\t\tawait exAppApi.disableExApp(appId)\n\t\t\tapp.active = false\n\t\t} finally {\n\t\t\tapp.loading = false\n\t\t}\n\t}\n\n\t/**\n\t * Uninstall an app by its id\n\t *\n\t * @param appId - The app to uninstall\n\t */\n\tasync function uninstallApp(appId: string) {\n\t\tconst app = getById(appId)\n\t\tif (!app) {\n\t\t\tthrow new Error(`App with id ${appId} not found`)\n\t\t}\n\n\t\tapp.loading = true\n\t\ttry {\n\t\t\tawait exAppApi.disableExApp(appId)\n\t\t\tapp.active = false\n\t\t\tapp.needsDownload = true\n\t\t\tapp.installed = false\n\t\t\tapp.daemon = null\n\t\t\tapp.status = {}\n\t\t\tif (app.update !== null) {\n\t\t\t\tupdateCount.value--\n\t\t\t}\n\t\t\tdelete app.update\n\t\t\tdelete app.error\n\t\t} finally {\n\t\t\tapp.loading = false\n\t\t}\n\t}\n\n\t/**\n\t * Update an external app\n\t *\n\t * @param appId - The app ID\n\t */\n\tasync function updateApp(appId: string) {\n\t\tconst app = getById(appId)\n\t\tif (!app) {\n\t\t\tthrow new Error(`App with id ${appId} not found`)\n\t\t}\n\n\t\tapp.loading = true\n\t\ttry {\n\t\t\tawait axios.get(generateUrl(`/apps/app_api/apps/update/${appId}`))\n\t\t\tapp.version = app.update || app.version\n\t\t\tapp.status = {\n\t\t\t\ttype: 'update',\n\t\t\t\taction: 'deploy',\n\t\t\t\tinit: 0,\n\t\t\t\tdeploy: 0,\n\t\t\t} satisfies IExAppStatus\n\t\t\tdelete app.update\n\t\t\tdelete app.error\n\t\t\tupdateCount.value--\n\n\t\t\tawait fetchAppStatus(appId)\n\t\t} catch (error) {\n\t\t\tlogger.error('Failed to update ex app', { appId, error })\n\t\t\tshowError(t('appstore', 'Could not update the app. Please try again later.'))\n\t\t} finally {\n\t\t\tapp.loading = false\n\t\t}\n\t}\n\n\t/**\n\t * Initialize the store.\n\t * This only needs to be called when an app management operation is performed.\n\t *\n\t * @param force - If the initialization should be forced (to run again)\n\t */\n\tasync function initialize(force = false) {\n\t\tif (force || (!defaultDaemon.value || !dockerDaemons.value.length)) {\n\t\t\tawait fetchDockerDaemons()\n\t\t}\n\t\tif (force || apps.value.length === 0) {\n\t\t\tawait fetchAllApps()\n\t\t}\n\t}\n\n\treturn {\n\t\tisEnabled,\n\n\t\tapps,\n\t\tupdateCount,\n\t\tdefaultDaemon,\n\t\tdockerDaemons,\n\t\tdaemonAccessible,\n\n\t\tgetById,\n\t\tdisableApp,\n\t\tenableApp,\n\t\tforceEnableApp,\n\t\tupdateApp,\n\t\tuninstallApp,\n\t\tinitialize,\n\t}\n\n\t/**\n\t * Fetch the configured docker daemons from the backend.\n\t */\n\tasync function fetchDockerDaemons() {\n\t\ttry {\n\t\t\tconst { data } = await axios.get(generateUrl('/apps/app_api/daemons'))\n\t\t\tdefaultDaemon.value = data.daemons.find((daemon: IDeployDaemon) => daemon.name === data.default_daemon_config)\n\t\t\tdockerDaemons.value = data.daemons.filter((daemon: IDeployDaemon) => daemon.accepts_deploy_id === 'docker-install')\n\t\t} catch (error) {\n\t\t\tlogger.error('[app-api-store] Failed to fetch Docker daemons', { error })\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t}\n\n\t/**\n\t * Fetch the list of external apps from the backend.\n\t */\n\tasync function fetchAllApps() {\n\t\ttry {\n\t\t\tapps.value = await exAppApi.fetchApps()\n\t\t} catch (error) {\n\t\t\tlogger.error('An error occurred while fetching apps', { error })\n\t\t\tshowError(t('appstore', 'An error occurred during the request. Unable to proceed.'))\n\t\t}\n\t}\n\n\t/**\n\t * Get the status of an external app.\n\t *\n\t * @param appId - The app ID to fetch the status for\n\t */\n\tasync function fetchAppStatus(appId: string) {\n\t\tconst app = getById(appId)\n\t\tif (!app) {\n\t\t\tlogger.error('[app-api-store] app not found while fetching status', { appId })\n\t\t\treturn\n\t\t}\n\n\t\tapp.loading = true\n\t\ttry {\n\t\t\tconst status = await exAppApi.fetchAppStatus(appId)\n\t\t\tapp.status = status\n\t\t\tlogger.debug('[app-api-store] initializingOrDeployingApps after setAppStatus', { initializingOrDeployingApps })\n\t\t\tif (initializingOrDeployingApps.value.length === 0) {\n\t\t\t\tlogger.debug('[app-api-store] Clearing interval')\n\t\t\t\tclearInterval(statusUpdater as number)\n\t\t\t\tstatusUpdater = null\n\t\t\t}\n\t\t\tif (app.status.error && initializingOrDeployingApps.value.length === 1) {\n\t\t\t\tclearInterval(statusUpdater as number)\n\t\t\t\tstatusUpdater = null\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tupdateAppsStatus()\n\t\t\tthrow e\n\t\t} finally {\n\t\t\tapp.loading = false\n\t\t}\n\t}\n\n\t/**\n\t * Update the status of all apps that are currently initializing or deploying\n\t */\n\tfunction updateAppsStatus() {\n\t\tclearInterval(statusUpdater as number)\n\t\tif (initializingOrDeployingApps.value.length === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tstatusUpdater = window.setInterval(() => {\n\t\t\tlogger.debug('[app-api-store] initializingOrDeployingApps', { initializingOrDeployingApps })\n\t\t\tfor (const app of initializingOrDeployingApps.value) {\n\t\t\t\tfetchAppStatus(app.id)\n\t\t\t}\n\t\t}, 2000)\n\t}\n})\n","/*!\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppBundle, IAppstoreApp, IAppstoreCategory, IAppstoreExApp } from '../apps.d.ts'\n\nimport { showError } from '@nextcloud/dialogs'\nimport { loadState } from '@nextcloud/initial-state'\nimport { t } from '@nextcloud/l10n'\nimport { defineStore } from 'pinia'\nimport { computed, readonly, ref } from 'vue'\nimport * as api from '../service/api.ts'\nimport { rebuildNavigation } from '../service/rebuild-navigation.ts'\nimport { canDisable, canInstall, canLimitToGroups, canUninstall, needForceEnable } from '../utils/appStatus.ts'\nimport logger from '../utils/logger.ts'\nimport { useExAppsStore } from './exApps.ts'\n\nexport const useAppsStore = defineStore('apps', () => {\n\tconst exApps = useExAppsStore()\n\n\t/**\n\t * All apps available in the appstore\n\t */\n\tconst appstoreApps = ref<IAppstoreApp[]>([])\n\t/**\n\t * All app categories available in the appstore\n\t */\n\tconst categories = ref<IAppstoreCategory[]>([])\n\t/**\n\t * All app bundles available in the appstore\n\t */\n\tconst bundles = readonly(loadState<IAppBundle[]>('appstore', 'appstoreBundles'))\n\n\t/**\n\t * Loading state of the store\n\t */\n\tconst isLoadingApps = ref(false)\n\tconst isLoadingCategories = ref(false)\n\n\t/**\n\t * All apps available\n\t */\n\tconst apps = computed(() => [...appstoreApps.value, ...(exApps.isEnabled ? exApps.apps : [])])\n\n\t/**\n\t * Get a category by its id\n\t *\n\t * @param categoryId - The id of the category\n\t */\n\tfunction getCategoryById(categoryId: string) {\n\t\treturn categories.value.find(({ id }) => id === categoryId) ?? null\n\t}\n\n\t/**\n\t * Get an app by its id\n\t *\n\t * @param appId - The id of the app\n\t */\n\tfunction getAppById(appId: string): IAppstoreApp | IAppstoreExApp | null {\n\t\treturn apps.value.find(({ id }) => id === appId) ?? null\n\t}\n\n\t/**\n\t * Get all apps of a category\n\t *\n\t * @param categoryId - The id of the category\n\t */\n\tfunction getAppsByCategory(categoryId: string): (IAppstoreApp | IAppstoreExApp)[] {\n\t\treturn apps.value.filter((app) => [app.category].flat().includes(categoryId))\n\t}\n\n\t/**\n\t * Enable an app by its id\n\t *\n\t * @param appId - The app to enable\n\t * @param force - Whether to force enable the app\n\t */\n\tasync function enableApp(appId: string, force = false) {\n\t\tconst app = getAppById(appId)\n\t\tif (!app) {\n\t\t\tthrow new Error(`App with id ${appId} not found`)\n\t\t}\n\n\t\tif (app.active || (!app.installed && !canInstall(app))) {\n\t\t\tthrow new Error(`App with id ${appId} cannot be enabled`)\n\t\t}\n\n\t\tif (!force && needForceEnable(app)) {\n\t\t\tthrow new Error(`App with id ${appId} requires force enable`)\n\t\t}\n\n\t\tapp.loading = true\n\t\ttry {\n\t\t\tif (app.app_api) {\n\t\t\t\tawait exApps.enableApp(appId)\n\t\t\t} else {\n\t\t\t\tawait api.enableApp(appId, force)\n\t\t\t}\n\t\t\tif (force) {\n\t\t\t\tapp.isCompatible = true\n\t\t\t}\n\t\t\tapp.active = true\n\t\t\tapp.installed = true\n\t\t\tapp.removable = true\n\t\t\tawait rebuildNavigation()\n\t\t} finally {\n\t\t\tapp.loading = false\n\t\t}\n\t}\n\n\t/**\n\t * Disable an app by its id\n\t *\n\t * @param appId - The app to disable\n\t */\n\tasync function disableApp(appId: string) {\n\t\tconst app = getAppById(appId)\n\t\tif (!app) {\n\t\t\tthrow new Error(`App with id ${appId} not found`)\n\t\t}\n\n\t\tif (!canDisable(app)) {\n\t\t\tthrow new Error(`App with id ${appId} cannot be disabled`)\n\t\t}\n\n\t\tapp.loading = true\n\t\ttry {\n\t\t\tif (app.app_api) {\n\t\t\t\tawait exApps.disableApp(appId)\n\t\t\t} else {\n\t\t\t\tawait api.disableApp(appId)\n\t\t\t}\n\t\t\tapp.active = false\n\t\t\t// revert \"force enable\"\n\t\t\tapp.isCompatible = app.missingDependencies === undefined || app.missingDependencies.length === 0\n\t\t\tawait rebuildNavigation()\n\t\t} finally {\n\t\t\tapp.loading = false\n\t\t}\n\t}\n\n\t/**\n\t * Uninstall an app by its id\n\t *\n\t * @param appId - The app to uninstall\n\t */\n\tasync function uninstallApp(appId: string) {\n\t\tconst app = getAppById(appId)\n\t\tif (!app) {\n\t\t\tthrow new Error(`App with id ${appId} not found`)\n\t\t}\n\n\t\tif (!canUninstall(app)) {\n\t\t\tthrow new Error(`App with id ${appId} cannot be uninstalled`)\n\t\t}\n\n\t\tapp.loading = true\n\t\ttry {\n\t\t\tif (app.app_api) {\n\t\t\t\tawait exApps.uninstallApp(appId)\n\t\t\t} else {\n\t\t\t\tawait api.uninstallApp(appId)\n\t\t\t}\n\t\t\tapp.active = false\n\t\t\tapp.installed = false\n\t\t\tawait rebuildNavigation()\n\t\t} finally {\n\t\t\tapp.loading = false\n\t\t}\n\t}\n\n\t/**\n\t * Limit access to an app to specific groups\n\t *\n\t * @param appId - The app to limit access to\n\t * @param groups - The groups which should have access\n\t */\n\tasync function limitAppToGroups(appId: string, groups: string[]) {\n\t\tconst app = getAppById(appId)\n\t\tif (!app) {\n\t\t\tthrow new Error(`App with id ${appId} not found`)\n\t\t}\n\n\t\tif (!canLimitToGroups(app)) {\n\t\t\tthrow new Error(`App with id ${appId} cannot be limited to groups`)\n\t\t}\n\n\t\tif (app.app_api) {\n\t\t\treturn\n\t\t}\n\n\t\ttry {\n\t\t\tapp.loading = true\n\t\t\tawait api.enableApp(appId, false, groups)\n\t\t\tapp.groups = groups\n\t\t} finally {\n\t\t\tapp.loading = false\n\t\t}\n\t}\n\n\t/**\n\t * Enable a whole bundle of apps by its id\n\t *\n\t * @param bundleId - The id of the bundle to enable\n\t */\n\tasync function enableBundle(bundleId: string) {\n\t\tconst bundle = bundles.find((b) => b.id === bundleId)\n\t\tif (!bundle) {\n\t\t\tthrow new Error(`Bundle with id ${bundleId} not found`)\n\t\t}\n\n\t\ttry {\n\t\t\tfor (const appId of bundle.appIdentifiers) {\n\t\t\t\tconst app = getAppById(appId)!\n\t\t\t\tapp.loading = true\n\t\t\t}\n\t\t\tawait api.enableBundle(bundle.id)\n\t\t\tfor (const appId of bundle.appIdentifiers) {\n\t\t\t\tconst app = getAppById(appId)!\n\t\t\t\tapp.active = true\n\t\t\t\tapp.installed = true\n\t\t\t\tapp.removable = true\n\t\t\t\tawait rebuildNavigation()\n\t\t\t}\n\t\t} finally {\n\t\t\tfor (const appId of bundle.appIdentifiers) {\n\t\t\t\tconst app = getAppById(appId)!\n\t\t\t\tapp.loading = false\n\t\t\t}\n\t\t}\n\t}\n\n\t// initialize store\n\tinitialize()\n\n\treturn {\n\t\tapps,\n\t\tbundles,\n\t\tcategories,\n\t\tisLoadingApps,\n\t\tisLoadingCategories,\n\n\t\tdisableApp,\n\t\tenableApp,\n\t\tuninstallApp,\n\t\tenableBundle,\n\n\t\tgetAppById,\n\t\tgetAppsByCategory,\n\t\tgetCategoryById,\n\t\tlimitAppToGroups,\n\t}\n\n\t/**\n\t * Initialize the store\n\t */\n\tasync function initialize() {\n\t\tawait Promise.allSettled([\n\t\t\tloadApps(),\n\t\t\tloadCategories(),\n\t\t\texApps.isEnabled ? exApps.initialize() : Promise.resolve(),\n\t\t])\n\t}\n\n\t/**\n\t * Load the app categories from the backend\n\t */\n\tasync function loadCategories() {\n\t\ttry {\n\t\t\tisLoadingCategories.value = true\n\t\t\tcategories.value = await api.getCategories()\n\t\t} catch (error) {\n\t\t\tlogger.error('Failed to load app categories', { error })\n\t\t\tshowError(t('appstore', 'Could not load app categories. Please try again later.'))\n\t\t} finally {\n\t\t\tisLoadingCategories.value = false\n\t\t}\n\t}\n\n\t/**\n\t * Load the apps from the backend\n\t */\n\tasync function loadApps() {\n\t\ttry {\n\t\t\tisLoadingApps.value = true\n\t\t\tappstoreApps.value = await api.getApps()\n\t\t} catch (error) {\n\t\t\tlogger.error('Failed to load apps list', { error })\n\t\t\tshowError(t('appstore', 'Could not load apps list. Please try again later.'))\n\t\t} finally {\n\t\t\tisLoadingApps.value = false\n\t\t}\n\t}\n})\n","/*!\n * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\n\nimport { showError } from '@nextcloud/dialogs'\nimport { loadState } from '@nextcloud/initial-state'\nimport { t } from '@nextcloud/l10n'\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport * as api from '../service/api.ts'\nimport { rebuildNavigation } from '../service/rebuild-navigation.ts'\nimport logger from '../utils/logger.ts'\nimport { useAppsStore } from './apps.ts'\nimport { useExAppsStore } from './exApps.ts'\n\nexport const useUpdatesStore = defineStore('updates', () => {\n\tconst exApps = useExAppsStore()\n\n\t/**\n\t * Number of apps with available updates\n\t */\n\tconst internalUpdateCount = ref(loadState<number>('appstore', 'appstoreUpdateCount', 0))\n\n\t/**\n\t * Total number of apps with available updates\n\t */\n\tconst updateCount = computed(() => internalUpdateCount.value + exApps.updateCount)\n\n\t/**\n\t * Update multiple apps by their app ids at the same time\n\t *\n\t * @param appIds - Ids of apps to update\n\t */\n\tasync function updateApps(appIds: string[]) {\n\t\tconst store = useAppsStore()\n\n\t\tconst apps = appIds.map((appId) => store.getAppById(appId))\n\t\tif (apps.some((app) => !app)) {\n\t\t\tthrow new Error('One or more apps not found')\n\t\t}\n\n\t\tconst exAppsToUpdate = (apps as (IAppstoreApp | IAppstoreExApp)[]).filter((app): app is IAppstoreExApp => 'app_api' in app && app.app_api)\n\t\tfor (const app of exAppsToUpdate) {\n\t\t\ttry {\n\t\t\t\tawait exApps.updateApp(app.id)\n\t\t\t\tapp.update = undefined\n\t\t\t\trebuildNavigation()\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error('Failed to update ex app', { appId: app.id, error })\n\t\t\t\tshowError(t('appstore', 'Could not update an exApp. Please try again later.'))\n\t\t\t}\n\t\t}\n\n\t\tconst appsToUpdate = (apps as (IAppstoreApp | IAppstoreExApp)[]).filter((app): app is IAppstoreApp => !('app_api' in app && app.app_api))\n\t\tif (appsToUpdate.length > 0) {\n\t\t\ttry {\n\t\t\t\tconst results = await Promise.allSettled(await api.updateApps(appsToUpdate.map((app) => app.id)))\n\t\t\t\tfor (const [index, app] of appsToUpdate.entries()) {\n\t\t\t\t\tconst result = results[index]\n\t\t\t\t\tif (result?.status === 'rejected') {\n\t\t\t\t\t\tlogger.error('Failed to update app', { appId: app.id, error: result.reason })\n\t\t\t\t\t\tshowError(t('appstore', 'Could not update {app}. Please try again later.', { app: app.name }))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tapp.update = undefined\n\t\t\t\t\t\tinternalUpdateCount.value = Math.max(internalUpdateCount.value - 1, 0)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trebuildNavigation()\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error('Failed to update one or more apps', { appsToUpdate, error })\n\t\t\t\tshowError(t('appstore', 'Could not update an app. Please try again later.'))\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Update the given app\n\t *\n\t * @param appId - The app id to update\n\t * @throws {Error} if the app is not found\n\t */\n\tasync function updateApp(appId: string) {\n\t\tupdateApps([appId])\n\t}\n\n\treturn {\n\t\tupdateCount,\n\t\tupdateApp,\n\t\tupdateApps,\n\t}\n})\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { LocationQuery } from 'vue-router'\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\n\nexport const useUserSettingsStore = defineStore('userSettings', () => {\n\tconst defaultGridSize = ref('')\n\n\tconst isGridView = ref(false)\n\tconst showIncompatible = ref(true)\n\n\tconst gridSizePx = computed(() => {\n\t\tif (defaultGridSize.value === 'm') {\n\t\t\treturn '468px'\n\t\t} else if (defaultGridSize.value === 'l') {\n\t\t\treturn '512px'\n\t\t}\n\t\treturn '320px'\n\t})\n\n\t/**\n\t * Get the query parameters for the current settings\n\t *\n\t * @param gridMode Optional override for the grid mode, if not provided it will use the current setting\n\t */\n\tfunction getQuery(gridMode?: boolean) {\n\t\tconst route = useRoute() ?? {}\n\t\treturn {\n\t\t\t...route.query,\n\t\t\tgrid: (gridMode ?? isGridView.value) ? (defaultGridSize.value || null) : undefined,\n\t\t\tcompatible: showIncompatible.value ? undefined : null,\n\t\t}\n\t}\n\n\tconst router = useRouter()\n\trouter.afterEach((to) => {\n\t\tupdateFromQuery(to.query)\n\t})\n\n\treturn {\n\t\tdefaultGridSize,\n\t\tgridSizePx,\n\n\t\tisGridView,\n\t\tshowIncompatible,\n\n\t\tgetQuery,\n\t}\n\n\t/**\n\t * Initializes the store with the current query parameters\n\t *\n\t * @param query The query parameters to initialize the store with\n\t */\n\tfunction updateFromQuery(query: LocationQuery) {\n\t\tisGridView.value = 'grid' in query\n\t\tdefaultGridSize.value = [query.grid ?? ''].flat()[0]!.toLowerCase()\n\t\tshowIncompatible.value = !('compatible' in query)\n\t}\n})\n","<!--\n - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport { emit } from '@nextcloud/event-bus'\nimport { loadState } from '@nextcloud/initial-state'\nimport { t } from '@nextcloud/l10n'\nimport { useHotKey } from '@nextcloud/vue'\nimport { watchDebounced } from '@vueuse/core'\nimport { computed, ref, useTemplateRef, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport NcAppNavigation from '@nextcloud/vue/components/NcAppNavigation'\nimport NcAppNavigationItem from '@nextcloud/vue/components/NcAppNavigationItem'\nimport NcAppNavigationSearch from '@nextcloud/vue/components/NcAppNavigationSearch'\nimport NcAppNavigationSpacer from '@nextcloud/vue/components/NcAppNavigationSpacer'\nimport NcCounterBubble from '@nextcloud/vue/components/NcCounterBubble'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\nimport NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'\nimport { APPSTORE_CATEGORY_ICONS, APPSTORE_CATEGORY_NAMES } from '../constants.ts'\nimport { useAppsStore } from '../store/apps.ts'\nimport { useUpdatesStore } from '../store/updates.ts'\nimport { useUserSettingsStore } from '../store/userSettings.ts'\n\nconst appstoreEnabled = loadState<boolean>('settings', 'appstoreEnabled', true)\n\nconst store = useAppsStore()\nconst updateStore = useUpdatesStore()\nconst userSettings = useUserSettingsStore()\nconst categories = computed(() => store.categories)\nconst categoriesLoading = computed(() => store.isLoadingCategories)\n\nconst route = useRoute()\nconst router = useRouter()\n\nconst searchElement = useTemplateRef('search')\n\nuseHotKey('f', () => {\n\tif (!searchElement.value?.$refs.inputElement) {\n\t\temit('toggle-navigation', {\n\t\t\topen: true,\n\t\t})\n\t\t// open animation\n\t\twindow.setTimeout(() => searchElement.value?.$refs.inputElement?.focus(), 400)\n\t}\n\tsearchElement.value?.$refs.inputElement?.focus()\n}, { ctrl: true, stop: true, prevent: true })\n\nconst search = ref('')\n// initialize the search value from the query parameter on mount\nwatch(() => route.query.q, (newQuery) => {\n\tsearch.value = [newQuery || ''].flat()[0]!\n}, { immediate: true })\n// update the query parameter when the search value changes, debounced to avoid excessive updates\nwatchDebounced(search, (newValue, oldValue) => {\n\tif (newValue.trim() === oldValue.trim()) {\n\t\treturn\n\t}\n\n\tif (router.currentRoute.value.name === 'apps-discover' || (router.currentRoute.value.name === 'apps-manage' && route.params.category === 'bundles')) {\n\t\trouter.push({\n\t\t\tname: 'apps-search',\n\t\t\tquery: {\n\t\t\t\t...route.query,\n\t\t\t\tq: newValue.trim() || undefined,\n\t\t\t},\n\t\t})\n\t\treturn\n\t}\n\n\trouter.replace({\n\t\t...route,\n\t\tquery: {\n\t\t\t...route.query,\n\t\t\tq: newValue.trim() || undefined,\n\t\t},\n\t})\n}, { debounce: 500 })\n\n/**\n * Check if the current instance has a support subscription from the Nextcloud GmbH\n *\n * For customers of the Nextcloud GmbH the app level will be set to `300` for apps that are supported in their subscription\n */\nconst isSubscribed = computed(() => store.apps.find(({ level }) => level === 300) !== undefined)\n</script>\n\n<template>\n\t<!-- Categories & filters -->\n\t<NcAppNavigation :aria-label=\"t('appstore', 'Appstore categories')\">\n\t\t<template #search>\n\t\t\t<NcAppNavigationSearch\n\t\t\t\tref=\"search\"\n\t\t\t\tv-model=\"search\"\n\t\t\t\t:label=\"t('appstore', 'Search apps…')\" />\n\t\t</template>\n\t\t<template #list>\n\t\t\t<NcAppNavigationItem\n\t\t\t\tv-if=\"appstoreEnabled\"\n\t\t\t\t:to=\"{ name: 'apps-discover' }\"\n\t\t\t\t:name=\"APPSTORE_CATEGORY_NAMES.discover\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcIconSvgWrapper :path=\"APPSTORE_CATEGORY_ICONS.discover\" />\n\t\t\t\t</template>\n\t\t\t</NcAppNavigationItem>\n\t\t\t<NcAppNavigationItem\n\t\t\t\t:to=\"{ name: 'apps-manage', params: { category: 'installed' } }\"\n\t\t\t\t:name=\"APPSTORE_CATEGORY_NAMES.installed\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcIconSvgWrapper :path=\"APPSTORE_CATEGORY_ICONS.installed\" />\n\t\t\t\t</template>\n\t\t\t</NcAppNavigationItem>\n\t\t\t<NcAppNavigationItem\n\t\t\t\t:to=\"{ name: 'apps-manage', params: { category: 'enabled' } }\"\n\t\t\t\t:name=\"APPSTORE_CATEGORY_NAMES.enabled\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcIconSvgWrapper :path=\"APPSTORE_CATEGORY_ICONS.enabled\" />\n\t\t\t\t</template>\n\t\t\t</NcAppNavigationItem>\n\t\t\t<NcAppNavigationItem\n\t\t\t\t:to=\"{ name: 'apps-manage', params: { category: 'disabled' } }\"\n\t\t\t\t:name=\"APPSTORE_CATEGORY_NAMES.disabled\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcIconSvgWrapper :path=\"APPSTORE_CATEGORY_ICONS.disabled\" />\n\t\t\t\t</template>\n\t\t\t</NcAppNavigationItem>\n\t\t\t<NcAppNavigationItem\n\t\t\t\tv-if=\"updateStore.updateCount > 0\"\n\t\t\t\t:to=\"{ name: 'apps-manage', params: { category: 'updates' } }\"\n\t\t\t\t:name=\"APPSTORE_CATEGORY_NAMES.updates\">\n\t\t\t\t<template #counter>\n\t\t\t\t\t<NcCounterBubble :count=\"updateStore.updateCount\" />\n\t\t\t\t</template>\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcIconSvgWrapper :path=\"APPSTORE_CATEGORY_ICONS.updates\" />\n\t\t\t\t</template>\n\t\t\t</NcAppNavigationItem>\n\t\t\t<NcAppNavigationItem\n\t\t\t\t:to=\"{ name: 'apps-bundles' }\"\n\t\t\t\t:name=\"APPSTORE_CATEGORY_NAMES.bundles\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcIconSvgWrapper :path=\"APPSTORE_CATEGORY_ICONS.bundles\" />\n\t\t\t\t</template>\n\t\t\t</NcAppNavigationItem>\n\n\t\t\t<NcAppNavigationSpacer />\n\n\t\t\t<!-- App store categories -->\n\t\t\t<li v-if=\"appstoreEnabled && categoriesLoading\" :class=\"$style.appstoreNavigation__categories_loading\">\n\t\t\t\t<NcLoadingIcon :size=\"20\" :name=\"t('appstore', 'Loading categories')\" />\n\t\t\t</li>\n\n\t\t\t<template v-else-if=\"appstoreEnabled && !categoriesLoading\">\n\t\t\t\t<NcAppNavigationItem\n\t\t\t\t\tv-if=\"isSubscribed\"\n\t\t\t\t\tid=\"app-category-supported\"\n\t\t\t\t\t:to=\"{ name: 'apps-category', params: { category: 'supported' }, query: userSettings.getQuery(true) }\"\n\t\t\t\t\t:name=\"APPSTORE_CATEGORY_NAMES.supported\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"APPSTORE_CATEGORY_ICONS.supported\" />\n\t\t\t\t\t</template>\n\t\t\t\t</NcAppNavigationItem>\n\t\t\t\t<NcAppNavigationItem\n\t\t\t\t\tid=\"app-category-featured\"\n\t\t\t\t\t:to=\"{ name: 'apps-category', params: { category: 'featured' }, query: userSettings.getQuery(true) }\"\n\t\t\t\t\t:name=\"APPSTORE_CATEGORY_NAMES.featured\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"APPSTORE_CATEGORY_ICONS.featured\" />\n\t\t\t\t\t</template>\n\t\t\t\t</NcAppNavigationItem>\n\n\t\t\t\t<NcAppNavigationItem\n\t\t\t\t\tv-for=\"category in categories\"\n\t\t\t\t\t:id=\"`app-category-${category.id}`\"\n\t\t\t\t\t:key=\"category.id\"\n\t\t\t\t\t:name=\"category.displayName\"\n\t\t\t\t\t:to=\"{\n\t\t\t\t\t\tname: 'apps-category',\n\t\t\t\t\t\tparams: { category: category.id },\n\t\t\t\t\t\tquery: userSettings.getQuery(true),\n\t\t\t\t\t}\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"category.icon\" />\n\t\t\t\t\t</template>\n\t\t\t\t</NcAppNavigationItem>\n\t\t\t</template>\n\t\t</template>\n\t</NcAppNavigation>\n</template>\n\n<style module>\n.appstoreNavigation__categories_loading {\n\tflex: 1;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { AppAction } from '../actions/index.ts'\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\n\nimport { computed } from 'vue'\nimport NcActionButton from '@nextcloud/vue/components/NcActionButton'\nimport NcActionLink from '@nextcloud/vue/components/NcActionLink'\nimport NcActionRouter from '@nextcloud/vue/components/NcActionRouter'\nimport NcActions from '@nextcloud/vue/components/NcActions'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\n\nconst { actions, maxInlineActions = 1 } = defineProps<{\n\tapp: IAppstoreApp | IAppstoreExApp\n\tactions: AppAction[]\n\tmaxInlineActions?: number\n\ticonOnly?: boolean\n}>()\n\nconst inlineActions = computed(() => {\n\tif (actions.length <= maxInlineActions) {\n\t\treturn actions\n\t}\n\treturn actions\n\t\t.filter((action) => action.inline !== false)\n\t\t.slice(0, maxInlineActions)\n})\n\nconst menuActions = computed(() => actions\n\t.filter((action) => !inlineActions.value.includes(action)))\n</script>\n\n<template>\n\t<div :class=\"$style.appActions\">\n\t\t<NcButton\n\t\t\tv-for=\"action in inlineActions\"\n\t\t\t:key=\"action.id\"\n\t\t\t:ariaLabel=\"iconOnly ? action.label(app) : undefined\"\n\t\t\t:title=\"iconOnly ? action.label(app) : undefined\"\n\t\t\t:variant=\"action.variant\"\n\t\t\t:href=\"'href' in action ? action.href(app) : undefined\"\n\t\t\t:to=\"'to' in action ? action.to(app) : undefined\"\n\t\t\t:target=\"'href' in action ? '_blank' : undefined\"\n\t\t\t@click=\"'callback' in action && action.callback(app)\">\n\t\t\t<template #icon>\n\t\t\t\t<NcIconSvgWrapper :path=\"action.icon\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"!iconOnly\" #default>\n\t\t\t\t{{ action.label(app) }}\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcActions forceMenu>\n\t\t\t<template v-for=\"action in menuActions\">\n\t\t\t\t<NcActionButton\n\t\t\t\t\tv-if=\"'callback' in action\"\n\t\t\t\t\t:key=\"'callback-' + action.id\"\n\t\t\t\t\tcloseAfterClick\n\t\t\t\t\t:variant=\"action.variant\"\n\t\t\t\t\t@click=\"action.callback(app)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"action.icon\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ action.label(app) }}\n\t\t\t\t</NcActionButton>\n\t\t\t\t<NcActionLink\n\t\t\t\t\tv-else-if=\"'href' in action\"\n\t\t\t\t\t:key=\"'link-' + action.id\"\n\t\t\t\t\tcloseAfterClick\n\t\t\t\t\t:variant=\"action.variant\"\n\t\t\t\t\t:href=\"action.href(app)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"action.icon\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ action.label(app) }}\n\t\t\t\t</NcActionLink>\n\t\t\t\t<NcActionRouter\n\t\t\t\t\tv-else\n\t\t\t\t\t:key=\"'route-' + action.id\"\n\t\t\t\t\tcloseAfterClick\n\t\t\t\t\t:variant=\"action.variant\"\n\t\t\t\t\t:to=\"action.to(app)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"action.icon\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ action.label(app) }}\n\t\t\t\t</NcActionRouter>\n\t\t\t</template>\n\t\t</NcActions>\n\t</div>\n</template>\n\n<style module>\n.appActions {\n\tdisplay: flex;\n\tflex-direction: row;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IAppstoreExApp } from '../../apps.d.ts'\n\nimport { mdiFileChart } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { ref } from 'vue'\nimport NcAppSidebarTab from '@nextcloud/vue/components/NcAppSidebarTab'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\n\nconst props = defineProps<{\n\tapp: IAppstoreExApp\n}>()\n\nconst gpuSupport = ref(props.app?.daemon?.deploy_config?.computeDevice?.id !== 'cpu' || false)\n</script>\n\n<template>\n\t<NcAppSidebarTab\n\t\tv-if=\"app?.daemon\"\n\t\tid=\"daemon\"\n\t\t:name=\"t('appstore', 'Daemon')\"\n\t\t:order=\"5\">\n\t\t<template #icon>\n\t\t\t<NcIconSvgWrapper :path=\"mdiFileChart\" :size=\"24\" />\n\t\t</template>\n\t\t<div :class=\"$style.appDeployDaemonTab\">\n\t\t\t<h4>{{ t('appstore', 'Deploy Daemon') }}</h4>\n\t\t\t<p><b>{{ t('appstore', 'Type') }}</b>: {{ app?.daemon.accepts_deploy_id }}</p>\n\t\t\t<p><b>{{ t('appstore', 'Name') }}</b>: {{ app?.daemon.name }}</p>\n\t\t\t<p><b>{{ t('appstore', 'Display Name') }}</b>: {{ app?.daemon.display_name }}</p>\n\t\t\t<p><b>{{ t('appstore', 'GPUs support') }}</b>: {{ gpuSupport }}</p>\n\t\t\t<p><b>{{ t('appstore', 'Compute device') }}</b>: {{ app?.daemon?.deploy_config?.computeDevice?.label }}</p>\n\t\t</div>\n\t</NcAppSidebarTab>\n</template>\n\n<style module>\n.appDeployDaemonTab {\n\tpadding: 20px;\n\n\th4 {\n\t\tfont-weight: bold;\n\t\tmargin: 10px auto;\n\t}\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IAppstoreApp, IAppstoreExApp } from '../../apps.d.ts'\n\nimport { mdiTextShort } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport NcAppSidebarTab from '@nextcloud/vue/components/NcAppSidebarTab'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\nimport MarkdownPreview from '../MarkdownPreview.vue'\n\ndefineProps<{\n\tapp: IAppstoreApp | IAppstoreExApp\n}>()\n</script>\n\n<template>\n\t<NcAppSidebarTab\n\t\tid=\"desc\"\n\t\t:name=\"t('appstore', 'Description')\"\n\t\t:order=\"0\">\n\t\t<template #icon>\n\t\t\t<NcIconSvgWrapper :path=\"mdiTextShort\" />\n\t\t</template>\n\t\t<div :class=\"$style.appDescriptionTab\">\n\t\t\t<MarkdownPreview :text=\"app.description\" :minHeadingLevel=\"3\" />\n\t\t</div>\n\t</NcAppSidebarTab>\n</template>\n\n<style module>\n.appDescriptionTab {\n\tpadding: 12px;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IDeployDaemon } from '../apps.d.ts'\n\nimport { mdiFileChart } from '@mdi/js'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\n\ndefineProps<{\n\tdaemon?: IDeployDaemon\n}>()\n</script>\n\n<template>\n\t<span\n\t\tv-if=\"daemon\"\n\t\t:class=\"$style.appDaemonBadge\"\n\t\t:title=\"daemon.name\">\n\t\t<NcIconSvgWrapper :path=\"mdiFileChart\" :size=\"20\" inline />\n\t\t{{ daemon.display_name }}\n\t</span>\n</template>\n\n<style module>\n.appDaemonBadge {\n\tcolor: var(--color-text-maxcontrast);\n\tbackground-color: transparent;\n\tborder: 1px solid var(--color-text-maxcontrast);\n\tborder-radius: var(--border-radius);\n\n\tdisplay: flex;\n\tflex-direction: row;\n\tgap: 6px;\n\tpadding: 3px 6px;\n\twidth: fit-content;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport { mdiStar, mdiStarShootingOutline } from '@mdi/js'\nimport { translate as t } from '@nextcloud/l10n'\nimport { computed } from 'vue'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\n\nconst props = defineProps<{\n\t/**\n\t * The app level\n\t */\n\tlevel?: number\n}>()\n\nconst isSupported = computed(() => props.level === 300)\nconst isFeatured = computed(() => props.level === 200)\nconst badgeIcon = computed(() => isSupported.value\n\t? mdiStarShootingOutline\n\t: mdiStar)\nconst badgeText = computed(() => isSupported.value ? t('appstore', 'Supported') : t('appstore', 'Featured'))\nconst badgeTitle = computed(() => isSupported.value\n\t? t('appstore', 'This app is supported via your current Nextcloud subscription.')\n\t: t('appstore', 'Featured apps are developed by and within the community. They offer central functionality and are ready for production use.'))\n</script>\n\n<template>\n\t<span\n\t\tv-if=\"isSupported || isFeatured\"\n\t\t:class=\"[ $style.appLevelBadge, { [$style.appLevelBadge__supported]: isSupported } ]\"\n\t\t:title=\"badgeTitle\">\n\t\t<NcIconSvgWrapper :path=\"badgeIcon\" :size=\"20\" inline />\n\t\t{{ badgeText }}\n\t</span>\n</template>\n\n<style module>\n.appLevelBadge {\n\tcolor: var(--color-text-maxcontrast);\n\tbackground-color: transparent;\n\tborder: 1px solid var(--color-text-maxcontrast);\n\tborder-radius: var(--border-radius);\n\n\tdisplay: flex;\n\tflex-direction: row;\n\tgap: var(--default-grid-baseline);\n\tpadding: 3px 6px;\n\twidth: fit-content;\n}\n\n.appLevelBadge__supported {\n\tbackground-color: var(--color-success);\n\tborder-color: var(--color-border-success);\n\tcolor: var(--color-success-text);\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\n\nimport { mdiStar, mdiStarHalfFull, mdiStarOutline } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { computed } from 'vue'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\n\nconst { app } = defineProps<{\n\tapp: IAppstoreApp | IAppstoreExApp\n}>()\n\nconst isShown = computed(() => !app.shipped && app.ratingNumOverall && app.ratingNumOverall > 5)\nconst score = computed(() => app.ratingOverall ?? 4)\n\nconst title = computed(() => {\n\tconst appScore = (score.value * 5).toFixed(1)\n\treturn t('appstore', 'Community rating: {score}/5', { score: appScore })\n})\n\nconst fullStars = computed(() => Math.floor(score.value * 5 + 0.25))\nconst emptyStars = computed(() => Math.min(Math.floor((1 - score.value) * 5 + 0.25), 5 - fullStars.value))\nconst hasHalfStar = computed(() => (fullStars.value + emptyStars.value) < 5)\n</script>\n\n<template>\n\t<span\n\t\tv-if=\"isShown\"\n\t\trole=\"img\"\n\t\t:aria-label=\"title\"\n\t\t:title=\"title\"\n\t\t:class=\"$style.badgeAppScore\">\n\t\t<NcIconSvgWrapper\n\t\t\tv-for=\"index in fullStars\"\n\t\t\t:key=\"`full-star-${index}`\"\n\t\t\t:path=\"mdiStar\"\n\t\t\tinline />\n\t\t<NcIconSvgWrapper v-if=\"hasHalfStar\" :path=\"mdiStarHalfFull\" inline />\n\t\t<NcIconSvgWrapper\n\t\t\tv-for=\"index in emptyStars\"\n\t\t\t:key=\"`empty-star-${index}`\"\n\t\t\t:path=\"mdiStarOutline\"\n\t\t\tinline />\n\t</span>\n</template>\n\n<style module>\n.badgeAppScore {\n\tdisplay: inline-flex;\n\tcolor: var(--color-favorite, #a08b00);\n\n\t> * {\n\t\tvertical-align: text-bottom;\n\t}\n}\n</style>\n","/**\n * SPDX-License-Identifier: AGPL-3.0-or-later\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n */\n\nimport type { OCSResponse } from '@nextcloud/typings/ocs'\nimport type { NcSelectUsersModel } from '@nextcloud/vue/components/NcSelectUsers'\n\nimport axios from '@nextcloud/axios'\nimport { generateOcsUrl } from '@nextcloud/router'\nimport PQueue from 'p-queue'\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport logger from '../utils/logger.ts'\n\nconst queue = new PQueue({ concurrency: 3 })\n\nexport const useGroupsStore = defineStore('groups', () => {\n\tconst groups = ref(new Map<string, NcSelectUsersModel>())\n\n\t/**\n\t * Get group details by id\n\t *\n\t * @param groupId - The id of the group to fetch\n\t */\n\tasync function fetchGroupById(groupId: string) {\n\t\treturn await queue.add(() => internalFetchGroupById(groupId))\n\t}\n\n\t/**\n\t * Search the API for groups matching the query\n\t *\n\t * @param query - Query to search\n\t */\n\tasync function searchGroups(query: string) {\n\t\tconst url = generateOcsUrl('/cloud/groups/details')\n\t\ttry {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\tconst { data } = await axios.get<OCSResponse<{ groups: any }>>(url, {\n\t\t\t\tparams: {\n\t\t\t\t\tsearch: query.trim(),\n\t\t\t\t\tlimit: 10,\n\t\t\t\t},\n\t\t\t})\n\t\t\tfor (const group of data.ocs.data.groups) {\n\t\t\t\tif (groups.value.has(group.id)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tgroups.value.set(group.id, {\n\t\t\t\t\tid: group.id,\n\t\t\t\t\tdisplayName: group.displayname,\n\t\t\t\t\tisNoUser: true,\n\t\t\t\t})\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.error('Failed to search groups', { error })\n\t\t}\n\t}\n\n\t/**\n\t * Get a group by its id\n\t *\n\t * @param groupId - The id of the group to retrieve\n\t */\n\tfunction getGroupById(groupId: string) {\n\t\treturn groups.value.get(groupId)\n\t}\n\n\treturn {\n\t\tgroups: computed(() => Array.from(groups.value.values())),\n\t\tsearchGroups,\n\t\tgetGroupById,\n\t\tfetchGroupById,\n\t}\n\n\t/**\n\t * Handle fetching group details by id\n\t *\n\t * @param groupId - The id of the group to fetch\n\t */\n\tasync function internalFetchGroupById(groupId: string) {\n\t\tif (!groups.value.has(groupId)) {\n\t\t\tawait searchGroups(groupId)\n\t\t}\n\t\treturn groups.value.get(groupId)\n\t}\n})\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { MaybeRefOrGetter } from 'vue'\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\n\nimport { readonly, ref, toValue, watch } from 'vue'\nimport { useGroupsStore } from '../store/groups.ts'\n\n/**\n * Get the groups an app is limited to and keep it up to date\n *\n * @param app - The app to get the groups\n */\nexport function useLimitedGroups(app: MaybeRefOrGetter<IAppstoreApp | IAppstoreExApp>) {\n\tconst groupsStore = useGroupsStore()\n\tconst groupsAppIsLimitedTo = ref<{ id: string, displayName: string }[]>([])\n\twatch(() => toValue(app).groups, async () => {\n\t\tconst groups = toValue(app).groups\n\t\tif (groups === undefined) {\n\t\t\tgroupsAppIsLimitedTo.value = []\n\t\t\treturn\n\t\t}\n\n\t\tconst promises = groups.map((group) => groupsStore.fetchGroupById(group))\n\t\tconst results = await Promise.all(promises)\n\t\tgroupsAppIsLimitedTo.value = results.filter(Boolean) as { id: string, displayName: string }[]\n\t}, { immediate: true })\n\n\treturn readonly(groupsAppIsLimitedTo)\n}\n","<!--\n - SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IAppstoreApp, IAppstoreExApp } from '../../apps.d.ts'\n\nimport { mdiTextBoxOutline } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { computed, useId } from 'vue'\nimport NcAppSidebarTab from '@nextcloud/vue/components/NcAppSidebarTab'\nimport NcDateTime from '@nextcloud/vue/components/NcDateTime'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\nimport NcNoteCard from '@nextcloud/vue/components/NcNoteCard'\nimport BadgeAppDaemon from '../BadgeAppDaemon.vue'\nimport BadgeAppLevel from '../BadgeAppLevel.vue'\nimport BadgeAppScore from '../BadgeAppScore.vue'\nimport { useLimitedGroups } from '../../composables/useLimitedGroups.ts'\nimport { useAppsStore } from '../../store/apps.ts'\nimport { canLimitToGroups } from '../../utils/appStatus.ts'\n\nconst { app } = defineProps<{ app: IAppstoreApp | IAppstoreExApp }>()\n\nconst store = useAppsStore()\n\nconst idLimitedToGroups = useId()\n\nconst lastModified = computed(() => app.releases\n\t?.map((release) => release.lastModified)\n\t.map((date) => Date.parse(date))\n\t.sort()\n\t.at(-1))\n\n/**\n * App authors as comma separated string\n */\nconst appAuthors = computed(() => {\n\tif (!app) {\n\t\treturn ''\n\t}\n\n\treturn [app.author].flat().map(authorName)\n\t\t.sort((a, b) => a.split(' ').at(-1)!.localeCompare(b.split(' ').at(-1)!))\n\t\t.join(', ')\n})\n\nconst appstoreUrl = computed(() => `https://apps.nextcloud.com/apps/${app.id}`)\nconst groupsAppIsLimitedTo = useLimitedGroups(() => app)\n\n/**\n * Further external resources (e.g. website)\n */\nconst externalResources = computed(() => {\n\tconst resources: { id: string, href: string, label: string }[] = []\n\tif (!app.internal) {\n\t\tresources.push({\n\t\t\tid: 'appstore',\n\t\t\thref: appstoreUrl.value,\n\t\t\tlabel: t('appstore', 'View in store'),\n\t\t})\n\t}\n\tif (app.website) {\n\t\tresources.push({\n\t\t\tid: 'website',\n\t\t\thref: app.website,\n\t\t\tlabel: t('appstore', 'Visit website'),\n\t\t})\n\t}\n\tif (app.documentation) {\n\t\tif (app.documentation.user) {\n\t\t\tresources.push({\n\t\t\t\tid: 'doc-user',\n\t\t\t\thref: app.documentation.user,\n\t\t\t\tlabel: t('appstore', 'Usage documentation'),\n\t\t\t})\n\t\t}\n\t\tif (app.documentation.admin) {\n\t\t\tresources.push({\n\t\t\t\tid: 'doc-admin',\n\t\t\t\thref: app.documentation.admin,\n\t\t\t\tlabel: t('appstore', 'Admin documentation'),\n\t\t\t})\n\t\t}\n\t\tif (app.documentation.developer) {\n\t\t\tresources.push({\n\t\t\t\tid: 'doc-developer',\n\t\t\t\thref: app.documentation.developer,\n\t\t\t\tlabel: t('appstore', 'Developer documentation'),\n\t\t\t})\n\t\t}\n\t}\n\treturn resources\n})\n\nconst appCategories = computed(() => {\n\treturn [app.category].flat()\n\t\t.map((id) => store.getCategoryById(id)?.displayName ?? id)\n\t\t.join(', ')\n})\n\nconst cannotLimitToGroups = computed(() => {\n\treturn app.active && !canLimitToGroups(app)\n})\n\n/**\n * Get the author name from the XML node\n *\n * @param xmlNode - The XML node to get the author name from\n */\nfunction authorName(xmlNode): string {\n\tif (xmlNode['@value']) {\n\t\t// Complex node (with email or homepage attribute)\n\t\treturn xmlNode['@value']\n\t}\n\t// Simple text node\n\treturn xmlNode\n}\n</script>\n\n<template>\n\t<NcAppSidebarTab\n\t\tid=\"details\"\n\t\t:name=\"t('appstore', 'Details')\"\n\t\t:order=\"1\">\n\t\t<template #icon>\n\t\t\t<NcIconSvgWrapper :path=\"mdiTextBoxOutline\" />\n\t\t</template>\n\t\t<div class=\"app-details\">\n\t\t\t<!-- Featured/Supported badges -->\n\t\t\t<div :class=\"$style.appstoreDetailsTab__badges\">\n\t\t\t\t<BadgeAppLevel :level=\"app.level\" />\n\t\t\t\t<BadgeAppDaemon v-if=\"app.app_api && app.daemon\" :daemon=\"app.daemon\" />\n\t\t\t\t<BadgeAppScore :app />\n\t\t\t</div>\n\n\t\t\t<NcNoteCard v-if=\"!app.isCompatible && app.missingDependencies && app.missingDependencies.length\" type=\"error\">\n\t\t\t\t{{ t('appstore', 'This app cannot be installed because the following dependencies are not fulfilled:') }}\n\t\t\t\t<ul :aria-label=\"t('appstore', 'Missing dependencies')\" :class=\"$style.appstoreDetailsTab__missingDependencies\">\n\t\t\t\t\t<li v-for=\"(dep, index) in app.missingDependencies\" :key=\"index\">\n\t\t\t\t\t\t{{ dep }}\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</NcNoteCard>\n\n\t\t\t<NcNoteCard v-if=\"cannotLimitToGroups\" type=\"info\">\n\t\t\t\t{{ t('appstore', 'This app cannot be limited to groups because it provides functionality that is executed before group membership is determined.') }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<div v-if=\"groupsAppIsLimitedTo.length\" :class=\"$style.appstoreDetailsTab__section\">\n\t\t\t\t<h4 :id=\"idLimitedToGroups\">\n\t\t\t\t\t{{ t('appstore', 'Limited to groups') }}\n\t\t\t\t</h4>\n\t\t\t\t<ul :aria-labelledby=\"idLimitedToGroups\" :class=\"$style.appstoreDetailsTab__sectionDetails\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"group of groupsAppIsLimitedTo\"\n\t\t\t\t\t\t:key=\"group.id\"\n\t\t\t\t\t\t:title=\"group.id\">\n\t\t\t\t\t\t{{ group.displayName }}\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\n\t\t\t<div v-if=\"lastModified && !app.shipped\" :class=\"$style.appstoreDetailsTab__section\">\n\t\t\t\t<h4>\n\t\t\t\t\t{{ t('appstore', 'Latest updated') }}\n\t\t\t\t</h4>\n\t\t\t\t<NcDateTime :class=\"$style.appstoreDetailsTab__sectionDetails\" :timestamp=\"lastModified\" />\n\t\t\t</div>\n\n\t\t\t<div :class=\"$style.appstoreDetailsTab__section\">\n\t\t\t\t<h4>\n\t\t\t\t\t{{ t('appstore', 'Author') }}\n\t\t\t\t</h4>\n\t\t\t\t<p :class=\"$style.appstoreDetailsTab__sectionDetails\">\n\t\t\t\t\t{{ appAuthors }}\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<div :class=\"$style.appstoreDetailsTab__section\">\n\t\t\t\t<h4>\n\t\t\t\t\t{{ t('appstore', 'Categories') }}\n\t\t\t\t</h4>\n\t\t\t\t<p :class=\"$style.appstoreDetailsTab__sectionDetails\">\n\t\t\t\t\t{{ appCategories }}\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<div v-if=\"externalResources.length > 0\" :class=\"$style.appstoreDetailsTab__section\">\n\t\t\t\t<h4>{{ t('appstore', 'Resources') }}</h4>\n\t\t\t\t<ul\n\t\t\t\t\t:class=\"$style.appstoreDetailsTab__resources\"\n\t\t\t\t\t:aria-label=\"t('appstore', 'Documentation resources')\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"resource of externalResources\"\n\t\t\t\t\t\t:key=\"resource.id\"\n\t\t\t\t\t\t:class=\"$style.appstoreDetailsTab__resourcesItem\">\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t:class=\"$style.appstoreDetailsTab__resourcesLink\"\n\t\t\t\t\t\t\t:href=\"resource.href\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noreferrer noopener\">\n\t\t\t\t\t\t\t{{ resource.label }} ↗\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</div>\n\t</NcAppSidebarTab>\n</template>\n\n<style module>\n.appstoreDetailsTab__badges {\n\tdisplay: flex;\n\tflex-direction: row;\n\tgap: 12px;\n}\n\n.appstoreDetailsTab__section {\n\tmargin-top: 15px;\n\n\th4 {\n\t\tfont-size: 16px;\n\t\tfont-weight: bold;\n\t\tmargin-block-end: 5px;\n\t}\n}\n\n.appstoreDetailsTab__sectionDetails {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.appstoreDetailsTab__missingDependencies {\n\tlist-style: disc;\n\tpadding-block: 0.5lh 0;\n\tpadding-inline: 1em 0;\n}\n\n.appstoreDetailsTab__resourcesLink {\n\ttext-decoration: underline;\n}\n\n.appstoreDetailsTab__resourcesItem {\n\tpadding-inline-start: 20px;\n\n\t&::before {\n\t\twidth: 5px;\n\t\theight: 5px;\n\t\tborder-radius: 100%;\n\t\tbackground-color: var(--color-main-text);\n\t\tcontent: \"\";\n\t\tfloat: inline-start;\n\t\tmargin-inline-start: -13px;\n\t\tposition: relative;\n\t\ttop: 10px;\n\t}\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IAppstoreApp, IAppstoreAppRelease, IAppstoreExApp } from '../../apps.d.ts'\n\nimport { mdiClockFast } from '@mdi/js'\nimport { getLanguage, t } from '@nextcloud/l10n'\nimport { computed } from 'vue'\nimport NcAppSidebarTab from '@nextcloud/vue/components/NcAppSidebarTab'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\nimport MarkdownPreview from '../MarkdownPreview.vue'\n\nconst props = defineProps<{ app: IAppstoreApp | IAppstoreExApp }>()\n\nconst releases = computed(() => (props.app.releases ?? [])\n\t.filter((release) => {\n\t\tconst values = Object.values(release.translations ?? {})\n\t\treturn values.length > 0 && values.some(({ changelog }) => !!changelog)\n\t}))\n\n/**\n * Create a changelog text from a release\n *\n * @param release - The release to create the changelog from\n */\nfunction createChangelogFromRelease(release: IAppstoreAppRelease) {\n\tconst localizedEntry = release.translations[getLanguage()]\n\treturn localizedEntry?.changelog ?? release.translations.en?.changelog ?? ''\n}\n</script>\n\n<template>\n\t<NcAppSidebarTab\n\t\tv-if=\"releases.length > 0\"\n\t\tid=\"changelog\"\n\t\t:name=\"t('appstore', 'Changelog')\"\n\t\t:order=\"2\">\n\t\t<template #icon>\n\t\t\t<NcIconSvgWrapper :path=\"mdiClockFast\" :size=\"24\" />\n\t\t</template>\n\t\t<div v-for=\"release in releases\" :key=\"release.version\" :class=\"$style.appReleasesTab\">\n\t\t\t<h3 :class=\"$style.appReleasesTab__heading\">\n\t\t\t\t{{ release.version }}\n\t\t\t</h3>\n\t\t\t<MarkdownPreview\n\t\t\t\t:class=\"$style.appReleasesTab__text\"\n\t\t\t\t:minHeadingLevel=\"3\"\n\t\t\t\t:text=\"createChangelogFromRelease(release)\" />\n\t\t</div>\n\t</NcAppSidebarTab>\n</template>\n\n<style module>\n.appReleasesTab__heading {\n\tborder-bottom: 1px solid var(--color-border);\n\tfont-size: 20px;\n}\n\n.appReleasesTab__text {\n\t/* Overwrite changelog heading styles */\n\th4 {\n\t\tfont-size: 19px;\n\t}\n\n\th5 {\n\t\tfont-size: 17px;\n\t}\n}\n</style>\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\nimport type { AppAction } from './index.ts'\n\nimport { mdiClose } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { useAppsStore } from '../store/apps.ts'\nimport { canDisable } from '../utils/appStatus.ts'\n\nexport const actionDisable: AppAction = {\n\tid: 'disable',\n\ticon: mdiClose,\n\torder: 10,\n\tenabled: canDisable,\n\tlabel: () => t('appstore', 'Disable'),\n\tasync callback(app: IAppstoreApp | IAppstoreExApp) {\n\t\tconst store = useAppsStore()\n\t\tawait store.disableApp(app.id)\n\t},\n}\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\nimport type { AppAction } from './index.ts'\n\nimport { mdiCheck } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { useAppsStore } from '../store/apps.ts'\nimport { canEnable, canInstall } from '../utils/appStatus.ts'\n\nexport const actionEnable: AppAction = {\n\tid: 'enable',\n\ticon: mdiCheck,\n\torder: 1,\n\tvariant: 'primary',\n\tenabled(app: IAppstoreApp | IAppstoreExApp) {\n\t\treturn !canInstall(app) && canEnable(app)\n\t},\n\tlabel: () => t('appstore', 'Enable'),\n\tasync callback(app: IAppstoreApp | IAppstoreExApp) {\n\t\tconst store = useAppsStore()\n\t\tawait store.enableApp(app.id)\n\t},\n}\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\nimport type { AppAction } from './index.ts'\n\nimport { mdiAlertCircleCheckOutline } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { useAppsStore } from '../store/apps.ts'\nimport { canForceEnable, canInstall, needForceEnable } from '../utils/appStatus.ts'\n\nexport const actionForceEnable: AppAction = {\n\tid: 'force-enable',\n\ticon: mdiAlertCircleCheckOutline,\n\torder: 3,\n\tinline: false,\n\tvariant: 'warning',\n\tlabel: () => t('appstore', 'Force enable'),\n\tenabled(app: IAppstoreApp | IAppstoreExApp) {\n\t\treturn !canInstall(app) && canForceEnable(app) && needForceEnable(app)\n\t},\n\tasync callback(app: IAppstoreApp | IAppstoreExApp) {\n\t\tconst store = useAppsStore()\n\t\tawait store.enableApp(app.id, true)\n\t},\n}\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\nimport type { AppAction } from './index.ts'\n\nimport { mdiDownload } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { useAppsStore } from '../store/apps.ts'\nimport { canInstall, needForceEnable } from '../utils/appStatus.ts'\n\nexport const actionInstall: AppAction = {\n\tid: 'install',\n\ticon: mdiDownload,\n\torder: 5,\n\tenabled(app) {\n\t\treturn canInstall(app) && !needForceEnable(app)\n\t},\n\tlabel: (app: IAppstoreApp | IAppstoreExApp) => {\n\t\tif (app.app_api) {\n\t\t\treturn t('appstore', 'Deploy and enable')\n\t\t}\n\t\tif (app.needsDownload) {\n\t\t\treturn t('appstore', 'Download and enable')\n\t\t}\n\t\treturn t('appstore', 'Install and enable')\n\t},\n\tasync callback(app: IAppstoreApp | IAppstoreExApp) {\n\t\tconst store = useAppsStore()\n\t\tawait store.enableApp(app.id)\n\t},\n}\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\nimport type { AppAction } from './index.ts'\n\nimport { mdiDownload } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { useAppsStore } from '../store/apps.ts'\nimport { canInstall, needForceEnable } from '../utils/appStatus.ts'\n\nexport const actionInstallForced: AppAction = {\n\tid: 'install-forced',\n\ticon: mdiDownload,\n\torder: 5,\n\tinline: false,\n\tenabled(app) {\n\t\treturn canInstall(app) && needForceEnable(app)\n\t},\n\tlabel: (app: IAppstoreApp | IAppstoreExApp) => {\n\t\tif (app.app_api) {\n\t\t\treturn t('appstore', 'Deploy and force enable')\n\t\t}\n\t\tif (app.needsDownload) {\n\t\t\treturn t('appstore', 'Download and force enable')\n\t\t}\n\t\treturn t('appstore', 'Install and force enable')\n\t},\n\tasync callback(app: IAppstoreApp | IAppstoreExApp) {\n\t\tconst store = useAppsStore()\n\t\tawait store.enableApp(app.id, true)\n\t},\n}\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\nimport type { AppAction } from './index.ts'\n\nimport { mdiBugOutline, mdiForumOutline, mdiStarOutline, mdiWeb } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\n\nexport const actionsInteract: AppAction[] = [\n\t{\n\t\tid: 'rate',\n\t\ticon: mdiStarOutline,\n\t\torder: 30,\n\t\tinline: false,\n\t\tlabel: () => t('appstore', 'Rate the app'),\n\t\tenabled(app: IAppstoreApp | IAppstoreExApp) {\n\t\t\treturn !app.shipped\n\t\t},\n\t\thref(app: IAppstoreApp | IAppstoreExApp) {\n\t\t\treturn `https://apps.nextcloud.com/apps/${encodeURIComponent(app.id)}#comments`\n\t\t},\n\t},\n\t{\n\t\tid: 'report-bug',\n\t\ticon: mdiBugOutline,\n\t\torder: 32,\n\t\tinline: false,\n\t\tlabel: () => t('appstore', 'Report a bug'),\n\t\tenabled(app: IAppstoreApp | IAppstoreExApp) {\n\t\t\treturn !!app.bugs\n\t\t},\n\t\thref(app: IAppstoreApp | IAppstoreExApp) {\n\t\t\treturn app.bugs!\n\t\t},\n\t},\n\t{\n\t\tid: 'discussion',\n\t\ticon: mdiForumOutline,\n\t\torder: 35,\n\t\tinline: false,\n\t\tlabel: () => t('appstore', 'Ask questions or discuss the app'),\n\t\tenabled(app: IAppstoreApp | IAppstoreExApp) {\n\t\t\treturn !!app.discussion\n\t\t},\n\t\thref(app: IAppstoreApp | IAppstoreExApp) {\n\t\t\treturn app.discussion!\n\t\t},\n\t},\n\t{\n\t\tid: 'website',\n\t\ticon: mdiWeb,\n\t\torder: 38,\n\t\tinline: false,\n\t\tlabel: () => t('appstore', 'Visit the website'),\n\t\tenabled(app: IAppstoreApp | IAppstoreExApp) {\n\t\t\treturn !!app.website\n\t\t},\n\t\thref(app: IAppstoreApp | IAppstoreExApp) {\n\t\t\treturn app.website!\n\t\t},\n\t},\n]\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\nimport type { AppAction } from './index.ts'\n\nimport { mdiAccountGroup } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { spawnDialog } from '@nextcloud/vue'\nimport { defineAsyncComponent } from 'vue'\nimport { canLimitToGroups } from '../utils/appStatus.ts'\n\nconst LimitToGroupDialog = defineAsyncComponent(() => import('../components/LimitToGroupDialog.vue'))\n\nexport const actionLimitToGroup: AppAction = {\n\tid: 'limit-to-group',\n\ticon: mdiAccountGroup,\n\torder: 16,\n\tinline: false,\n\tlabel: () => t('appstore', 'Limit to groups'),\n\tenabled: canLimitToGroups,\n\tasync callback(app: IAppstoreApp | IAppstoreExApp) {\n\t\tawait spawnDialog(LimitToGroupDialog, { app })\n\t},\n}\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\nimport type { AppAction } from './index.ts'\n\nimport { mdiTrashCanOutline } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { useAppsStore } from '../store/apps.ts'\nimport { canUninstall } from '../utils/appStatus.ts'\n\nexport const actionRemove: AppAction = {\n\tid: 'remove',\n\torder: 20,\n\ticon: mdiTrashCanOutline,\n\tvariant: 'error',\n\tinline: false,\n\tenabled: canUninstall,\n\tlabel: () => t('appstore', 'Remove'),\n\tasync callback(app: IAppstoreApp | IAppstoreExApp) {\n\t\tconst store = useAppsStore()\n\t\tawait store.uninstallApp(app.id)\n\t},\n}\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\nimport type { AppAction } from './index.ts'\n\nimport { mdiUpdate } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { useExAppsStore } from '../store/exApps.ts'\nimport { useUpdatesStore } from '../store/updates.ts'\nimport { canUpdate } from '../utils/appStatus.ts'\n\nexport const actionUpdate: AppAction = {\n\tid: 'update',\n\ticon: mdiUpdate,\n\tvariant: 'primary',\n\torder: 0,\n\tenabled(app) {\n\t\tif (!canUpdate(app)) {\n\t\t\treturn false\n\t\t}\n\t\tif (app.app_api) {\n\t\t\tif (app.daemon && app.daemon?.accepts_deploy_id === 'manual-install') {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst exAppsStore = useExAppsStore()\n\t\t\treturn exAppsStore.daemonAccessible\n\t\t}\n\t\treturn true\n\t},\n\tlabel: (app: IAppstoreApp | IAppstoreExApp) => t('appstore', 'Update to {version}', { version: app.update! }),\n\tasync callback(app: IAppstoreApp | IAppstoreExApp) {\n\t\tconst store = useUpdatesStore()\n\t\tawait store.updateApp(app.id)\n\t},\n}\n","/*\n * SPDX-License-Identifier: AGPL-3.0-or-later\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n */\n\nimport type { RouteLocationRaw } from 'vue-router'\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\n\nimport { actionDisable } from './actionDisable.ts'\nimport { actionEnable } from './actionEnable.ts'\nimport { actionForceEnable } from './actionForceEnable.ts'\nimport { actionInstall } from './actionInstall.ts'\nimport { actionInstallForced } from './actionInstallForced.ts'\nimport { actionsInteract } from './actionInteract.ts'\nimport { actionLimitToGroup } from './actionLimitToGroup.ts'\nimport { actionRemove } from './actionRemove.ts'\nimport { actionUpdate } from './actionUpdate.ts'\n\ninterface AppActionBase {\n\tenabled: (app: IAppstoreApp | IAppstoreExApp) => boolean\n\n\tid: string\n\ticon: string\n\torder: number\n\tlabel: (app: IAppstoreApp | IAppstoreExApp) => string\n\tvariant?: 'primary' | 'error' | 'warning'\n\tinline?: boolean\n}\n\ninterface AppActionWithCallback extends AppActionBase {\n\tcallback: (app: IAppstoreApp | IAppstoreExApp) => Promise<void>\n}\n\ninterface AppActionWithHref extends AppActionBase {\n\thref: (app: IAppstoreApp | IAppstoreExApp) => string\n}\n\ninterface AppActionWithRoute extends AppActionBase {\n\tto: (app: IAppstoreApp | IAppstoreExApp) => RouteLocationRaw\n}\n\nexport type AppAction = AppActionWithCallback | AppActionWithHref | AppActionWithRoute\n\nexport const actions = [\n\tactionUpdate,\n\tactionEnable,\n\tactionDisable,\n\tactionForceEnable,\n\tactionInstall,\n\tactionInstallForced,\n\tactionRemove,\n\tactionLimitToGroup,\n\t...actionsInteract,\n].sort((a, b) => a.order - b.order)\n","/*!\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { MaybeRefOrGetter } from 'vue'\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\n\nimport { computed, toValue } from 'vue'\nimport { actions } from '../actions/index.ts'\n\n/**\n * Get the available actions for an app\n *\n * @param app - The app to get the actions for\n */\nexport function useActions(app: MaybeRefOrGetter<IAppstoreApp | IAppstoreExApp | null>) {\n\treturn computed(() => toValue(app) ? actions.filter((action) => action.enabled(toValue(app)!)) : [])\n}\n","/*!\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { Ref } from 'vue'\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\n\nimport { mdiCog, mdiCogOutline } from '@mdi/js'\nimport { computed, ref, watchEffect } from 'vue'\nimport { APPSTORE_CATEGORY_ICONS } from '../constants.ts'\nimport logger from '../utils/logger.ts'\n\n/**\n * Get the app icon raw SVG for use with `NcIconSvgWrapper` (do never use without sanitizing)\n * It has a fallback to the categroy icon.\n *\n * @param app The app to get the icon for\n */\nexport function useAppIcon(app: Ref<IAppstoreApp | IAppstoreExApp | null>) {\n\tconst appIcon = ref<string | null>(null)\n\n\t/**\n\t * Fallback value if no app icon available\n\t */\n\tconst categoryIcon = computed(() => {\n\t\tlet path: string\n\t\tif (app.value?.app_api) {\n\t\t\t// Use different default icon for ExApps (AppAPI)\n\t\t\tpath = mdiCogOutline\n\t\t} else {\n\t\t\tpath = [app.value?.category ?? []].flat()\n\t\t\t\t.map((name) => APPSTORE_CATEGORY_ICONS[name])\n\t\t\t\t.filter((icon) => !!icon)\n\t\t\t\t.at(0)\n\t\t\t\t?? (!app.value?.app_api ? mdiCog : mdiCogOutline)\n\t\t}\n\t\treturn path ? `<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"${path}\" /></svg>` : null\n\t})\n\n\twatchEffect(async () => {\n\t\t// Note: Only variables until the first `await` will be watched!\n\t\tif (!app.value?.icon) {\n\t\t\tappIcon.value = categoryIcon.value\n\t\t} else {\n\t\t\tappIcon.value = null\n\t\t\t// Now try to load the real app icon\n\t\t\ttry {\n\t\t\t\tconst response = await window.fetch(app.value.icon)\n\t\t\t\tconst blob = await response.blob()\n\t\t\t\tconst rawSvg = await blob.text()\n\t\t\t\tappIcon.value = rawSvg.replaceAll(/fill=\"#(fff|ffffff)([a-z0-9]{1,2})?\"/ig, 'fill=\"currentColor\"')\n\t\t\t} catch (error) {\n\t\t\t\tappIcon.value = categoryIcon.value\n\t\t\t\tlogger.error('Could not load app icon', { error })\n\t\t\t}\n\t\t}\n\t})\n\n\treturn {\n\t\tappIcon,\n\t}\n}\n","<!--\n - SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport { t } from '@nextcloud/l10n'\nimport { computed, onMounted, ref, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport NcAppSidebar from '@nextcloud/vue/components/NcAppSidebar'\nimport NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\nimport AppActions from '../components/AppActions.vue'\nimport AppDeployDaemonTab from '../components/AppstoreSidebar/AppDeployDaemonTab.vue'\nimport AppDescriptionTab from '../components/AppstoreSidebar/AppDescriptionTab.vue'\nimport AppDetailsTab from '../components/AppstoreSidebar/AppDetailsTab.vue'\nimport AppReleasesTab from '../components/AppstoreSidebar/AppReleasesTab.vue'\nimport { useActions } from '../composables/useActions.ts'\nimport { useAppIcon } from '../composables/useAppIcon.ts'\nimport { useAppsStore } from '../store/apps.ts'\nimport { useUserSettingsStore } from '../store/userSettings.ts'\n\nconst route = useRoute()\nconst router = useRouter()\nconst store = useAppsStore()\nconst userSettings = useUserSettingsStore()\n\nconst appId = computed<string>(() => [route.params.id].flat()[0]!)\nconst app = computed(() => store.getAppById(appId.value) ?? null)\nconst { appIcon } = useAppIcon(app)\n\n/**\n * The second text line shown on the sidebar\n */\nconst licenseText = computed(() => {\n\tif (!app.value) {\n\t\treturn ''\n\t}\n\n\tif (app.value.license) {\n\t\treturn t('appstore', 'Version {version}, {license}-licensed', { version: app.value.version, license: String(app.value.license).toUpperCase() })\n\t}\n\treturn t('appstore', 'Version {version}', { version: app.value.version })\n})\n\nconst activeTab = ref('details')\nwatch([app], () => {\n\tactiveTab.value = 'details'\n})\n\n/**\n * Hide the details sidebar by pushing a new route\n */\nfunction hideAppDetails() {\n\trouter.replace({\n\t\tname: route.name!,\n\t\tparams: {\n\t\t\t...route.params,\n\t\t\tid: undefined,\n\t\t},\n\t\tquery: userSettings.getQuery(),\n\t})\n}\n\n/**\n * Whether the app screenshot is loaded\n */\nconst screenshotLoaded = ref(false)\nconst hasScreenshot = computed(() => app.value?.screenshot && screenshotLoaded.value)\n/**\n * Preload the app screenshot\n */\nfunction loadScreenshot() {\n\tif (app.value?.releases && app.value?.screenshot) {\n\t\tconst image = new Image()\n\t\timage.onload = () => {\n\t\t\tscreenshotLoaded.value = true\n\t\t}\n\t\timage.src = app.value.screenshot\n\t}\n}\n// Watch app and set screenshot loaded when\nwatch([app], loadScreenshot)\nonMounted(loadScreenshot)\n\nconst actions = useActions(() => app.value)\n</script>\n\n<template>\n\t<!-- Selected app details -->\n\t<NcAppSidebar\n\t\tv-model:active=\"activeTab\"\n\t\t:class=\"[$style.appstoreSidebar, { [$style.appstoreSidebar_withScreenshot]: hasScreenshot }]\"\n\t\t:background=\"hasScreenshot ? app!.screenshot : undefined\"\n\t\t:compact=\"!hasScreenshot\"\n\t\t:name=\"app?.name ?? appId\"\n\t\t:title=\"app?.name ?? appId\"\n\t\t:subname=\"licenseText\"\n\t\t:subtitle=\"licenseText\"\n\t\t@close=\"hideAppDetails\">\n\t\t<!-- Fallback icon in case no app icon is available -->\n\t\t<template v-if=\"!hasScreenshot\" #header>\n\t\t\t<NcIconSvgWrapper\n\t\t\t\t:class=\"$style.appstoreSidebar__fallbackIcon\"\n\t\t\t\t:svg=\"appIcon ?? ''\"\n\t\t\t\t:size=\"64\" />\n\t\t</template>\n\n\t\t<template v-if=\"app\" #description>\n\t\t\t<AppActions\n\t\t\t\t:app\n\t\t\t\t:actions\n\t\t\t\ticonOnly\n\t\t\t\t:maxInlineActions=\"6\" />\n\t\t</template>\n\n\t\t<!-- Tab content -->\n\t\t<NcEmptyContent v-if=\"!app\" name=\"No such app\" />\n\t\t<template v-else>\n\t\t\t<AppDescriptionTab :app />\n\t\t\t<AppReleasesTab :app />\n\t\t\t<AppDetailsTab :app />\n\t\t\t<AppDeployDaemonTab v-if=\"app.app_api\" :app />\n\t\t</template>\n\t</NcAppSidebar>\n</template>\n\n<style module>\n/* If a screenshot is available it should cover the whole figure */\n.appstoreSidebar_withScreenshot {\n\t:global(.app-sidebar-header__figure) {\n\t\tbackground-size: cover;\n\t}\n}\n\n.appstoreSidebar__fallbackIcon {\n\twidth: 100%;\n\theight: 100%;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport { t } from '@nextcloud/l10n'\nimport { computed } from 'vue'\nimport { useRoute } from 'vue-router'\nimport NcAppContent from '@nextcloud/vue/components/NcAppContent'\nimport NcContent from '@nextcloud/vue/components/NcContent'\nimport AppstoreNavigation from './views/AppstoreNavigation.vue'\nimport AppstoreSidebar from './views/AppstoreSidebar.vue'\nimport { APPSTORE_CATEGORY_NAMES } from './constants.ts'\nimport { useAppsStore } from './store/apps.ts'\n\nconst route = useRoute()\nconst store = useAppsStore()\n\nconst currentCategory = computed(() => {\n\tif (route.params.category) {\n\t\treturn [route.params.category].flat()[0]!\n\t}\n\tif (route.name === 'apps-bundles') {\n\t\treturn 'bundles'\n\t} else if (route.name === 'apps-search') {\n\t\treturn 'search'\n\t}\n\treturn 'discover'\n})\n\nconst heading = computed(() => {\n\tif (currentCategory.value in APPSTORE_CATEGORY_NAMES) {\n\t\treturn APPSTORE_CATEGORY_NAMES[currentCategory.value]\n\t}\n\treturn store.getCategoryById(currentCategory.value)?.displayName ?? currentCategory.value\n})\nconst pageTitle = computed(() => `${heading.value} - ${t('appstore', 'App store')}`)\n\nconst showSidebar = computed(() => !!route.params.id)\n</script>\n\n<template>\n\t<NcContent appName=\"appstore\">\n\t\t<AppstoreNavigation />\n\t\t<NcAppContent\n\t\t\t:class=\"$style.appstoreApp__content\"\n\t\t\t:pageHeading=\"t('appstore', 'App store')\"\n\t\t\t:pageTitle>\n\t\t\t<h2 v-if=\"heading\" :class=\"$style.appstoreApp__heading\">\n\t\t\t\t{{ heading }}\n\t\t\t</h2>\n\t\t\t<router-view />\n\t\t</NcAppContent>\n\t\t<AppstoreSidebar v-if=\"showSidebar\" />\n\t</NcContent>\n</template>\n\n<style module>\n.appstoreApp__content {\n\tpadding-inline-end: var(--body-container-margin);\n\tposition: relative;\n}\n\n.appstoreApp__heading {\n\tmargin-block-start: var(--app-navigation-padding);\n\tmargin-inline-start: calc(var(--default-clickable-area) + var(--app-navigation-padding) * 2);\n\tmin-height: var(--default-clickable-area);\n\tline-height: var(--default-clickable-area);\n\tvertical-align: center;\n}\n</style>\n","/*!\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { RouteRecordRaw } from 'vue-router'\n\nimport { loadState } from '@nextcloud/initial-state'\n\nconst appstoreEnabled = loadState<boolean>('appstore', 'appstoreEnabled', true)\n\n// Dynamic loading\nconst AppstoreDiscover = () => import('../views/AppstoreDiscover.vue')\nconst AppstoreManage = () => import('../views/AppstoreManage.vue')\nconst AppstoreBundles = () => import('../views/AppstoreBundles.vue')\nconst AppstoreBrowse = () => import('../views/AppstoreBrowse.vue')\nconst AppstoreSearch = () => import('../views/AppstoreSearch.vue')\n\nconst routes: RouteRecordRaw[] = [\n\t{\n\t\tpath: '/:index(index.php/)?settings/apps',\n\t\tname: 'apps',\n\t\tredirect: appstoreEnabled\n\t\t\t? {\n\t\t\t\t\tname: 'apps-discover',\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\tname: 'apps-manage',\n\t\t\t\t\tparams: { category: 'installed' },\n\t\t\t\t},\n\t\tchildren: [\n\t\t\t{\n\t\t\t\tpath: 'discover/:id?',\n\t\t\t\tname: 'apps-discover',\n\t\t\t\tcomponent: AppstoreDiscover,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: 'bundles/:id?',\n\t\t\t\tname: 'apps-bundles',\n\t\t\t\tcomponent: AppstoreBundles,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: ':category(installed|enabled|disabled|updates)/:id?',\n\t\t\t\tname: 'apps-manage',\n\t\t\t\tcomponent: AppstoreManage,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: ':category/:id?',\n\t\t\t\tname: 'apps-category',\n\t\t\t\tcomponent: AppstoreBrowse,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: 'search/:id?',\n\t\t\t\tname: 'apps-search',\n\t\t\t\tcomponent: AppstoreSearch,\n\t\t\t},\n\t\t],\n\t},\n]\n\nexport default routes\n","/**\n * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { generateUrl } from '@nextcloud/router'\nimport { createRouter, createWebHistory } from 'vue-router'\nimport routes from './routes.ts'\n\nconst router = createRouter({\n\thistory: createWebHistory(generateUrl('')),\n\tlinkActiveClass: 'active',\n\troutes,\n})\n\nexport default router\n","/**\n * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { createPinia } from 'pinia'\nimport { createApp } from 'vue'\nimport AppstoreApp from './AppstoreApp.vue'\nimport router from './router/index.ts'\n\nimport 'vite/modulepreload-polyfill'\n\nconst pinia = createPinia()\nconst app = createApp(AppstoreApp)\napp.config.idPrefix = 'appstore'\napp.use(pinia)\napp.use(router)\napp.mount('#content')\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { NcSelectUsersModel } from '@nextcloud/vue/components/NcSelectUsers'\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\n\nimport { t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport { useDebounceFn } from '@vueuse/core'\nimport { computed, ref, watch } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcDialog from '@nextcloud/vue/components/NcDialog'\nimport NcSelectUsers from '@nextcloud/vue/components/NcSelectUsers'\nimport { useAppsStore } from '../store/apps.ts'\nimport { useGroupsStore } from '../store/groups.ts'\n\nconst { app } = defineProps<{ app: IAppstoreApp | IAppstoreExApp }>()\nconst emit = defineEmits<{ close: [] }>()\n\nconst store = useAppsStore()\nconst groupsStore = useGroupsStore()\n\nconst loading = ref(false)\nconst groups = ref<NcSelectUsersModel[]>([])\nwatch(() => app, () => {\n\tgroups.value = (app.groups ?? [])\n\t\t.map((g) => {\n\t\t\tconst group = groupsStore.getGroupById(g)\n\t\t\tif (!group) {\n\t\t\t\tgroupsStore.searchGroups(g)\n\t\t\t}\n\t\t\treturn group ?? { id: g, displayName: g, isNoUser: true }\n\t\t})\n}, { immediate: true })\n\nconst availableGroups = computed(() => groupsStore.groups.filter((group) => !groups.value.includes(group)))\nconst onSearch = useDebounceFn(groupsStore.searchGroups, 400)\n\n/**\n * Save the limitation of this app\n */\nasync function onSave() {\n\ttry {\n\t\tloading.value = true\n\t\tawait store.limitAppToGroups(app.id, groups.value.map((g) => g.id))\n\t\temit('close')\n\t} finally {\n\t\tloading.value = false\n\t}\n}\n\n/**\n * Handle reset\n */\nasync function onReset() {\n\ttry {\n\t\tloading.value = true\n\t\tawait store.limitAppToGroups(app.id, [])\n\t\temit('close')\n\t} finally {\n\t\tloading.value = false\n\t}\n}\n</script>\n\n<template>\n\t<NcDialog\n\t\tisForm\n\t\t:name=\"t('appstore', 'Limit to groups')\"\n\t\t@submit=\"onSave\"\n\t\t@reset=\"onReset\">\n\t\t<p>{{ t('appstore', 'Restrict the usage of {app} to members of the following groups.', { app: app.name }) }}</p>\n\t\t<NcSelectUsers\n\t\t\tv-model=\"groups\"\n\t\t\t:class=\"$style.limitToGroupDialog__input\"\n\t\t\tkeepOpen\n\t\t\tlabelOutside\n\t\t\tmultiple\n\t\t\t:options=\"availableGroups\"\n\t\t\t@search=\"onSearch\" />\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"loading\" type=\"reset\">\n\t\t\t\t{{ t('appstore', 'Reset limitation') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton :disabled=\"loading\" type=\"submit\" variant=\"primary\">\n\t\t\t\t<template v-if=\"loading\" #icon>\n\t\t\t\t\t<NcLoadingIcon />\n\t\t\t\t</template>\n\n\t\t\t\t{{ t('appstore', 'Save') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</NcDialog>\n</template>\n\n<style module>\n.limitToGroupDialog__input {\n\twidth: 100%;\n\tpadding-block: 1lh calc(2 * var(--default-clickable-area) + var(--default-grid-baseline));\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'\n\nimport { mdiCogOutline } from '@mdi/js'\nimport { computed, ref, watch } from 'vue'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\n\nconst { app, noFallback, size = 20 } = defineProps<{\n\tapp: IAppstoreApp | IAppstoreExApp\n\tnoFallback?: boolean\n\tsize?: number\n}>()\n\nconst isSvg = computed(() => app.icon?.endsWith('.svg'))\nconst svgIcon = ref<string>('')\nwatch(() => app.icon, async () => {\n\tsvgIcon.value = ''\n\tif (app.icon?.endsWith('.svg')) {\n\t\tconst response = await fetch(app.icon)\n\t\tif (response.ok) {\n\t\t\tsvgIcon.value = await response.text()\n\t\t\tsvgIcon.value = svgIcon.value\n\t\t\t\t.replaceAll(/(?<=[\";])fill:\\s?(#fff(fff)?|white)(;|(?=\"))/gi, '')\n\t\t\t\t.replaceAll(/(?<=\\s)fill=\"[^\"]+\"/gi, '')\n\t\t\t\t.replaceAll(/(?<=\\s)color=\"[^\"]+\"/gi, '')\n\t\t}\n\t}\n}, { immediate: true })\n</script>\n\n<template>\n\t<span :class=\"$style.appIcon\">\n\t\t<NcIconSvgWrapper\n\t\t\tv-if=\"svgIcon\"\n\t\t\t:size\n\t\t\t:svg=\"svgIcon\" />\n\t\t<img\n\t\t\tv-else-if=\"app.icon && !isSvg\"\n\t\t\t:class=\"$style.appIcon__image\"\n\t\t\talt=\"\"\n\t\t\t:src=\"app.icon\"\n\t\t\t:height=\"size\"\n\t\t\t:width=\"size\">\n\t\t<NcIconSvgWrapper\n\t\t\tv-else-if=\"!noFallback\"\n\t\t\t:path=\"mdiCogOutline\"\n\t\t\t:size />\n\t</span>\n</template>\n\n<style module>\n.appIcon {\n\tdisplay: inline-flex;\n\tjustify-content: center;\n}\n\n.appIcon__image {\n\tfilter: var(--invert-if-dark);\n\tobject-fit: cover;\n\theight: 100%;\n\twidth: 100%;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { AppAction } from '../../actions/index.ts'\nimport type { IAppstoreApp, IAppstoreExApp } from '../../apps.d.ts'\n\nimport { mdiInformationOutline } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { computed } from 'vue'\nimport { useRoute } from 'vue-router'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcChip from '@nextcloud/vue/components/NcChip'\nimport NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'\nimport AppActions from '../AppActions.vue'\nimport AppIcon from '../AppIcon.vue'\nimport BadgeAppDaemon from '../BadgeAppDaemon.vue'\nimport BadgeAppLevel from '../BadgeAppLevel.vue'\nimport { useActions } from '../../composables/useActions.ts'\nimport { useLimitedGroups } from '../../composables/useLimitedGroups.ts'\n\nconst { app, isNarrow } = defineProps<{\n\tapp: IAppstoreApp | IAppstoreExApp\n\tisNarrow?: boolean\n\tisWide?: boolean\n}>()\n\nconst route = useRoute()\nconst detailsRoute = computed(() => ({\n\t...route,\n\tparams: {\n\t\t...route.params,\n\t\tid: app.id,\n\t},\n\tquery: {\n\t\t...route.query,\n\t},\n}))\n\nconst detailsAction = computed<AppAction>(() => ({\n\tid: 'details',\n\torder: 99,\n\tenabled: () => true,\n\tlabel: () => t('appstore', 'Show details'),\n\ticon: mdiInformationOutline,\n\tto: () => detailsRoute.value,\n\tinline: false,\n}))\n\nconst groupsAppIsLimitedTo = useLimitedGroups(() => app)\nconst rawActions = useActions(() => app)\nconst actions = computed(() => [\n\t...rawActions.value,\n\tdetailsAction.value,\n])\n</script>\n\n<template>\n\t<tr :class=\"$style.appTableRow\">\n\t\t<td :class=\"$style.appTableRow__nameCell\">\n\t\t\t<NcButton\n\t\t\t\talignment=\"start\"\n\t\t\t\t:title=\"t('appstore', 'Show details')\"\n\t\t\t\t:to=\"detailsRoute\"\n\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\twide>\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"app.loading\" :size=\"24\" />\n\t\t\t\t\t<AppIcon v-else :app :size=\"24\" />\n\t\t\t\t</template>\n\t\t\t\t{{ app.name }}\n\t\t\t\t<span v-if=\"app.loading\" class=\"hidden-visually\">({{ t('appstore', 'is loading…') }})</span>\n\t\t\t\t<span class=\"hidden-visually\">({{ t('appstore', 'Show details') }})</span>\n\t\t\t</NcButton>\n\t\t</td>\n\t\t<td>\n\t\t\t<span :class=\"$style.appTableRow__versionCell\">{{ app.version }}</span>\n\t\t</td>\n\t\t<td v-if=\"!isNarrow\">\n\t\t\t<div :class=\"$style.appTableRow__levelCell\">\n\t\t\t\t<BadgeAppLevel v-if=\"app.level\" :level=\"app.level\" />\n\t\t\t\t<BadgeAppDaemon v-if=\"'daemon' in app && app.daemon\" :daemon=\"app.daemon\" />\n\t\t\t</div>\n\t\t</td>\n\t\t<td v-if=\"isWide\">\n\t\t\t<ul\n\t\t\t\tv-if=\"groupsAppIsLimitedTo.length > 0\"\n\t\t\t\t:class=\"$style.appTableRow__groupsCell\"\n\t\t\t\t:title=\"groupsAppIsLimitedTo.map((group) => group.displayName).join(', ')\">\n\t\t\t\t<template v-for=\"group, index in groupsAppIsLimitedTo\" :key=\"group.id\">\n\t\t\t\t\t<li v-if=\"index === 3\" aria-hidden=\"true\">\n\t\t\t\t\t\t…\n\t\t\t\t\t</li>\n\t\t\t\t\t<li :class=\"{ 'hidden-visually': index > 2 }\">\n\t\t\t\t\t\t<NcChip :text=\"group.displayName\" noClose />\n\t\t\t\t\t</li>\n\t\t\t\t</template>\n\t\t\t</ul>\n\t\t</td>\n\t\t<td>\n\t\t\t<div :class=\"$style.appTableRow__actionsCell\">\n\t\t\t\t<AppActions\n\t\t\t\t\t:class=\"$style.appTableRow__actionsCellActions\"\n\t\t\t\t\t:app\n\t\t\t\t\t:actions\n\t\t\t\t\t:iconOnly=\"isNarrow\" />\n\t\t\t</div>\n\t\t</td>\n\t</tr>\n</template>\n\n<style module>\n.appTableRow {\n\theight: calc(var(--default-clickable-area) + var(--default-grid-baseline));\n}\n\n.appTableRow td {\n\tpadding-block: var(--default-grid-baseline);\n\tvertical-align: middle;\n}\n\n.appTableRow__nameCell {\n\t/* Padding is needed to have proper focus-visible */\n\tpadding-inline: var(--default-grid-baseline);\n}\n\n.appTableRow__levelCell {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--default-grid-baseline)\n}\n\n.appTableRow__versionCell {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.appTableRow__groupsCell {\n\tdisplay: flex;\n\tgap: var(--default-grid-baseline);\n}\n\n.appTableRow__actionsCell {\n\tdisplay: flex;\n\tgap: var(--default-grid-baseline);\n\tjustify-content: end;\n}\n\n.appTableRow__actionsCellActions {\n\twidth: 100%;\n\tjustify-content: end;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IAppstoreApp, IAppstoreExApp } from '../../apps.d.ts'\n\nimport { t } from '@nextcloud/l10n'\nimport { useElementSize } from '@vueuse/core'\nimport { computed, useTemplateRef } from 'vue'\nimport AppTableRow from './AppTableRow.vue'\n\ndefineProps<{\n\tapps: (IAppstoreApp | IAppstoreExApp)[]\n}>()\n\nconst tableElement = useTemplateRef('table')\nconst { width: tableWidth } = useElementSize(tableElement)\n\nconst isNarrow = computed(() => tableWidth.value < 768)\nconst isWide = computed(() => tableWidth.value >= 1280)\n</script>\n\n<template>\n\t<table\n\t\tref=\"table\"\n\t\t:class=\"[$style.appTable, {\n\t\t\t[$style.appTable_narrow]: isNarrow,\n\t\t\t[$style.appTable_wide]: isWide,\n\t\t}]\">\n\t\t<colgroup>\n\t\t\t<col :class=\"$style.appTable__colName\">\n\t\t\t<col :class=\"$style.appTable__colVersion\">\n\t\t\t<col v-if=\"!isNarrow\" :class=\"$style.appTable__colSupport\">\n\t\t\t<col v-if=\"isWide\" :class=\"$style.appTable__colGroups\">\n\t\t\t<col :class=\"$style.appTable__colActions\">\n\t\t</colgroup>\n\t\t<thead hidden>\n\t\t\t<tr>\n\t\t\t\t<th>{{ t('appstore', 'App name') }}</th>\n\t\t\t\t<th>{{ t('appstore', 'Version') }}</th>\n\t\t\t\t<th v-if=\"!isNarrow\">\n\t\t\t\t\t{{ t('appstore', 'Support level') }}\n\t\t\t\t</th>\n\t\t\t\t<th v-if=\"isWide\">\n\t\t\t\t\t{{ t('appstore', 'Groups') }}\n\t\t\t\t</th>\n\t\t\t\t<th>{{ t('appstore', 'Actions') }}</th>\n\t\t\t</tr>\n\t\t</thead>\n\t\t<tbody>\n\t\t\t<AppTableRow\n\t\t\t\tv-for=\"app in apps\"\n\t\t\t\t:key=\"app.id\"\n\t\t\t\t:app\n\t\t\t\t:isNarrow\n\t\t\t\t:isWide />\n\t\t</tbody>\n\t</table>\n</template>\n\n<style module>\n.appTable {\n\ttable-layout: fixed;\n\twidth: 100%;\n}\n\n.appTable__colName {\n\twidth: 45%;\n}\n\n.appTable_narrow .appTable__colName {\n\twidth: 60%;\n}\n\n.appTable_wide .appTable__colName {\n\twidth: 37%;\n}\n\n.appTable__colSupport {\n\twidth: 15%;\n}\n\n.appTable_wide .appTable__colSupport {\n\twidth: 12%;\n}\n\n.appTable__colActions {\n\twidth: 25%;\n}\n\n.appTable_wide .appTable__colActions {\n\twidth: 20%;\n}\n\n.appTable_narrow .appTable__colActions {\n\twidth: calc(3 * var(--default-grid-baseline) + 2 * var(--default-clickable-area));\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IAppBundle, IAppstoreApp } from '../apps.d.ts'\n\nimport { mdiDownloadMultiple } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { computed } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\nimport NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'\nimport AppTable from '../components/AppTable/AppTable.vue'\nimport { useAppsStore } from '../store/apps.ts'\nimport { canEnable } from '../utils/appStatus.ts'\n\nconst store = useAppsStore()\n\nconst appBundles = computed(() => store.bundles.map((bundle) => ({\n\t...bundle,\n\tapps: bundle.appIdentifiers\n\t\t.map((id) => store.apps.find((app) => app.id === id))\n\t\t.filter(Boolean) as IAppstoreApp[],\n\tisEnabling: false,\n})))\n\n/**\n * Check if a bundle can be enabled\n *\n * @param bundle - The bundle to check\n */\nfunction canEnableBundle(bundle: IAppBundle): boolean {\n\treturn bundle.appIdentifiers.every((id) => {\n\t\tconst app = store.apps.find((app) => app.id === id)\n\t\treturn app && (app.active || canEnable(app))\n\t})\n}\n\n/**\n * Check if a bundle is enabled\n *\n * @param bundle - The bundle to check\n */\nfunction isBundleEnabled(bundle: IAppBundle): boolean {\n\treturn bundle.appIdentifiers.every((id) => {\n\t\tconst app = store.apps.find((app) => app.id === id)\n\t\treturn app && app.active\n\t})\n}\n\n/**\n * Enable all apps in a bundle\n *\n * @param bundle - The bundle to enable all apps\n */\nasync function enableAll(bundle: typeof appBundles.value[number]) {\n\tbundle.isEnabling = true\n\tawait store.enableBundle(bundle.id)\n\tbundle.isEnabling = false\n}\n</script>\n\n<template>\n\t<!-- Apps list -->\n\t<NcEmptyContent\n\t\tv-if=\"store.isLoadingApps\"\n\t\t:name=\"t('appstore', 'Loading app list')\">\n\t\t<template #icon>\n\t\t\t<NcLoadingIcon :size=\"64\" />\n\t\t</template>\n\t</NcEmptyContent>\n\n\t<template v-else>\n\t\t<section v-for=\"bundle of appBundles\" :key=\"bundle.id\">\n\t\t\t<div :class=\"$style.appstoreBundles__header\">\n\t\t\t\t<h3>{{ bundle.name }}</h3>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"!isBundleEnabled(bundle)\"\n\t\t\t\t\t:disabled=\"!canEnableBundle(bundle)\"\n\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t@click=\"enableAll(bundle)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"mdiDownloadMultiple\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ t('appstore', 'Download and enable all') }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\n\t\t\t<AppTable\n\t\t\t\t:class=\"$style.appstoreBundles__appTable\"\n\t\t\t\t:apps=\"bundle.apps\" />\n\t\t</section>\n\t</template>\n</template>\n\n<style module>\n.appstoreBundles__header {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tjustify-content: space-between;\n\tgap: var(--default-clickable-area);\n\tpadding-inline: var(--default-grid-baseline);\n}\n\n.appstoreBundles__appTable:last-of-type {\n\tmargin-bottom: var(--body-container-margin);\n}\n</style>\n"],"file":"appstore-main.mjs"}