refactor(server): e2e utilities (#11000)

This commit is contained in:
forehalo
2025-03-19 17:00:20 +00:00
parent 21c4a29f55
commit f889886b31
153 changed files with 214 additions and 32 deletions

View File

@@ -0,0 +1,107 @@
import type { Mock } from 'vitest';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { gqlFetcherFactory } from '../fetcher';
import type { GraphQLQuery } from '../graphql';
const query: GraphQLQuery = {
id: 'query',
query: 'query { field }',
op: 'query',
};
let fetch: Mock;
let gql: ReturnType<typeof gqlFetcherFactory>;
describe('GraphQL fetcher', () => {
beforeEach(() => {
fetch = vi.fn(() =>
Promise.resolve(
new Response(JSON.stringify({ data: { field: 1 } }), {
headers: {
'content-type': 'application/json',
},
})
)
);
gql = gqlFetcherFactory('https://example.com/graphql', fetch);
});
afterEach(() => {
fetch.mockReset();
});
it('should send POST request to given endpoint', async () => {
await gql(
// @ts-expect-error variables is actually optional
{ query }
);
expect(fetch).toBeCalledTimes(1);
expect(fetch.mock.lastCall?.[0]).toBe('https://example.com/graphql');
const ctx = fetch.mock.lastCall?.[1] as RequestInit;
expect(ctx.method).toBe('POST');
});
it('should send with correct graphql JSON body', async () => {
await gql({
query,
// @ts-expect-error forgive the fake variables
variables: { a: 1, b: '2', c: { d: false } },
});
expect(fetch.mock.lastCall?.[1]).toEqual(
expect.objectContaining({
body: '{"query":"query { field }","variables":{"a":1,"b":"2","c":{"d":false}},"operationName":"query"}',
headers: expect.objectContaining({
'content-type': 'application/json',
'x-operation-name': 'query',
}),
method: 'POST',
})
);
});
it('should correctly ignore nil variables', async () => {
await gql({
query,
// @ts-expect-error forgive the fake variables
variables: { a: false, b: null, c: undefined },
});
expect(fetch.mock.lastCall?.[1].body).toMatchInlineSnapshot(
`"{"query":"query { field }","variables":{"a":false,"b":null},"operationName":"query"}"`
);
await gql({
query,
// @ts-expect-error forgive the fake variables
variables: { a: false, b: null, c: undefined },
keepNilVariables: false,
});
expect(fetch.mock.lastCall?.[1].body).toMatchInlineSnapshot(
`"{"query":"query { field }","variables":{"a":false},"operationName":"query"}"`
);
});
it('should correct handle graphql error', async () => {
fetch.mockResolvedValue(
new Response(
JSON.stringify({
data: null,
errors: [{ message: 'error', path: ['field'] }],
}),
{
headers: {
'content-type': 'application/json',
},
status: 400,
}
)
);
await expect(
gql({ query, variables: void 0 })
).rejects.toMatchInlineSnapshot(`[GraphQLError: error]`);
});
});

View File

@@ -0,0 +1,237 @@
import { DebugLogger } from '@affine/debug';
import { GraphQLError } from '@affine/error';
import type { ExecutionResult } from 'graphql';
import { isNil, isObject, merge } from 'lodash-es';
import type { GraphQLQuery } from './graphql';
import type { Mutations, Queries } from './schema';
export type NotArray<T> = T extends Array<unknown> ? never : T;
export type FetchInit = RequestInit & { timeout?: number };
export type _QueryVariables<Q extends GraphQLQuery> =
Q['id'] extends Queries['name']
? Extract<Queries, { name: Q['id'] }>['variables']
: Q['id'] extends Mutations['name']
? Extract<Mutations, { name: Q['id'] }>['variables']
: undefined;
export type QueryVariables<Q extends GraphQLQuery> =
_QueryVariables<Q> extends never | Record<string, never>
? never
: _QueryVariables<Q>;
export type QueryResponse<Q extends GraphQLQuery> = Extract<
Queries | Mutations,
{ name: Q['id'] }
>['response'];
type NullableKeys<T> = {
[K in keyof T]: null extends T[K] ? K : never;
}[keyof T];
type NonNullableKeys<T> = {
[K in keyof T]: null extends T[K] ? never : K;
}[keyof T];
export type RecursiveMaybeFields<T> = T extends
| number
| boolean
| string
| null
| undefined
? T
: {
[K in NullableKeys<T>]?: RecursiveMaybeFields<T[K]>;
} & {
[K in NonNullableKeys<T>]: RecursiveMaybeFields<T[K]>;
};
type AllowedRequestContext = Omit<RequestInit, 'method' | 'body'>;
export interface RequestBody {
operationName?: string;
variables: any;
query: string;
form?: FormData;
}
type QueryVariablesOption<Q extends GraphQLQuery> =
QueryVariables<Q> extends never
? {
variables?: undefined;
}
: { variables: RecursiveMaybeFields<QueryVariables<Q>> };
export type RequestOptions<Q extends GraphQLQuery> = QueryVariablesOption<Q> & {
/**
* parameter passed to `fetch` function
*/
context?: AllowedRequestContext;
/**
* Whether keep null or undefined value in variables.
*
* if `false` given, `{ a: 0, b: undefined, c: null }` will be converted to `{ a: 0 }`
*
* @default true
*/
keepNilVariables?: boolean;
/**
* Request timeout in milliseconds
* @default 15000
*/
timeout?: number;
};
export type QueryOptions<Q extends GraphQLQuery> = RequestOptions<Q> & {
query: Q;
};
export type MutationOptions<M extends GraphQLQuery> = RequestOptions<M> & {
mutation: M;
};
function filterEmptyValue(vars: any) {
const newVars: Record<string, any> = {};
Object.entries(vars).forEach(([key, value]) => {
if (isNil(value)) {
return;
}
if (isObject(value) && !(value instanceof File)) {
newVars[key] = filterEmptyValue(value);
return;
}
newVars[key] = value;
});
return newVars;
}
export function transformToForm(body: RequestBody) {
const form = new FormData();
const gqlBody: {
name?: string;
query: string;
variables: any;
map: any;
} = {
query: body.query,
variables: body.variables,
map: {},
};
if (body.operationName) {
gqlBody.name = body.operationName;
}
const map: Record<string, string[]> = {};
const files: File[] = [];
if (body.variables) {
let i = 0;
const buildMap = (key: string, value: any) => {
if (value instanceof File) {
map['' + i] = [key];
files[i] = value;
i++;
} else if (Array.isArray(value)) {
value.forEach((v, index) => {
buildMap(`${key}.${index}`, v);
});
} else if (isObject(value)) {
Object.entries(value).forEach(([k, v]) => {
buildMap(`${key}.${k}`, v);
});
}
};
buildMap('variables', body.variables);
}
form.set('operations', JSON.stringify(gqlBody));
form.set('map', JSON.stringify(map));
for (const [i, file] of files.entries()) {
form.set(`${i}`, file);
}
return form;
}
function formatRequestBody<Q extends GraphQLQuery>({
query,
variables,
keepNilVariables,
}: QueryOptions<Q>): RequestBody | FormData {
const body: RequestBody = {
query: query.query,
variables:
(keepNilVariables ?? true) ? variables : filterEmptyValue(variables),
};
if (query.op) {
body.operationName = query.op;
}
if (query.file) {
return transformToForm(body);
}
return body;
}
export const gqlFetcherFactory = (
endpoint: string,
fetcher: (input: string, init?: FetchInit) => Promise<Response> = fetch
) => {
const logger = new DebugLogger('GraphQL');
const gqlFetch = async <Query extends GraphQLQuery>(
options: QueryOptions<Query>
): Promise<QueryResponse<Query>> => {
if (
BUILD_CONFIG.appBuildType === 'canary' &&
options.query.deprecations?.length
) {
options.query.deprecations.forEach(deprecation => {
logger.warn(deprecation);
});
}
const body = formatRequestBody(options);
const isFormData = body instanceof FormData;
const headers: Record<string, string> = {
'x-operation-name': options.query.op,
};
if (!isFormData) {
headers['content-type'] = 'application/json';
}
const ret = fetcher(
endpoint,
merge(options.context, {
method: 'POST',
headers,
body: isFormData ? body : JSON.stringify(body),
timeout: options.timeout,
})
).then(async res => {
if (res.headers.get('content-type')?.startsWith('application/json')) {
const result = (await res.json()) as ExecutionResult;
if (res.status >= 400 || result.errors) {
if (result.errors && result.errors.length > 0) {
// throw the first error is enough
const firstError = result.errors[0];
throw new GraphQLError(firstError.message, firstError);
} else {
throw new GraphQLError('Empty GraphQL error body');
}
} else if (result.data) {
// we have to cast here because the type of result.data is a union type
return result.data as any;
}
}
throw new GraphQLError(
'GraphQL query responds unexpected result, query ' + options.query.op
);
});
return ret;
};
return gqlFetch;
};

View File

@@ -0,0 +1,6 @@
mutation activateLicense($workspaceId: String!, $license: String!) {
activateLicense(workspaceId: $workspaceId, license: $license) {
installedAt
validatedAt
}
}

View File

@@ -0,0 +1,23 @@
#import './fragments/password-limits.gql'
#import './fragments/credentials-requirement.gql'
query adminServerConfig {
serverConfig {
version
baseUrl
name
features
type
initialized
credentialsRequirement {
...CredentialsRequirements
}
availableUpgrade {
changelog
version
publishedAt
url
}
availableUserFeatures
}
}

View File

@@ -0,0 +1,7 @@
mutation deleteBlob(
$workspaceId: String!
$key: String!
$permanently: Boolean
) {
deleteBlob(workspaceId: $workspaceId, key: $key, permanently: $permanently)
}

View File

@@ -0,0 +1,10 @@
query listBlobs($workspaceId: String!) {
workspace(id: $workspaceId) {
blobs {
key
size
mime
createdAt
}
}
}

View File

@@ -0,0 +1,3 @@
mutation releaseDeletedBlobs($workspaceId: String!) {
releaseDeletedBlobs(workspaceId: $workspaceId)
}

View File

@@ -0,0 +1,3 @@
mutation setBlob($workspaceId: String!, $blob: Upload!) {
setBlob(workspaceId: $workspaceId, blob: $blob)
}

View File

@@ -0,0 +1,11 @@
mutation cancelSubscription(
$plan: SubscriptionPlan = Pro
$workspaceId: String
) {
cancelSubscription(plan: $plan, workspaceId: $workspaceId) {
id
status
nextBillAt
canceledAt
}
}

View File

@@ -0,0 +1,6 @@
mutation changeEmail($token: String!, $email: String!) {
changeEmail(token: $token, email: $email) {
id
email
}
}

View File

@@ -0,0 +1,3 @@
mutation createChangePasswordUrl($callbackUrl: String!, $userId: String!) {
createChangePasswordUrl(callbackUrl: $callbackUrl, userId: $userId)
}

View File

@@ -0,0 +1,7 @@
mutation changePassword(
$token: String!
$userId: String!
$newPassword: String!
) {
changePassword(token: $token, userId: $userId, newPassword: $newPassword)
}

View File

@@ -0,0 +1,7 @@
mutation addContextCategory($options: AddRemoveContextCategoryInput!) {
addContextCategory(options: $options) {
id
createdAt
type
}
}

View File

@@ -0,0 +1,3 @@
mutation removeContextCategory($options: AddRemoveContextCategoryInput!) {
removeContextCategory(options: $options)
}

View File

@@ -0,0 +1,3 @@
mutation createCopilotContext($workspaceId: String!, $sessionId: String!) {
createCopilotContext(workspaceId: $workspaceId, sessionId: $sessionId)
}

View File

@@ -0,0 +1,7 @@
mutation addContextDoc($options: AddContextDocInput!) {
addContextDoc(options: $options) {
id
createdAt
status
}
}

View File

@@ -0,0 +1,3 @@
mutation removeContextDoc($options: RemoveContextDocInput!) {
removeContextDoc(options: $options)
}

View File

@@ -0,0 +1,11 @@
mutation addContextFile($content: Upload!, $options: AddContextFileInput!) {
addContextFile(content: $content, options: $options) {
id
createdAt
name
chunkSize
error
status
blobId
}
}

View File

@@ -0,0 +1,14 @@
query matchContext($contextId: String!, $content: String!, $limit: SafeInt) {
currentUser {
copilot {
contexts(contextId: $contextId) {
matchContext(content: $content, limit: $limit) {
fileId
chunk
content
distance
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
mutation removeContextFile($options: RemoveContextFileInput!) {
removeContextFile(options: $options)
}

View File

@@ -0,0 +1,26 @@
query listContextObject(
$workspaceId: String!
$sessionId: String!
$contextId: String!
) {
currentUser {
copilot(workspaceId: $workspaceId) {
contexts(sessionId: $sessionId, contextId: $contextId) {
docs {
id
status
createdAt
}
files {
id
name
blobId
chunkSize
error
status
createdAt
}
}
}
}
}

View File

@@ -0,0 +1,10 @@
query listContext($workspaceId: String!, $sessionId: String!) {
currentUser {
copilot(workspaceId: $workspaceId) {
contexts(sessionId: $sessionId) {
id
workspaceId
}
}
}
}

View File

@@ -0,0 +1,14 @@
query matchWorkspaceContext($contextId: String!, $content: String!, $limit: SafeInt) {
currentUser {
copilot {
contexts(contextId: $contextId) {
matchWorkspaceContext(content: $content, limit: $limit) {
docId
chunk
content
distance
}
}
}
}
}

View File

@@ -0,0 +1,6 @@
query getWorkspaceEmbeddingStatus($workspaceId: String!) {
queryWorkspaceEmbeddingStatus(workspaceId: $workspaceId) {
total
embedded
}
}

View File

@@ -0,0 +1,3 @@
mutation queueWorkspaceEmbedding($workspaceId: String!, $docId: [String!]!) {
queueWorkspaceEmbedding(workspaceId: $workspaceId, docId: $docId)
}

View File

@@ -0,0 +1,18 @@
query getCopilotHistoryIds(
$workspaceId: String!
$docId: String
$options: QueryChatHistoriesInput
) {
currentUser {
copilot(workspaceId: $workspaceId) {
histories(docId: $docId, options: $options) {
sessionId
messages {
id
role
createdAt
}
}
}
}
}

View File

@@ -0,0 +1,23 @@
query getCopilotHistories(
$workspaceId: String!
$docId: String
$options: QueryChatHistoriesInput
) {
currentUser {
copilot(workspaceId: $workspaceId) {
histories(docId: $docId, options: $options) {
sessionId
tokens
action
createdAt
messages {
id
role
content
attachments
createdAt
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
mutation createCopilotMessage($options: CreateChatMessageInput!) {
createCopilotMessage(options: $options)
}

View File

@@ -0,0 +1,19 @@
query getPrompts {
listCopilotPrompts {
name
model
action
config {
jsonMode
frequencyPenalty
presencePenalty
temperature
topP
}
messages {
role
content
params
}
}
}

View File

@@ -0,0 +1,22 @@
mutation updatePrompt(
$name: String!
$messages: [CopilotPromptMessageInput!]!
) {
updateCopilotPrompt(name: $name, messages: $messages) {
name
model
action
config {
jsonMode
frequencyPenalty
presencePenalty
temperature
topP
}
messages {
role
content
params
}
}
}

View File

@@ -0,0 +1,10 @@
query copilotQuota {
currentUser {
copilot {
quota {
limit
used
}
}
}
}

View File

@@ -0,0 +1,3 @@
mutation cleanupCopilotSession($input: DeleteSessionInput!) {
cleanupCopilotSession(options: $input)
}

View File

@@ -0,0 +1,3 @@
mutation createCopilotSession($options: CreateChatSessionInput!) {
createCopilotSession(options: $options)
}

View File

@@ -0,0 +1,3 @@
mutation forkCopilotSession($options: ForkChatSessionInput!) {
forkCopilotSession(options: $options)
}

View File

@@ -0,0 +1,3 @@
mutation updateCopilotSession($options: UpdateChatSessionInput!) {
updateCopilotSession(options: $options)
}

View File

@@ -0,0 +1,15 @@
query getCopilotSessions(
$workspaceId: String!
$docId: String
$options: QueryChatSessionsInput
) {
currentUser {
copilot(workspaceId: $workspaceId) {
sessions(docId: $docId, options: $options) {
id
parentSessionId
promptName
}
}
}
}

View File

@@ -0,0 +1,3 @@
mutation createCheckoutSession($input: CreateCheckoutSessionInput!) {
createCheckoutSession(input: $input)
}

View File

@@ -0,0 +1,3 @@
mutation createCustomerPortal {
createCustomerPortal
}

View File

@@ -0,0 +1,3 @@
mutation createSelfhostCustomerPortal ($workspaceId: String!) {
createSelfhostWorkspaceCustomerPortal(workspaceId: $workspaceId)
}

View File

@@ -0,0 +1,5 @@
mutation createUser($input: CreateUserInput!) {
createUser(input: $input) {
id
}
}

View File

@@ -0,0 +1,7 @@
mutation createWorkspace {
createWorkspace {
id
public
createdAt
}
}

View File

@@ -0,0 +1,3 @@
mutation deactivateLicense($workspaceId: String!) {
deactivateLicense(workspaceId: $workspaceId)
}

View File

@@ -0,0 +1,5 @@
mutation deleteAccount {
deleteAccount {
success
}
}

View File

@@ -0,0 +1,5 @@
mutation deleteUser($id: String!) {
deleteUser(id: $id) {
success
}
}

View File

@@ -0,0 +1,3 @@
mutation deleteWorkspace($id: String!) {
deleteWorkspace(id: $id)
}

View File

@@ -0,0 +1,6 @@
mutation disableUser($id: String!) {
banUser(id: $id) {
email
disabled
}
}

View File

@@ -0,0 +1,21 @@
query getDocRolePermissions($workspaceId: String!, $docId: String!) {
workspace(id: $workspaceId) {
doc(docId: $docId) {
permissions {
Doc_Copy
Doc_Delete
Doc_Duplicate
Doc_Properties_Read
Doc_Properties_Update
Doc_Publish
Doc_Read
Doc_Restore
Doc_TransferOwner
Doc_Trash
Doc_Update
Doc_Users_Manage
Doc_Users_Read
}
}
}
}

View File

@@ -0,0 +1,6 @@
mutation enableUser($id: String!) {
enableUser(id: $id) {
email
disabled
}
}

View File

@@ -0,0 +1,5 @@
fragment CredentialsRequirements on CredentialsRequirementType {
password {
...PasswordLimits
}
}

View File

@@ -0,0 +1,4 @@
fragment PasswordLimits on PasswordLimitsType {
minLength
maxLength
}

View File

@@ -0,0 +1,3 @@
mutation generateLicenseKey($sessionId: String!) {
generateLicenseKey(sessionId: $sessionId)
}

View File

@@ -0,0 +1,11 @@
# for the admin panel only, do not use it in the app
query getCurrentUserFeatures {
currentUser {
id
name
email
emailVerified
avatarUrl
features
}
}

View File

@@ -0,0 +1,12 @@
query getCurrentUser {
currentUser {
id
name
email
emailVerified
avatarUrl
token {
sessionToken
}
}
}

View File

@@ -0,0 +1,7 @@
query getDocDefaultRole($workspaceId: String!, $docId: String!) {
workspace(id: $workspaceId) {
doc(docId: $docId) {
defaultRole
}
}
}

View File

@@ -0,0 +1,14 @@
query getInviteInfo($inviteId: String!) {
getInviteInfo(inviteId: $inviteId) {
workspace {
id
name
avatar
}
user {
id
name
avatarUrl
}
}
}

View File

@@ -0,0 +1,3 @@
query getIsAdmin($workspaceId: String!) {
isAdmin(workspaceId: $workspaceId)
}

View File

@@ -0,0 +1,3 @@
query getIsOwner($workspaceId: String!) {
isOwner(workspaceId: $workspaceId)
}

View File

@@ -0,0 +1,11 @@
query getLicense($workspaceId: String!) {
workspace(id: $workspaceId) {
license {
expiredAt
installedAt
quantity
recurring
validatedAt
}
}
}

View File

@@ -0,0 +1,5 @@
query getMemberCountByWorkspaceId($workspaceId: String!) {
workspace(id: $workspaceId) {
memberCount
}
}

View File

@@ -0,0 +1,15 @@
query getMembersByWorkspaceId($workspaceId: String!, $skip: Int, $take: Int, $query: String) {
workspace(id: $workspaceId) {
memberCount
members(skip: $skip, take: $take, query: $query) {
id
name
email
avatarUrl
permission
inviteId
emailVerified
status
}
}
}

View File

@@ -0,0 +1,5 @@
query oauthProviders {
serverConfig {
oauthProviders
}
}

View File

@@ -0,0 +1,24 @@
query getPageGrantedUsersList($pagination: PaginationInput!, $docId: String!, $workspaceId: String!) {
workspace(id: $workspaceId) {
doc(docId: $docId) {
grantedUsersList(pagination: $pagination) {
totalCount
pageInfo {
endCursor
hasNextPage
}
edges {
node {
role
user {
id
name
email
avatarUrl
}
}
}
}
}
}
}

View File

@@ -0,0 +1,7 @@
query getPublicUserById($id: String!) {
publicUserById(id: $id) {
id
avatarUrl
name
}
}

View File

@@ -0,0 +1,11 @@
query getServerRuntimeConfig {
serverRuntimeConfig {
id
module
key
description
value
type
updatedAt
}
}

View File

@@ -0,0 +1,6 @@
query getServerServiceConfigs {
serverServiceConfigs {
name
config
}
}

View File

@@ -0,0 +1,20 @@
query getUserByEmail($email: String!) {
userByEmail(email: $email) {
id
name
email
features
hasPassword
emailVerified
avatarUrl
quota {
humanReadable {
blobLimit
historyPeriod
memberLimit
name
storageQuota
}
}
}
}

View File

@@ -0,0 +1,6 @@
query getUserFeatures {
currentUser {
id
features
}
}

View File

@@ -0,0 +1,16 @@
query getUser($email: String!) {
user(email: $email) {
__typename
... on UserType {
id
name
avatarUrl
email
hasPassword
}
... on LimitedUserType {
email
hasPassword
}
}
}

View File

@@ -0,0 +1,3 @@
query getUsersCount {
usersCount
}

View File

@@ -0,0 +1,7 @@
query getWorkspaceInfo($workspaceId: String!) {
isAdmin(workspaceId: $workspaceId)
isOwner(workspaceId: $workspaceId)
workspace(id: $workspaceId) {
team
}
}

View File

@@ -0,0 +1,10 @@
query getWorkspacePageById($workspaceId: String!, $pageId: String!) {
workspace(id: $workspaceId) {
doc(docId: $pageId) {
id
mode
defaultRole
public
}
}
}

View File

@@ -0,0 +1,16 @@
query getWorkspacePageMetaById($id: String!, $pageId: String!) {
workspace(id: $id) {
pageMeta(pageId: $pageId) {
createdAt
updatedAt
createdBy {
name
avatarUrl
}
updatedBy {
name
avatarUrl
}
}
}
}

View File

@@ -0,0 +1,5 @@
query getWorkspacePublicById($id: String!) {
workspace(id: $id) {
public
}
}

View File

@@ -0,0 +1,8 @@
query getWorkspacePublicPages($workspaceId: String!) {
workspace(id: $workspaceId) {
publicDocs {
id
mode
}
}
}

View File

@@ -0,0 +1,15 @@
query getWorkspaceSubscription($workspaceId: String!) {
workspace(id: $workspaceId) {
subscription {
id
status
plan
recurring
start
end
nextBillAt
canceledAt
variant
}
}
}

View File

@@ -0,0 +1,5 @@
query getWorkspace($id: String!) {
workspace(id: $id) {
id
}
}

View File

@@ -0,0 +1,10 @@
query getWorkspaces {
workspaces {
id
initialized
team
owner {
id
}
}
}

View File

@@ -0,0 +1,3 @@
mutation grantDocUserRoles($input: GrantDocUserRolesInput!) {
grantDocUserRoles(input: $input)
}

View File

@@ -0,0 +1,17 @@
query listHistory(
$workspaceId: String!
$pageDocId: String!
$take: Int
$before: DateTime
) {
workspace(id: $workspaceId) {
histories(guid: $pageDocId, take: $take, before: $before) {
id
timestamp
editor {
name
avatarUrl
}
}
}
}

View File

@@ -0,0 +1,14 @@
mutation ImportUsers($input: ImportUsersInput!) {
importUsers(input: $input) {
__typename
... on UserType {
id
name
email
}
... on UserImportFailedType {
email
error
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
query getInvoicesCount {
currentUser {
invoiceCount
}
}

View File

@@ -0,0 +1,15 @@
query invoices($take: Int!, $skip: Int!) {
currentUser {
invoiceCount
invoices(take: $take, skip: $skip) {
id
status
currency
amount
reason
lastPaymentError
link
createdAt
}
}
}

View File

@@ -0,0 +1,3 @@
mutation leaveWorkspace($workspaceId: String!, $sendLeaveMail: Boolean) {
leaveWorkspace(workspaceId: $workspaceId, sendLeaveMail: $sendLeaveMail)
}

View File

@@ -0,0 +1,25 @@
query listNotifications($pagination: PaginationInput!) {
currentUser {
notifications(pagination: $pagination) {
totalCount
edges {
cursor
node {
id
type
level
read
createdAt
updatedAt
body
}
}
pageInfo {
startCursor
endCursor
hasNextPage
hasPreviousPage
}
}
}
}

View File

@@ -0,0 +1,12 @@
query listUsers($filter: ListUserInput!) {
users(filter: $filter) {
id
name
email
disabled
features
hasPassword
emailVerified
avatarUrl
}
}

View File

@@ -0,0 +1,3 @@
mutation mentionUser($input: MentionInput!) {
mentionUser(input: $input)
}

View File

@@ -0,0 +1,5 @@
query notificationCount {
currentUser {
notificationCount
}
}

View File

@@ -0,0 +1,10 @@
query prices {
prices {
type
plan
currency
amount
yearlyAmount
lifetimeAmount
}
}

View File

@@ -0,0 +1,10 @@
mutation publishPage(
$workspaceId: String!
$pageId: String!
$mode: PublicDocMode = Page
) {
publishDoc(workspaceId: $workspaceId, docId: $pageId, mode: $mode) {
id
mode
}
}

View File

@@ -0,0 +1,22 @@
query quota {
currentUser {
id
quota {
name
blobLimit
storageQuota
historyPeriod
memberLimit
humanReadable {
name
blobLimit
storageQuota
historyPeriod
memberLimit
}
}
quotaUsage {
storageQuota
}
}
}

View File

@@ -0,0 +1,3 @@
mutation readNotification($id: String!) {
readNotification(id: $id)
}

View File

@@ -0,0 +1,7 @@
mutation recoverDoc(
$workspaceId: String!
$docId: String!
$timestamp: DateTime!
) {
recoverDoc(workspaceId: $workspaceId, guid: $docId, timestamp: $timestamp)
}

View File

@@ -0,0 +1,5 @@
mutation removeAvatar {
removeAvatar {
success
}
}

View File

@@ -0,0 +1,12 @@
mutation resumeSubscription(
$plan: SubscriptionPlan = Pro
$workspaceId: String
) {
resumeSubscription(plan: $plan, workspaceId: $workspaceId) {
id
status
nextBillAt
start
end
}
}

View File

@@ -0,0 +1,3 @@
mutation revokeDocUserRoles($input: RevokeDocUserRoleInput!) {
revokeDocUserRoles(input: $input)
}

View File

@@ -0,0 +1,3 @@
mutation revokeMemberPermission($workspaceId: String!, $userId: String!) {
revoke(workspaceId: $workspaceId, userId: $userId)
}

View File

@@ -0,0 +1,7 @@
mutation revokePublicPage($workspaceId: String!, $pageId: String!) {
revokePublicDoc(workspaceId: $workspaceId, docId: $pageId) {
id
mode
public
}
}

View File

@@ -0,0 +1,3 @@
mutation sendChangeEmail($callbackUrl: String!) {
sendChangeEmail(callbackUrl: $callbackUrl)
}

View File

@@ -0,0 +1,3 @@
mutation sendChangePasswordEmail($callbackUrl: String!) {
sendChangePasswordEmail(callbackUrl: $callbackUrl)
}

Some files were not shown because too many files have changed in this diff Show More