mirror of
https://github.com/gotson/komga.git
synced 2025-12-09 10:05:10 +01:00
users dialog wip
This commit is contained in:
parent
646047e01c
commit
11cc783c87
6 changed files with 201 additions and 19 deletions
20
next-ui/src/colada/mutations/update-user.ts
Normal file
20
next-ui/src/colada/mutations/update-user.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import {defineMutation, useMutation, useQueryCache} from '@pinia/colada'
|
||||
import {komgaClient} from '@/api/komga-client'
|
||||
import type {components} from '@/generated/openapi/komga'
|
||||
|
||||
export const useUpdateUser = defineMutation(() => {
|
||||
const queryCache = useQueryCache()
|
||||
return useMutation({
|
||||
mutation: (user: components['schemas']['UserDto']) =>
|
||||
komgaClient.PATCH('/api/v2/users/{id}', {
|
||||
params: {path: {id: user.id}},
|
||||
body: user,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
queryCache.invalidateQueries({key: ['users']})
|
||||
},
|
||||
onError: (error) => {
|
||||
console.log('update user error', error)
|
||||
},
|
||||
})
|
||||
})
|
||||
4
next-ui/src/components.d.ts
vendored
4
next-ui/src/components.d.ts
vendored
|
|
@ -21,6 +21,10 @@ declare module 'vue' {
|
|||
AppFooter: typeof import('./components/AppFooter.vue')['default']
|
||||
BuildCommit: typeof import('./components/BuildCommit.vue')['default']
|
||||
BuildVersion: typeof import('./components/BuildVersion.vue')['default']
|
||||
DialogConfirm: typeof import('./components/dialogs/DialogConfirm.vue')['default']
|
||||
DialogConfirmEdit: typeof import('./components/dialogs/DialogConfirmEdit.vue')['default']
|
||||
FormUserChangePassword: typeof import('./components/forms/user/FormUserChangePassword.vue')['default']
|
||||
FormUserRoles: typeof import('./components/forms/user/FormUserRoles.vue')['default']
|
||||
HelloWorld: typeof import('./components/HelloWorld.vue')['default']
|
||||
LoginForm: typeof import('./components/LoginForm.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
|
|
|
|||
67
next-ui/src/components/dialogs/DialogConfirmEdit.vue
Normal file
67
next-ui/src/components/dialogs/DialogConfirmEdit.vue
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<template>
|
||||
<v-dialog
|
||||
v-model="showDialog"
|
||||
:activator="activator"
|
||||
:max-width="maxWidth"
|
||||
>
|
||||
<v-confirm-edit
|
||||
v-model="record"
|
||||
hide-actions
|
||||
@save="close()"
|
||||
>
|
||||
<template #default="{ model: proxyModel, cancel, save, isPristine }">
|
||||
<v-card
|
||||
:title="title"
|
||||
:subtitle="subtitle"
|
||||
>
|
||||
<template #text>
|
||||
<slot
|
||||
name="text"
|
||||
:proxy-model="proxyModel"
|
||||
:cancel="cancel"
|
||||
:save="save"
|
||||
:is-pristine="isPristine"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #actions>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
text="Cancel"
|
||||
@click="close()"
|
||||
/>
|
||||
<v-btn
|
||||
:disabled="isPristine"
|
||||
text="Save"
|
||||
@click="save"
|
||||
/>
|
||||
</template>
|
||||
</v-card>
|
||||
</template>
|
||||
</v-confirm-edit>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const showDialog = defineModel<boolean>('dialog', {required: false})
|
||||
const record = defineModel<unknown>('record', {required: true})
|
||||
|
||||
interface Props {
|
||||
title?: string,
|
||||
subtitle?: string,
|
||||
maxWidth?: string | number,
|
||||
activator?: Element | string,
|
||||
}
|
||||
|
||||
const {
|
||||
title = undefined,
|
||||
subtitle = undefined,
|
||||
maxWidth = undefined,
|
||||
activator = undefined,
|
||||
} = defineProps<Props>()
|
||||
|
||||
function close() {
|
||||
showDialog.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
10
next-ui/src/components/forms/user/FormUserChangePassword.vue
Normal file
10
next-ui/src/components/forms/user/FormUserChangePassword.vue
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<template>
|
||||
<v-text-field />
|
||||
<v-text-field />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type {components} from '@/generated/openapi/komga'
|
||||
|
||||
const user = defineModel<components["schemas"]["UserDto"] | undefined>({required: true})
|
||||
</script>
|
||||
22
next-ui/src/components/forms/user/FormUserRoles.vue
Normal file
22
next-ui/src/components/forms/user/FormUserRoles.vue
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<template>
|
||||
<v-checkbox
|
||||
v-for="role in userRoles"
|
||||
:key="role.value"
|
||||
v-model="user.roles"
|
||||
:label="role.text"
|
||||
:value="role.value"
|
||||
hide-details
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {UserRoles} from '@/types/UserRoles.ts'
|
||||
import type {components} from '@/generated/openapi/komga'
|
||||
|
||||
const user = defineModel<components["schemas"]["UserDto"]>({required: true})
|
||||
|
||||
const userRoles = computed(() => Object.keys(UserRoles).map(x => ({
|
||||
text: x,
|
||||
value: x,
|
||||
})))
|
||||
</script>
|
||||
|
|
@ -27,34 +27,54 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<template #[`item.actions`]="{ item }">
|
||||
<template #[`item.actions`]="{ item : user }">
|
||||
<div class="d-flex ga-1 justify-end">
|
||||
<v-icon-btn
|
||||
v-tooltip:bottom="'Reset password'"
|
||||
icon="mdi-lock-reset"
|
||||
@click="changePassword(item.id)"
|
||||
@click="showDialog(ACTION.PASSWORD, user)"
|
||||
@mouseenter="activator = $event.currentTarget"
|
||||
/>
|
||||
<v-icon-btn
|
||||
v-tooltip:bottom="'Edit restrictions'"
|
||||
icon="mdi-book-lock"
|
||||
:disabled="me?.id == item.id"
|
||||
@click="editRestrictions(item.id)"
|
||||
:disabled="me?.id == user.id"
|
||||
@click="showDialog(ACTION.RESTRICTIONS, user)"
|
||||
@mouseenter="activator = $event.currentTarget"
|
||||
/>
|
||||
<v-icon-btn
|
||||
v-tooltip:bottom="'Edit user'"
|
||||
icon="mdi-pencil"
|
||||
:disabled="me?.id == item.id"
|
||||
@click="editUser(item.id)"
|
||||
:disabled="me?.id == user.id"
|
||||
@click="showDialog(ACTION.EDIT, user)"
|
||||
@mouseenter="activator = $event.currentTarget"
|
||||
/>
|
||||
<v-icon-btn
|
||||
v-tooltip:bottom="'Delete user'"
|
||||
icon="mdi-delete"
|
||||
:disabled="me?.id == item.id"
|
||||
@click="deleteUser(item.id)"
|
||||
:disabled="me?.id == user.id"
|
||||
@click="showDialog(ACTION.DELETE, user)"
|
||||
@mouseenter="activator = $event.currentTarget"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
<DialogConfirmEdit
|
||||
v-model:record="userRecord"
|
||||
:activator="activator"
|
||||
:title="dialogTitle"
|
||||
:subtitle="userRecord?.email"
|
||||
max-width="400"
|
||||
@update:record="handleConfirmation()"
|
||||
>
|
||||
<template #text="{proxyModel}">
|
||||
<component
|
||||
:is="dialogComponent"
|
||||
v-model="proxyModel.value"
|
||||
/>
|
||||
</template>
|
||||
</DialogConfirmEdit>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
|
|
@ -64,12 +84,18 @@ import {komgaClient} from '@/api/komga-client.ts'
|
|||
import type {components} from '@/generated/openapi/komga'
|
||||
import {useCurrentUser} from '@/colada/queries/current-user.ts'
|
||||
import {UserRoles} from '@/types/UserRoles.ts'
|
||||
import {useUpdateUser} from '@/colada/mutations/update-user.ts'
|
||||
import FormUserChangePassword from '@/components/forms/user/FormUserChangePassword.vue'
|
||||
import FormUserRoles from '@/components/forms/user/FormUserRoles.vue'
|
||||
import type {Component} from 'vue'
|
||||
|
||||
// API data
|
||||
const {data: users, error, isLoading} = useUsers()
|
||||
const {data: me} = useCurrentUser()
|
||||
|
||||
const hideFooter = computed(() => users.value && users.value.length < 11)
|
||||
|
||||
// Table
|
||||
const hideFooter = computed(() => users.value && users.value.length < 11)
|
||||
const headers = [
|
||||
{title: 'Email', key: 'email'},
|
||||
{title: 'Latest Activity', key: 'activity', value: (item: components["schemas"]["UserDto"]) => latestActivity[item.id]},
|
||||
|
|
@ -104,20 +130,53 @@ watch(users, (users) => {
|
|||
})
|
||||
|
||||
|
||||
function editRestrictions(userId: string) {
|
||||
console.log('edit restrictions: ', userId)
|
||||
// Dialogs handling
|
||||
const userRecord = ref<components["schemas"]["UserDto"]>()
|
||||
const currentAction = ref<ACTION>()
|
||||
const activator = ref<Element>()
|
||||
const dialogTitle = ref<string>()
|
||||
const dialogComponent = shallowRef<Component>()
|
||||
|
||||
const {mutate: mutateUser} = useUpdateUser()
|
||||
|
||||
enum ACTION {
|
||||
EDIT, DELETE, RESTRICTIONS, PASSWORD
|
||||
}
|
||||
|
||||
function deleteUser(userId: string) {
|
||||
console.log('delete: ', userId)
|
||||
function showDialog(action: ACTION, user: components["schemas"]["UserDto"]) {
|
||||
currentAction.value = action
|
||||
switch (action) {
|
||||
case ACTION.EDIT:
|
||||
dialogTitle.value = 'Edit Roles'
|
||||
dialogComponent.value = FormUserRoles
|
||||
break;
|
||||
case ACTION.DELETE:
|
||||
dialogTitle.value = 'Delete User'
|
||||
dialogComponent.value = FormUserRoles
|
||||
break;
|
||||
case ACTION.RESTRICTIONS:
|
||||
dialogTitle.value = 'Edit Restrictions'
|
||||
dialogComponent.value = FormUserRoles
|
||||
break;
|
||||
case ACTION.PASSWORD:
|
||||
dialogTitle.value = 'Change Password'
|
||||
dialogComponent.value = FormUserChangePassword
|
||||
}
|
||||
userRecord.value = user
|
||||
}
|
||||
|
||||
function editUser(userId: string) {
|
||||
console.log('edit: ', userId)
|
||||
}
|
||||
|
||||
function changePassword(userId: string) {
|
||||
console.log('change password: ', userId)
|
||||
function handleConfirmation() {
|
||||
switch (currentAction.value) {
|
||||
case ACTION.EDIT:
|
||||
mutateUser(userRecord.value!)
|
||||
break;
|
||||
case ACTION.DELETE:
|
||||
break;
|
||||
case ACTION.RESTRICTIONS:
|
||||
break;
|
||||
case ACTION.PASSWORD:
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue