From c97ccb48a13a4d1d141284f4493fe2efd2908308 Mon Sep 17 00:00:00 2001 From: Chuck Driesler Date: Fri, 2 Aug 2024 12:04:20 +0100 Subject: [PATCH] fix(workspaces): support workspace logos as base64 strings (#2556) * fix(workspaces): support workspace logos as base64 strings * fix(workspaces): fix those testsss * fix(workspaces): migration! and more test fixes --- .../typedefs/workspaces.graphql | 9 +++-- .../modules/core/graph/generated/graphql.ts | 9 +++-- .../graph/generated/graphql.ts | 7 ++-- .../modules/shared/test/unit/eventBus.spec.ts | 2 +- .../modules/workspaces/domain/operations.ts | 4 -- .../modules/workspaces/errors/workspace.ts | 5 +++ .../workspaces/graph/mocks/workspaces.ts | 4 +- .../workspaces/graph/resolvers/workspaces.ts | 11 ++---- .../server/modules/workspaces/helpers/db.ts | 2 +- .../modules/workspaces/helpers/images.spec.ts | 26 +++++++++++++ .../modules/workspaces/helpers/images.ts | 15 ++++++++ .../workspaces/repositories/workspaces.ts | 2 +- .../modules/workspaces/services/management.ts | 38 ++++++------------- .../workspaces/tests/helpers/creation.ts | 5 +-- .../tests/integration/repositories.spec.ts | 2 +- .../tests/unit/services/management.spec.ts | 3 +- .../modules/workspacesCore/domain/types.ts | 2 +- .../migrations/20240801000000_logos.ts | 15 ++++++++ .../server/test/graphql/generated/graphql.ts | 27 ++++++------- packages/server/test/graphql/workspaces.ts | 2 +- 20 files changed, 115 insertions(+), 75 deletions(-) create mode 100644 packages/server/modules/workspaces/helpers/images.spec.ts create mode 100644 packages/server/modules/workspaces/helpers/images.ts create mode 100644 packages/server/modules/workspacesCore/migrations/20240801000000_logos.ts diff --git a/packages/server/assets/workspacesCore/typedefs/workspaces.graphql b/packages/server/assets/workspacesCore/typedefs/workspaces.graphql index 53973eba1..bdc66e89a 100644 --- a/packages/server/assets/workspacesCore/typedefs/workspaces.graphql +++ b/packages/server/assets/workspacesCore/typedefs/workspaces.graphql @@ -21,7 +21,10 @@ input WorkspaceUpdateInput { id: String! name: String description: String - logoUrl: String + """ + Logo image as base64-encoded string + """ + logo: String } input WorkspaceRoleUpdateInput { @@ -93,9 +96,9 @@ type Workspace { createdAt: DateTime! updatedAt: DateTime! """ - Optional url for workspace logo image + Logo image as base64-encoded string """ - logoUrl: String + logo: String """ Active user's role for this workspace. `null` if request is not authenticated, or the workspace is not explicitly shared with you. """ diff --git a/packages/server/modules/core/graph/generated/graphql.ts b/packages/server/modules/core/graph/generated/graphql.ts index c43f00bb2..fdf46d3a9 100644 --- a/packages/server/modules/core/graph/generated/graphql.ts +++ b/packages/server/modules/core/graph/generated/graphql.ts @@ -3743,8 +3743,8 @@ export type Workspace = { id: Scalars['ID']['output']; /** Only available to workspace owners */ invitedTeam?: Maybe>; - /** Optional url for workspace logo image */ - logoUrl?: Maybe; + /** Logo image as base64-encoded string */ + logo?: Maybe; name: Scalars['String']['output']; projects: ProjectCollection; /** Active user's role for this workspace. `null` if request is not authenticated, or the workspace is not explicitly shared with you. */ @@ -3879,7 +3879,8 @@ export type WorkspaceRoleUpdateInput = { export type WorkspaceUpdateInput = { description?: InputMaybe; id: Scalars['String']['input']; - logoUrl?: InputMaybe; + /** Logo image as base64-encoded string */ + logo?: InputMaybe; name?: InputMaybe; }; @@ -5702,7 +5703,7 @@ export type WorkspaceResolvers, ParentType, ContextType>; id?: Resolver; invitedTeam?: Resolver>, ParentType, ContextType>; - logoUrl?: Resolver, ParentType, ContextType>; + logo?: Resolver, ParentType, ContextType>; name?: Resolver; projects?: Resolver>; role?: Resolver, ParentType, ContextType>; diff --git a/packages/server/modules/cross-server-sync/graph/generated/graphql.ts b/packages/server/modules/cross-server-sync/graph/generated/graphql.ts index 8dcc7d73e..9e5b2d87b 100644 --- a/packages/server/modules/cross-server-sync/graph/generated/graphql.ts +++ b/packages/server/modules/cross-server-sync/graph/generated/graphql.ts @@ -3732,8 +3732,8 @@ export type Workspace = { id: Scalars['ID']['output']; /** Only available to workspace owners */ invitedTeam?: Maybe>; - /** Optional url for workspace logo image */ - logoUrl?: Maybe; + /** Logo image as base64-encoded string */ + logo?: Maybe; name: Scalars['String']['output']; projects: ProjectCollection; /** Active user's role for this workspace. `null` if request is not authenticated, or the workspace is not explicitly shared with you. */ @@ -3868,7 +3868,8 @@ export type WorkspaceRoleUpdateInput = { export type WorkspaceUpdateInput = { description?: InputMaybe; id: Scalars['String']['input']; - logoUrl?: InputMaybe; + /** Logo image as base64-encoded string */ + logo?: InputMaybe; name?: InputMaybe; }; diff --git a/packages/server/modules/shared/test/unit/eventBus.spec.ts b/packages/server/modules/shared/test/unit/eventBus.spec.ts index d0644a3c0..dc0e88635 100644 --- a/packages/server/modules/shared/test/unit/eventBus.spec.ts +++ b/packages/server/modules/shared/test/unit/eventBus.spec.ts @@ -9,7 +9,7 @@ const createFakeWorkspace = (): Workspace => { return { id: cryptoRandomString({ length: 10 }), description: cryptoRandomString({ length: 10 }), - logoUrl: null, + logo: null, name: cryptoRandomString({ length: 10 }), updatedAt: new Date(), createdAt: new Date() diff --git a/packages/server/modules/workspaces/domain/operations.ts b/packages/server/modules/workspaces/domain/operations.ts index d323f4623..aa32692f7 100644 --- a/packages/server/modules/workspaces/domain/operations.ts +++ b/packages/server/modules/workspaces/domain/operations.ts @@ -104,10 +104,6 @@ export type GrantWorkspaceProjectRoles = ( args: GrantWorkspaceProjectRolesArgs ) => Promise -/** Blob */ - -export type StoreBlob = (args: string) => Promise - /** Events */ export type EmitWorkspaceEvent = (args: { diff --git a/packages/server/modules/workspaces/errors/workspace.ts b/packages/server/modules/workspaces/errors/workspace.ts index cae2c3bd1..4b9c3fcac 100644 --- a/packages/server/modules/workspaces/errors/workspace.ts +++ b/packages/server/modules/workspaces/errors/workspace.ts @@ -11,6 +11,11 @@ export class WorkspaceInvalidRoleError extends BaseError { static code = 'WORKSPACE_INVALID_ROLE_ERROR' } +export class WorkspaceInvalidLogoError extends BaseError { + static defaultMessage = 'Provided logo is not valid' + static code = 'WORKSPACE_INVALID_LOGO_ERROR' +} + export class WorkspaceQueryError extends BaseError { static defaultMessage = 'Unexpected error during query operation' static code = 'WORKSPACE_QUERY_ERROR' diff --git a/packages/server/modules/workspaces/graph/mocks/workspaces.ts b/packages/server/modules/workspaces/graph/mocks/workspaces.ts index 1b916386a..8c162e464 100644 --- a/packages/server/modules/workspaces/graph/mocks/workspaces.ts +++ b/packages/server/modules/workspaces/graph/mocks/workspaces.ts @@ -30,7 +30,7 @@ const config: SpeckleModuleMocksConfig = FF_WORKSPACES_MODULE_ENABLED throw new Error('Fake workspace create error') } - return getMockRef('Workspace', { values: omit(args.input, ['logoUrl']) }) + return getMockRef('Workspace', { values: omit(args.input, ['logo']) }) }, delete: () => { const val = faker.datatype.boolean() @@ -50,7 +50,7 @@ const config: SpeckleModuleMocksConfig = FF_WORKSPACES_MODULE_ENABLED type: 'Workspace', id: args.input.id }, - omit(args.input, ['logoUrl', 'id']) + omit(args.input, ['logo', 'id']) ) return getMockRef('Workspace', { id: args.input.id }) diff --git a/packages/server/modules/workspaces/graph/resolvers/workspaces.ts b/packages/server/modules/workspaces/graph/resolvers/workspaces.ts index 77dd71c65..96109fa03 100644 --- a/packages/server/modules/workspaces/graph/resolvers/workspaces.ts +++ b/packages/server/modules/workspaces/graph/resolvers/workspaces.ts @@ -131,9 +131,7 @@ export = FF_WORKSPACES_MODULE_ENABLED const createWorkspace = createWorkspaceFactory({ upsertWorkspace: upsertWorkspaceFactory({ db }), upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db }), - emitWorkspaceEvent: getEventBus().emit, - // TODO: Integrate with blobstorage - storeBlob: async () => '' + emitWorkspaceEvent: getEventBus().emit }) const workspace = await createWorkspace({ @@ -141,8 +139,7 @@ export = FF_WORKSPACES_MODULE_ENABLED workspaceInput: { name, description: description || null, - // TODO: Resolve how logos will be created - logoUrl: null + logo: null }, userResourceAccessLimits: context.resourceAccessRules }) @@ -159,9 +156,7 @@ export = FF_WORKSPACES_MODULE_ENABLED const updateWorkspace = updateWorkspaceFactory({ getWorkspace: getWorkspaceFactory({ db }), upsertWorkspace: upsertWorkspaceFactory({ db }), - emitWorkspaceEvent: getEventBus().emit, - // TODO: Integrate with blobstorage - storeBlob: async () => '' + emitWorkspaceEvent: getEventBus().emit }) const workspace = await updateWorkspace({ diff --git a/packages/server/modules/workspaces/helpers/db.ts b/packages/server/modules/workspaces/helpers/db.ts index aeb5600c6..21d1c90a4 100644 --- a/packages/server/modules/workspaces/helpers/db.ts +++ b/packages/server/modules/workspaces/helpers/db.ts @@ -6,7 +6,7 @@ export const Workspaces = buildTableHelper('workspaces', [ 'description', 'createdAt', 'updatedAt', - 'logoUrl' + 'logo' ]) export const WorkspaceAcl = buildTableHelper('workspace_acl', [ diff --git a/packages/server/modules/workspaces/helpers/images.spec.ts b/packages/server/modules/workspaces/helpers/images.spec.ts new file mode 100644 index 000000000..d6e723657 --- /dev/null +++ b/packages/server/modules/workspaces/helpers/images.spec.ts @@ -0,0 +1,26 @@ +import { validateImageString } from '@/modules/workspaces/helpers/images' +import { expectToThrow } from '@/test/assertionHelper' + +describe('validateImageString', () => { + describe('a valid base64 encoded image', () => { + const image = + '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' + it('should pass', () => { + validateImageString(image) + }) + }) + + describe('an image above the size limit', () => { + it('should fail', async () => { + await expectToThrow(() => + validateImageString('especkle'.repeat(10 * 1024 * 1024)) + ) + }) + }) + + describe('a string not encoded in base64', () => { + it('should fail', async () => { + await expectToThrow(() => validateImageString('👈😔👉')) + }) + }) +}) diff --git a/packages/server/modules/workspaces/helpers/images.ts b/packages/server/modules/workspaces/helpers/images.ts new file mode 100644 index 000000000..3eb74875d --- /dev/null +++ b/packages/server/modules/workspaces/helpers/images.ts @@ -0,0 +1,15 @@ +import { WorkspaceInvalidLogoError } from '@/modules/workspaces/errors/workspace' + +export const validateImageString = (image: string): void => { + // Validate string is a reasonable size + if (new TextEncoder().encode(image).length > 1024 * 1024 * 10) { + throw new WorkspaceInvalidLogoError('Provided logo is too large') + } + + // Validate string is base64 + if (Buffer.from(image, 'base64').toString('base64') !== image) { + throw new WorkspaceInvalidLogoError('Provided logo is malformed') + } + + // TODO: Validate string is image? +} diff --git a/packages/server/modules/workspaces/repositories/workspaces.ts b/packages/server/modules/workspaces/repositories/workspaces.ts index aec355c96..125522005 100644 --- a/packages/server/modules/workspaces/repositories/workspaces.ts +++ b/packages/server/modules/workspaces/repositories/workspaces.ts @@ -91,7 +91,7 @@ export const upsertWorkspaceFactory = .workspaces(db) .insert(workspace) .onConflict('id') - .merge(['description', 'logoUrl', 'name', 'updatedAt']) + .merge(['description', 'logo', 'name', 'updatedAt']) } export const getWorkspaceRolesFactory = diff --git a/packages/server/modules/workspaces/services/management.ts b/packages/server/modules/workspaces/services/management.ts index ccfb0e680..ce57e1aec 100644 --- a/packages/server/modules/workspaces/services/management.ts +++ b/packages/server/modules/workspaces/services/management.ts @@ -2,7 +2,6 @@ import { WorkspaceEvents } from '@/modules/workspacesCore/domain/events' import { EmitWorkspaceEvent, GetWorkspace, - StoreBlob, UpsertWorkspace, UpsertWorkspaceRole } from '@/modules/workspaces/domain/operations' @@ -37,23 +36,14 @@ import { TokenResourceIdentifierType } from '@/modules/core/domain/tokens/types' import { ForbiddenError } from '@/modules/shared/errors' - -const tryStoreBlobFactory = - (storeBlob: StoreBlob) => - async (blob?: string | null): Promise => { - let logoUrl: string | null = null - if (blob) { - logoUrl = await storeBlob(blob) - } - return logoUrl - } +import { validateImageString } from '@/modules/workspaces/helpers/images' type WorkspaceCreateArgs = { userId: string workspaceInput: { name: string description: string | null - logoUrl: string | null + logo: string | null } userResourceAccessLimits: MaybeNullOrUndefined } @@ -62,13 +52,11 @@ export const createWorkspaceFactory = ({ upsertWorkspace, upsertWorkspaceRole, - emitWorkspaceEvent, - storeBlob + emitWorkspaceEvent }: { upsertWorkspace: UpsertWorkspace upsertWorkspaceRole: UpsertWorkspaceRole emitWorkspaceEvent: EventBus['emit'] - storeBlob: StoreBlob }) => async ({ userId, @@ -84,14 +72,11 @@ export const createWorkspaceFactory = throw new ForbiddenError('You are not authorized to create a workspace') } - const logoUrl = await tryStoreBlobFactory(storeBlob)(workspaceInput.logoUrl) - const workspace = { ...workspaceInput, id: cryptoRandomString({ length: 10 }), createdAt: new Date(), - updatedAt: new Date(), - logoUrl + updatedAt: new Date() } await upsertWorkspace({ workspace }) // assign the creator as workspace administrator @@ -117,7 +102,7 @@ type WorkspaceUpdateArgs = { workspaceInput: { name?: string | null description?: string | null - logoUrl?: string | null + logo?: string | null } updaterResourceAccessLimits: MaybeNullOrUndefined } @@ -126,13 +111,11 @@ export const updateWorkspaceFactory = ({ getWorkspace, upsertWorkspace, - emitWorkspaceEvent, - storeBlob + emitWorkspaceEvent }: { getWorkspace: GetWorkspace upsertWorkspace: UpsertWorkspace emitWorkspaceEvent: EventBus['emit'] - storeBlob: StoreBlob }) => async ({ workspaceUpdaterId, @@ -147,19 +130,20 @@ export const updateWorkspaceFactory = updaterResourceAccessLimits ) + if (!!workspaceInput.logo) { + validateImageString(workspaceInput.logo) + } + const currentWorkspace = await getWorkspace({ workspaceId }) if (!currentWorkspace) { throw new WorkspaceNotFoundError() } - const logoUrl = await tryStoreBlobFactory(storeBlob)(workspaceInput.logoUrl) - const workspace = { ...currentWorkspace, ...removeNullOrUndefinedKeys(workspaceInput), - updatedAt: new Date(), - logoUrl + updatedAt: new Date() } await upsertWorkspace({ workspace }) diff --git a/packages/server/modules/workspaces/tests/helpers/creation.ts b/packages/server/modules/workspaces/tests/helpers/creation.ts index c2c6cfa5c..c2476699e 100644 --- a/packages/server/modules/workspaces/tests/helpers/creation.ts +++ b/packages/server/modules/workspaces/tests/helpers/creation.ts @@ -43,7 +43,7 @@ export type BasicTestWorkspace = { ownerId: string name: string description?: string - logoUrl?: string + logo?: string } export const createTestWorkspace = async ( @@ -53,7 +53,6 @@ export const createTestWorkspace = async ( const createWorkspace = createWorkspaceFactory({ upsertWorkspace: upsertWorkspaceFactory({ db }), upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db }), - storeBlob: () => Promise.resolve(''), emitWorkspaceEvent: (...args) => getEventBus().emit(...args) }) @@ -62,7 +61,7 @@ export const createTestWorkspace = async ( workspaceInput: { name: workspace.name, description: workspace.description || null, - logoUrl: workspace.logoUrl || null + logo: workspace.logo || null }, userResourceAccessLimits: null }) diff --git a/packages/server/modules/workspaces/tests/integration/repositories.spec.ts b/packages/server/modules/workspaces/tests/integration/repositories.spec.ts index 0596f09c4..fdf889500 100644 --- a/packages/server/modules/workspaces/tests/integration/repositories.spec.ts +++ b/packages/server/modules/workspaces/tests/integration/repositories.spec.ts @@ -45,7 +45,7 @@ const createAndStoreTestWorkspace = async (): Promise => { createdAt: new Date(), updatedAt: new Date(), description: null, - logoUrl: null + logo: null } await upsertWorkspace({ workspace }) diff --git a/packages/server/modules/workspaces/tests/unit/services/management.spec.ts b/packages/server/modules/workspaces/tests/unit/services/management.spec.ts index 85a4ead2d..2fed98d7e 100644 --- a/packages/server/modules/workspaces/tests/unit/services/management.spec.ts +++ b/packages/server/modules/workspaces/tests/unit/services/management.spec.ts @@ -47,7 +47,6 @@ const buildCreateWorkspaceWithTestContext = ( context.eventData.payload = payload return [] }, - storeBlob: async () => cryptoRandomString({ length: 10 }), ...dependecyOverrides } @@ -61,7 +60,7 @@ const getCreateWorkspaceInput = () => { userId: cryptoRandomString({ length: 10 }), workspaceInput: { description: 'foobar', - logoUrl: null, + logo: null, name: cryptoRandomString({ length: 6 }) } } diff --git a/packages/server/modules/workspacesCore/domain/types.ts b/packages/server/modules/workspacesCore/domain/types.ts index 59c079262..0fbf7c66c 100644 --- a/packages/server/modules/workspacesCore/domain/types.ts +++ b/packages/server/modules/workspacesCore/domain/types.ts @@ -6,7 +6,7 @@ export type Workspace = { description: string | null createdAt: Date updatedAt: Date - logoUrl: string | null + logo: string | null } export type WorkspaceWithOptionalRole = Workspace & { role?: WorkspaceRoles } diff --git a/packages/server/modules/workspacesCore/migrations/20240801000000_logos.ts b/packages/server/modules/workspacesCore/migrations/20240801000000_logos.ts new file mode 100644 index 000000000..6ccb2c2c5 --- /dev/null +++ b/packages/server/modules/workspacesCore/migrations/20240801000000_logos.ts @@ -0,0 +1,15 @@ +import { Knex } from 'knex' + +export async function up(knex: Knex): Promise { + await knex.schema.alterTable('workspaces', (table) => { + table.dropColumn('logoUrl') + table.text('logo') + }) +} + +export async function down(knex: Knex): Promise { + await knex.schema.alterTable('workspaces', (table) => { + table.dropColumn('logo') + table.text('logoUrl') + }) +} diff --git a/packages/server/test/graphql/generated/graphql.ts b/packages/server/test/graphql/generated/graphql.ts index 722423d95..b6318f851 100644 --- a/packages/server/test/graphql/generated/graphql.ts +++ b/packages/server/test/graphql/generated/graphql.ts @@ -3733,8 +3733,8 @@ export type Workspace = { id: Scalars['ID']['output']; /** Only available to workspace owners */ invitedTeam?: Maybe>; - /** Optional url for workspace logo image */ - logoUrl?: Maybe; + /** Logo image as base64-encoded string */ + logo?: Maybe; name: Scalars['String']['output']; projects: ProjectCollection; /** Active user's role for this workspace. `null` if request is not authenticated, or the workspace is not explicitly shared with you. */ @@ -3869,7 +3869,8 @@ export type WorkspaceRoleUpdateInput = { export type WorkspaceUpdateInput = { description?: InputMaybe; id: Scalars['String']['input']; - logoUrl?: InputMaybe; + /** Logo image as base64-encoded string */ + logo?: InputMaybe; name?: InputMaybe; }; @@ -4406,7 +4407,7 @@ export type MarkProjectVersionReceivedMutationVariables = Exact<{ export type MarkProjectVersionReceivedMutation = { __typename?: 'Mutation', versionMutations: { __typename?: 'VersionMutations', markReceived: boolean } }; -export type TestWorkspaceFragment = { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string, logoUrl?: string | null }; +export type TestWorkspaceFragment = { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string, logo?: string | null }; export type TestWorkspaceTeamFragment = { __typename?: 'Workspace', team: Array<{ __typename?: 'WorkspaceCollaborator', id: string, role: string }> }; @@ -4417,26 +4418,26 @@ export type CreateWorkspaceMutationVariables = Exact<{ }>; -export type CreateWorkspaceMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', create: { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string, logoUrl?: string | null } } }; +export type CreateWorkspaceMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', create: { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string, logo?: string | null } } }; export type GetWorkspaceQueryVariables = Exact<{ workspaceId: Scalars['String']['input']; }>; -export type GetWorkspaceQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string, logoUrl?: string | null, team: Array<{ __typename?: 'WorkspaceCollaborator', id: string, role: string }> } }; +export type GetWorkspaceQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string, logo?: string | null, team: Array<{ __typename?: 'WorkspaceCollaborator', id: string, role: string }> } }; export type UpdateWorkspaceMutationVariables = Exact<{ input: WorkspaceUpdateInput; }>; -export type UpdateWorkspaceMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', update: { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string, logoUrl?: string | null } } }; +export type UpdateWorkspaceMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', update: { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string, logo?: string | null } } }; export type GetActiveUserWorkspacesQueryVariables = Exact<{ [key: string]: never; }>; -export type GetActiveUserWorkspacesQuery = { __typename?: 'Query', activeUser?: { __typename?: 'User', workspaces: { __typename?: 'WorkspaceCollection', items: Array<{ __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string, logoUrl?: string | null }> } } | null }; +export type GetActiveUserWorkspacesQuery = { __typename?: 'Query', activeUser?: { __typename?: 'User', workspaces: { __typename?: 'WorkspaceCollection', items: Array<{ __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string, logo?: string | null }> } } | null }; export type UpdateWorkspaceRoleMutationVariables = Exact<{ input: WorkspaceRoleUpdateInput; @@ -4475,7 +4476,7 @@ export const StreamInviteDataFragmentDoc = {"kind":"Document","definitions":[{"k export const BasicStreamFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicStreamFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Stream"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"isPublic"}},{"kind":"Field","name":{"kind":"Name","value":"isDiscoverable"}},{"kind":"Field","name":{"kind":"Name","value":"allowPublicComments"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const BaseUserFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BaseUserFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"bio"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"verified"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]} as unknown as DocumentNode; export const BaseLimitedUserFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BaseLimitedUserFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedUser"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"bio"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"verified"}}]}}]} as unknown as DocumentNode; -export const TestWorkspaceFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}}]}}]} as unknown as DocumentNode; +export const TestWorkspaceFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}}]}}]} as unknown as DocumentNode; export const TestWorkspaceTeamFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspaceTeam"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const TestWorkspaceProjectFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspaceProject"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const CreateWorkspaceInviteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateWorkspaceInvite"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceInviteCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"invites"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workspaceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicWorkspace"}},{"kind":"Field","name":{"kind":"Name","value":"invitedTeam"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicPendingWorkspaceCollaborator"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicPendingWorkspaceCollaborator"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PendingWorkspaceCollaborator"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"inviteId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"invitedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"token"}}]}}]} as unknown as DocumentNode; @@ -4547,10 +4548,10 @@ export const GetPendingEmailVerificationStatusDocument = {"kind":"Document","def export const RequestVerificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RequestVerification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"requestVerification"}}]}}]} as unknown as DocumentNode; export const CreateProjectVersionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateProjectVersion"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateVersionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"versionMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"sourceApplication"}},{"kind":"Field","name":{"kind":"Name","value":"model"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"referencedObject"}}]}}]}}]}}]} as unknown as DocumentNode; export const MarkProjectVersionReceivedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MarkProjectVersionReceived"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MarkReceivedVersionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"versionMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"markReceived"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]}}]} as unknown as DocumentNode; -export const CreateWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspace"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}}]}}]} as unknown as DocumentNode; -export const GetWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspace"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspaceTeam"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspaceTeam"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; -export const UpdateWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceUpdateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"update"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspace"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}}]}}]} as unknown as DocumentNode; -export const GetActiveUserWorkspacesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetActiveUserWorkspaces"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaces"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspace"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}}]}}]} as unknown as DocumentNode; +export const CreateWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspace"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}}]}}]} as unknown as DocumentNode; +export const GetWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspace"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspaceTeam"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspaceTeam"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; +export const UpdateWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceUpdateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"update"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspace"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}}]}}]} as unknown as DocumentNode; +export const GetActiveUserWorkspacesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetActiveUserWorkspaces"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaces"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspace"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}}]}}]} as unknown as DocumentNode; export const UpdateWorkspaceRoleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateWorkspaceRole"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceRoleUpdateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateRole"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateWorkspaceProjectDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateWorkspaceProject"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ProjectCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projectMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspaceProject"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspaceProject"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const GetWorkspaceProjectsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspaceProjects"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceProjectsFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"cursor"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspaceProject"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspaceProject"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/server/test/graphql/workspaces.ts b/packages/server/test/graphql/workspaces.ts index 62487f229..1b4f7ff72 100644 --- a/packages/server/test/graphql/workspaces.ts +++ b/packages/server/test/graphql/workspaces.ts @@ -7,7 +7,7 @@ export const workspaceFragment = gql` description createdAt updatedAt - logoUrl + logo } `