feat: doc status & share status (#14426)

#### PR Dependency Tree


* **PR #14426** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Admin dashboard: view workspace analytics (storage, sync activity, top
shared links) with charts and configurable windows.
* Document analytics tab: see total/unique/guest views and trends over
selectable time windows.
* Last-accessed members: view who last accessed a document, with
pagination.
* Shared links analytics: browse and paginate all shared links with
view/unique/guest metrics and share URLs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-02-13 01:01:29 +08:00
committed by GitHub
parent b46bf91575
commit b4be9118ad
44 changed files with 5701 additions and 86 deletions
@@ -0,0 +1,39 @@
query adminAllSharedLinks(
$pagination: PaginationInput!
$filter: AdminAllSharedLinksFilterInput
) {
adminAllSharedLinks(pagination: $pagination, filter: $filter) {
totalCount
analyticsWindow {
from
to
timezone
bucket
requestedSize
effectiveSize
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
edges {
cursor
node {
workspaceId
docId
title
publishedAt
docUpdatedAt
workspaceOwnerId
lastUpdaterId
shareUrl
views
uniqueViews
guestViews
lastAccessedAt
}
}
}
}
@@ -0,0 +1,56 @@
query adminDashboard($input: AdminDashboardInput) {
adminDashboard(input: $input) {
syncActiveUsers
syncActiveUsersTimeline {
minute
activeUsers
}
syncWindow {
from
to
timezone
bucket
requestedSize
effectiveSize
}
copilotConversations
workspaceStorageBytes
blobStorageBytes
workspaceStorageHistory {
date
value
}
blobStorageHistory {
date
value
}
storageWindow {
from
to
timezone
bucket
requestedSize
effectiveSize
}
topSharedLinks {
workspaceId
docId
title
shareUrl
publishedAt
views
uniqueViews
guestViews
lastAccessedAt
}
topSharedLinksWindow {
from
to
timezone
bucket
requestedSize
effectiveSize
}
generatedAt
}
}
@@ -0,0 +1,37 @@
query getDocLastAccessedMembers(
$workspaceId: String!
$docId: String!
$pagination: PaginationInput!
$query: String
$includeTotal: Boolean
) {
workspace(id: $workspaceId) {
doc(docId: $docId) {
lastAccessedMembers(
pagination: $pagination
query: $query
includeTotal: $includeTotal
) {
totalCount
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
edges {
cursor
node {
user {
id
name
avatarUrl
}
lastAccessedAt
lastDocId
}
}
}
}
}
}
@@ -0,0 +1,33 @@
query getDocPageAnalytics(
$workspaceId: String!
$docId: String!
$input: DocPageAnalyticsInput
) {
workspace(id: $workspaceId) {
doc(docId: $docId) {
analytics(input: $input) {
window {
from
to
timezone
bucket
requestedSize
effectiveSize
}
series {
date
totalViews
uniqueViews
guestViews
}
summary {
totalViews
uniqueViews
guestViews
lastAccessedAt
}
generatedAt
}
}
}
}
@@ -144,6 +144,108 @@ export const revokeUserAccessTokenMutation = {
}`,
};
export const adminAllSharedLinksQuery = {
id: 'adminAllSharedLinksQuery' as const,
op: 'adminAllSharedLinks',
query: `query adminAllSharedLinks($pagination: PaginationInput!, $filter: AdminAllSharedLinksFilterInput) {
adminAllSharedLinks(pagination: $pagination, filter: $filter) {
totalCount
analyticsWindow {
from
to
timezone
bucket
requestedSize
effectiveSize
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
edges {
cursor
node {
workspaceId
docId
title
publishedAt
docUpdatedAt
workspaceOwnerId
lastUpdaterId
shareUrl
views
uniqueViews
guestViews
lastAccessedAt
}
}
}
}`,
};
export const adminDashboardQuery = {
id: 'adminDashboardQuery' as const,
op: 'adminDashboard',
query: `query adminDashboard($input: AdminDashboardInput) {
adminDashboard(input: $input) {
syncActiveUsers
syncActiveUsersTimeline {
minute
activeUsers
}
syncWindow {
from
to
timezone
bucket
requestedSize
effectiveSize
}
copilotConversations
workspaceStorageBytes
blobStorageBytes
workspaceStorageHistory {
date
value
}
blobStorageHistory {
date
value
}
storageWindow {
from
to
timezone
bucket
requestedSize
effectiveSize
}
topSharedLinks {
workspaceId
docId
title
shareUrl
publishedAt
views
uniqueViews
guestViews
lastAccessedAt
}
topSharedLinksWindow {
from
to
timezone
bucket
requestedSize
effectiveSize
}
generatedAt
}
}`,
};
export const adminServerConfigQuery = {
id: 'adminServerConfigQuery' as const,
op: 'adminServerConfig',
@@ -1877,6 +1979,76 @@ export const getDocDefaultRoleQuery = {
}`,
};
export const getDocLastAccessedMembersQuery = {
id: 'getDocLastAccessedMembersQuery' as const,
op: 'getDocLastAccessedMembers',
query: `query getDocLastAccessedMembers($workspaceId: String!, $docId: String!, $pagination: PaginationInput!, $query: String, $includeTotal: Boolean) {
workspace(id: $workspaceId) {
doc(docId: $docId) {
lastAccessedMembers(
pagination: $pagination
query: $query
includeTotal: $includeTotal
) {
totalCount
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
edges {
cursor
node {
user {
id
name
avatarUrl
}
lastAccessedAt
lastDocId
}
}
}
}
}
}`,
};
export const getDocPageAnalyticsQuery = {
id: 'getDocPageAnalyticsQuery' as const,
op: 'getDocPageAnalytics',
query: `query getDocPageAnalytics($workspaceId: String!, $docId: String!, $input: DocPageAnalyticsInput) {
workspace(id: $workspaceId) {
doc(docId: $docId) {
analytics(input: $input) {
window {
from
to
timezone
bucket
requestedSize
effectiveSize
}
series {
date
totalViews
uniqueViews
guestViews
}
summary {
totalViews
uniqueViews
guestViews
lastAccessedAt
}
generatedAt
}
}
}
}`,
};
export const getDocSummaryQuery = {
id: 'getDocSummaryQuery' as const,
op: 'getDocSummary',
+409
View File
@@ -66,6 +66,91 @@ export interface AddContextFileInput {
contextId: Scalars['String']['input'];
}
export interface AdminAllSharedLink {
__typename?: 'AdminAllSharedLink';
docId: Scalars['String']['output'];
docUpdatedAt: Maybe<Scalars['DateTime']['output']>;
guestViews: Maybe<Scalars['SafeInt']['output']>;
lastAccessedAt: Maybe<Scalars['DateTime']['output']>;
lastUpdaterId: Maybe<Scalars['String']['output']>;
publishedAt: Maybe<Scalars['DateTime']['output']>;
shareUrl: Scalars['String']['output'];
title: Maybe<Scalars['String']['output']>;
uniqueViews: Maybe<Scalars['SafeInt']['output']>;
views: Maybe<Scalars['SafeInt']['output']>;
workspaceId: Scalars['String']['output'];
workspaceOwnerId: Maybe<Scalars['String']['output']>;
}
export interface AdminAllSharedLinkEdge {
__typename?: 'AdminAllSharedLinkEdge';
cursor: Scalars['String']['output'];
node: AdminAllSharedLink;
}
export interface AdminAllSharedLinksFilterInput {
analyticsWindowDays?: InputMaybe<Scalars['Int']['input']>;
includeTotal?: InputMaybe<Scalars['Boolean']['input']>;
keyword?: InputMaybe<Scalars['String']['input']>;
orderBy?: InputMaybe<AdminSharedLinksOrder>;
updatedAfter?: InputMaybe<Scalars['DateTime']['input']>;
workspaceId?: InputMaybe<Scalars['String']['input']>;
}
export interface AdminDashboard {
__typename?: 'AdminDashboard';
blobStorageBytes: Scalars['SafeInt']['output'];
blobStorageHistory: Array<AdminDashboardValueDayPoint>;
copilotConversations: Scalars['SafeInt']['output'];
generatedAt: Scalars['DateTime']['output'];
storageWindow: TimeWindow;
syncActiveUsers: Scalars['Int']['output'];
syncActiveUsersTimeline: Array<AdminDashboardMinutePoint>;
syncWindow: TimeWindow;
topSharedLinks: Array<AdminSharedLinkTopItem>;
topSharedLinksWindow: TimeWindow;
workspaceStorageBytes: Scalars['SafeInt']['output'];
workspaceStorageHistory: Array<AdminDashboardValueDayPoint>;
}
export interface AdminDashboardInput {
sharedLinkWindowDays?: InputMaybe<Scalars['Int']['input']>;
storageHistoryDays?: InputMaybe<Scalars['Int']['input']>;
syncHistoryHours?: InputMaybe<Scalars['Int']['input']>;
timezone?: InputMaybe<Scalars['String']['input']>;
}
export interface AdminDashboardMinutePoint {
__typename?: 'AdminDashboardMinutePoint';
activeUsers: Scalars['Int']['output'];
minute: Scalars['DateTime']['output'];
}
export interface AdminDashboardValueDayPoint {
__typename?: 'AdminDashboardValueDayPoint';
date: Scalars['DateTime']['output'];
value: Scalars['SafeInt']['output'];
}
export interface AdminSharedLinkTopItem {
__typename?: 'AdminSharedLinkTopItem';
docId: Scalars['String']['output'];
guestViews: Scalars['SafeInt']['output'];
lastAccessedAt: Maybe<Scalars['DateTime']['output']>;
publishedAt: Maybe<Scalars['DateTime']['output']>;
shareUrl: Scalars['String']['output'];
title: Maybe<Scalars['String']['output']>;
uniqueViews: Scalars['SafeInt']['output'];
views: Scalars['SafeInt']['output'];
workspaceId: Scalars['String']['output'];
}
export enum AdminSharedLinksOrder {
PublishedAtDesc = 'PublishedAtDesc',
UpdatedAtDesc = 'UpdatedAtDesc',
ViewsDesc = 'ViewsDesc',
}
export interface AdminUpdateWorkspaceInput {
avatarKey?: InputMaybe<Scalars['String']['input']>;
enableAi?: InputMaybe<Scalars['Boolean']['input']>;
@@ -851,6 +936,19 @@ export interface DocHistoryType {
workspaceId: Scalars['String']['output'];
}
export interface DocMemberLastAccess {
__typename?: 'DocMemberLastAccess';
lastAccessedAt: Scalars['DateTime']['output'];
lastDocId: Maybe<Scalars['String']['output']>;
user: PublicUserType;
}
export interface DocMemberLastAccessEdge {
__typename?: 'DocMemberLastAccessEdge';
cursor: Scalars['String']['output'];
node: DocMemberLastAccess;
}
/** Doc mode */
export enum DocMode {
edgeless = 'edgeless',
@@ -863,6 +961,35 @@ export interface DocNotFoundDataType {
spaceId: Scalars['String']['output'];
}
export interface DocPageAnalytics {
__typename?: 'DocPageAnalytics';
generatedAt: Scalars['DateTime']['output'];
series: Array<DocPageAnalyticsPoint>;
summary: DocPageAnalyticsSummary;
window: TimeWindow;
}
export interface DocPageAnalyticsInput {
timezone?: InputMaybe<Scalars['String']['input']>;
windowDays?: InputMaybe<Scalars['Int']['input']>;
}
export interface DocPageAnalyticsPoint {
__typename?: 'DocPageAnalyticsPoint';
date: Scalars['DateTime']['output'];
guestViews: Scalars['SafeInt']['output'];
totalViews: Scalars['SafeInt']['output'];
uniqueViews: Scalars['SafeInt']['output'];
}
export interface DocPageAnalyticsSummary {
__typename?: 'DocPageAnalyticsSummary';
guestViews: Scalars['SafeInt']['output'];
lastAccessedAt: Maybe<Scalars['DateTime']['output']>;
totalViews: Scalars['SafeInt']['output'];
uniqueViews: Scalars['SafeInt']['output'];
}
export interface DocPermissions {
__typename?: 'DocPermissions';
Doc_Comments_Create: Scalars['Boolean']['output'];
@@ -897,6 +1024,8 @@ export enum DocRole {
export interface DocType {
__typename?: 'DocType';
/** Doc page analytics in a time window */
analytics: DocPageAnalytics;
createdAt: Maybe<Scalars['DateTime']['output']>;
/** Doc create user */
createdBy: Maybe<PublicUserType>;
@@ -905,6 +1034,8 @@ export interface DocType {
/** paginated doc granted users list */
grantedUsersList: PaginatedGrantedDocUserType;
id: Scalars['String']['output'];
/** Paginated last accessed members of the current doc */
lastAccessedMembers: PaginatedDocMemberLastAccess;
/** Doc last updated user */
lastUpdatedBy: Maybe<PublicUserType>;
lastUpdaterId: Maybe<Scalars['String']['output']>;
@@ -919,10 +1050,20 @@ export interface DocType {
workspaceId: Scalars['String']['output'];
}
export interface DocTypeAnalyticsArgs {
input?: InputMaybe<DocPageAnalyticsInput>;
}
export interface DocTypeGrantedUsersListArgs {
pagination: PaginationInput;
}
export interface DocTypeLastAccessedMembersArgs {
includeTotal?: InputMaybe<Scalars['Boolean']['input']>;
pagination: PaginationInput;
query?: InputMaybe<Scalars['String']['input']>;
}
export interface DocTypeEdge {
__typename?: 'DocTypeEdge';
cursor: Scalars['String']['output'];
@@ -2282,6 +2423,14 @@ export interface PageInfo {
startCursor: Maybe<Scalars['String']['output']>;
}
export interface PaginatedAdminAllSharedLink {
__typename?: 'PaginatedAdminAllSharedLink';
analyticsWindow: TimeWindow;
edges: Array<AdminAllSharedLinkEdge>;
pageInfo: PageInfo;
totalCount: Maybe<Scalars['Int']['output']>;
}
export interface PaginatedCommentChangeObjectType {
__typename?: 'PaginatedCommentChangeObjectType';
edges: Array<CommentChangeObjectTypeEdge>;
@@ -2310,6 +2459,13 @@ export interface PaginatedCopilotWorkspaceFileType {
totalCount: Scalars['Int']['output'];
}
export interface PaginatedDocMemberLastAccess {
__typename?: 'PaginatedDocMemberLastAccess';
edges: Array<DocMemberLastAccessEdge>;
pageInfo: PageInfo;
totalCount: Maybe<Scalars['Int']['output']>;
}
export interface PaginatedDocType {
__typename?: 'PaginatedDocType';
edges: Array<DocTypeEdge>;
@@ -2376,6 +2532,10 @@ export interface PublicUserType {
export interface Query {
__typename?: 'Query';
/** List all shared links across workspaces for admin panel */
adminAllSharedLinks: PaginatedAdminAllSharedLink;
/** Get aggregated dashboard metrics for admin panel */
adminDashboard: AdminDashboard;
/** Get workspace detail for admin */
adminWorkspace: Maybe<AdminWorkspace>;
/** List workspaces for admin */
@@ -2428,6 +2588,15 @@ export interface Query {
workspaces: Array<WorkspaceType>;
}
export interface QueryAdminAllSharedLinksArgs {
filter?: InputMaybe<AdminAllSharedLinksFilterInput>;
pagination: PaginationInput;
}
export interface QueryAdminDashboardArgs {
input?: InputMaybe<AdminDashboardInput>;
}
export interface QueryAdminWorkspaceArgs {
id: Scalars['String']['input'];
}
@@ -2871,6 +3040,21 @@ export enum SubscriptionVariant {
Onetime = 'Onetime',
}
export enum TimeBucket {
Day = 'Day',
Minute = 'Minute',
}
export interface TimeWindow {
__typename?: 'TimeWindow';
bucket: TimeBucket;
effectiveSize: Scalars['Int']['output'];
from: Scalars['DateTime']['output'];
requestedSize: Scalars['Int']['output'];
timezone: Scalars['String']['output'];
to: Scalars['DateTime']['output'];
}
export interface TranscriptionItemType {
__typename?: 'TranscriptionItemType';
end: Scalars['String']['output'];
@@ -3409,6 +3593,124 @@ export type RevokeUserAccessTokenMutation = {
revokeUserAccessToken: boolean;
};
export type AdminAllSharedLinksQueryVariables = Exact<{
pagination: PaginationInput;
filter?: InputMaybe<AdminAllSharedLinksFilterInput>;
}>;
export type AdminAllSharedLinksQuery = {
__typename?: 'Query';
adminAllSharedLinks: {
__typename?: 'PaginatedAdminAllSharedLink';
totalCount: number | null;
analyticsWindow: {
__typename?: 'TimeWindow';
from: string;
to: string;
timezone: string;
bucket: TimeBucket;
requestedSize: number;
effectiveSize: number;
};
pageInfo: {
__typename?: 'PageInfo';
hasNextPage: boolean;
hasPreviousPage: boolean;
startCursor: string | null;
endCursor: string | null;
};
edges: Array<{
__typename?: 'AdminAllSharedLinkEdge';
cursor: string;
node: {
__typename?: 'AdminAllSharedLink';
workspaceId: string;
docId: string;
title: string | null;
publishedAt: string | null;
docUpdatedAt: string | null;
workspaceOwnerId: string | null;
lastUpdaterId: string | null;
shareUrl: string;
views: number | null;
uniqueViews: number | null;
guestViews: number | null;
lastAccessedAt: string | null;
};
}>;
};
};
export type AdminDashboardQueryVariables = Exact<{
input?: InputMaybe<AdminDashboardInput>;
}>;
export type AdminDashboardQuery = {
__typename?: 'Query';
adminDashboard: {
__typename?: 'AdminDashboard';
syncActiveUsers: number;
copilotConversations: number;
workspaceStorageBytes: number;
blobStorageBytes: number;
generatedAt: string;
syncActiveUsersTimeline: Array<{
__typename?: 'AdminDashboardMinutePoint';
minute: string;
activeUsers: number;
}>;
syncWindow: {
__typename?: 'TimeWindow';
from: string;
to: string;
timezone: string;
bucket: TimeBucket;
requestedSize: number;
effectiveSize: number;
};
workspaceStorageHistory: Array<{
__typename?: 'AdminDashboardValueDayPoint';
date: string;
value: number;
}>;
blobStorageHistory: Array<{
__typename?: 'AdminDashboardValueDayPoint';
date: string;
value: number;
}>;
storageWindow: {
__typename?: 'TimeWindow';
from: string;
to: string;
timezone: string;
bucket: TimeBucket;
requestedSize: number;
effectiveSize: number;
};
topSharedLinks: Array<{
__typename?: 'AdminSharedLinkTopItem';
workspaceId: string;
docId: string;
title: string | null;
shareUrl: string;
publishedAt: string | null;
views: number;
uniqueViews: number;
guestViews: number;
lastAccessedAt: string | null;
}>;
topSharedLinksWindow: {
__typename?: 'TimeWindow';
from: string;
to: string;
timezone: string;
bucket: TimeBucket;
requestedSize: number;
effectiveSize: number;
};
};
};
export type AdminServerConfigQueryVariables = Exact<{ [key: string]: never }>;
export type AdminServerConfigQuery = {
@@ -5916,6 +6218,93 @@ export type GetDocDefaultRoleQuery = {
};
};
export type GetDocLastAccessedMembersQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
docId: Scalars['String']['input'];
pagination: PaginationInput;
query?: InputMaybe<Scalars['String']['input']>;
includeTotal?: InputMaybe<Scalars['Boolean']['input']>;
}>;
export type GetDocLastAccessedMembersQuery = {
__typename?: 'Query';
workspace: {
__typename?: 'WorkspaceType';
doc: {
__typename?: 'DocType';
lastAccessedMembers: {
__typename?: 'PaginatedDocMemberLastAccess';
totalCount: number | null;
pageInfo: {
__typename?: 'PageInfo';
hasNextPage: boolean;
hasPreviousPage: boolean;
startCursor: string | null;
endCursor: string | null;
};
edges: Array<{
__typename?: 'DocMemberLastAccessEdge';
cursor: string;
node: {
__typename?: 'DocMemberLastAccess';
lastAccessedAt: string;
lastDocId: string | null;
user: {
__typename?: 'PublicUserType';
id: string;
name: string;
avatarUrl: string | null;
};
};
}>;
};
};
};
};
export type GetDocPageAnalyticsQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
docId: Scalars['String']['input'];
input?: InputMaybe<DocPageAnalyticsInput>;
}>;
export type GetDocPageAnalyticsQuery = {
__typename?: 'Query';
workspace: {
__typename?: 'WorkspaceType';
doc: {
__typename?: 'DocType';
analytics: {
__typename?: 'DocPageAnalytics';
generatedAt: string;
window: {
__typename?: 'TimeWindow';
from: string;
to: string;
timezone: string;
bucket: TimeBucket;
requestedSize: number;
effectiveSize: number;
};
series: Array<{
__typename?: 'DocPageAnalyticsPoint';
date: string;
totalViews: number;
uniqueViews: number;
guestViews: number;
}>;
summary: {
__typename?: 'DocPageAnalyticsSummary';
totalViews: number;
uniqueViews: number;
guestViews: number;
lastAccessedAt: string | null;
};
};
};
};
};
export type GetDocSummaryQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
docId: Scalars['String']['input'];
@@ -7199,6 +7588,16 @@ export type Queries =
variables: ListUserAccessTokensQueryVariables;
response: ListUserAccessTokensQuery;
}
| {
name: 'adminAllSharedLinksQuery';
variables: AdminAllSharedLinksQueryVariables;
response: AdminAllSharedLinksQuery;
}
| {
name: 'adminDashboardQuery';
variables: AdminDashboardQueryVariables;
response: AdminDashboardQuery;
}
| {
name: 'adminServerConfigQuery';
variables: AdminServerConfigQueryVariables;
@@ -7419,6 +7818,16 @@ export type Queries =
variables: GetDocDefaultRoleQueryVariables;
response: GetDocDefaultRoleQuery;
}
| {
name: 'getDocLastAccessedMembersQuery';
variables: GetDocLastAccessedMembersQueryVariables;
response: GetDocLastAccessedMembersQuery;
}
| {
name: 'getDocPageAnalyticsQuery';
variables: GetDocPageAnalyticsQueryVariables;
response: GetDocPageAnalyticsQuery;
}
| {
name: 'getDocSummaryQuery';
variables: GetDocSummaryQueryVariables;