Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(settings): Split account management into navigation and content
The should ease the maintenance of it due to reduced complexity.

Signed-off-by: Ferdinand Thiessen <[email protected]>
  • Loading branch information
susnux committed Mar 11, 2024
commit 30d5b0281140653192ba01fcbd11b0e367af96a0
34 changes: 19 additions & 15 deletions apps/settings/src/components/UserList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@
<NcLoadingIcon v-if="isInitialLoad && loading.users"
:name="t('settings', 'Loading accounts …')"
:size="64" />
<NcIconSvgWrapper v-else
:svg="usersSvg" />
<NcIconSvgWrapper v-else :path="mdiAccountGroup" :size="64" />
</template>
</NcEmptyContent>

Expand Down Expand Up @@ -78,16 +77,16 @@
</template>

<script>
import Vue from 'vue'
import { mdiAccountGroup } from '@mdi/js'
import { showError } from '@nextcloud/dialogs'
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import { Fragment } from 'vue-frag'

import Vue from 'vue'
import NcEmptyContent from '@nextcloud/vue/dist/Components/NcEmptyContent.js'
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'

import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import { showError } from '@nextcloud/dialogs'

import VirtualList from './Users/VirtualList.vue'
import NewUserModal from './Users/NewUserModal.vue'
import UserListFooter from './Users/UserListFooter.vue'
Expand All @@ -97,9 +96,7 @@ import UserRow from './Users/UserRow.vue'
import { defaultQuota, isObfuscated, unlimitedQuota } from '../utils/userUtils.ts'
import logger from '../logger.ts'

import usersSvg from '../../img/users.svg?raw'

const newUser = {
const newUser = Object.freeze({
id: '',
displayName: '',
password: '',
Expand All @@ -112,7 +109,7 @@ const newUser = {
code: 'en',
name: t('settings', 'Default language'),
},
}
})

export default {
name: 'UserList',
Expand All @@ -139,19 +136,26 @@ export default {
},
},

