Skip to content

Commit 5b4a478

Browse files
committed
permissions selection with multiselect
1 parent 8543e7d commit 5b4a478

File tree

2 files changed

+45
-27
lines changed

2 files changed

+45
-27
lines changed

components.d.ts

+5-10
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,27 @@ export {}
88
declare module 'vue' {
99
export interface GlobalComponents {
1010
CheckBox: typeof import('./src/components/CheckBox.vue')['default']
11+
ComboboxButton: typeof import('@headlessui/vue')['ComboboxButton']
12+
ComboboxInput: typeof import('@headlessui/vue')['ComboboxInput']
13+
ComboboxOption: typeof import('@headlessui/vue')['ComboboxOption']
14+
ComboboxOptions: typeof import('@headlessui/vue')['ComboboxOptions']
1115
Dialog: typeof import('@headlessui/vue')['Dialog']
1216
DialogPanel: typeof import('@headlessui/vue')['DialogPanel']
1317
DialogTitle: typeof import('@headlessui/vue')['DialogTitle']
1418
DynamicForm: typeof import('./src/components/DynamicForm.vue')['default']
1519
ErrorBox: typeof import('./src/components/ErrorBox.vue')['default']
1620
Header: typeof import('./src/components/Header.vue')['default']
17-
HeroiconsAdjustmentsVertical: typeof import('~icons/heroicons/adjustments-vertical')['default']
1821
HeroiconsArrowDown20Solid: typeof import('~icons/heroicons/arrow-down20-solid')['default']
1922
HeroiconsArrowPath: typeof import('~icons/heroicons/arrow-path')['default']
2023
HeroiconsBars3Solid: typeof import('~icons/heroicons/bars3-solid')['default']
2124
HeroiconsBoltSolid: typeof import('~icons/heroicons/bolt-solid')['default']
25+
HeroiconsChevronDown: typeof import('~icons/heroicons/chevron-down')['default']
2226
HeroiconsChevronUpDown20Solid: typeof import('~icons/heroicons/chevron-up-down20-solid')['default']
2327
HeroiconsClipboard: typeof import('~icons/heroicons/clipboard')['default']
24-
HeroiconsCloudArrowDownSolid: typeof import('~icons/heroicons/cloud-arrow-down-solid')['default']
2528
HeroiconsCog6Tooth20Solid: typeof import('~icons/heroicons/cog6-tooth20-solid')['default']
2629
HeroiconsDocumentTextSolid: typeof import('~icons/heroicons/document-text-solid')['default']
2730
HeroiconsGlobeAlt: typeof import('~icons/heroicons/globe-alt')['default']
2831
HeroiconsHome20Solid: typeof import('~icons/heroicons/home20-solid')['default']
29-
HeroiconsInformationCircleSolid: typeof import('~icons/heroicons/information-circle-solid')['default']
3032
HeroiconsLink20Solid: typeof import('~icons/heroicons/link20-solid')['default']
3133
HeroiconsMagnifyingGlass20Solid: typeof import('~icons/heroicons/magnifying-glass20-solid')['default']
3234
HeroiconsMicrophoneSolid: typeof import('~icons/heroicons/microphone-solid')['default']
@@ -51,17 +53,13 @@ declare module 'vue' {
5153
Pagination: typeof import('./src/components/Pagination.vue')['default']
5254
PhArrowCounterClockwiseBold: typeof import('~icons/ph/arrow-counter-clockwise-bold')['default']
5355
PhBrainFill: typeof import('~icons/ph/brain-fill')['default']
54-
PhCaretLeftFill: typeof import('~icons/ph/caret-left-fill')['default']
55-
PhCaretRightFill: typeof import('~icons/ph/caret-right-fill')['default']
5656
PhChatCenteredDots: typeof import('~icons/ph/chat-centered-dots')['default']
5757
PhChats: typeof import('~icons/ph/chats')['default']
5858
PhExportBold: typeof import('~icons/ph/export-bold')['default']
5959
PhFileFill: typeof import('~icons/ph/file-fill')['default']
6060
PhFiles: typeof import('~icons/ph/files')['default']
6161
PhFloppyDiskBold: typeof import('~icons/ph/floppy-disk-bold')['default']
6262
PhInfo: typeof import('~icons/ph/info')['default']
63-
PhLightbulbFilamentFill: typeof import('~icons/ph/lightbulb-filament-fill')['default']
64-
PhListMagnifyingGlass: typeof import('~icons/ph/list-magnifying-glass')['default']
6563
PhNut: typeof import('~icons/ph/nut')['default']
6664
PhPencilFill: typeof import('~icons/ph/pencil-fill')['default']
6765
PhPlugFill: typeof import('~icons/ph/plug-fill')['default']
@@ -70,15 +68,12 @@ declare module 'vue' {
7068
PhTextbox: typeof import('~icons/ph/textbox')['default']
7169
PhToolbox: typeof import('~icons/ph/toolbox')['default']
7270
PhTrashFill: typeof import('~icons/ph/trash-fill')['default']
73-
PhUser: typeof import('~icons/ph/user')['default']
74-
PhUserFill: typeof import('~icons/ph/user-fill')['default']
7571
RouterLink: typeof import('vue-router')['RouterLink']
7672
RouterView: typeof import('vue-router')['RouterView']
7773
SelectBox: typeof import('./src/components/SelectBox.vue')['default']
7874
SidePanel: typeof import('./src/components/SidePanel.vue')['default']
7975
ThemeButton: typeof import('./src/components/ThemeButton.vue')['default']
8076
TransitionChild: typeof import('@headlessui/vue')['TransitionChild']
8177
TransitionRoot: typeof import('@headlessui/vue')['TransitionRoot']
82-
UseImage: typeof import('@vueuse/components')['UseImage']
8378
}
8479
}

src/views/SettingsView.vue

+40-17
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { startCase, lowerCase, cloneDeep } from 'lodash'
44
import { apiClient, tryRequest } from '@services/ApiService'
55
import ModalBox from '@components/ModalBox.vue'
66
import SidePanel from '@components/SidePanel.vue'
7-
import type { Status, UserCreate, UserResponse, UserUpdate } from 'ccat-api'
7+
import type { AuthPermission, Status, UserCreate, UserResponse, UserUpdate } from 'ccat-api'
8+
import { Listbox, ListboxButton, ListboxOptions, ListboxOption } from '@headlessui/vue'
89
910
const getStatus = async () => {
1011
const result = await tryRequest(apiClient?.api?.status.home(), 'Getting Cheshire Cat status', 'Unable to fetch Cheshire Cat status')
@@ -56,6 +57,25 @@ const createOrUpdateUser = () => {
5657
else createUser(userInfo as UserCreate)
5758
editPanel.value?.togglePanel()
5859
}
60+
61+
const userPermissions = ref<Record<string, AuthPermission[]>>({
62+
STATUS: currentUser.value?.permissions?.STATUS ?? [],
63+
MEMORY: currentUser.value?.permissions?.MEMORY ?? [],
64+
CONVERSATION: currentUser.value?.permissions?.CONVERSATION ?? [],
65+
SETTINGS: currentUser.value?.permissions?.SETTINGS ?? [],
66+
LLM: currentUser.value?.permissions?.LLM ?? [],
67+
EMBEDDER: currentUser.value?.permissions?.EMBEDDER ?? [],
68+
AUTH_HANDLER: currentUser.value?.permissions?.AUTH_HANDLER ?? [],
69+
USERS: currentUser.value?.permissions?.USERS ?? [],
70+
UPLOAD: currentUser.value?.permissions?.UPLOAD ?? [],
71+
PLUGINS: currentUser.value?.permissions?.PLUGINS ?? [],
72+
STATIC: currentUser.value?.permissions?.STATIC ?? [],
73+
});
74+
75+
// Function to handle selecting all permissions for a resource
76+
const fillAll = (resource: string) => {
77+
userPermissions.value[resource] = availablePerms.value[resource] ?? [];
78+
};
5979
</script>
6080

6181
<template>
@@ -202,22 +222,25 @@ const createOrUpdateUser = () => {
202222
<div class="label py-0">
203223
<span class="label-text">{{ startCase(lowerCase(r)) }}</span>
204224
</div>
205-
<div class="flex items-center gap-2">
206-
<div v-for="p in l" :key="p" class="form-control">
207-
<label class="label cursor-pointer gap-2 py-1">
208-
<input :checked="currentUser?.permissions?.[r]?.includes(p)" type="checkbox"
209-
class="checkbox-primary checkbox checkbox-xs rounded" @click="() => {
210-
if (currentUser?.permissions?.[r]?.includes(p)) {
211-
currentUser.permissions[r] = currentUser.permissions[r].filter((perm: string) => perm !== p)
212-
} else if (currentUser?.permissions?.[r]) {
213-
currentUser!.permissions![r].push(p)
214-
} else {
215-
currentUser!.permissions![r] = [p]
216-
}
217-
}" />
218-
<span class="label-text">{{ p }}</span>
219-
</label>
220-
</div>
225+
<div class="label py-0">
226+
<Listbox multiple v-model="userPermissions[r]">
227+
<ListboxButton class="w-full input input-sm input-bordered">
228+
{{ userPermissions[r].map((p) => p).join(', ') ||
229+
currentUser?.permissions?.[r]?.join(', ') }}
230+
</ListboxButton>
231+
<ListboxOptions class="w-full">
232+
<ListboxOption v-for="permission in l" as="template" v-slot="{ active, selected }">
233+
<li :class="{
234+
'bg-blue-500 text-white': active,
235+
'bg-white text-black': !active,
236+
}">
237+
<CheckIcon v-show="selected" />
238+
{{ permission as string }}
239+
</li>
240+
</ListboxOption>
241+
</ListboxOptions>
242+
</Listbox>
243+
<button class="btn btn-outline btn-info btn-xs ml-1" @click="fillAll(r)">All</button>
221244
</div>
222245
</label>
223246
</div>

0 commit comments

Comments
 (0)