mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-17 01:56:27 +08:00
feat: improve admin panel design (#14464)
This commit is contained in:
@@ -56,7 +56,7 @@ defineModuleConfig('mailer', {
|
||||
env: 'MAILER_PASSWORD',
|
||||
},
|
||||
'SMTP.sender': {
|
||||
desc: 'Sender of all the emails (e.g. "AFFiNE Self Hosted <noreply@example.com>")',
|
||||
desc: 'Sender of all the emails (e.g. "AFFiNE Self Hosted <noreply@example.com>")',
|
||||
default: 'AFFiNE Self Hosted <noreply@example.com>',
|
||||
env: 'MAILER_SENDER',
|
||||
},
|
||||
@@ -92,7 +92,7 @@ defineModuleConfig('mailer', {
|
||||
default: '',
|
||||
},
|
||||
'fallbackSMTP.sender': {
|
||||
desc: 'Sender of all the emails (e.g. "AFFiNE Self Hosted <noreply@example.com>")',
|
||||
desc: 'Sender of all the emails (e.g. "AFFiNE Self Hosted <noreply@example.com>")',
|
||||
default: '',
|
||||
},
|
||||
'fallbackSMTP.ignoreTLS': {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import {
|
||||
Args,
|
||||
Field,
|
||||
Info,
|
||||
InputType,
|
||||
Int,
|
||||
Mutation,
|
||||
@@ -14,6 +15,12 @@ import {
|
||||
ResolveField,
|
||||
Resolver,
|
||||
} from '@nestjs/graphql';
|
||||
import {
|
||||
type FragmentDefinitionNode,
|
||||
type GraphQLResolveInfo,
|
||||
Kind,
|
||||
type SelectionNode,
|
||||
} from 'graphql';
|
||||
import { SafeIntResolver } from 'graphql-scalars';
|
||||
|
||||
import { PaginationInput, URLHelper } from '../../../base';
|
||||
@@ -53,6 +60,44 @@ registerEnumType(AdminSharedLinksOrder, {
|
||||
name: 'AdminSharedLinksOrder',
|
||||
});
|
||||
|
||||
function hasSelectedField(
|
||||
selections: readonly SelectionNode[],
|
||||
fieldName: string,
|
||||
fragments: Record<string, FragmentDefinitionNode>
|
||||
): boolean {
|
||||
for (const selection of selections) {
|
||||
if (selection.kind === Kind.FIELD) {
|
||||
if (selection.name.value === fieldName) {
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selection.kind === Kind.INLINE_FRAGMENT) {
|
||||
if (
|
||||
hasSelectedField(
|
||||
selection.selectionSet.selections,
|
||||
fieldName,
|
||||
fragments
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const fragment = fragments[selection.name.value];
|
||||
if (
|
||||
fragment &&
|
||||
hasSelectedField(fragment.selectionSet.selections, fieldName, fragments)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@InputType()
|
||||
class ListWorkspaceInput {
|
||||
@Field(() => Int, { defaultValue: 20 })
|
||||
@@ -471,22 +516,40 @@ export class AdminWorkspaceResolver {
|
||||
})
|
||||
async adminDashboard(
|
||||
@Args('input', { nullable: true, type: () => AdminDashboardInput })
|
||||
input?: AdminDashboardInput
|
||||
input?: AdminDashboardInput,
|
||||
@Info() info?: GraphQLResolveInfo
|
||||
) {
|
||||
this.assertCloudOnly();
|
||||
const includeTopSharedLinks = Boolean(
|
||||
info?.fieldNodes.some(
|
||||
node =>
|
||||
node.selectionSet &&
|
||||
hasSelectedField(
|
||||
node.selectionSet.selections,
|
||||
'topSharedLinks',
|
||||
info.fragments
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const dashboard = await this.models.workspaceAnalytics.adminGetDashboard({
|
||||
timezone: input?.timezone,
|
||||
storageHistoryDays: input?.storageHistoryDays,
|
||||
syncHistoryHours: input?.syncHistoryHours,
|
||||
sharedLinkWindowDays: input?.sharedLinkWindowDays,
|
||||
includeTopSharedLinks,
|
||||
});
|
||||
|
||||
return {
|
||||
...dashboard,
|
||||
topSharedLinks: dashboard.topSharedLinks.map(link => ({
|
||||
...link,
|
||||
shareUrl: this.url.link(`/workspace/${link.workspaceId}/${link.docId}`),
|
||||
})),
|
||||
topSharedLinks: includeTopSharedLinks
|
||||
? dashboard.topSharedLinks.map(link => ({
|
||||
...link,
|
||||
shareUrl: this.url.link(
|
||||
`/workspace/${link.workspaceId}/${link.docId}`
|
||||
),
|
||||
}))
|
||||
: [],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user