From 33a2c0b59eea01699741ffb06ac31b82bcd1aefd Mon Sep 17 00:00:00 2001 From: Yuriha <121590760+yuriha-chan@users.noreply.github.com> Date: Sat, 24 Jun 2023 07:51:44 +0900 Subject: Make role tag clickable on user pages (#11019) --- packages/frontend/src/pages/user/home.vue | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'packages/frontend/src/pages') diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index 2e69eb367b..23588763bc 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -44,8 +44,10 @@
- - {{ role.name }} + + + {{ role.name }} +
-- cgit v1.2.3-freya From a1327fa9e1329f2fb00d70b1e2332cea015bfdee Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 2 Jul 2023 08:28:26 +0900 Subject: perf(backend): allow get for some endpoints --- packages/backend/src/server/api/endpoints/get-online-users-count.ts | 2 ++ packages/backend/src/server/api/endpoints/hashtags/trend.ts | 2 ++ packages/frontend/src/pages/admin/overview.stats.vue | 2 +- packages/frontend/src/widgets/WidgetOnlineUsers.vue | 2 +- packages/frontend/src/widgets/WidgetTrends.vue | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) (limited to 'packages/frontend/src/pages') diff --git a/packages/backend/src/server/api/endpoints/get-online-users-count.ts b/packages/backend/src/server/api/endpoints/get-online-users-count.ts index dea0f4799c..810bde03e8 100644 --- a/packages/backend/src/server/api/endpoints/get-online-users-count.ts +++ b/packages/backend/src/server/api/endpoints/get-online-users-count.ts @@ -9,6 +9,8 @@ export const meta = { tags: ['meta'], requireCredential: false, + allowGet: true, + cacheSec: 60 * 1, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/hashtags/trend.ts b/packages/backend/src/server/api/endpoints/hashtags/trend.ts index cf45cc6c24..ce1cd9f01f 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/trend.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/trend.ts @@ -26,6 +26,8 @@ export const meta = { tags: ['hashtags'], requireCredential: false, + allowGet: true, + cacheSec: 60 * 1, res: { type: 'array', diff --git a/packages/frontend/src/pages/admin/overview.stats.vue b/packages/frontend/src/pages/admin/overview.stats.vue index 142e70c698..f746ad14b9 100644 --- a/packages/frontend/src/pages/admin/overview.stats.vue +++ b/packages/frontend/src/pages/admin/overview.stats.vue @@ -73,7 +73,7 @@ let fetching = $ref(true); onMounted(async () => { const [_stats, _onlineUsersCount] = await Promise.all([ os.api('stats', {}), - os.api('get-online-users-count').then(res => res.count), + os.apiGet('get-online-users-count').then(res => res.count), ]); stats = _stats; onlineUsersCount = _onlineUsersCount; diff --git a/packages/frontend/src/widgets/WidgetOnlineUsers.vue b/packages/frontend/src/widgets/WidgetOnlineUsers.vue index c920c3ca53..7e01eba487 100644 --- a/packages/frontend/src/widgets/WidgetOnlineUsers.vue +++ b/packages/frontend/src/widgets/WidgetOnlineUsers.vue @@ -40,7 +40,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name, const onlineUsersCount = ref(0); const tick = () => { - os.api('get-online-users-count').then(res => { + os.apiGet('get-online-users-count').then(res => { onlineUsersCount.value = res.count; }); }; diff --git a/packages/frontend/src/widgets/WidgetTrends.vue b/packages/frontend/src/widgets/WidgetTrends.vue index 36f908d5ea..5fce4aedca 100644 --- a/packages/frontend/src/widgets/WidgetTrends.vue +++ b/packages/frontend/src/widgets/WidgetTrends.vue @@ -53,7 +53,7 @@ const stats = ref([]); const fetching = ref(true); const fetch = () => { - os.api('hashtags/trend').then(res => { + os.apiGet('hashtags/trend').then(res => { stats.value = res; fetching.value = false; }); -- cgit v1.2.3-freya From af3258dc79488b73435819e7799eb1515f15a6aa Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 2 Jul 2023 16:02:32 +0900 Subject: perf(backend): make some features optionable Resolve #11064 Resolve #11065 --- CHANGELOG.md | 4 ++++ locales/index.d.ts | 2 ++ locales/ja-JP.yml | 2 ++ packages/backend/assets/avatar.png | Bin 0 -> 13477 bytes .../migration/1688280713783-add-meta-options.js | 13 +++++++++++++ packages/backend/src/daemons/ServerStatsService.ts | 12 +++++++++--- packages/backend/src/models/entities/Meta.ts | 10 ++++++++++ packages/backend/src/server/ServerService.ts | 15 +++++++++++---- .../backend/src/server/api/endpoints/admin/meta.ts | 10 ++++++++++ .../src/server/api/endpoints/admin/update-meta.ts | 10 ++++++++++ .../backend/src/server/api/endpoints/server-info.ts | 19 +++++++++++++++++++ packages/frontend/src/pages/admin/other-settings.vue | 14 ++++++++++++++ .../frontend/src/widgets/server-metric/index.vue | 2 +- 13 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 packages/backend/assets/avatar.png create mode 100644 packages/backend/migration/1688280713783-add-meta-options.js (limited to 'packages/frontend/src/pages') diff --git a/CHANGELOG.md b/CHANGELOG.md index 681105fb7e..72c4f53d18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ ## 13.x.x (unreleased) +### General +- identicon生成を無効にしてパフォーマンスを向上させることができるようになりました +- サーバーのマシン情報の公開を無効にしてパフォーマンスを向上させることができるようになりました + ### Client - Fix: サーバーメトリクスが90度傾いている diff --git a/locales/index.d.ts b/locales/index.d.ts index eed29f408c..af6b803278 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1066,6 +1066,8 @@ export interface Locale { "additionalEmojiDictionary": string; "installed": string; "branding": string; + "enableServerMachineStats": string; + "enableIdenticonGeneration": string; "_initialAccountSetting": { "accountCreated": string; "letsStartAccountSetup": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 8004e53575..e7202bfbb5 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1063,6 +1063,8 @@ goToMisskey: "Misskeyへ" additionalEmojiDictionary: "絵文字の追加辞書" installed: "インストール済み" branding: "ブランディング" +enableServerMachineStats: "サーバーのマシン情報を公開する" +enableIdenticonGeneration: "ユーザーごとのIdenticon生成を有効にする" _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" diff --git a/packages/backend/assets/avatar.png b/packages/backend/assets/avatar.png new file mode 100644 index 0000000000..1b95a0c560 Binary files /dev/null and b/packages/backend/assets/avatar.png differ diff --git a/packages/backend/migration/1688280713783-add-meta-options.js b/packages/backend/migration/1688280713783-add-meta-options.js new file mode 100644 index 0000000000..12406fe085 --- /dev/null +++ b/packages/backend/migration/1688280713783-add-meta-options.js @@ -0,0 +1,13 @@ +export class AddMetaOptions1688280713783 { + name = 'AddMetaOptions1688280713783' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "enableServerMachineStats" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`ALTER TABLE "meta" ADD "enableIdenticonGeneration" boolean NOT NULL DEFAULT true`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableIdenticonGeneration"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableServerMachineStats"`); + } +} diff --git a/packages/backend/src/daemons/ServerStatsService.ts b/packages/backend/src/daemons/ServerStatsService.ts index 6cd71c0e2a..375fd5e516 100644 --- a/packages/backend/src/daemons/ServerStatsService.ts +++ b/packages/backend/src/daemons/ServerStatsService.ts @@ -3,6 +3,7 @@ import si from 'systeminformation'; import Xev from 'xev'; import * as osUtils from 'os-utils'; import { bindThis } from '@/decorators.js'; +import { MetaService } from '@/core/MetaService.js'; import type { OnApplicationShutdown } from '@nestjs/common'; const ev = new Xev(); @@ -14,9 +15,10 @@ const round = (num: number) => Math.round(num * 10) / 10; @Injectable() export class ServerStatsService implements OnApplicationShutdown { - private intervalId: NodeJS.Timer; + private intervalId: NodeJS.Timer | null = null; constructor( + private metaService: MetaService, ) { } @@ -24,7 +26,9 @@ export class ServerStatsService implements OnApplicationShutdown { * Report server stats regularly */ @bindThis - public start(): void { + public async start(): Promise { + if (!(await this.metaService.fetch(true)).enableServerMachineStats) return; + const log = [] as any[]; ev.on('requestServerStatsLog', x => { @@ -64,7 +68,9 @@ export class ServerStatsService implements OnApplicationShutdown { @bindThis public dispose(): void { - clearInterval(this.intervalId); + if (this.intervalId) { + clearInterval(this.intervalId); + } } @bindThis diff --git a/packages/backend/src/models/entities/Meta.ts b/packages/backend/src/models/entities/Meta.ts index f799551f30..a251c0b31c 100644 --- a/packages/backend/src/models/entities/Meta.ts +++ b/packages/backend/src/models/entities/Meta.ts @@ -413,6 +413,16 @@ export class Meta { }) public enableChartsForFederatedInstances: boolean; + @Column('boolean', { + default: false, + }) + public enableServerMachineStats: boolean; + + @Column('boolean', { + default: true, + }) + public enableIdenticonGeneration: boolean; + @Column('jsonb', { default: { }, }) diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts index c3d45e4ad6..1bae71617b 100644 --- a/packages/backend/src/server/ServerService.ts +++ b/packages/backend/src/server/ServerService.ts @@ -16,6 +16,7 @@ import { createTemp } from '@/misc/create-temp.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; +import { MetaService } from '@/core/MetaService.js'; import { ActivityPubServerService } from './ActivityPubServerService.js'; import { NodeinfoServerService } from './NodeinfoServerService.js'; import { ApiServerService } from './api/ApiServerService.js'; @@ -45,6 +46,7 @@ export class ServerService implements OnApplicationShutdown { @Inject(DI.emojisRepository) private emojisRepository: EmojisRepository, + private metaService: MetaService, private userEntityService: UserEntityService, private apiServerService: ApiServerService, private openApiServerService: OpenApiServerService, @@ -161,11 +163,16 @@ export class ServerService implements OnApplicationShutdown { }); fastify.get<{ Params: { x: string } }>('/identicon/:x', async (request, reply) => { - const [temp, cleanup] = await createTemp(); - await genIdenticon(request.params.x, fs.createWriteStream(temp)); reply.header('Content-Type', 'image/png'); reply.header('Cache-Control', 'public, max-age=86400'); - return fs.createReadStream(temp).on('close', () => cleanup()); + + if ((await this.metaService.fetch()).enableIdenticonGeneration) { + const [temp, cleanup] = await createTemp(); + await genIdenticon(request.params.x, fs.createWriteStream(temp)); + return fs.createReadStream(temp).on('close', () => cleanup()); + } else { + return reply.redirect('/static-assets/avatar.png'); + } }); fastify.get<{ Params: { code: string } }>('/verify-email/:code', async (request, reply) => { @@ -224,7 +231,7 @@ export class ServerService implements OnApplicationShutdown { @bindThis public async dispose(): Promise { - await this.streamingApiServerService.detach(); + await this.streamingApiServerService.detach(); await this.#fastify.close(); } diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 4cc1b6011f..28aec7a090 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -262,6 +262,14 @@ export const meta = { type: 'boolean', optional: false, nullable: false, }, + enableServerMachineStats: { + type: 'boolean', + optional: false, nullable: false, + }, + enableIdenticonGeneration: { + type: 'boolean', + optional: false, nullable: false, + }, policies: { type: 'object', optional: false, nullable: false, @@ -364,6 +372,8 @@ export default class extends Endpoint { enableActiveEmailValidation: instance.enableActiveEmailValidation, enableChartsForRemoteUser: instance.enableChartsForRemoteUser, enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances, + enableServerMachineStats: instance.enableServerMachineStats, + enableIdenticonGeneration: instance.enableIdenticonGeneration, policies: { ...DEFAULT_POLICIES, ...instance.policies }, }; }); diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 1de5e9efd3..5c9d8e3fac 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -96,6 +96,8 @@ export const paramDef = { enableActiveEmailValidation: { type: 'boolean' }, enableChartsForRemoteUser: { type: 'boolean' }, enableChartsForFederatedInstances: { type: 'boolean' }, + enableServerMachineStats: { type: 'boolean' }, + enableIdenticonGeneration: { type: 'boolean' }, serverRules: { type: 'array', items: { type: 'string' } }, preservedUsernames: { type: 'array', items: { type: 'string' } }, }, @@ -399,6 +401,14 @@ export default class extends Endpoint { set.enableChartsForFederatedInstances = ps.enableChartsForFederatedInstances; } + if (ps.enableServerMachineStats !== undefined) { + set.enableServerMachineStats = ps.enableServerMachineStats; + } + + if (ps.enableIdenticonGeneration !== undefined) { + set.enableIdenticonGeneration = ps.enableIdenticonGeneration; + } + if (ps.serverRules !== undefined) { set.serverRules = ps.serverRules; } diff --git a/packages/backend/src/server/api/endpoints/server-info.ts b/packages/backend/src/server/api/endpoints/server-info.ts index 1620e8ae52..552441e430 100644 --- a/packages/backend/src/server/api/endpoints/server-info.ts +++ b/packages/backend/src/server/api/endpoints/server-info.ts @@ -2,9 +2,12 @@ import * as os from 'node:os'; import si from 'systeminformation'; import { Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; +import { MetaService } from '@/core/MetaService.js'; export const meta = { requireCredential: false, + allowGet: true, + cacheSec: 60 * 1, tags: ['meta'], } as const; @@ -19,8 +22,24 @@ export const paramDef = { @Injectable() export default class extends Endpoint { constructor( + private metaService: MetaService, ) { super(meta, paramDef, async () => { + if (!(await this.metaService.fetch()).enableServerMachineStats) return { + machine: '?', + cpu: { + model: '?', + cores: 0, + }, + mem: { + total: 0, + }, + fs: { + total: 0, + used: 0, + }, + }; + const memStats = await si.mem(); const fsStats = await si.fsSize(); diff --git a/packages/frontend/src/pages/admin/other-settings.vue b/packages/frontend/src/pages/admin/other-settings.vue index 15d720a070..d3e1d9efc1 100644 --- a/packages/frontend/src/pages/admin/other-settings.vue +++ b/packages/frontend/src/pages/admin/other-settings.vue @@ -4,6 +4,14 @@
+ + + + + + + + @@ -27,17 +35,23 @@ import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; import MkSwitch from '@/components/MkSwitch.vue'; +let enableServerMachineStats: boolean = $ref(false); +let enableIdenticonGeneration: boolean = $ref(false); let enableChartsForRemoteUser: boolean = $ref(false); let enableChartsForFederatedInstances: boolean = $ref(false); async function init() { const meta = await os.api('admin/meta'); + enableServerMachineStats = meta.enableServerMachineStats; + enableIdenticonGeneration = meta.enableIdenticonGeneration; enableChartsForRemoteUser = meta.enableChartsForRemoteUser; enableChartsForFederatedInstances = meta.enableChartsForFederatedInstances; } function save() { os.apiWithDialog('admin/update-meta', { + enableServerMachineStats, + enableIdenticonGeneration, enableChartsForRemoteUser, enableChartsForFederatedInstances, }).then(() => { diff --git a/packages/frontend/src/widgets/server-metric/index.vue b/packages/frontend/src/widgets/server-metric/index.vue index e019ff540b..1a78f4bcd6 100644 --- a/packages/frontend/src/widgets/server-metric/index.vue +++ b/packages/frontend/src/widgets/server-metric/index.vue @@ -62,7 +62,7 @@ const { widgetProps, configure, save } = useWidgetPropsManager(name, const meta = ref(null); -os.api('server-info', {}).then(res => { +os.apiGet('server-info', {}).then(res => { meta.value = res; }); -- cgit v1.2.3-freya From 92d9946f597c2b06552b23ba370708aea86575c0 Mon Sep 17 00:00:00 2001 From: tamaina Date: Wed, 5 Jul 2023 00:59:37 +0900 Subject: enhance(frontend): Better Timeline(MkPagination) Experience (#11066) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance(frontend): Better MkPagination Appearance * fix * fix * 新規投稿が空でも先頭に戻ったらunshiftItemsする * use Map * refactor, 型エラー潰し * refactor --- packages/frontend/src/components/MkPagination.vue | 170 +++++++++++++++------ packages/frontend/src/pages/admin/abuses.vue | 2 +- .../frontend/src/pages/custom-emojis-manager.vue | 2 +- 3 files changed, 127 insertions(+), 47 deletions(-) (limited to 'packages/frontend/src/pages') diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue index 598529bf58..b361d568e8 100644 --- a/packages/frontend/src/components/MkPagination.vue +++ b/packages/frontend/src/components/MkPagination.vue @@ -21,14 +21,14 @@
- + {{ i18n.ts.loadMore }}
- +
- + {{ i18n.ts.loadMore }} @@ -50,6 +50,7 @@ import { i18n } from '@/i18n'; const SECOND_FETCH_LIMIT = 30; const TOLERANCE = 16; +const APPEAR_MINIMUM_INTERVAL = 600; export type Paging = { endpoint: E; @@ -71,6 +72,16 @@ export type Paging pageEl?: HTMLElement; }; + +type MisskeyEntityMap = Map; + +function arrayToEntries(entities: MisskeyEntity[]): [string, MisskeyEntity][] { + return entities.map(en => [en.id, en]); +} + +function concatMapWithArray(map: MisskeyEntityMap, entities: MisskeyEntity[]): MisskeyEntityMap { + return new Map([...map, ...arrayToEntries(entities)]); +} diff --git a/packages/frontend/src/pages/admin/overview.federation.vue b/packages/frontend/src/pages/admin/overview.federation.vue index ab78c4c393..469d2e6927 100644 --- a/packages/frontend/src/pages/admin/overview.federation.vue +++ b/packages/frontend/src/pages/admin/overview.federation.vue @@ -58,7 +58,7 @@ let federationSubActiveDiff = $ref(null); let fetching = $ref(true); const { handler: externalTooltipHandler } = useChartTooltip(); - + onMounted(async () => { const chart = await os.apiGet('charts/federation', { limit: 2, span: 'day' }); federationPubActive = chart.pubActive[0]; diff --git a/packages/frontend/src/pages/admin/overview.queue.vue b/packages/frontend/src/pages/admin/overview.queue.vue index 69ca89e226..b08757aeb8 100644 --- a/packages/frontend/src/pages/admin/overview.queue.vue +++ b/packages/frontend/src/pages/admin/overview.queue.vue @@ -122,4 +122,4 @@ onUnmounted(() => { } } } - + diff --git a/packages/frontend/src/pages/admin/overview.vue b/packages/frontend/src/pages/admin/overview.vue index e8295c81b5..838c197f05 100644 --- a/packages/frontend/src/pages/admin/overview.vue +++ b/packages/frontend/src/pages/admin/overview.vue @@ -30,7 +30,7 @@ - + diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue index a1fa9d2932..02a2d4366a 100644 --- a/packages/frontend/src/pages/admin/roles.editor.vue +++ b/packages/frontend/src/pages/admin/roles.editor.vue @@ -210,7 +210,7 @@
- + - - diff --git a/packages/frontend/src/pages/my-lists/index.vue b/packages/frontend/src/pages/my-lists/index.vue index cee241c489..0f59ca0b36 100644 --- a/packages/frontend/src/pages/my-lists/index.vue +++ b/packages/frontend/src/pages/my-lists/index.vue @@ -3,38 +3,43 @@
+
+
+ +
{{ i18n.ts.nothing }}
+
+
+ {{ i18n.ts.createList }} - -
- -
{{ list.name }}
- -
-
-
+
+ +
{{ list.name }}
+ +
+
diff --git a/packages/frontend/src/const.ts b/packages/frontend/src/const.ts index ad7fa372e9..1d883c038e 100644 --- a/packages/frontend/src/const.ts +++ b/packages/frontend/src/const.ts @@ -57,6 +57,9 @@ export const ROLE_POLICIES = [ 'ltlAvailable', 'canPublicNote', 'canInvite', + 'inviteLimit', + 'inviteLimitCycle', + 'inviteExpirationTime', 'canManageCustomEmojis', 'canSearchNotes', 'canHideAds', diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue index 226eb8d026..e91f65b5d5 100644 --- a/packages/frontend/src/pages/admin/index.vue +++ b/packages/frontend/src/pages/admin/index.vue @@ -80,7 +80,7 @@ const menuDef = $computed(() => [{ }, ...(instance.disableRegistration ? [{ type: 'button', icon: 'ti ti-user-plus', - text: i18n.ts.invite, + text: i18n.ts.createInviteCode, action: invite, }] : [])], }, { @@ -95,6 +95,11 @@ const menuDef = $computed(() => [{ text: i18n.ts.users, to: '/admin/users', active: currentPage?.route.name === 'users', + }, { + icon: 'ti ti-user-plus', + text: i18n.ts.invite, + to: '/admin/invites', + active: currentPage?.route.name === 'invites', }, { icon: 'ti ti-badges', text: i18n.ts.roles, @@ -240,10 +245,10 @@ provideMetadataReceiver((info) => { }); const invite = () => { - os.api('invite').then(x => { + os.api('admin/invite/create').then(x => { os.alert({ type: 'info', - text: x.code, + text: x?.[0].code, }); }).catch(err => { os.alert({ diff --git a/packages/frontend/src/pages/admin/invites.vue b/packages/frontend/src/pages/admin/invites.vue new file mode 100644 index 0000000000..70a9c93713 --- /dev/null +++ b/packages/frontend/src/pages/admin/invites.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue index 02a2d4366a..7fe5624fb5 100644 --- a/packages/frontend/src/pages/admin/roles.editor.vue +++ b/packages/frontend/src/pages/admin/roles.editor.vue @@ -171,6 +171,65 @@
+ + + +
+ + + + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+