feat(webui): split account settings into different views

This commit is contained in:
Gauthier Roebroeck 2025-01-21 15:12:31 +08:00
parent c36e10d93d
commit 169c47e701
7 changed files with 166 additions and 115 deletions

View file

@ -1,84 +1,89 @@
<template>
<div style="position: relative">
<div v-if="apiKeys.length > 0">
<v-list elevation="3"
three-line
>
<div v-for="(apiKey, index) in apiKeys" :key="apiKey.id">
<v-list-item>
<v-list-item-content>
<v-list-item-title>{{ apiKey.comment }}</v-list-item-title>
<v-list-item-subtitle>
{{
$t('account_settings.api_key.created_date', {
date:
new Intl.DateTimeFormat($i18n.locale, {
dateStyle: 'medium',
timeStyle: 'short'
}).format(apiKey.createdDate)
})
}}
</v-list-item-subtitle>
<v-list-item-subtitle v-if="apiKeyLastActivity[apiKey.id] !== undefined">
{{
$t('settings_user.latest_activity', {
date:
new Intl.DateTimeFormat($i18n.locale, {
dateStyle: 'medium',
timeStyle: 'short'
}).format(apiKeyLastActivity[apiKey.id])
})
}}
</v-list-item-subtitle>
<v-list-item-subtitle v-else>{{ $t('settings_user.no_recent_activity') }}</v-list-item-subtitle>
</v-list-item-content>
<div v-if="apiKeys">
<div v-if="apiKeys.length > 0">
<v-list elevation="3"
three-line
>
<div v-for="(apiKey, index) in apiKeys" :key="apiKey.id">
<v-list-item>
<v-list-item-content>
<v-list-item-title>{{ apiKey.comment }}</v-list-item-title>
<v-list-item-subtitle>
{{
$t('account_settings.api_key.created_date', {
date:
new Intl.DateTimeFormat($i18n.locale, {
dateStyle: 'medium',
timeStyle: 'short'
}).format(apiKey.createdDate)
})
}}
</v-list-item-subtitle>
<v-list-item-subtitle v-if="apiKeyLastActivity[apiKey.id] !== undefined">
{{
$t('settings_user.latest_activity', {
date:
new Intl.DateTimeFormat($i18n.locale, {
dateStyle: 'medium',
timeStyle: 'short'
}).format(apiKeyLastActivity[apiKey.id])
})
}}
</v-list-item-subtitle>
<v-list-item-subtitle v-else>{{ $t('settings_user.no_recent_activity') }}</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
<v-tooltip bottom>
<template v-slot:activator="{ on }">
<v-btn icon @click="promptSyncPointDelete(apiKey)" v-on="on">
<v-icon>mdi-book-refresh</v-icon>
</v-btn>
</template>
<span>{{ $t('account_settings.api_key.force_kobo_sync') }}</span>
</v-tooltip>
</v-list-item-action>
<v-list-item-action>
<v-tooltip bottom>
<template v-slot:activator="{ on }">
<v-btn icon @click="promptSyncPointDelete(apiKey)" v-on="on">
<v-icon>mdi-book-refresh</v-icon>
</v-btn>
</template>
<span>{{ $t('account_settings.api_key.force_kobo_sync') }}</span>
</v-tooltip>
</v-list-item-action>
<v-list-item-action>
<v-btn icon @click="promptDeleteApiKey(apiKey)">
<v-icon>mdi-delete</v-icon>
<v-list-item-action>
<v-btn icon @click="promptDeleteApiKey(apiKey)">
<v-icon>mdi-delete</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
<v-divider v-if="index !== apiKeys.length-1"/>
</div>
</v-list>
<v-btn fab absolute bottom color="primary"
:right="!$vuetify.rtl"
:left="$vuetify.rtl"
class="mx-6"
small
@click="generateApiKey"
>
<v-icon>mdi-plus</v-icon>
</v-btn>
</div>
<div v-else>
<v-container fluid class="pa-0">
<v-row>
<v-col>{{ $t('account_settings.api_key.no_keys') }}</v-col>
</v-row>
<v-row>
<v-col>
<v-btn color="primary" @click="generateApiKey">{{
$t('account_settings.api_key.generate_api_key')
}}
</v-btn>
</v-list-item-action>
</v-list-item>
</v-col>
<v-divider v-if="index !== apiKeys.length-1"/>
</div>
</v-list>
</v-row>
<v-btn fab absolute bottom color="primary"
:right="!$vuetify.rtl"
:left="$vuetify.rtl"
class="mx-6"
small
@click="generateApiKey"
>
<v-icon>mdi-plus</v-icon>
</v-btn>
</div>
<div v-else>
<v-container fluid class="pa-0">
<v-row>
<v-col>{{ $t('account_settings.api_key.no_keys') }}</v-col>
</v-row>
<v-row>
<v-col>
<v-btn color="primary" @click="generateApiKey">{{ $t('account_settings.api_key.generate_api_key') }}</v-btn>
</v-col>
</v-row>
</v-container>
</v-container>
</div>
</div>
<confirmation-dialog
@ -120,7 +125,7 @@ export default Vue.extend({
components: {ApiKeyAddDialog, ConfirmationDialog},
data: () => {
return {
apiKeys: [] as ApiKeyDto[],
apiKeys: undefined as ApiKeyDto[],
apiKeyToDelete: {} as ApiKeyDto,
apiKeySyncPointsToDelete: {} as ApiKeyDto,
modalDeleteApiKey: false,

View file

@ -25,7 +25,9 @@
"generate_api_key": "Generate API key",
"no_keys": "No API Keys created yet"
},
"change_password": "change password"
"change_password": "change password",
"details": "Details",
"my_account": "My Account"
},
"announcements": {
"mark_all_read": "Mark all as read",

View file

@ -135,11 +135,20 @@ const router = new Router({
name: 'history',
component: () => import(/* webpackChunkName: "history" */ './views/HistoryView.vue'),
},
{
path: '/account',
name: 'account',
component: () => import(/* webpackChunkName: "account" */ './views/AccountSettings.vue'),
path: '/account/me',
name: 'account-me',
component: () => import(/* webpackChunkName: "account-me" */ './views/AccountView.vue'),
},
{
path: '/account/api-keys',
name: 'account-api-keys',
component: () => import(/* webpackChunkName: "account-api-keys" */ './views/ApiKeys.vue'),
},
{
path: '/account/authentication-activity',
name: 'account-activity',
component: () => import(/* webpackChunkName: "account-activity" */ './views/SelfAuthenticationActivity.vue'),
},
{
path: '/libraries/:libraryId?',

View file

@ -1,9 +1,5 @@
<template>
<v-container fluid class="pa-6">
<v-row>
<v-col class="text-h5">{{ $t('account_settings.account_settings') }}</v-col>
</v-row>
<v-row align="center">
<v-col cols="12" md="8" lg="6" xl="4">
<span class="text-capitalize">{{ $t('common.email') }}</span>
@ -34,26 +30,6 @@
</v-col>
</v-row>
<v-row>
<v-col class="text-h5">{{ $t('users.api_keys') }}</v-col>
</v-row>
<v-row>
<v-col cols="12" md="10" lg="8" xl="4">
<api-key-table/>
</v-col>
</v-row>
<v-row>
<v-col class="text-h5">{{ $t('users.authentication_activity') }}</v-col>
</v-row>
<v-row>
<v-col>
<authentication-activity-table for-me/>
</v-col>
</v-row>
<password-change-dialog v-model="modalPasswordChange"
:user="me"
/>
@ -64,13 +40,11 @@
<script lang="ts">
import PasswordChangeDialog from '@/components/dialogs/PasswordChangeDialog.vue'
import Vue from 'vue'
import AuthenticationActivityTable from '@/components/AuthenticationActivityTable.vue'
import {UserDto} from '@/types/komga-users'
import ApiKeyTable from '@/components/ApiKeyTable.vue'
export default Vue.extend({
name: 'AccountSettings',
components: {ApiKeyTable, AuthenticationActivityTable, PasswordChangeDialog},
components: {PasswordChangeDialog},
data: () => {
return {
modalPasswordChange: false,

View file

@ -0,0 +1,23 @@
<template>
<v-container fluid class="pa-6">
<v-row>
<v-col cols="12" md="10" lg="8" xl="4">
<api-key-table/>
</v-col>
</v-row>
</v-container>
</template>
<script lang="ts">
import Vue from 'vue'
import ApiKeyTable from '@/components/ApiKeyTable.vue'
export default Vue.extend({
name: 'ApiKeys',
components: {ApiKeyTable},
})
</script>
<style scoped>
</style>

View file

@ -234,14 +234,27 @@
</v-list-item>
</v-list-group>
<v-list-item :to="{name: 'account'}">
<v-list-item-action>
<v-icon>mdi-account</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>{{ $t('account_settings.account_settings') }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
<!-- ACCOUNT -->
<v-list-group prepend-icon="mdi-account"
no-action
v-model="expandAccount"
>
<template v-slot:activator>
<v-list-item-title>{{ $t('account_settings.my_account') }}</v-list-item-title>
</template>
<v-list-item :to="{name: 'account-me'}">
<v-list-item-title>{{ $t('account_settings.details') }}</v-list-item-title>
</v-list-item>
<v-list-item :to="{name: 'account-api-keys'}">
<v-list-item-title>{{ $t('users.api_keys') }}</v-list-item-title>
</v-list-item>
<v-list-item :to="{name: 'account-activity'}">
<v-list-item-title>{{ $t('users.authentication_activity') }}</v-list-item-title>
</v-list-item>
</v-list-group>
<v-list-item @click="logout">
<v-list-item-icon>
@ -332,6 +345,7 @@ export default Vue.extend({
expandDuplicatePages: false,
expandMediaManagement: false,
expandImport: false,
expandAccount: false,
}
},
async created() {
@ -416,6 +430,7 @@ export default Vue.extend({
this.expandMediaManagement = to.path.includes('/media-management/')
this.expandImport = to.path.includes('/import/')
this.expandDuplicatePages = to.path.includes('/duplicate-pages/')
this.expandAccount = to.path.includes('/account/')
},
toggleDrawer() {
this.drawerVisible = !this.drawerVisible

View file

@ -0,0 +1,23 @@
<template>
<v-container fluid class="pa-6">
<v-row>
<v-col>
<authentication-activity-table for-me/>
</v-col>
</v-row>
</v-container>
</template>
<script lang="ts">
import Vue from 'vue'
import AuthenticationActivityTable from '@/components/AuthenticationActivityTable.vue'
export default Vue.extend({
name: 'SelfAuthenticationActivity',
components: {AuthenticationActivityTable},
})
</script>
<style scoped>
</style>