mirror of
https://github.com/nextcloud/server.git
synced 2026-10-18 05:49:26 +02:00
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
1 line
15 KiB
Plaintext
1 line
15 KiB
Plaintext
{"version":3,"file":"core-recommendedapps.mjs","sources":["../build/frontend/core/src/components/setup/RecommendedApps.vue","../build/frontend/core/src/recommendedapps.ts"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { IAppstoreApp } from '../../../../apps/appstore/src/apps.d.ts'\n\nimport { loadState } from '@nextcloud/initial-state'\nimport { t } from '@nextcloud/l10n'\nimport { imagePath } from '@nextcloud/router'\nimport { computed, onMounted, ref } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'\nimport * as appstoreApi from '../../../../apps/appstore/src/service/api.ts'\nimport { canInstall } from '../../../../apps/appstore/src/utils/appStatus.ts'\nimport { logger } from '../../utils/logger.ts'\n\ninterface RecommendedApp extends IAppstoreApp {\n\tloading: boolean\n\tisSelected: boolean\n\terror?: string\n}\n\ninterface Recommendation {\n\tname?: string\n\tdescription?: string\n\ticon?: string\n\t/** Installed along with the other apps, but not offered on its own */\n\thidden?: boolean\n\t/** The apps it is installed along with */\n\trequired?: string[]\n}\n\nconst recommended: Record<string, Recommendation> = {\n\tcalendar: {\n\t\tdescription: t('core', 'Schedule work & meetings, synced with all your devices.'),\n\t\ticon: imagePath('core', 'places/calendar.svg'),\n\t},\n\tcontacts: {\n\t\tdescription: t('core', 'Keep your colleagues and friends in one place without leaking their private info.'),\n\t\ticon: imagePath('core', 'places/contacts.svg'),\n\t},\n\tmail: {\n\t\tdescription: t('core', 'Simple email app nicely integrated with Files, Contacts and Calendar.'),\n\t\ticon: imagePath('core', 'actions/mail.svg'),\n\t},\n\tspreed: {\n\t\tdescription: t('core', 'Chatting, video calls, screen sharing, online meetings and web conferencing – in your browser and with mobile apps.'),\n\t\ticon: imagePath('core', 'apps/spreed.svg'),\n\t},\n\trichdocuments: {\n\t\tname: 'Nextcloud Office',\n\t\tdescription: t('core', 'Collaborative documents, spreadsheets and presentations, built on Collabora Online.'),\n\t\ticon: imagePath('core', 'apps/richdocuments.svg'),\n\t},\n\tnotes: {\n\t\tdescription: t('core', 'Distraction free note taking app.'),\n\t\ticon: imagePath('core', 'apps/notes.svg'),\n\t},\n\trichdocumentscode: {\n\t\thidden: true,\n\t\trequired: ['richdocuments'],\n\t},\n}\n\nconst defaultPageUrl = loadState<string>('core', 'defaultPageUrl')\n\nconst showInstallButton = ref(false)\nconst installingApps = ref(false)\nconst loadingApps = ref(true)\nconst loadingAppsError = ref(false)\nconst recommendedApps = ref<RecommendedApp[]>([])\n\nconst isAnyAppSelected = computed(() => recommendedApps.value.some((app) => app.isSelected && !app.active))\n\nonMounted(async () => {\n\ttry {\n\t\tconst apps = await appstoreApi.getApps()\n\t\tlogger.info(`${apps.length} apps fetched`)\n\n\t\trecommendedApps.value = apps\n\t\t\t.filter((app) => app.id in recommended)\n\t\t\t.map((app) => ({\n\t\t\t\t...app,\n\t\t\t\tloading: false,\n\t\t\t\tisSelected: app.isCompatible && !isHidden(app.id),\n\t\t\t}))\n\t\tlogger.debug(`${recommendedApps.value.length} recommended apps found`, { apps: recommendedApps.value })\n\n\t\tshowInstallButton.value = true\n\t} catch (error) {\n\t\tlogger.error('could not fetch app list', { error })\n\t\tloadingAppsError.value = true\n\t} finally {\n\t\tloadingApps.value = false\n\t}\n})\n\n/**\n * Install the selected apps and the hidden apps they require.\n */\nasync function installApps() {\n\tconst availableApps = recommendedApps.value.filter((app) => app.active || (app.isSelected && canInstall(app)))\n\tconst appsToInstall = [\n\t\t...availableApps.filter((app) => !app.active && app.isSelected),\n\t\t...recommendedApps.value.filter((app) => isHidden(app.id)\n\t\t\t&& (recommended[app.id]!.required ?? []).every((requiredAppId) => availableApps.some((requiredApp) => requiredApp.id === requiredAppId))),\n\t]\n\n\tlogger.debug(`Installing ${appsToInstall.length} recommended apps`, { appIds: appsToInstall.map((app) => app.id) })\n\tinstallingApps.value = true\n\tfor (const app of appsToInstall) {\n\t\tapp.loading = true\n\t}\n\n\tconst results = await Promise.allSettled(appsToInstall.map((app) => appstoreApi.enableApp(app.id)))\n\tresults.forEach((result, index) => {\n\t\tconst app = appsToInstall[index]!\n\t\tapp.loading = false\n\t\tif (result.status === 'fulfilled') {\n\t\t\tapp.active = true\n\t\t\treturn\n\t\t}\n\n\t\tif (result.reason instanceof Error && result.reason.message === 'Dialog closed') {\n\t\t\tlogger.info(`User cancelled the password confirmation for recommended app ${app.id}`)\n\t\t\tapp.error = t('core', 'Password confirmation was aborted')\n\t\t} else {\n\t\t\tlogger.error(`could not install recommended app ${app.id}`, { error: result.reason })\n\t\t\tapp.error = t('core', 'App download or installation failed')\n\t\t}\n\t\tapp.isSelected = false\n\t})\n\tinstallingApps.value = false\n}\n\n/**\n * @param appId - The app id\n */\nfunction customIcon(appId: string): string {\n\tconst icon = recommended[appId]?.icon\n\tif (!icon) {\n\t\tlogger.warn(`no app icon for recommended app ${appId}`)\n\t\treturn imagePath('core', 'places/default-app-icon.svg')\n\t}\n\treturn icon\n}\n\n/**\n * @param app - The app\n */\nfunction customName(app: RecommendedApp): string {\n\treturn recommended[app.id]?.name || app.name\n}\n\n/**\n * @param appId - The app id\n */\nfunction customDescription(appId: string): string {\n\tconst description = recommended[appId]?.description\n\tif (description === undefined) {\n\t\tlogger.warn(`no app description for recommended app ${appId}`)\n\t\treturn ''\n\t}\n\treturn description\n}\n\n/**\n * @param appId - The app id\n */\nfunction isHidden(appId: string): boolean {\n\treturn !!recommended[appId]?.hidden\n}\n\n/**\n * @param app - The app to (de)select for installation\n */\nfunction toggleSelect(app: RecommendedApp) {\n\t// nothing can be selected while the apps are loading or installing\n\tif (!showInstallButton.value) {\n\t\treturn\n\t}\n\tapp.isSelected = !app.isSelected\n}\n</script>\n\n<template>\n\t<div class=\"guest-box\" data-cy-setup-recommended-apps>\n\t\t<h2>{{ t('core', 'Recommended apps') }}</h2>\n\t\t<p v-if=\"loadingApps\" class=\"loading\" :class=\"[$style.status]\">\n\t\t\t{{ t('core', 'Loading apps …') }}\n\t\t</p>\n\t\t<p v-else-if=\"loadingAppsError\" :class=\"$style.status\">\n\t\t\t{{ t('core', 'Could not fetch list of apps from the App Store.') }}\n\t\t</p>\n\n\t\t<template v-for=\"app in recommendedApps\" :key=\"app.id\">\n\t\t\t<div v-if=\"!isHidden(app.id)\" :class=\"$style.app\">\n\t\t\t\t<img :class=\"$style.app__icon\" :src=\"customIcon(app.id)\" alt=\"\">\n\t\t\t\t<div :class=\"$style.app__info\">\n\t\t\t\t\t<h3>{{ customName(app) }}</h3>\n\t\t\t\t\t<p v-text=\"customDescription(app.id)\" />\n\t\t\t\t\t<p v-if=\"app.error\">\n\t\t\t\t\t\t<strong>{{ app.error }}</strong>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p v-else-if=\"app.active\">\n\t\t\t\t\t\t<strong>{{ t('core', 'App already installed') }}</strong>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p v-else-if=\"!app.isCompatible\">\n\t\t\t\t\t\t<strong>{{ t('core', 'Cannot install this app because it is not compatible') }}</strong>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p v-else-if=\"!canInstall(app)\">\n\t\t\t\t\t\t<strong>{{ t('core', 'Cannot install this app') }}</strong>\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t:class=\"$style.app__switch\"\n\t\t\t\t\t:modelValue=\"app.isSelected || app.active\"\n\t\t\t\t\t:disabled=\"!app.isCompatible || app.active\"\n\t\t\t\t\t:loading=\"app.loading\"\n\t\t\t\t\t@update:modelValue=\"toggleSelect(app)\" />\n\t\t\t</div>\n\t\t</template>\n\n\t\t<div :class=\"$style.actions\">\n\t\t\t<NcButton\n\t\t\t\tv-if=\"showInstallButton && !installingApps\"\n\t\t\t\tdata-cy-setup-recommended-apps-skip\n\t\t\t\t:href=\"defaultPageUrl\"\n\t\t\t\tvariant=\"tertiary\">\n\t\t\t\t{{ t('core', 'Skip') }}\n\t\t\t</NcButton>\n\n\t\t\t<NcButton\n\t\t\t\tv-if=\"showInstallButton\"\n\t\t\t\tdata-cy-setup-recommended-apps-install\n\t\t\t\t:disabled=\"installingApps || !isAnyAppSelected\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t@click=\"installApps\">\n\t\t\t\t{{ installingApps ? t('core', 'Installing apps …') : t('core', 'Install recommended apps') }}\n\t\t\t</NcButton>\n\t\t</div>\n\t</div>\n</template>\n\n<style module lang=\"scss\">\n.actions {\n\tdisplay: flex;\n\tjustify-content: end;\n\tmargin-top: 8px;\n}\n\n.status {\n\theight: 100px;\n\ttext-align: center;\n}\n\n.app {\n\tdisplay: flex;\n\tflex-direction: row;\n\n\t&__icon {\n\t\theight: 50px;\n\t\twidth: 50px;\n\t\tpadding: 12px;\n\t\tfilter: var(--background-invert-if-dark);\n\t}\n\n\t&__info {\n\t\tpadding: 12px;\n\n\t\th3, p {\n\t\t\ttext-align: start;\n\t\t}\n\n\t\th3 {\n\t\t\tmargin-top: 0;\n\t\t}\n\n\t\tp:last-child {\n\t\t\tmargin-top: 10px;\n\t\t}\n\t}\n\n\t&__switch {\n\t\tmargin-inline-start: auto;\n\t\tpadding: 0 2px;\n\t}\n}\n</style>\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport axios from '@nextcloud/axios'\nimport { addPasswordConfirmationInterceptors } from '@nextcloud/password-confirmation'\nimport { createApp } from 'vue'\nimport RecommendedApps from './components/setup/RecommendedApps.vue'\n\naddPasswordConfirmationInterceptors(axios)\n\ncreateApp(RecommendedApps).mount('#recommended-apps')\n"],"names":["recommended","t","imagePath","defaultPageUrl","loadState","showInstallButton","ref","installingApps","loadingApps","loadingAppsError","recommendedApps","isAnyAppSelected","computed","app","onMounted","apps","appstoreApi.getApps","logger","isHidden","error","installApps","availableApps","canInstall","appsToInstall","requiredAppId","requiredApp","appstoreApi.enableApp","result","index","customIcon","appId","customName","customDescription","description","toggleSelect","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_unref","_normalizeClass","$style","_Fragment","_renderList","_toDisplayString","_hoisted_4","_hoisted_5","_hoisted_7","_hoisted_6","_createVNode","NcCheckboxRadioSwitch","$event","_createBlock","NcButton","addPasswordConfirmationInterceptors","axios","createApp","RecommendedApps"],"mappings":"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"} |