aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2024-02-22 16:45:42 +0100
committerFerdinand Thiessen <opensource@fthiessen.de>2024-03-11 16:02:34 +0100
commit1100e908b79ddecd1198c682ac3dcc41f2871122 (patch)
tree3f7e61648adcccaec1a5b6c7f67ab1c3b6c59b65 /apps
parent2b794b41ad0eb9610674fc44543006a9da9d624e (diff)
downloadnextcloud-server-1100e908b79ddecd1198c682ac3dcc41f2871122.tar.gz
nextcloud-server-1100e908b79ddecd1198c682ac3dcc41f2871122.zip
feat(settings): Split account management and app store views into chunks
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps')
-rw-r--r--apps/settings/src/app-types.ts70
-rw-r--r--apps/settings/src/components/AppList.vue32
-rw-r--r--apps/settings/src/store/apps.js1
-rw-r--r--apps/settings/src/views/AppStore.vue73
-rw-r--r--apps/settings/src/views/UserManagement.vue (renamed from apps/settings/src/views/Users.vue)210
-rw-r--r--apps/settings/src/views/UserManagementNavigation.vue5
6 files changed, 258 insertions, 133 deletions
diff --git a/apps/settings/src/app-types.ts b/apps/settings/src/app-types.ts
new file mode 100644
index 00000000000..99f0c1ef679
--- /dev/null
+++ b/apps/settings/src/app-types.ts
@@ -0,0 +1,70 @@
+/**
+ * @copyright Copyright (c) 2024 Ferdinand Thiessen <opensource@fthiessen.de>
+ *
+ * @author Ferdinand Thiessen <opensource@fthiessen.de>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+export interface IAppstoreCategory {
+ /**
+ * The category ID
+ */
+ id: string
+ /**
+ * The display name (can be localized)
+ */
+ displayName: string
+ /**
+ * Inline SVG path
+ */
+ icon: string
+}
+
+export interface IAppstoreAppRelease {
+ version: string
+ translations: {
+ [key: string]: {
+ changelog: string
+ }
+ }
+}
+
+export interface IAppstoreApp {
+ id: string
+ name: string
+ summary: string
+ description: string
+ licence: string
+ author: string[] | Record<string, string>
+ level: number
+ version: string
+ category: string|string[]
+
+ preview?: string
+ screenshot?: string
+
+ active: boolean
+ internal: boolean
+ removeable: boolean
+ installed: boolean
+ canInstall: boolean
+ canUninstall: boolean
+ isCompatible: boolean
+
+ appstoreData: Record<string, never>
+ releases: IAppstoreAppRelease[]
+}
diff --git a/apps/settings/src/components/AppList.vue b/apps/settings/src/components/AppList.vue
index 324fa6b0537..320d6a60e95 100644
--- a/apps/settings/src/components/AppList.vue
+++ b/apps/settings/src/components/AppList.vue
@@ -139,6 +139,7 @@
</template>
<script>
+import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import AppItem from './AppList/AppItem.vue'
import pLimit from 'p-limit'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
@@ -149,7 +150,19 @@ export default {
AppItem,
NcButton,
},
- props: ['category'],
+
+ props: {
+ category: {
+ type: String,
+ required: true,
+ },
+ },
+
+ data() {
+ return {
+ search: '',
+ }
+ },
computed: {
counter() {
return this.apps.filter(app => app.update).length
@@ -247,7 +260,24 @@ export default {
}
},
},
+
+ beforeDestroy() {
+ unsubscribe('nextcloud:unified-search.search', this.setSearch)
+ unsubscribe('nextcloud:unified-search.reset', this.resetSearch)
+ },
+
+ beforeCreate() {
+ subscribe('nextcloud:unified-search.search', this.setSearch)
+ subscribe('nextcloud:unified-search.reset', this.resetSearch)
+ },
+
methods: {
+ setSearch(value) {
+ this.search = value
+ },
+ resetSearch() {
+ this.search = ''
+ },
toggleBundle(id) {
if (this.allBundlesEnabled(id)) {
return this.disableBundle(id)
diff --git a/apps/settings/src/store/apps.js b/apps/settings/src/store/apps.js
index b6cf640fcb9..b8528f58412 100644
--- a/apps/settings/src/store/apps.js
+++ b/apps/settings/src/store/apps.js
@@ -34,7 +34,6 @@ const state = {
categories: [],
updateCount: loadState('settings', 'appstoreUpdateCount', 0),
loading: {},
- loadingList: false,
gettingCategoriesPromise: null,
}
diff --git a/apps/settings/src/views/AppStore.vue b/apps/settings/src/views/AppStore.vue
index 06c47611238..3c3c53d4330 100644
--- a/apps/settings/src/views/AppStore.vue
+++ b/apps/settings/src/views/AppStore.vue
@@ -1,42 +1,51 @@
<!--
- - @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
- -
- - @author Julius Härtl <jus@bitgrid.net>
- - @author Ferdinand Thiessen <opensource@fthiessen.de>
- -
- - @license AGPL-3.0-or-later
- -
- - This program is free software: you can redistribute it and/or modify
- - it under the terms of the GNU Affero General Public License as
- - published by the Free Software Foundation, either version 3 of the
- - License, or (at your option) any later version.
- -
- - This program is distributed in the hope that it will be useful,
- - but WITHOUT ANY WARRANTY; without even the implied warranty of
- - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- - GNU Affero General Public License for more details.
- -
- - You should have received a copy of the GNU Affero General Public License
- - along with this program. If not, see <http://www.gnu.org/licenses/>.
- -
- -->
+ - @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
+ -
+ - @author Julius Härtl <jus@bitgrid.net>
+ - @author Ferdinand Thiessen <opensource@fthiessen.de>
+ -
+ - @license AGPL-3.0-or-later
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -
+ -->
<template>
<!-- Apps list -->
<NcAppContent class="app-settings-content"
:page-heading="pageHeading">
- <AppList :category="currentCategory" />
+ <NcEmptyContent v-if="isLoading"
+ class="empty-content__loading"
+ :name="t('settings', 'Loading app list')">
+ <template #icon>
+ <NcLoadingIcon :size="64" />
+ </template>
+ </NcEmptyContent>
+ <AppList v-else :category="currentCategory" />
</NcAppContent>
</template>
<script setup lang="ts">
import { translate as t } from '@nextcloud/l10n'
-import { computed, watch } from 'vue'
+import { computed, getCurrentInstance, onBeforeMount, watch } from 'vue'
import { useRoute } from 'vue-router/composables'
import { APPS_SECTION_ENUM } from '../constants/AppsConstants.js'
import { useAppsStore } from '../store/apps-store'
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 AppList from '../components/AppList.vue'
const route = useRoute()
@@ -60,4 +69,22 @@ const pageHeading = computed(() => {
watch([pageHeading], () => {
window.document.title = `${pageHeading.value} - Apps - Nextcloud`
})
+
+// TODO this part should be migrated to pinia
+const instance = getCurrentInstance()
+/** Is the app list loading */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+const isLoading = computed(() => (instance?.proxy as any).$store.getters.loading('list'))
+onBeforeMount(() => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (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')
+})
</script>
+
+<style scoped>
+.empty-content__loading {
+ height: 100%;
+}
+</style>
diff --git a/apps/settings/src/views/Users.vue b/apps/settings/src/views/UserManagement.vue
index d44fa7c8416..d25071e63ed 100644
--- a/apps/settings/src/views/Users.vue
+++ b/apps/settings/src/views/UserManagement.vue
@@ -22,119 +22,117 @@
<template>
<Fragment>
- <NcContent app-name="settings">
- <NcAppNavigation :aria-label="t('settings', 'Account management')">
- <NcAppNavigationNew button-id="new-user-button"
- :text="t('settings','New account')"
- @click="showNewUserMenu"
- @keyup.enter="showNewUserMenu"
- @keyup.space="showNewUserMenu">
+ <NcAppNavigation :aria-label="t('settings', 'Account management')">
+ <NcAppNavigationNew button-id="new-user-button"
+ :text="t('settings','New account')"
+ @click="showNewUserMenu"
+ @keyup.enter="showNewUserMenu"
+ @keyup.space="showNewUserMenu">
+ <template #icon>
+ <Plus :size="20" />
+ </template>
+ </NcAppNavigationNew>
+
+ <NcAppNavigationList data-cy-users-settings-navigation-groups="system">
+ <NcAppNavigationItem id="everyone"
+ :exact="true"
+ :name="t('settings', 'Active accounts')"
+ :to="{ name: 'users' }">
<template #icon>
- <Plus :size="20" />
+ <AccountGroup :size="20" />
+ </template>
+ <template #counter>
+ <NcCounterBubble v-if="userCount" :type="!selectedGroupDecoded ? 'highlighted' : undefined">
+ {{ userCount }}
+ </NcCounterBubble>
</template>
- </NcAppNavigationNew>
+ </NcAppNavigationItem>
- <NcAppNavigationList data-cy-users-settings-navigation-groups="system">
- <NcAppNavigationItem id="everyone"
- :exact="true"
- :name="t('settings', 'Active accounts')"
- :to="{ name: 'users' }">
+ <NcAppNavigationItem v-if="settings.isAdmin"
+ id="admin"
+ :exact="true"
+ :name="t('settings', 'Admins')"
+ :to="{ name: 'group', params: { selectedGroup: 'admin' } }">
+ <template #icon>
+ <ShieldAccount :size="20" />
+ </template>
+ <template v-if="adminGroupMenu.count > 0" #counter>
+ <NcCounterBubble :type="selectedGroupDecoded === 'admin' ? 'highlighted' : undefined">
+ {{ adminGroupMenu.count }}
+ </NcCounterBubble>
+ </template>
+ </NcAppNavigationItem>
+
+ <!-- Hide the disabled if none, if we don't have the data (-1) show it -->
+ <NcAppNavigationItem v-if="disabledGroupMenu.usercount > 0 || disabledGroupMenu.usercount === -1"
+ id="disabled"
+ :exact="true"
+ :name="t('settings', 'Disabled users')"
+ :to="{ name: 'group', params: { selectedGroup: 'disabled' } }">
+ <template #icon>
+ <AccountOff :size="20" />
+ </template>
+ <template v-if="disabledGroupMenu.usercount > 0" #counter>
+ <NcCounterBubble :type="selectedGroupDecoded === 'disabled' ? 'highlighted' : undefined">
+ {{ disabledGroupMenu.usercount }}
+ </NcCounterBubble>
+ </template>
+ </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" />
+ <Plus v-else :size="20" />
+ </template>
+ <template #actions>
+ <NcActionText>
<template #icon>
<AccountGroup :size="20" />
</template>
- <template #counter>
- <NcCounterBubble v-if="userCount" :type="!selectedGroupDecoded ? 'highlighted' : undefined">
- {{ userCount }}
- </NcCounterBubble>
- </template>
- </NcAppNavigationItem>
-
- <NcAppNavigationItem v-if="settings.isAdmin"
- id="admin"
- :exact="true"
- :name="t('settings', 'Admins')"
- :to="{ name: 'group', params: { selectedGroup: 'admin' } }">
- <template #icon>
- <ShieldAccount :size="20" />
- </template>
- <template v-if="adminGroupMenu.count > 0" #counter>
- <NcCounterBubble :type="selectedGroupDecoded === 'admin' ? 'highlighted' : undefined">
- {{ adminGroupMenu.count }}
- </NcCounterBubble>
- </template>
- </NcAppNavigationItem>
-
- <!-- Hide the disabled if none, if we don't have the data (-1) show it -->
- <NcAppNavigationItem v-if="disabledGroupMenu.usercount > 0 || disabledGroupMenu.usercount === -1"
- id="disabled"
- :exact="true"
- :name="t('settings', 'Disabled users')"
- :to="{ name: 'group', params: { selectedGroup: 'disabled' } }">
+ {{ 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 data-cy-users-settings-navigation-groups="custom">
+ <GroupListItem v-for="group in groupList"
+ :id="group.id"
+ :key="group.id"
+ :active="selectedGroupDecoded === group.id"
+ :name="group.title"
+ :count="group.count" />
+ </NcAppNavigationList>
+
+ <template #footer>
+ <ul class="app-navigation-entry__settings">
+ <NcAppNavigationItem :name="t('settings', 'Account management settings')"
+ @click="isDialogOpen = true">
<template #icon>
- <AccountOff :size="20" />
- </template>
- <template v-if="disabledGroupMenu.usercount > 0" #counter>
- <NcCounterBubble :type="selectedGroupDecoded === 'disabled' ? 'highlighted' : undefined">
- {{ disabledGroupMenu.usercount }}
- </NcCounterBubble>
+ <Cog :size="20" />
</template>
</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" />
- <Plus v-else :size="20" />
- </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 data-cy-users-settings-navigation-groups="custom">
- <GroupListItem v-for="group in groupList"
- :id="group.id"
- :key="group.id"
- :active="selectedGroupDecoded === group.id"
- :name="group.title"
- :count="group.count" />
- </NcAppNavigationList>
-
- <template #footer>
- <ul class="app-navigation-entry__settings">
- <NcAppNavigationItem :name="t('settings', 'Account management settings')"
- @click="isDialogOpen = true">
- <template #icon>
- <Cog :size="20" />
- </template>
- </NcAppNavigationItem>
- </ul>
- </template>
- </NcAppNavigation>
+ </ul>
+ </template>
+ </NcAppNavigation>
- <NcAppContent :page-heading="pageHeading">
- <UserList :selected-group="selectedGroupDecoded"
- :external-actions="externalActions" />
- </NcAppContent>
- </NcContent>
+ <NcAppContent :page-heading="pageHeading">
+ <UserList :selected-group="selectedGroupDecoded"
+ :external-actions="externalActions" />
+ </NcAppContent>
<UserSettingsDialog :open.sync="isDialogOpen" />
</Fragment>
@@ -155,7 +153,6 @@ import NcAppNavigationCaption from '@nextcloud/vue/dist/Components/NcAppNavigati
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 NcContent from '@nextcloud/vue/dist/Components/NcContent.js'
import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js'
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
@@ -163,7 +160,6 @@ import AccountGroup from 'vue-material-design-icons/AccountGroup.vue'
import AccountOff from 'vue-material-design-icons/AccountOff.vue'
import Cog from 'vue-material-design-icons/Cog.vue'
import Plus from 'vue-material-design-icons/Plus.vue'
-import ShieldAccount from 'vue-material-design-icons/ShieldAccount.vue'
import GroupListItem from '../components/GroupListItem.vue'
import UserList from '../components/UserList.vue'
@@ -172,7 +168,7 @@ import UserSettingsDialog from '../components/Users/UserSettingsDialog.vue'
Vue.use(VueLocalStorage)
export default {
- name: 'Users',
+ name: 'UserManagement',
components: {
AccountGroup,
@@ -188,11 +184,9 @@ export default {
NcAppNavigationItem,
NcAppNavigationList,
NcAppNavigationNew,
- NcContent,
NcCounterBubble,
NcLoadingIcon,
Plus,
- ShieldAccount,
UserList,
UserSettingsDialog,
},
diff --git a/apps/settings/src/views/UserManagementNavigation.vue b/apps/settings/src/views/UserManagementNavigation.vue
new file mode 100644
index 00000000000..a32313f8edf
--- /dev/null
+++ b/apps/settings/src/views/UserManagementNavigation.vue
@@ -0,0 +1,5 @@
+<template>
+ <div>...</div>
+</template>
+<script setup>
+</script>