]> source.dussan.org Git - nextcloud-server.git/commitdiff
refactor(app-store): Merge both app related stores into one Pinia store
authorFerdinand Thiessen <opensource@fthiessen.de>
Wed, 23 Oct 2024 10:38:07 +0000 (12:38 +0200)
committerFerdinand Thiessen <opensource@fthiessen.de>
Wed, 23 Oct 2024 11:00:24 +0000 (13:00 +0200)
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
apps/settings/src/store/appStore.ts [new file with mode: 0644]
apps/settings/src/store/apps-store.ts [deleted file]
apps/settings/src/store/apps.js [deleted file]
apps/settings/src/store/index.js

diff --git a/apps/settings/src/store/appStore.ts b/apps/settings/src/store/appStore.ts
new file mode 100644 (file)
index 0000000..b9f015a
--- /dev/null
@@ -0,0 +1,141 @@
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import type { IAppStoreApp, IAppStoreCategory } from '../constants/AppStoreTypes.ts'
+
+import { showError } from '@nextcloud/dialogs'
+import { loadState } from '@nextcloud/initial-state'
+import { translate as t } from '@nextcloud/l10n'
+import { defineStore } from 'pinia'
+
+import { getAllApps, getCategories } from '../service/AppStoreApi.ts'
+import AppStoreCategoryIcons from '../constants/AppStoreCategoryIcons.ts'
+import logger from '../logger'
+import Vue from 'vue'
+
+const showApiError = () => showError(t('settings', 'An error occurred during the request. Unable to proceed.'))
+
+export const useAppStore = defineStore('settings-apps', {
+       state: () => ({
+               apps: [] as IAppStoreApp[],
+               categories: [] as IAppStoreCategory[],
+               updateCount: loadState<number>('settings', 'appstoreUpdateCount', 0),
+               loading: {
+                       apps: false,
+                       categories: false,
+               },
+               loadingList: false,
+               gettingCategoriesPromise: null,
+       }),
+
+       actions: {
+               /**
+                * Helper to modify an app in the local app store.
+                * @param app The app to modify
+                * @param partialApp Changes to apply to the app
+                */
+               updateApp(app: IAppStoreApp, partialApp: Partial<IAppStoreApp>) {
+                       const updatedApp = structuredClone(app)
+                       for (const [key, value] of Object.entries(partialApp)) {
+                               if (value === undefined) {
+                                       delete updatedApp[key]
+                               } else {
+                                       updatedApp[key] = value
+                               }
+                       }
+
+                       const index = this.apps.findIndex((a) => a.id === app.id)
+                       Vue.set(this.apps, index, updatedApp)
+               },
+
+               async loadCategories(force = false) {
+                       if (this.categories.length > 0 && !force) {
+                               return
+                       }
+
+                       try {
+                               this.loading.categories = true
+                               const categories = await getCategories()
+
+                               for (const category of categories) {
+                                       category.icon = AppStoreCategoryIcons[category.id] ?? ''
+                               }
+
+                               this.categories = categories
+                       } catch (error) {
+                               logger.error(error as Error)
+                               showApiError()
+                       } finally {
+                               this.loading.categories = false
+                       }
+               },
+
+               async loadApps(force = false) {
+                       if (this.apps.length > 0 && !force) {
+                               return
+                       }
+
+                       try {
+                               this.loading.apps = true
+                               const apps = await getAllApps()
+                               this.apps = apps
+                       } catch (error) {
+                               logger.error(error as Error)
+                               showApiError()
+                       } finally {
+                               this.loading.apps = false
+                       }
+               },
+
+               getCategoryById(categoryId: string) {
+                       return this.categories.find(({ id }) => id === categoryId) ?? null
+               },
+
+               /**
+                * Get an app by their app id
+                * @param appId The app id to search
+                */
+               getAppById(appId: string): IAppStoreApp|null {
+                       return this.apps.find(({ id }) => id === appId) ?? null
+               },
+
+               /**
+                * Get all apps that are part of the specified bundle
+                * @param bundleId The bundle id to filter
+                */
+               getAppsByBundle(bundleId: string): IAppStoreApp[] {
+                       return this.apps.filter((app) => app.bundleIds && app.bundleIds.includes(bundleId))
+               },
+
+               /**
+                * Get all apps that are listed in the specified category
+                * @param categoryId The category id to filter
+                */
+               getAppsByCategory(categoryId: string): IAppStoreApp[] {
+                       // Also handle special categories
+                       switch (categoryId) {
+                               case 'enabled':
+                                       return this.apps.filter((app) => app.active)
+                                       break
+                               case 'disabled':
+                                       return this.apps.filter((app) => app.installed && !app.active)
+                                       break
+                               case 'updates':
+                                       return this.apps.filter((app) => app.update)
+                                       break
+                               case 'installed':
+                                       return this.apps.filter((app) => app.installed)
+                                       break
+                               case 'featured':
+                                       return this.apps.filter((app) => app.level === 200)
+                                       break
+                               case 'supported':
+                                       return this.apps.filter((app) => app.level === 300)
+                               default:
+                                       return this.apps.filter((app) => app.category === categoryId || app.category.includes(categoryId))
+                               }
+               },
+       },
+})
diff --git a/apps/settings/src/store/apps-store.ts b/apps/settings/src/store/apps-store.ts
deleted file mode 100644 (file)
index eaf8a0d..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-import type { IAppstoreApp, IAppstoreCategory } from '../app-types.ts'
-
-import { showError } from '@nextcloud/dialogs'
-import { loadState } from '@nextcloud/initial-state'
-import { translate as t } from '@nextcloud/l10n'
-import { generateUrl } from '@nextcloud/router'
-import { defineStore } from 'pinia'
-
-import axios from '@nextcloud/axios'
-
-import logger from '../logger'
-import APPSTORE_CATEGORY_ICONS from '../constants/AppstoreCategoryIcons.ts'
-
-const showApiError = () => showError(t('settings', 'An error occurred during the request. Unable to proceed.'))
-
-export const useAppsStore = defineStore('settings-apps', {
-       state: () => ({
-               apps: [] as IAppstoreApp[],
-               categories: [] as IAppstoreCategory[],
-               updateCount: loadState<number>('settings', 'appstoreUpdateCount', 0),
-               loading: {
-                       apps: false,
-                       categories: false,
-               },
-               loadingList: false,
-               gettingCategoriesPromise: null,
-       }),
-
-       actions: {
-               async loadCategories(force = false) {
-                       if (this.categories.length > 0 && !force) {
-                               return
-                       }
-
-                       try {
-                               this.loading.categories = true
-                               const { data: categories } = await axios.get<IAppstoreCategory[]>(generateUrl('settings/apps/categories'))
-
-                               for (const category of categories) {
-                                       category.icon = APPSTORE_CATEGORY_ICONS[category.id] ?? ''
-                               }
-
-                               this.$patch({
-                                       categories,
-                               })
-                       } catch (error) {
-                               logger.error(error as Error)
-                               showApiError()
-                       } finally {
-                               this.loading.categories = false
-                       }
-               },
-
-               async loadApps(force = false) {
-                       if (this.apps.length > 0 && !force) {
-                               return
-                       }
-
-                       try {
-                               this.loading.apps = true
-                               const { data } = await axios.get<{ apps: IAppstoreApp[] }>(generateUrl('settings/apps/list'))
-
-                               this.$patch({
-                                       apps: data.apps,
-                               })
-                       } catch (error) {
-                               logger.error(error as Error)
-                               showApiError()
-                       } finally {
-                               this.loading.apps = false
-                       }
-               },
-
-               getCategoryById(categoryId: string) {
-                       return this.categories.find(({ id }) => id === categoryId) ?? null
-               },
-
-               getAppById(appId: string): IAppstoreApp|null {
-                       return this.apps.find(({ id }) => id === appId) ?? null
-               },
-       },
-})
diff --git a/apps/settings/src/store/apps.js b/apps/settings/src/store/apps.js
deleted file mode 100644 (file)
index ed5a724..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-/**
- * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-import api from './api.js'
-import Vue from 'vue'
-import { generateUrl } from '@nextcloud/router'
-import { showError, showInfo } from '@nextcloud/dialogs'
-import { loadState } from '@nextcloud/initial-state'
-
-const state = {
-       apps: [],
-       bundles: loadState('settings', 'appstoreBundles', []),
-       categories: [],
-       updateCount: loadState('settings', 'appstoreUpdateCount', 0),
-       loading: {},
-       gettingCategoriesPromise: null,
-}
-
-const mutations = {
-
-       APPS_API_FAILURE(state, error) {
-               showError(t('settings', 'An error occurred during the request. Unable to proceed.') + '<br>' + error.error.response.data.data.message, { isHTML: true })
-               console.error(state, error)
-       },
-
-       initCategories(state, { categories, updateCount }) {
-               state.categories = categories
-               state.updateCount = updateCount
-       },
-
-       updateCategories(state, categoriesPromise) {
-               state.gettingCategoriesPromise = categoriesPromise
-       },
-
-       setUpdateCount(state, updateCount) {
-               state.updateCount = updateCount
-       },
-
-       addCategory(state, category) {
-               state.categories.push(category)
-       },
-
-       appendCategories(state, categoriesArray) {
-               // convert obj to array
-               state.categories = categoriesArray
-       },
-
-       setAllApps(state, apps) {
-               state.apps = apps
-       },
-
-       setError(state, { appId, error }) {
-               if (!Array.isArray(appId)) {
-                       appId = [appId]
-               }
-               appId.forEach((_id) => {
-                       const app = state.apps.find(app => app.id === _id)
-                       app.error = error
-               })
-       },
-
-       clearError(state, { appId, error }) {
-               const app = state.apps.find(app => app.id === appId)
-               app.error = null
-       },
-
-       enableApp(state, { appId, groups }) {
-               const app = state.apps.find(app => app.id === appId)
-               app.active = true
-               app.groups = groups
-       },
-
-       setInstallState(state, { appId, canInstall }) {
-               const app = state.apps.find(app => app.id === appId)
-               if (app) {
-                       app.canInstall = canInstall === true
-               }
-       },
-
-       disableApp(state, appId) {
-               const app = state.apps.find(app => app.id === appId)
-               app.active = false
-               app.groups = []
-               if (app.removable) {
-                       app.canUnInstall = true
-               }
-       },
-
-       uninstallApp(state, appId) {
-               state.apps.find(app => app.id === appId).active = false
-               state.apps.find(app => app.id === appId).groups = []
-               state.apps.find(app => app.id === appId).needsDownload = true
-               state.apps.find(app => app.id === appId).installed = false
-               state.apps.find(app => app.id === appId).canUnInstall = false
-               state.apps.find(app => app.id === appId).canInstall = true
-       },
-
-       updateApp(state, appId) {
-               const app = state.apps.find(app => app.id === appId)
-               const version = app.update
-               app.update = null
-               app.version = version
-               state.updateCount--
-
-       },
-
-       resetApps(state) {
-               state.apps = []
-       },
-       reset(state) {
-               state.apps = []
-               state.categories = []
-               state.updateCount = 0
-       },
-       startLoading(state, id) {
-               if (Array.isArray(id)) {
-                       id.forEach((_id) => {
-                               Vue.set(state.loading, _id, true)
-                       })
-               } else {
-                       Vue.set(state.loading, id, true)
-               }
-       },
-       stopLoading(state, id) {
-               if (Array.isArray(id)) {
-                       id.forEach((_id) => {
-                               Vue.set(state.loading, _id, false)
-                       })
-               } else {
-                       Vue.set(state.loading, id, false)
-               }
-       },
-}
-
-const getters = {
-       loading(state) {
-               return function(id) {
-                       return state.loading[id]
-               }
-       },
-       getCategories(state) {
-               return state.categories
-       },
-       getAllApps(state) {
-               return state.apps
-       },
-       getAppBundles(state) {
-               return state.bundles
-       },
-       getUpdateCount(state) {
-               return state.updateCount
-       },
-       getCategoryById: (state) => (selectedCategoryId) => {
-               return state.categories.find((category) => category.id === selectedCategoryId)
-       },
-}
-
-const actions = {
-
-       enableApp(context, { appId, groups }) {
-               let apps
-               if (Array.isArray(appId)) {
-                       apps = appId
-               } else {
-                       apps = [appId]
-               }
-               return api.requireAdmin().then((response) => {
-                       context.commit('startLoading', apps)
-                       context.commit('startLoading', 'install')
-                       return api.post(generateUrl('settings/apps/enable'), { appIds: apps, groups })
-                               .then((response) => {
-                                       context.commit('stopLoading', apps)
-                                       context.commit('stopLoading', 'install')
-                                       apps.forEach(_appId => {
-                                               context.commit('enableApp', { appId: _appId, groups })
-                                       })
-
-                                       // check for server health
-                                       return api.get(generateUrl('apps/files/'))
-                                               .then(() => {
-                                                       if (response.data.update_required) {
-                                                               showInfo(
-                                                                       t(
-                                                                               'settings',
-                                                                               'The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds.',
-                                                                       ),
-                                                                       {
-                                                                               onClick: () => window.location.reload(),
-                                                                               close: false,
-
-                                                                       },
-                                                               )
-                                                               setTimeout(function() {
-                                                                       location.reload()
-                                                               }, 5000)
-                                                       }
-                                               })
-                                               .catch(() => {
-                                                       if (!Array.isArray(appId)) {
-                                                               showError(t('settings', 'Error: This app cannot be enabled because it makes the server unstable'))
-                                                               context.commit('setError', {
-                                                                       appId: apps,
-                                                                       error: t('settings', 'Error: This app cannot be enabled because it makes the server unstable'),
-                                                               })
-                                                               context.dispatch('disableApp', { appId })
-                                                       }
-                                               })
-                               })
-                               .catch((error) => {
-                                       context.commit('stopLoading', apps)
-                                       context.commit('stopLoading', 'install')
-                                       context.commit('setError', {
-                                               appId: apps,
-                                               error: error.response.data.data.message,
-                                       })
-                                       context.commit('APPS_API_FAILURE', { appId, error })
-                               })
-               }).catch((error) => context.commit('API_FAILURE', { appId, error }))
-       },
-       forceEnableApp(context, { appId, groups }) {
-               let apps
-               if (Array.isArray(appId)) {
-                       apps = appId
-               } else {
-                       apps = [appId]
-               }
-               return api.requireAdmin().then(() => {
-                       context.commit('startLoading', apps)
-                       context.commit('startLoading', 'install')
-                       return api.post(generateUrl('settings/apps/force'), { appId })
-                               .then((response) => {
-                                       context.commit('setInstallState', { appId, canInstall: true })
-                               })
-                               .catch((error) => {
-                                       context.commit('stopLoading', apps)
-                                       context.commit('stopLoading', 'install')
-                                       context.commit('setError', {
-                                               appId: apps,
-                                               error: error.response.data.data.message,
-                                       })
-                                       context.commit('APPS_API_FAILURE', { appId, error })
-                               })
-                               .finally(() => {
-                                       context.commit('stopLoading', apps)
-                                       context.commit('stopLoading', 'install')
-                               })
-               }).catch((error) => context.commit('API_FAILURE', { appId, error }))
-       },
-       disableApp(context, { appId }) {
-               let apps
-               if (Array.isArray(appId)) {
-                       apps = appId
-               } else {
-                       apps = [appId]
-               }
-               return api.requireAdmin().then((response) => {
-                       context.commit('startLoading', apps)
-                       return api.post(generateUrl('settings/apps/disable'), { appIds: apps })
-                               .then((response) => {
-                                       context.commit('stopLoading', apps)
-                                       apps.forEach(_appId => {
-                                               context.commit('disableApp', _appId)
-                                       })
-                                       return true
-                               })
-                               .catch((error) => {
-                                       context.commit('stopLoading', apps)
-                                       context.commit('APPS_API_FAILURE', { appId, error })
-                               })
-               }).catch((error) => context.commit('API_FAILURE', { appId, error }))
-       },
-       uninstallApp(context, { appId }) {
-               return api.requireAdmin().then((response) => {
-                       context.commit('startLoading', appId)
-                       return api.get(generateUrl(`settings/apps/uninstall/${appId}`))
-                               .then((response) => {
-                                       context.commit('stopLoading', appId)
-                                       context.commit('uninstallApp', appId)
-                                       return true
-                               })
-                               .catch((error) => {
-                                       context.commit('stopLoading', appId)
-                                       context.commit('APPS_API_FAILURE', { appId, error })
-                               })
-               }).catch((error) => context.commit('API_FAILURE', { appId, error }))
-       },
-
-       updateApp(context, { appId }) {
-               return api.requireAdmin().then((response) => {
-                       context.commit('startLoading', appId)
-                       context.commit('startLoading', 'install')
-                       return api.get(generateUrl(`settings/apps/update/${appId}`))
-                               .then((response) => {
-                                       context.commit('stopLoading', 'install')
-                                       context.commit('stopLoading', appId)
-                                       context.commit('updateApp', appId)
-                                       return true
-                               })
-                               .catch((error) => {
-                                       context.commit('stopLoading', appId)
-                                       context.commit('stopLoading', 'install')
-                                       context.commit('APPS_API_FAILURE', { appId, error })
-                               })
-               }).catch((error) => context.commit('API_FAILURE', { appId, error }))
-       },
-
-       getAllApps(context) {
-               context.commit('startLoading', 'list')
-               return api.get(generateUrl('settings/apps/list'))
-                       .then((response) => {
-                               context.commit('setAllApps', response.data.apps)
-                               context.commit('stopLoading', 'list')
-                               return true
-                       })
-                       .catch((error) => context.commit('API_FAILURE', error))
-       },
-
-       async getCategories(context, { shouldRefetchCategories = false } = {}) {
-               if (shouldRefetchCategories || !context.state.gettingCategoriesPromise) {
-                       context.commit('startLoading', 'categories')
-                       try {
-                               const categoriesPromise = api.get(generateUrl('settings/apps/categories'))
-                               context.commit('updateCategories', categoriesPromise)
-                               const categoriesPromiseResponse = await categoriesPromise
-                               if (categoriesPromiseResponse.data.length > 0) {
-                                       context.commit('appendCategories', categoriesPromiseResponse.data)
-                                       context.commit('stopLoading', 'categories')
-                                       return true
-                               }
-                               context.commit('stopLoading', 'categories')
-                               return false
-                       } catch (error) {
-                               context.commit('API_FAILURE', error)
-                       }
-               }
-               return context.state.gettingCategoriesPromise
-       },
-
-}
-
-export default { state, mutations, getters, actions }
index 910185edb5107141cc15d7023e75ed9adf85e7ef..032140cb2b7cab78cba311d4df0aad899d6a6d6a 100644 (file)
@@ -6,7 +6,6 @@
 import Vue from 'vue'
 import Vuex, { Store } from 'vuex'
 import users from './users.js'
-import apps from './apps.js'
 import settings from './users-settings.js'
 import oc from './oc.js'
 import { showError } from '@nextcloud/dialogs'
@@ -34,7 +33,6 @@ export const useStore = () => {
                store = new Store({
                        modules: {
                                users,
-                               apps,
                                settings,
                                oc,
                        },