diff options
Diffstat (limited to 'apps/settings/src/components/AppList')
4 files changed, 104 insertions, 22 deletions
diff --git a/apps/settings/src/components/AppList/AppDaemonBadge.vue b/apps/settings/src/components/AppList/AppDaemonBadge.vue new file mode 100644 index 00000000000..ca81e7fab0b --- /dev/null +++ b/apps/settings/src/components/AppList/AppDaemonBadge.vue @@ -0,0 +1,37 @@ +<!-- + - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> +<template> + <span v-if="daemon" + class="app-daemon-badge" + :title="daemon.name"> + <NcIconSvgWrapper :path="mdiFileChart" :size="20" inline /> + {{ daemon.display_name }} + </span> +</template> + +<script setup lang="ts"> +import type { IDeployDaemon } from '../../app-types.ts' +import { mdiFileChart } from '@mdi/js' +import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' + +defineProps<{ + daemon?: IDeployDaemon +}>() +</script> + +<style scoped lang="scss"> +.app-daemon-badge { + color: var(--color-text-maxcontrast); + background-color: transparent; + border: 1px solid var(--color-text-maxcontrast); + border-radius: var(--border-radius); + + display: flex; + flex-direction: row; + gap: 6px; + padding: 3px 6px; + width: fit-content; +} +</style> diff --git a/apps/settings/src/components/AppList/AppItem.vue b/apps/settings/src/components/AppList/AppItem.vue index 881be612445..95a98a93cde 100644 --- a/apps/settings/src/components/AppList/AppItem.vue +++ b/apps/settings/src/components/AppList/AppItem.vue @@ -14,9 +14,13 @@ <component :is="dataItemTag" class="app-image app-image-icon" :headers="getDataItemHeaders(`app-table-col-icon`)"> - <div v-if="(listView && !app.preview) || (!listView && !screenshotLoaded)" class="icon-settings-dark" /> + <div v-if="!app?.app_api && shouldDisplayDefaultIcon" class="icon-settings-dark" /> + <NcIconSvgWrapper v-else-if="app.app_api && shouldDisplayDefaultIcon" + :path="mdiCogOutline" + :size="listView ? 24 : 48" + style="min-width: auto; min-height: auto; height: 100%;" /> - <svg v-else-if="listView && app.preview" + <svg v-else-if="listView && app.preview && !app.app_api" width="32" height="32" viewBox="0 0 32 32"> @@ -71,10 +75,11 @@ <div v-if="app.error" class="warning"> {{ app.error }} </div> - <div v-if="isLoading" class="icon icon-loading-small" /> + <div v-if="isLoading || isInitializing" class="icon icon-loading-small" /> <NcButton v-if="app.update" type="primary" - :disabled="installing || isLoading" + :disabled="installing || isLoading || !defaultDeployDaemonAccessible || isManualInstall" + :title="updateButtonText" @click.stop="update(app.id)"> {{ t('settings', 'Update to {update}', {update:app.update}) }} </NcButton> @@ -86,36 +91,46 @@ {{ t('settings', 'Remove') }} </NcButton> <NcButton v-if="app.active" - :disabled="installing || isLoading" + :disabled="installing || isLoading || isInitializing || isDeploying" @click.stop="disable(app.id)"> - {{ t('settings','Disable') }} + {{ disableButtonText }} </NcButton> <NcButton v-if="!app.active && (app.canInstall || app.isCompatible)" :title="enableButtonTooltip" :aria-label="enableButtonTooltip" type="primary" - :disabled="!app.canInstall || installing || isLoading" - @click.stop="enable(app.id)"> + :disabled="!app.canInstall || installing || isLoading || !defaultDeployDaemonAccessible || isInitializing || isDeploying" + @click.stop="enableButtonAction"> {{ enableButtonText }} </NcButton> <NcButton v-else-if="!app.active" :title="forceEnableButtonTooltip" :aria-label="forceEnableButtonTooltip" type="secondary" - :disabled="installing || isLoading" + :disabled="installing || isLoading || !defaultDeployDaemonAccessible" @click.stop="forceEnable(app.id)"> {{ forceEnableButtonText }} </NcButton> + + <DaemonSelectionDialog v-if="app?.app_api && showSelectDaemonModal" + :show.sync="showSelectDaemonModal" + :app="app" /> </component> </component> </template> <script> +import { useAppsStore } from '../../store/apps-store.js' + import AppScore from './AppScore.vue' import AppLevelBadge from './AppLevelBadge.vue' import AppManagement from '../../mixins/AppManagement.js' import SvgFilterMixin from '../SvgFilterMixin.vue' -import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' +import NcButton from '@nextcloud/vue/components/NcButton' +import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' +import { mdiCogOutline } from '@mdi/js' +import { useAppApiStore } from '../../store/app-api-store.ts' +import DaemonSelectionDialog from '../AppAPI/DaemonSelectionDialog.vue' export default { name: 'AppItem', @@ -123,6 +138,8 @@ export default { AppLevelBadge, AppScore, NcButton, + NcIconSvgWrapper, + DaemonSelectionDialog, }, mixins: [AppManagement, SvgFilterMixin], props: { @@ -151,11 +168,22 @@ export default { default: false, }, }, + setup() { + const store = useAppsStore() + const appApiStore = useAppApiStore() + + return { + store, + appApiStore, + mdiCogOutline, + } + }, data() { return { isSelected: false, scrolled: false, screenshotLoaded: false, + showSelectDaemonModal: false, } }, computed: { @@ -168,6 +196,9 @@ export default { withSidebar() { return !!this.$route.params.id }, + shouldDisplayDefaultIcon() { + return (this.listView && !this.app.preview) || (!this.listView && !this.screenshotLoaded) + }, }, watch: { '$route.params.id'(id) { @@ -195,6 +226,23 @@ export default { getDataItemHeaders(columnName) { return this.useBundleView ? [this.headers, columnName].join(' ') : null }, + showSelectionModal() { + this.showSelectDaemonModal = true + }, + async enableButtonAction() { + if (!this.app?.app_api) { + this.enable(this.app.id) + return + } + await this.appApiStore.fetchDockerDaemons() + if (this.appApiStore.dockerDaemons.length === 1 && this.app.needsDownload) { + this.enable(this.app.id, this.appApiStore.dockerDaemons[0]) + } else if (this.app.needsDownload) { + this.showSelectionModal() + } else { + this.enable(this.app.id, this.app.daemon) + } + }, }, } </script> @@ -228,7 +276,7 @@ export default { .app-image { width: var(--default-clickable-area); height: auto; - text-align: right; + text-align: end; } .app-image-icon svg, @@ -257,8 +305,7 @@ export default { .app-name--link::after { content: ''; position: absolute; - left: 0; - right: 0; + inset-inline: 0; height: var(--app-item-height); } @@ -271,7 +318,7 @@ export default { .icon-loading-small { display: inline-block; top: 4px; - margin-right: 10px; + margin-inline-end: 10px; } } @@ -317,10 +364,8 @@ export default { .app-name--link::after { content: ''; position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; + inset-block: 0; + inset-inline: 0; } .app-actions { diff --git a/apps/settings/src/components/AppList/AppLevelBadge.vue b/apps/settings/src/components/AppList/AppLevelBadge.vue index cceb5b0ecf9..8461f5eb6b9 100644 --- a/apps/settings/src/components/AppList/AppLevelBadge.vue +++ b/apps/settings/src/components/AppList/AppLevelBadge.vue @@ -13,9 +13,9 @@ </template> <script setup lang="ts"> -import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js' +import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' -import { mdiCheck, mdiStarShooting } from '@mdi/js' +import { mdiCheck, mdiStarShootingOutline } from '@mdi/js' import { translate as t } from '@nextcloud/l10n' import { computed } from 'vue' @@ -28,7 +28,7 @@ const props = defineProps<{ const isSupported = computed(() => props.level === 300) const isFeatured = computed(() => props.level === 200) -const badgeIcon = computed(() => isSupported.value ? mdiStarShooting : mdiCheck) +const badgeIcon = computed(() => isSupported.value ? mdiStarShootingOutline : mdiCheck) const badgeText = computed(() => isSupported.value ? t('settings', 'Supported') : t('settings', 'Featured')) const badgeTitle = computed(() => isSupported.value ? t('settings', 'This app is supported via your current Nextcloud subscription.') diff --git a/apps/settings/src/components/AppList/AppScore.vue b/apps/settings/src/components/AppList/AppScore.vue index 7eebc620a0b..a1dd4c03842 100644 --- a/apps/settings/src/components/AppList/AppScore.vue +++ b/apps/settings/src/components/AppList/AppScore.vue @@ -20,7 +20,7 @@ </span> </template> <script lang="ts"> -import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js' +import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' import { mdiStar, mdiStarHalfFull, mdiStarOutline } from '@mdi/js' import { translate as t } from '@nextcloud/l10n' import { defineComponent } from 'vue' |