diff options
Diffstat (limited to 'apps/settings/src/views')
-rw-r--r-- | apps/settings/src/views/AdminSettingsSharing.vue | 9 | ||||
-rw-r--r-- | apps/settings/src/views/AppStore.vue | 18 | ||||
-rw-r--r-- | apps/settings/src/views/AppStoreNavigation.vue | 20 | ||||
-rw-r--r-- | apps/settings/src/views/AppStoreSidebar.vue | 33 | ||||
-rw-r--r-- | apps/settings/src/views/SettingsApp.vue | 2 | ||||
-rw-r--r-- | apps/settings/src/views/UserManagement.vue | 11 | ||||
-rw-r--r-- | apps/settings/src/views/UserManagementNavigation.vue | 150 | ||||
-rw-r--r-- | apps/settings/src/views/user-types.d.ts | 17 |
8 files changed, 127 insertions, 133 deletions
diff --git a/apps/settings/src/views/AdminSettingsSharing.vue b/apps/settings/src/views/AdminSettingsSharing.vue index 8871beba0d9..d26fba6c8fa 100644 --- a/apps/settings/src/views/AdminSettingsSharing.vue +++ b/apps/settings/src/views/AdminSettingsSharing.vue @@ -16,13 +16,12 @@ </template> <script lang="ts"> -import { - NcNoteCard, - NcSettingsSection, -} from '@nextcloud/vue' import { loadState } from '@nextcloud/initial-state' -import { translate as t } from '@nextcloud/l10n' +import { t } from '@nextcloud/l10n' import { defineComponent } from 'vue' + +import NcNoteCard from '@nextcloud/vue/components/NcNoteCard' +import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection' import AdminSettingsSharingForm from '../components/AdminSettingsSharingForm.vue' export default defineComponent({ diff --git a/apps/settings/src/views/AppStore.vue b/apps/settings/src/views/AppStore.vue index 614cb9d2837..82c8c31e75d 100644 --- a/apps/settings/src/views/AppStore.vue +++ b/apps/settings/src/views/AppStore.vue @@ -23,20 +23,22 @@ <script setup lang="ts"> import { translate as t } from '@nextcloud/l10n' -import { computed, getCurrentInstance, onBeforeMount, watchEffect } from 'vue' +import { computed, getCurrentInstance, onBeforeMount, onBeforeUnmount, watchEffect } from 'vue' import { useRoute } from 'vue-router/composables' import { useAppsStore } from '../store/apps-store' import { APPS_SECTION_ENUM } from '../constants/AppsConstants' -import NcAppContent from '@nextcloud/vue/dist/Components/NcAppContent.js' -import NcEmptyContent from '@nextcloud/vue/dist/Components/NcEmptyContent.js' -import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' +import NcAppContent from '@nextcloud/vue/components/NcAppContent' +import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent' +import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon' import AppList from '../components/AppList.vue' import AppStoreDiscoverSection from '../components/AppStoreDiscover/AppStoreDiscoverSection.vue' +import { useAppApiStore } from '../store/app-api-store.ts' const route = useRoute() const store = useAppsStore() +const appApiStore = useAppApiStore() /** * ID of the current active category, default is `discover` @@ -60,6 +62,14 @@ onBeforeMount(() => { (instance?.proxy as any).$store.dispatch('getCategories', { shouldRefetchCategories: true }); // eslint-disable-next-line @typescript-eslint/no-explicit-any (instance?.proxy as any).$store.dispatch('getAllApps') + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if ((instance?.proxy as any).$store.getters.isAppApiEnabled) { + appApiStore.fetchAllApps() + appApiStore.updateAppsStatus() + } +}) +onBeforeUnmount(() => { + clearInterval(appApiStore.getStatusUpdater) }) </script> diff --git a/apps/settings/src/views/AppStoreNavigation.vue b/apps/settings/src/views/AppStoreNavigation.vue index 98aee80a802..83191baac40 100644 --- a/apps/settings/src/views/AppStoreNavigation.vue +++ b/apps/settings/src/views/AppStoreNavigation.vue @@ -6,7 +6,8 @@ <!-- Categories & filters --> <NcAppNavigation :aria-label="t('settings', 'Apps')"> <template #list> - <NcAppNavigationItem id="app-category-discover" + <NcAppNavigationItem v-if="appstoreEnabled" + id="app-category-discover" :to="{ name: 'apps-category', params: { category: 'discover'} }" :name="APPS_SECTION_ENUM.discover"> <template #icon> @@ -34,12 +35,12 @@ <NcIconSvgWrapper :path="APPSTORE_CATEGORY_ICONS.disabled" /> </template> </NcAppNavigationItem> - <NcAppNavigationItem v-if="updateCount > 0" + <NcAppNavigationItem v-if="store.updateCount > 0" id="app-category-updates" :to="{ name: 'apps-category', params: { category: 'updates' } }" :name="APPS_SECTION_ENUM.updates"> <template #counter> - <NcCounterBubble>{{ updateCount }}</NcCounterBubble> + <NcCounterBubble>{{ store.updateCount }}</NcCounterBubble> </template> <template #icon> <NcIconSvgWrapper :path="APPSTORE_CATEGORY_ICONS.updates" /> @@ -104,16 +105,15 @@ import { computed, onBeforeMount } from 'vue' import { APPS_SECTION_ENUM } from '../constants/AppsConstants' import { useAppsStore } from '../store/apps-store' -import NcAppNavigation from '@nextcloud/vue/dist/Components/NcAppNavigation.js' -import NcAppNavigationItem from '@nextcloud/vue/dist/Components/NcAppNavigationItem.js' -import NcAppNavigationSpacer from '@nextcloud/vue/dist/Components/NcAppNavigationSpacer.js' -import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js' -import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js' -import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' +import NcAppNavigation from '@nextcloud/vue/components/NcAppNavigation' +import NcAppNavigationItem from '@nextcloud/vue/components/NcAppNavigationItem' +import NcAppNavigationSpacer from '@nextcloud/vue/components/NcAppNavigationSpacer' +import NcCounterBubble from '@nextcloud/vue/components/NcCounterBubble' +import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' +import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon' import APPSTORE_CATEGORY_ICONS from '../constants/AppstoreCategoryIcons.ts' -const updateCount = loadState<number>('settings', 'appstoreUpdateCount', 0) const appstoreEnabled = loadState<boolean>('settings', 'appstoreEnabled', true) const developerDocsUrl = loadState<string>('settings', 'appstoreDeveloperDocs', '') diff --git a/apps/settings/src/views/AppStoreSidebar.vue b/apps/settings/src/views/AppStoreSidebar.vue index 5811b26b56e..b4041066c67 100644 --- a/apps/settings/src/views/AppStoreSidebar.vue +++ b/apps/settings/src/views/AppStoreSidebar.vue @@ -26,6 +26,7 @@ <!-- Featured/Supported badges --> <div class="app-sidebar__badges"> <AppLevelBadge :level="app.level" /> + <AppDaemonBadge v-if="app.app_api && app.daemon" :daemon="app.daemon" /> <AppScore v-if="hasRating" :score="rating" /> </div> </template> @@ -34,6 +35,7 @@ <AppDescriptionTab :app="app" /> <AppDetailsTab :app="app" /> <AppReleasesTab :app="app" /> + <AppDeployDaemonTab :app="app" /> </NcAppSidebar> </template> @@ -43,21 +45,36 @@ import { computed, onMounted, ref, watch } from 'vue' import { useRoute, useRouter } from 'vue-router/composables' import { useAppsStore } from '../store/apps-store' -import NcAppSidebar from '@nextcloud/vue/dist/Components/NcAppSidebar.js' -import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js' +import NcAppSidebar from '@nextcloud/vue/components/NcAppSidebar' +import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' import AppScore from '../components/AppList/AppScore.vue' import AppDescriptionTab from '../components/AppStoreSidebar/AppDescriptionTab.vue' import AppDetailsTab from '../components/AppStoreSidebar/AppDetailsTab.vue' import AppReleasesTab from '../components/AppStoreSidebar/AppReleasesTab.vue' +import AppDeployDaemonTab from '../components/AppStoreSidebar/AppDeployDaemonTab.vue' import AppLevelBadge from '../components/AppList/AppLevelBadge.vue' +import AppDaemonBadge from '../components/AppList/AppDaemonBadge.vue' import { useAppIcon } from '../composables/useAppIcon.ts' +import { useStore } from '../store' +import { useAppApiStore } from '../store/app-api-store.ts' const route = useRoute() const router = useRouter() const store = useAppsStore() +const appApiStore = useAppApiStore() +const legacyStore = useStore() const appId = computed(() => route.params.id ?? '') -const app = computed(() => store.getAppById(appId.value)!) +const app = computed(() => { + if (legacyStore.getters.isAppApiEnabled) { + const exApp = appApiStore.getAllApps + .find((app) => app.id === appId.value) ?? null + if (exApp) { + return exApp + } + } + return store.getAppById(appId.value)! +}) const hasRating = computed(() => app.value.appstoreData?.ratingNumOverall > 5) const rating = computed(() => app.value.appstoreData?.ratingNumRecent > 5 ? app.value.appstoreData.ratingRecent @@ -69,7 +86,15 @@ const { appIcon } = useAppIcon(app) /** * The second text line shown on the sidebar */ -const licenseText = computed(() => app.value ? t('settings', 'Version {version}, {license}-licensed', { version: app.value.version, license: app.value.licence.toString().toUpperCase() }) : '') +const licenseText = computed(() => { + if (!app.value) { + return '' + } + if (app.value.license !== '') { + return t('settings', 'Version {version}, {license}-licensed', { version: app.value.version, license: app.value.licence.toString().toUpperCase() }) + } + return t('settings', 'Version {version}', { version: app.value.version }) +}) const activeTab = ref('details') watch([app], () => { activeTab.value = 'details' }) diff --git a/apps/settings/src/views/SettingsApp.vue b/apps/settings/src/views/SettingsApp.vue index e8231333a68..7e135175ef6 100644 --- a/apps/settings/src/views/SettingsApp.vue +++ b/apps/settings/src/views/SettingsApp.vue @@ -12,5 +12,5 @@ </template> <script setup lang="ts"> -import NcContent from '@nextcloud/vue/dist/Components/NcContent.js' +import NcContent from '@nextcloud/vue/components/NcContent' </script> diff --git a/apps/settings/src/views/UserManagement.vue b/apps/settings/src/views/UserManagement.vue index 4c1797d8b90..9ab76f921a0 100644 --- a/apps/settings/src/views/UserManagement.vue +++ b/apps/settings/src/views/UserManagement.vue @@ -12,9 +12,10 @@ <script> import { translate as t } from '@nextcloud/l10n' +import { emit } from '@nextcloud/event-bus' import { defineComponent } from 'vue' -import NcAppContent from '@nextcloud/vue/dist/Components/NcAppContent.js' +import NcAppContent from '@nextcloud/vue/components/NcAppContent' import UserList from '../components/UserList.vue' export default defineComponent({ @@ -35,7 +36,7 @@ export default defineComponent({ computed: { pageHeading() { if (this.selectedGroupDecoded === null) { - return t('settings', 'Active accounts') + return t('settings', 'All accounts') } const matchHeading = { admin: t('settings', 'Admins'), @@ -54,11 +55,6 @@ export default defineComponent({ }, beforeMount() { - this.$store.commit('initGroups', { - groups: this.$store.getters.getServerData.groups, - orderBy: this.$store.getters.getServerData.sortGroups, - userCount: this.$store.getters.getServerData.userCount, - }) this.$store.dispatch('getPasswordPolicyMinLength') }, @@ -69,6 +65,7 @@ export default defineComponent({ window.OCA.Settings.UserList = window.OCA.Settings.UserList ?? {} // and add the registerAction method window.OCA.Settings.UserList.registerAction = this.registerAction + emit('settings:user-management:loaded') }, methods: { diff --git a/apps/settings/src/views/UserManagementNavigation.vue b/apps/settings/src/views/UserManagementNavigation.vue index 0c98784135b..95a12ac7c51 100644 --- a/apps/settings/src/views/UserManagementNavigation.vue +++ b/apps/settings/src/views/UserManagementNavigation.vue @@ -3,7 +3,8 @@ - SPDX-License-Identifier: AGPL-3.0-or-later --> <template> - <NcAppNavigation :aria-label="t('settings', 'Account management')"> + <NcAppNavigation class="account-management__navigation" + :aria-label="t('settings', 'Account management')"> <NcAppNavigationNew button-id="new-user-button" :text="t('settings','New account')" @click="showNewUserMenu" @@ -18,10 +19,10 @@ data-cy-users-settings-navigation-groups="system"> <NcAppNavigationItem id="everyone" :exact="true" - :name="t('settings', 'Active accounts')" + :name="t('settings', 'All accounts')" :to="{ name: 'users' }"> <template #icon> - <NcIconSvgWrapper :path="mdiAccount" /> + <NcIconSvgWrapper :path="mdiAccountOutline" /> </template> <template #counter> <NcCounterBubble v-if="userCount" :type="!selectedGroupDecoded ? 'highlighted' : undefined"> @@ -30,13 +31,13 @@ </template> </NcAppNavigationItem> - <NcAppNavigationItem v-if="isAdmin" + <NcAppNavigationItem v-if="settings.isAdmin" id="admin" :exact="true" :name="t('settings', 'Admins')" :to="{ name: 'group', params: { selectedGroup: 'admin' } }"> <template #icon> - <NcIconSvgWrapper :path="mdiShieldAccount" /> + <NcIconSvgWrapper :path="mdiShieldAccountOutline" /> </template> <template #counter> <NcCounterBubble v-if="adminGroup && adminGroup.count > 0" @@ -46,6 +47,22 @@ </template> </NcAppNavigationItem> + <NcAppNavigationItem v-if="isAdminOrDelegatedAdmin" + id="recent" + :exact="true" + :name="t('settings', 'Recently active')" + :to="{ name: 'group', params: { selectedGroup: '__nc_internal_recent' } }"> + <template #icon> + <NcIconSvgWrapper :path="mdiHistory" /> + </template> + <template #counter> + <NcCounterBubble v-if="recentGroup?.usercount" + :type="selectedGroupDecoded === '__nc_internal_recent' ? 'highlighted' : undefined"> + {{ recentGroup.usercount }} + </NcCounterBubble> + </template> + </NcAppNavigationItem> + <!-- Hide the disabled if none, if we don't have the data (-1) show it --> <NcAppNavigationItem v-if="disabledGroup && (disabledGroup.usercount > 0 || disabledGroup.usercount === -1)" id="disabled" @@ -53,7 +70,7 @@ :name="t('settings', 'Disabled accounts')" :to="{ name: 'group', params: { selectedGroup: 'disabled' } }"> <template #icon> - <NcIconSvgWrapper :path="mdiAccountOff" /> + <NcIconSvgWrapper :path="mdiAccountOffOutline" /> </template> <template v-if="disabledGroup.usercount > 0" #counter> <NcCounterBubble :type="selectedGroupDecoded === 'disabled' ? 'highlighted' : undefined"> @@ -63,49 +80,14 @@ </NcAppNavigationItem> </NcAppNavigationList> - <NcAppNavigationCaption :name="t('settings', 'Groups')" - :disabled="loadingAddGroup" - :aria-label="loadingAddGroup ? t('settings', 'Creating group…') : t('settings', 'Create group')" - force-menu - is-heading - :open.sync="isAddGroupOpen"> - <template #actionsTriggerIcon> - <NcLoadingIcon v-if="loadingAddGroup" /> - <NcIconSvgWrapper v-else :path="mdiPlus" /> - </template> - <template #actions> - <NcActionText> - <template #icon> - <AccountGroup :size="20" /> - </template> - {{ t('settings', 'Create group') }} - </NcActionText> - <NcActionInput :label="t('settings', 'Group name')" - data-cy-users-settings-new-group-name - :label-outside="false" - :disabled="loadingAddGroup" - :value.sync="newGroupName" - :error="hasAddGroupError" - :helper-text="hasAddGroupError ? t('settings', 'Please enter a valid group name') : ''" - @submit="createGroup" /> - </template> - </NcAppNavigationCaption> - - <NcAppNavigationList class="account-management__group-list" data-cy-users-settings-navigation-groups="custom"> - <GroupListItem v-for="group in userGroups" - :id="group.id" - :key="group.id" - :active="selectedGroupDecoded === group.id" - :name="group.title" - :count="group.count" /> - </NcAppNavigationList> + <AppNavigationGroupList /> <template #footer> <NcButton class="account-management__settings-toggle" type="tertiary" @click="isDialogOpen = true"> <template #icon> - <NcIconSvgWrapper :path="mdiCog" /> + <NcIconSvgWrapper :path="mdiCogOutline" /> </template> {{ t('settings', 'Account management settings') }} </NcButton> @@ -115,31 +97,26 @@ </template> <script setup lang="ts"> -import { mdiAccount, mdiAccountOff, mdiCog, mdiPlus, mdiShieldAccount } from '@mdi/js' -import { showError } from '@nextcloud/dialogs' +import { mdiAccountOutline, mdiAccountOffOutline, mdiCogOutline, mdiPlus, mdiShieldAccountOutline, mdiHistory } from '@mdi/js' import { translate as t } from '@nextcloud/l10n' import { computed, ref } from 'vue' -import NcActionInput from '@nextcloud/vue/dist/Components/NcActionInput.js' -import NcActionText from '@nextcloud/vue/dist/Components/NcActionText.js' -import NcAppNavigation from '@nextcloud/vue/dist/Components/NcAppNavigation.js' -import NcAppNavigationCaption from '@nextcloud/vue/dist/Components/NcAppNavigationCaption.js' -import NcAppNavigationItem from '@nextcloud/vue/dist/Components/NcAppNavigationItem.js' -import NcAppNavigationList from '@nextcloud/vue/dist/Components/NcAppNavigationList.js' -import NcAppNavigationNew from '@nextcloud/vue/dist/Components/NcAppNavigationNew.js' -import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' -import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js' -import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js' -import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' - -import GroupListItem from '../components/GroupListItem.vue' +import NcAppNavigation from '@nextcloud/vue/components/NcAppNavigation' +import NcAppNavigationItem from '@nextcloud/vue/components/NcAppNavigationItem' +import NcAppNavigationList from '@nextcloud/vue/components/NcAppNavigationList' +import NcAppNavigationNew from '@nextcloud/vue/components/NcAppNavigationNew' +import NcButton from '@nextcloud/vue/components/NcButton' +import NcCounterBubble from '@nextcloud/vue/components/NcCounterBubble' +import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' + import UserSettingsDialog from '../components/Users/UserSettingsDialog.vue' +import AppNavigationGroupList from '../components/AppNavigationGroupList.vue' + import { useStore } from '../store' -import { useRoute, useRouter } from 'vue-router/composables' +import { useRoute } from 'vue-router/composables' import { useFormatGroups } from '../composables/useGroupsNavigation' const route = useRoute() -const router = useRouter() const store = useStore() /** State of the 'new-account' dialog */ @@ -154,48 +131,12 @@ const selectedGroupDecoded = computed(() => selectedGroup.value ? decodeURICompo const userCount = computed(() => store.getters.getUserCount) /** All available groups */ const groups = computed(() => store.getters.getSortedGroups) -const { adminGroup, disabledGroup, userGroups } = useFormatGroups(groups) - -/** True if the current user is an administrator */ -const isAdmin = computed(() => store.getters.getServerData.isAdmin) +const { adminGroup, recentGroup, disabledGroup } = useFormatGroups(groups) -/** True if the 'add-group' dialog is open - needed to be able to close it when the group is created */ -const isAddGroupOpen = ref(false) -/** True if the group creation is in progress to show loading spinner and disable adding another one */ -const loadingAddGroup = ref(false) -/** Error state for creating a new group */ -const hasAddGroupError = ref(false) -/** Name of the group to create (used in the group creation dialog) */ -const newGroupName = ref('') - -/** - * Create a new group - */ -async function createGroup() { - hasAddGroupError.value = false - const groupId = newGroupName.value.trim() - if (groupId === '') { - hasAddGroupError.value = true - return - } - - isAddGroupOpen.value = false - loadingAddGroup.value = true - - try { - await store.dispatch('addGroup', groupId) - await router.push({ - name: 'group', - params: { - selectedGroup: encodeURIComponent(groupId), - }, - }) - newGroupName.value = '' - } catch { - showError(t('settings', 'Failed to create group')) - } - loadingAddGroup.value = false -} +/** Server settings for current user */ +const settings = computed(() => store.getters.getServerData) +/** True if the current user is a (delegated) admin */ +const isAdminOrDelegatedAdmin = computed(() => settings.value.isAdmin || settings.value.isDelegatedAdmin) /** * Open the new-user form dialog @@ -209,7 +150,12 @@ function showNewUserMenu() { </script> <style scoped lang="scss"> -.account-management{ +.account-management { + &__navigation { + :deep(.app-navigation__body) { + will-change: scroll-position; + } + } &__system-list { height: auto !important; overflow: visible !important; diff --git a/apps/settings/src/views/user-types.d.ts b/apps/settings/src/views/user-types.d.ts index b8cd30e53d9..21c63a13b03 100644 --- a/apps/settings/src/views/user-types.d.ts +++ b/apps/settings/src/views/user-types.d.ts @@ -3,7 +3,14 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ export interface IGroup { + /** + * Id + */ id: string + + /** + * Display name + */ name: string /** @@ -15,4 +22,14 @@ export interface IGroup { * Number of disabled users */ disabled: number + + /** + * True if users can be added to this group + */ + canAdd?: boolean + + /** + * True if users can be removed from this group + */ + canRemove?: boolean } |