aboutsummaryrefslogtreecommitdiffstats
path: root/apps/settings/src/views
diff options
context:
space:
mode:
Diffstat (limited to 'apps/settings/src/views')
-rw-r--r--apps/settings/src/views/AdminSettingsSharing.vue9
-rw-r--r--apps/settings/src/views/AppStore.vue18
-rw-r--r--apps/settings/src/views/AppStoreNavigation.vue20
-rw-r--r--apps/settings/src/views/AppStoreSidebar.vue33
-rw-r--r--apps/settings/src/views/SettingsApp.vue2
-rw-r--r--apps/settings/src/views/UserManagement.vue11
-rw-r--r--apps/settings/src/views/UserManagementNavigation.vue150
-rw-r--r--apps/settings/src/views/user-types.d.ts17
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
}