-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Expand file tree
/
Copy pathUserSectionAppMenu.vue
More file actions
167 lines (146 loc) · 5.4 KB
/
Copy pathUserSectionAppMenu.vue
File metadata and controls
167 lines (146 loc) · 5.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
<!--
- SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import type { INavigationEntry } from '../../../../core/src/types/navigation.d.ts'
import type { IApp } from './AppOrderSelector.vue'
import axios from '@nextcloud/axios'
import { showError } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { generateOcsUrl } from '@nextcloud/router'
import { computed, ref } from 'vue'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
import IconUndo from 'vue-material-design-icons/Undo.vue'
import AppOrderSelector from './AppOrderSelector.vue'
import { logger } from '../utils/logger.ts'
/** The app order user setting */
type IAppOrder = Record<string, { order: number, app?: string }>
/** OCS responses */
interface IOCSResponse<T> {
ocs: {
meta: unknown
data: T
}
}
const {
/** The app order currently defined by the user */
userAppOrder,
/** The enforced default app set by the administrator (if any) */
enforcedDefaultApp,
} = loadState<{ userAppOrder: IAppOrder, enforcedDefaultApp: string }>('theming', 'navigationBar')
/**
* Array of all available apps, it is set by a core controller for the app menu, so it is always available
*/
const initialAppOrder = loadState<INavigationEntry[]>('core', 'apps')
.filter(({ type }) => type === 'link')
.map((app) => ({ ...app, label: app.name, default: app.default && app.id === enforcedDefaultApp }))
/**
* The current apporder (sorted by user)
*/
const appOrder = ref([...initialAppOrder])
/**
* Check if a custom app order is used or the default is shown
*/
const hasCustomAppOrder = ref(!Array.isArray(userAppOrder) || Object.values(userAppOrder).length > 0)
/**
* Track if the app order has changed, so the user can be informed to reload
*/
const hasAppOrderChanged = computed(() => initialAppOrder.some(({ id }, index) => id !== appOrder.value[index]?.id))
/** ID of the "app order has changed" NcNodeCard, used for the aria-details of the apporder */
const elementIdAppOrderChanged = 'theming-apporder-changed-infocard'
/** ID of the "you can not change the default app" NcNodeCard, used for the aria-details of the apporder */
const elementIdEnforcedDefaultApp = 'theming-apporder-changed-infocard'
/**
* The aria-details value of the app order selector
* contains the space separated list of element ids of NcNoteCards
*/
const ariaDetailsAppOrder = computed(() => (hasAppOrderChanged.value ? `${elementIdAppOrderChanged} ` : '') + (enforcedDefaultApp ? elementIdEnforcedDefaultApp : ''))
/**
* Update the app order, called when the user sorts entries
*
* @param value The new app order value
*/
async function updateAppOrder(value: IApp[]) {
const order: IAppOrder = {}
value.forEach(({ app, id }, index) => {
order[id] = { order: index, app }
})
try {
await saveSetting('apporder', order)
appOrder.value = value as never
hasCustomAppOrder.value = true
} catch (error) {
logger.error('Could not set the app order', { error })
showError(t('theming', 'Could not set the app order'))
}
}
/**
* Reset the app order to the default
*/
async function resetAppOrder() {
try {
await saveSetting('apporder', [])
hasCustomAppOrder.value = false
// Reset our app order list
const { data } = await axios.get<IOCSResponse<INavigationEntry[]>>(generateOcsUrl('/core/navigation/apps'), {
headers: {
'OCS-APIRequest': 'true',
},
})
appOrder.value = data.ocs.data.map((app) => ({ ...app, label: app.name, default: app.default && app.app === enforcedDefaultApp }))
} catch (error) {
logger.error('Could not reset the app order', { error })
showError(t('theming', 'Could not reset the app order'))
}
}
/**
* @param key - The config key
* @param value - The config value
*/
async function saveSetting(key: string, value: unknown) {
const url = generateOcsUrl('apps/provisioning_api/api/v1/config/users/{appId}/{configKey}', {
appId: 'core',
configKey: key,
})
return await axios.post(url, {
configValue: JSON.stringify(value),
})
}
</script>
<template>
<NcSettingsSection :name="t('theming', 'Navigation bar settings')">
<p>
{{ t('theming', 'You can configure the app order used for the navigation bar. The first entry will be the default app, opened after login or when clicking on the logo.') }}
</p>
<NcNoteCard v-if="enforcedDefaultApp" :id="elementIdEnforcedDefaultApp" type="info">
{{ t('theming', 'The default app can not be changed because it was configured by the administrator.') }}
</NcNoteCard>
<NcNoteCard v-if="hasAppOrderChanged" :id="elementIdAppOrderChanged" type="info">
{{ t('theming', 'The app order was changed, to see it in action you have to reload the page.') }}
</NcNoteCard>
<AppOrderSelector
:class="$style.userSectionAppMenu__selector"
:aria-details="ariaDetailsAppOrder"
:modelValue="appOrder"
@update:modelValue="updateAppOrder" />
<NcButton
data-test-id="btn-apporder-reset"
:disabled="!hasCustomAppOrder"
variant="tertiary"
@click="resetAppOrder">
<template #icon>
<IconUndo :size="20" />
</template>
{{ t('theming', 'Reset default app order') }}
</NcButton>
</NcSettingsSection>
</template>
<style module>
.userSectionAppMenu__selector {
margin-block: 12px;
}
</style>