data() {
setup() {
// non reactive properties
return {
mdiAccountGroup,
rowHeight: 55,

UserRow,
}
},

data() {
return {
loading: {
all: false,
groups: false,
users: false,
},
newUser: { ...newUser },
isInitialLoad: true,
rowHeight: 55,
usersSvg,
searchQuery: '',
newUser: Object.assign({}, newUser),
}
},

Expand Down Expand Up @@ -252,7 +256,7 @@ export default {

watch: {
// watch url change and group select
async selectedGroup(val, old) {
async selectedGroup(val) {
this.isInitialLoad = true
// if selected is the disabled group but it's empty
await this.redirectIfDisabled()
Expand Down
31 changes: 17 additions & 14 deletions apps/settings/src/components/Users/UserSettingsDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@

<NcAppSettingsSection id="default-settings"
:name="t('settings', 'Defaults')">
<label for="default-quota-select">{{ t('settings', 'Default quota') }}</label>
<NcSelect v-model="defaultQuota"
input-id="default-quota-select"
:input-label="t('settings', 'Default quota')"
placement="top"
:taggable="true"
:options="quotaOptions"
Expand All @@ -75,9 +74,11 @@
</template>

<script>
import axios from '@nextcloud/axios'
import { getBuilder } from '@nextcloud/browser-storage'
import { formatFileSize, parseFileSize } from '@nextcloud/files'
import { generateUrl } from '@nextcloud/router'

import axios from '@nextcloud/axios'
import NcAppSettingsDialog from '@nextcloud/vue/dist/Components/NcAppSettingsDialog.js'
import NcAppSettingsSection from '@nextcloud/vue/dist/Components/NcAppSettingsSection.js'
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
Expand All @@ -102,6 +103,15 @@ export default {
},
},

setup() {
const localStorage = getBuilder('settings')
.persist(true)
.clearOnLogout(true)
.build()

return { localStorage }
},

data() {
return {
selectedQuota: false,
Expand Down Expand Up @@ -213,15 +223,15 @@ export default {
methods: {
getLocalstorage(key) {
// force initialization
const localConfig = this.$localStorage.get(key)
const localConfig = JSON.parse(this.localStorage.getItem(key) ?? 'null')
// if localstorage is null, fallback to original values
this.$store.commit('setShowConfig', { key, value: localConfig !== null ? localConfig === 'true' : this.showConfig[key] })
return this.showConfig[key]
},

setLocalStorage(key, status) {
this.$store.commit('setShowConfig', { key, value: status })
this.$localStorage.set(key, status)
this.localStorage.setItem(key, JSON.stringify(status))
return status
},

Expand All @@ -236,12 +246,12 @@ export default {
quota = quota?.id || quota.label
}
// only used for new presets sent through @Tag
const validQuota = OC.Util.computerFileSize(quota)
const validQuota = parseFileSize(quota)
if (validQuota === null) {
return unlimitedQuota
} else {
// unify format output
quota = OC.Util.humanFileSize(OC.Util.computerFileSize(quota))
quota = formatFileSize(parseFileSize(quota))
return { id: quota, label: quota }
}
},
Expand Down Expand Up @@ -271,10 +281,3 @@ export default {
},
}
</script>

<style lang="scss" scoped>
label[for="default-quota-select"] {
display: block;
padding: 4px 0;
}
</style>
52 changes: 52 additions & 0 deletions apps/settings/src/composables/useGroupsNavigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { ComputedRef, Ref } from 'vue'
import type { IGroup } from '../views/user-types'

import { computed } from 'vue'

/**
* Format a group to a menu entry
*
* @param group the group
*/
function formatGroupMenu(group?: IGroup) {
if (typeof group === 'undefined') {
return null
}

const item = {
id: group.id,
title: group.name,
usercount: group.usercount,
count: Math.max(0, group.usercount - group.disabled),
}

return item
}

export const useFormatGroups = (groups: Ref<IGroup[]>|ComputedRef<IGroup[]>) => {
/**
* All non-disabled non-admin groups
*/
const userGroups = computed(() => {
const formatted = groups.value
// filter out disabled and admin
.filter(group => group.id !== 'disabled' && group.id !== 'admin')
// format group
.map(group => formatGroupMenu(group))
// remove invalid
.filter(group => group !== null)
return formatted as NonNullable<ReturnType<typeof formatGroupMenu>>[]
})

/**
* The admin group if found otherwise null
*/
const adminGroup = computed(() => formatGroupMenu(groups.value.find(group => group.id === 'admin')))

/**
* The group of disabled users
*/
const disabledGroup = computed(() => formatGroupMenu(groups.value.find(group => group.id === 'disabled')))

return { adminGroup, disabledGroup, userGroups }
}
7 changes: 2 additions & 5 deletions apps/settings/src/main-apps-users-management.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ import { translate as t, translatePlural as n } from '@nextcloud/l10n'

import SettingsApp from './views/SettingsApp.vue'
import router from './router/index.ts'
import store from './store/index.js'
import { useStore } from './store/index.js'
import { getRequestToken } from '@nextcloud/auth'
import { PiniaVuePlugin, createPinia } from 'pinia'

Vue.use(VTooltip, { defaultHtml: false })

const store = useStore()
sync(store, router)

// CSP config for webpack dynamic chunk loading
Expand All @@ -44,10 +45,6 @@ __webpack_nonce__ = btoa(getRequestToken() ?? '')
// bind to window
Vue.prototype.t = t
Vue.prototype.n = n
Vue.prototype.OC = window.OC
Vue.prototype.OCA = window.OCA
// @ts-expect-error This is a private property we use
Vue.prototype.oc_userconfig = window.oc_userconfig
Vue.use(PiniaVuePlugin)

const pinia = createPinia()
Expand Down
26 changes: 16 additions & 10 deletions apps/settings/src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,20 @@ const mutations = {
},
}

export default new Store({
modules: {
users,
apps,
settings,
oc,
},
strict: debug,
let store = null

mutations,
})
export const useStore = () => {
if (store === null) {
store = new Store({
modules: {
users,
apps,
settings,
oc,
},
strict: debug,
mutations,
})
}
return store
}
Loading