diff --git a/packages/frontend-2/components/project/VisibilitySelect.vue b/packages/frontend-2/components/project/VisibilitySelect.vue index 42d7a3c4e..73d089a31 100644 --- a/packages/frontend-2/components/project/VisibilitySelect.vue +++ b/packages/frontend-2/components/project/VisibilitySelect.vue @@ -38,38 +38,43 @@ diff --git a/packages/frontend-2/components/project/model-page/dialog/embed/Embed.vue b/packages/frontend-2/components/project/model-page/dialog/embed/Embed.vue index 89809cc00..dc2e96638 100644 --- a/packages/frontend-2/components/project/model-page/dialog/embed/Embed.vue +++ b/packages/frontend-2/components/project/model-page/dialog/embed/Embed.vue @@ -89,13 +89,16 @@ diff --git a/packages/frontend-2/components/project/page/settings/general/block/Discussions.vue b/packages/frontend-2/components/project/page/settings/general/block/Discussions.vue index dc32dc4fa..9cc314e9c 100644 --- a/packages/frontend-2/components/project/page/settings/general/block/Discussions.vue +++ b/packages/frontend-2/components/project/page/settings/general/block/Discussions.vue @@ -18,7 +18,10 @@ diff --git a/packages/frontend-2/lib/auth/helpers/authPolicies.ts b/packages/frontend-2/lib/auth/helpers/authPolicies.ts deleted file mode 100644 index 975502bf2..000000000 --- a/packages/frontend-2/lib/auth/helpers/authPolicies.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import type { NuxtApp } from '#app' -import type { - ApolloQueryResult, - MaybeMasked, - OperationVariables, - QueryOptions -} from '@apollo/client/core' - -export type AuthLoaderDependencies = { - nuxtApp: NuxtApp - /** - * Use this to query GQL, instead of taking apollo client from nuxtApp. This ensures - * appropriate caching settings - */ - query: ( - options: QueryOptions - ) => Promise>> -} - -export type AuthLoaderFactory = (deps: AuthLoaderDependencies) => T - -/** - * Can be used in auth policy checks to reference the active user's id, whatever it is, - * without having to resolve it - */ -export const ActiveUserId = '__APP_ACTIVE_USER_ID__' diff --git a/packages/frontend-2/lib/common/generated/gql/gql.ts b/packages/frontend-2/lib/common/generated/gql/gql.ts index 32facd897..aeceefaf7 100644 --- a/packages/frontend-2/lib/common/generated/gql/gql.ts +++ b/packages/frontend-2/lib/common/generated/gql/gql.ts @@ -88,7 +88,7 @@ type Documents = { "\n fragment ProjectPageModelsCardDeleteDialog on Model {\n id\n name\n }\n": typeof types.ProjectPageModelsCardDeleteDialogFragmentDoc, "\n fragment ProjectPageModelsCardRenameDialog on Model {\n id\n name\n description\n }\n": typeof types.ProjectPageModelsCardRenameDialogFragmentDoc, "\n query ProjectPageSettingsGeneral($projectId: String!) {\n project(id: $projectId) {\n id\n ...ProjectPageSettingsGeneralBlockProjectInfo_Project\n ...ProjectPageSettingsGeneralBlockAccess_Project\n ...ProjectPageSettingsGeneralBlockDiscussions_Project\n ...ProjectPageSettingsGeneralBlockLeave_Project\n ...ProjectPageSettingsGeneralBlockDelete_Project\n ...ProjectPageTeamInternals_Project\n }\n }\n": typeof types.ProjectPageSettingsGeneralDocument, - "\n fragment ProjectPageSettingsGeneralBlockAccess_Project on Project {\n id\n visibility\n permissions {\n canUpdate {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.ProjectPageSettingsGeneralBlockAccess_ProjectFragmentDoc, + "\n fragment ProjectPageSettingsGeneralBlockAccess_Project on Project {\n id\n visibility\n workspaceId\n permissions {\n canUpdate {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.ProjectPageSettingsGeneralBlockAccess_ProjectFragmentDoc, "\n fragment ProjectPageSettingsGeneralBlockDelete_Project on Project {\n ...ProjectsDeleteDialog_Project\n permissions {\n canUpdate {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.ProjectPageSettingsGeneralBlockDelete_ProjectFragmentDoc, "\n fragment ProjectPageSettingsGeneralBlockDiscussions_Project on Project {\n id\n visibility\n allowPublicComments\n permissions {\n canUpdateAllowPublicComments {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.ProjectPageSettingsGeneralBlockDiscussions_ProjectFragmentDoc, "\n fragment ProjectPageSettingsGeneralBlockLeave_Project on Project {\n id\n name\n role\n team {\n role\n user {\n ...LimitedUserAvatar\n role\n }\n }\n workspace {\n id\n }\n permissions {\n canLeave {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.ProjectPageSettingsGeneralBlockLeave_ProjectFragmentDoc, @@ -499,7 +499,7 @@ const documents: Documents = { "\n fragment ProjectPageModelsCardDeleteDialog on Model {\n id\n name\n }\n": types.ProjectPageModelsCardDeleteDialogFragmentDoc, "\n fragment ProjectPageModelsCardRenameDialog on Model {\n id\n name\n description\n }\n": types.ProjectPageModelsCardRenameDialogFragmentDoc, "\n query ProjectPageSettingsGeneral($projectId: String!) {\n project(id: $projectId) {\n id\n ...ProjectPageSettingsGeneralBlockProjectInfo_Project\n ...ProjectPageSettingsGeneralBlockAccess_Project\n ...ProjectPageSettingsGeneralBlockDiscussions_Project\n ...ProjectPageSettingsGeneralBlockLeave_Project\n ...ProjectPageSettingsGeneralBlockDelete_Project\n ...ProjectPageTeamInternals_Project\n }\n }\n": types.ProjectPageSettingsGeneralDocument, - "\n fragment ProjectPageSettingsGeneralBlockAccess_Project on Project {\n id\n visibility\n permissions {\n canUpdate {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.ProjectPageSettingsGeneralBlockAccess_ProjectFragmentDoc, + "\n fragment ProjectPageSettingsGeneralBlockAccess_Project on Project {\n id\n visibility\n workspaceId\n permissions {\n canUpdate {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.ProjectPageSettingsGeneralBlockAccess_ProjectFragmentDoc, "\n fragment ProjectPageSettingsGeneralBlockDelete_Project on Project {\n ...ProjectsDeleteDialog_Project\n permissions {\n canUpdate {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.ProjectPageSettingsGeneralBlockDelete_ProjectFragmentDoc, "\n fragment ProjectPageSettingsGeneralBlockDiscussions_Project on Project {\n id\n visibility\n allowPublicComments\n permissions {\n canUpdateAllowPublicComments {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.ProjectPageSettingsGeneralBlockDiscussions_ProjectFragmentDoc, "\n fragment ProjectPageSettingsGeneralBlockLeave_Project on Project {\n id\n name\n role\n team {\n role\n user {\n ...LimitedUserAvatar\n role\n }\n }\n workspace {\n id\n }\n permissions {\n canLeave {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.ProjectPageSettingsGeneralBlockLeave_ProjectFragmentDoc, @@ -1149,7 +1149,7 @@ export function graphql(source: "\n query ProjectPageSettingsGeneral($projectId /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment ProjectPageSettingsGeneralBlockAccess_Project on Project {\n id\n visibility\n permissions {\n canUpdate {\n ...FullPermissionCheckResult\n }\n }\n }\n"): (typeof documents)["\n fragment ProjectPageSettingsGeneralBlockAccess_Project on Project {\n id\n visibility\n permissions {\n canUpdate {\n ...FullPermissionCheckResult\n }\n }\n }\n"]; +export function graphql(source: "\n fragment ProjectPageSettingsGeneralBlockAccess_Project on Project {\n id\n visibility\n workspaceId\n permissions {\n canUpdate {\n ...FullPermissionCheckResult\n }\n }\n }\n"): (typeof documents)["\n fragment ProjectPageSettingsGeneralBlockAccess_Project on Project {\n id\n visibility\n workspaceId\n permissions {\n canUpdate {\n ...FullPermissionCheckResult\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/frontend-2/lib/common/generated/gql/graphql.ts b/packages/frontend-2/lib/common/generated/gql/graphql.ts index e1d2e0542..a7d0bd309 100644 --- a/packages/frontend-2/lib/common/generated/gql/graphql.ts +++ b/packages/frontend-2/lib/common/generated/gql/graphql.ts @@ -2067,7 +2067,7 @@ export type Project = { versions: VersionCollection; /** Return metadata about resources being requested in the viewer */ viewerResources: Array; - visibility: SimpleProjectVisibility; + visibility: ProjectVisibility; webhooks: WebhookCollection; workspace?: Maybe; workspaceId?: Maybe; @@ -2688,9 +2688,14 @@ export const ProjectVersionsUpdatedMessageType = { export type ProjectVersionsUpdatedMessageType = typeof ProjectVersionsUpdatedMessageType[keyof typeof ProjectVersionsUpdatedMessageType]; export const ProjectVisibility = { + /** Only accessible to explicit collaborators */ Private: 'PRIVATE', + /** Accessible to everyone (even non-logged in users) */ Public: 'PUBLIC', - Unlisted: 'UNLISTED' + /** Legacy - same as public */ + Unlisted: 'UNLISTED', + /** Accessible to everyone in the project's workspace */ + Workspace: 'WORKSPACE' } as const; export type ProjectVisibility = typeof ProjectVisibility[keyof typeof ProjectVisibility]; @@ -3240,13 +3245,6 @@ export type SetPrimaryUserEmailInput = { id: Scalars['ID']['input']; }; -/** Visibility without the "discoverable" option */ -export const SimpleProjectVisibility = { - Private: 'PRIVATE', - Unlisted: 'UNLISTED' -} as const; - -export type SimpleProjectVisibility = typeof SimpleProjectVisibility[keyof typeof SimpleProjectVisibility]; export type SmartTextEditorValue = { __typename?: 'SmartTextEditorValue'; /** File attachments, if any */ @@ -3323,6 +3321,7 @@ export type Stream = { /** * Whether the stream (if public) can be found on public stream exploration pages * and searches + * @deprecated Discoverability as a feature has been removed. */ isDiscoverable: Scalars['Boolean']['output']; /** Whether the stream can be viewed by non-contributors */ @@ -5193,7 +5192,7 @@ export type HeaderWorkspaceSwitcherHeaderExpiredSso_LimitedWorkspaceFragment = { export type HeaderWorkspaceSwitcherHeaderWorkspace_WorkspaceFragment = { __typename?: 'Workspace', id: string, name: string, logo?: string | null, role?: string | null, plan?: { __typename?: 'WorkspacePlan', name: WorkspacePlans } | null, team: { __typename?: 'WorkspaceCollaboratorCollection', totalCount: number } }; -export type HeaderNavShare_ProjectFragment = { __typename?: 'Project', id: string, visibility: SimpleProjectVisibility, role?: string | null }; +export type HeaderNavShare_ProjectFragment = { __typename?: 'Project', id: string, visibility: ProjectVisibility, role?: string | null }; export type HeaderNavNotificationsProjectInvite_PendingStreamCollaboratorFragment = { __typename?: 'PendingStreamCollaborator', id: string, projectId: string, projectName: string, token?: string | null, workspaceSlug?: string | null, invitedBy: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null }, user?: { __typename?: 'LimitedUser', id: string } | null }; @@ -5213,9 +5212,9 @@ export type InviteDialogProjectRowProjectCollaboratorsQuery = { __typename?: 'Qu export type ProjectModelPageHeaderProjectFragment = { __typename?: 'Project', id: string, name: string, model: { __typename?: 'Model', id: string, name: string, description?: string | null }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, role?: string | null } | null }; -export type ProjectModelPageVersionsPaginationFragment = { __typename?: 'Project', id: string, visibility: SimpleProjectVisibility, role?: string | null, model: { __typename?: 'Model', id: string, versions: { __typename?: 'VersionCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Version', id: string, message?: string | null, createdAt: string, previewUrl: string, referencedObject?: string | null, sourceApplication?: string | null, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'VersionPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> } } }; +export type ProjectModelPageVersionsPaginationFragment = { __typename?: 'Project', id: string, visibility: ProjectVisibility, role?: string | null, model: { __typename?: 'Model', id: string, versions: { __typename?: 'VersionCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Version', id: string, message?: string | null, createdAt: string, previewUrl: string, referencedObject?: string | null, sourceApplication?: string | null, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'VersionPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> } } }; -export type ProjectModelPageVersionsProjectFragment = { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: SimpleProjectVisibility, role?: string | null, model: { __typename?: 'Model', id: string, name: string, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, versions: { __typename?: 'VersionCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Version', id: string, message?: string | null, createdAt: string, previewUrl: string, referencedObject?: string | null, sourceApplication?: string | null, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'VersionPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> } }, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string, name: string, logo?: string | null, role?: string | null } | null }; +export type ProjectModelPageVersionsProjectFragment = { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: ProjectVisibility, role?: string | null, model: { __typename?: 'Model', id: string, name: string, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, versions: { __typename?: 'VersionCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Version', id: string, message?: string | null, createdAt: string, previewUrl: string, referencedObject?: string | null, sourceApplication?: string | null, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'VersionPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> } }, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string, name: string, logo?: string | null, role?: string | null } | null }; export type ProjectModelPageDialogDeleteVersionFragment = { __typename?: 'Version', id: string, message?: string | null }; @@ -5223,7 +5222,7 @@ export type ProjectModelPageDialogEditMessageVersionFragment = { __typename?: 'V export type ProjectModelPageDialogMoveToVersionFragment = { __typename?: 'Version', id: string, message?: string | null }; -export type ProjectsModelPageEmbed_ProjectFragment = { __typename?: 'Project', id: string, visibility: SimpleProjectVisibility, role?: string | null }; +export type ProjectsModelPageEmbed_ProjectFragment = { __typename?: 'Project', id: string, visibility: ProjectVisibility, role?: string | null }; export type ProjectModelPageVersionsCardVersionFragment = { __typename?: 'Version', id: string, message?: string | null, createdAt: string, previewUrl: string, referencedObject?: string | null, sourceApplication?: string | null, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'VersionPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; @@ -5241,9 +5240,9 @@ export type ProjectPageAutomationFunctions_AutomationFragment = { __typename?: ' export type ProjectPageAutomationHeader_AutomationFragment = { __typename?: 'Automation', id: string, name: string, enabled: boolean, isTestAutomation: boolean, currentRevision?: { __typename?: 'AutomationRevision', id: string, triggerDefinitions: Array<{ __typename?: 'VersionCreatedTriggerDefinition', model?: { __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null }> } | null }; -export type ProjectPageAutomationHeader_ProjectFragment = { __typename?: 'Project', id: string, role?: string | null, workspaceId?: string | null, visibility: SimpleProjectVisibility, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; +export type ProjectPageAutomationHeader_ProjectFragment = { __typename?: 'Project', id: string, role?: string | null, workspaceId?: string | null, visibility: ProjectVisibility, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; -export type ProjectPageAutomationModels_ProjectFragment = { __typename?: 'Project', id: string, role?: string | null, visibility: SimpleProjectVisibility, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; +export type ProjectPageAutomationModels_ProjectFragment = { __typename?: 'Project', id: string, role?: string | null, visibility: ProjectVisibility, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; export type ProjectPageAutomationRuns_AutomationFragment = { __typename?: 'Automation', id: string, name: string, enabled: boolean, isTestAutomation: boolean, runs: { __typename?: 'AutomateRunCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'AutomateRun', id: string, status: AutomateRunStatus, createdAt: string, updatedAt: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', statusMessage?: string | null, id: string, status: AutomateRunStatus }>, trigger: { __typename?: 'VersionCreatedTrigger', version?: { __typename?: 'Version', id: string } | null, model?: { __typename?: 'Model', id: string } | null } }> }, currentRevision?: { __typename?: 'AutomationRevision', functions: Array<{ __typename?: 'AutomationRevisionFunction', release: { __typename?: 'AutomateFunctionRelease', function: { __typename?: 'AutomateFunction', id: string, name: string } } }> } | null }; @@ -5277,15 +5276,15 @@ export type ProjectDiscussionsPageResults_ProjectFragment = { __typename?: 'Proj export type ProjectPageModelsActionsFragment = { __typename?: 'Model', id: string, name: string, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; -export type ProjectPageModelsActions_ProjectFragment = { __typename?: 'Project', id: string, visibility: SimpleProjectVisibility, role?: string | null, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; +export type ProjectPageModelsActions_ProjectFragment = { __typename?: 'Project', id: string, visibility: ProjectVisibility, role?: string | null, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; -export type ProjectPageModelsCardProjectFragment = { __typename?: 'Project', id: string, role?: string | null, visibility: SimpleProjectVisibility, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; +export type ProjectPageModelsCardProjectFragment = { __typename?: 'Project', id: string, role?: string | null, visibility: ProjectVisibility, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; export type ProjectModelsPageHeader_ProjectFragment = { __typename?: 'Project', id: string, name: string, sourceApps: Array, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, workspace?: { __typename?: 'Workspace', id: string, role?: string | null, slug: string, name: string, readOnly: boolean, plan?: { __typename?: 'WorkspacePlan', name: WorkspacePlans } | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; -export type ProjectModelsPageResults_ProjectFragment = { __typename?: 'Project', id: string, role?: string | null, visibility: SimpleProjectVisibility, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string } | null, modelCount: { __typename?: 'ModelCollection', totalCount: number }, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; +export type ProjectModelsPageResults_ProjectFragment = { __typename?: 'Project', id: string, role?: string | null, visibility: ProjectVisibility, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string } | null, modelCount: { __typename?: 'ModelCollection', totalCount: number }, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; -export type ProjectPageModelsStructureItem_ProjectFragment = { __typename?: 'Project', id: string, visibility: SimpleProjectVisibility, role?: string | null, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; +export type ProjectPageModelsStructureItem_ProjectFragment = { __typename?: 'Project', id: string, visibility: ProjectVisibility, role?: string | null, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; export type SingleLevelModelTreeItemFragment = { __typename?: 'ModelsTreeItem', id: string, name: string, fullName: string, hasChildren: boolean, updatedAt: string, model?: { __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null }; @@ -5298,13 +5297,13 @@ export type ProjectPageSettingsGeneralQueryVariables = Exact<{ }>; -export type ProjectPageSettingsGeneralQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: SimpleProjectVisibility, allowPublicComments: boolean, role?: string | null, permissions: { __typename?: 'ProjectPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdateAllowPublicComments: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canLeave: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number } } }; +export type ProjectPageSettingsGeneralQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: ProjectVisibility, workspaceId?: string | null, allowPublicComments: boolean, role?: string | null, permissions: { __typename?: 'ProjectPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdateAllowPublicComments: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canLeave: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number } } }; -export type ProjectPageSettingsGeneralBlockAccess_ProjectFragment = { __typename?: 'Project', id: string, visibility: SimpleProjectVisibility, permissions: { __typename?: 'ProjectPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; +export type ProjectPageSettingsGeneralBlockAccess_ProjectFragment = { __typename?: 'Project', id: string, visibility: ProjectVisibility, workspaceId?: string | null, permissions: { __typename?: 'ProjectPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; export type ProjectPageSettingsGeneralBlockDelete_ProjectFragment = { __typename?: 'Project', id: string, name: string, role?: string | null, permissions: { __typename?: 'ProjectPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, models: { __typename?: 'ModelCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null, versions: { __typename?: 'VersionCollection', totalCount: number } }; -export type ProjectPageSettingsGeneralBlockDiscussions_ProjectFragment = { __typename?: 'Project', id: string, visibility: SimpleProjectVisibility, allowPublicComments: boolean, permissions: { __typename?: 'ProjectPermissionChecks', canUpdateAllowPublicComments: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; +export type ProjectPageSettingsGeneralBlockDiscussions_ProjectFragment = { __typename?: 'Project', id: string, visibility: ProjectVisibility, allowPublicComments: boolean, permissions: { __typename?: 'ProjectPermissionChecks', canUpdateAllowPublicComments: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; export type ProjectPageSettingsGeneralBlockLeave_ProjectFragment = { __typename?: 'Project', id: string, name: string, role?: string | null, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, workspace?: { __typename?: 'Workspace', id: string } | null, permissions: { __typename?: 'ProjectPermissionChecks', canLeave: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; @@ -5312,15 +5311,15 @@ export type ProjectPageSettingsGeneralBlockProjectInfo_ProjectFragment = { __typ export type ProjectPageSettingsWebhooks_ProjectFragment = { __typename?: 'Project', id: string, permissions: { __typename?: 'ProjectPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; -export type ProjectsPageTeamDialogManagePermissions_ProjectFragment = { __typename?: 'Project', id: string, visibility: SimpleProjectVisibility, role?: string | null }; +export type ProjectsPageTeamDialogManagePermissions_ProjectFragment = { __typename?: 'Project', id: string, visibility: ProjectVisibility, role?: string | null }; export type ProjectsDashboard_UserProjectCollectionFragment = { __typename?: 'UserProjectCollection', numberOfHidden: number }; export type ProjectsDashboard_UserFragment = { __typename?: 'User', permissions: { __typename?: 'RootPermissionChecks', canCreatePersonalProject: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; -export type ProjectsDashboardFilledProjectFragment = { __typename?: 'ProjectCollection', items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: SimpleProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }; +export type ProjectsDashboardFilledProjectFragment = { __typename?: 'ProjectCollection', items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }; -export type ProjectsDashboardFilledUserFragment = { __typename?: 'UserProjectCollection', items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: SimpleProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }; +export type ProjectsDashboardFilledUserFragment = { __typename?: 'UserProjectCollection', items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }; export type ProjectsDeleteDialog_ProjectFragment = { __typename?: 'Project', id: string, name: string, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null, versions: { __typename?: 'VersionCollection', totalCount: number } }; @@ -5336,7 +5335,7 @@ export type SettingsServerRegionsAddEditDialog_ServerRegionItemFragment = { __ty export type SettingsServerRegionsTable_ServerRegionItemFragment = { __typename?: 'ServerRegionItem', id: string, name: string, key: string, description?: string | null }; -export type SettingsSharedProjects_ProjectFragment = { __typename?: 'Project', id: string, name: string, visibility: SimpleProjectVisibility, createdAt: string, updatedAt: string, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', name: string, id: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null }; +export type SettingsSharedProjects_ProjectFragment = { __typename?: 'Project', id: string, name: string, visibility: ProjectVisibility, createdAt: string, updatedAt: string, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', name: string, id: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null }; export type SettingsUserProfileChangePassword_UserFragment = { __typename?: 'User', id: string, email?: string | null }; @@ -5376,7 +5375,7 @@ export type SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceFragment = { _ export type SettingsWorkspacesSecuritySsoWrapper_WorkspaceFragment = { __typename?: 'Workspace', id: string, role?: string | null, slug: string, hasAccessToSSO: boolean, sso?: { __typename?: 'WorkspaceSso', provider?: { __typename?: 'WorkspaceSsoProvider', id: string, name: string, clientId: string, issuerUrl: string } | null } | null }; -export type ModelPageProjectFragment = { __typename?: 'Project', id: string, createdAt: string, name: string, visibility: SimpleProjectVisibility, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, role?: string | null } | null }; +export type ModelPageProjectFragment = { __typename?: 'Project', id: string, createdAt: string, name: string, visibility: ProjectVisibility, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, role?: string | null } | null }; export type ViewerCommentThreadDataFragment = { __typename?: 'Comment', id: string, permissions: { __typename?: 'CommentPermissionChecks', canArchive: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; @@ -5394,7 +5393,7 @@ export type WorkspaceDashboard_WorkspaceFragment = { __typename?: 'Workspace', i export type WorkspaceDashboardHeader_WorkspaceFragment = { __typename?: 'Workspace', id: string, role?: string | null, slug: string, name: string, domainBasedMembershipProtectionEnabled: boolean, team: { __typename?: 'WorkspaceCollaboratorCollection', totalCount: number, items: Array<{ __typename?: 'WorkspaceCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }> }, invitedTeam?: Array<{ __typename?: 'PendingWorkspaceCollaborator', id: string, role: string, email?: string | null }> | null, adminWorkspacesJoinRequests?: { __typename?: 'WorkspaceJoinRequestCollection', totalCount: number, items: Array<{ __typename?: 'WorkspaceJoinRequest', status: WorkspaceJoinRequestStatus, id: string }> } | null, plan?: { __typename?: 'WorkspacePlan', name: WorkspacePlans, status: WorkspacePlanStatuses, createdAt: string } | null, permissions: { __typename?: 'WorkspacePermissionChecks', canCreateProject: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveProjectToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, subscription?: { __typename?: 'WorkspaceSubscription', billingInterval: BillingInterval, currentBillingCycleEnd: string } | null, domains?: Array<{ __typename?: 'WorkspaceDomain', domain: string, id: string }> | null }; -export type WorkspaceDashboardProjectList_ProjectCollectionFragment = { __typename?: 'ProjectCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: SimpleProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }; +export type WorkspaceDashboardProjectList_ProjectCollectionFragment = { __typename?: 'ProjectCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }; export type WorkspaceDashboardProjectList_WorkspaceFragment = { __typename?: 'Workspace', id: string, name: string, slug: string, role?: string | null, plan?: { __typename?: 'WorkspacePlan', name: WorkspacePlans } | null, permissions: { __typename?: 'WorkspacePermissionChecks', canCreateProject: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveProjectToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; @@ -5785,19 +5784,19 @@ export type NavigationWorkspaceInvitesQuery = { __typename?: 'Query', activeUser export type ProjectPageTeamInternals_ProjectFragment = { __typename?: 'Project', id: string, role?: string | null, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, user: { __typename?: 'LimitedUser', id: string, role?: string | null, name: string, avatar?: string | null } }> }; -export type ProjectPageTeamDialogFragment = { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: SimpleProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null }; +export type ProjectPageTeamDialogFragment = { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null }; -export type ProjectDashboardItemNoModelsFragment = { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: SimpleProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; +export type ProjectDashboardItemNoModelsFragment = { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; -export type ProjectDashboardItemFragment = { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: SimpleProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; +export type ProjectDashboardItemFragment = { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; export type PendingFileUploadFragment = { __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }; export type ProjectPageLatestItemsModelItemFragment = { __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; -export type ProjectUpdatableMetadataFragment = { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: SimpleProjectVisibility, allowPublicComments: boolean, permissions: { __typename?: 'ProjectPermissionChecks', canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdateAllowPublicComments: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canLeave: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; +export type ProjectUpdatableMetadataFragment = { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, permissions: { __typename?: 'ProjectPermissionChecks', canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdateAllowPublicComments: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canLeave: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; -export type ProjectPageLatestItemsModelsFragment = { __typename?: 'Project', id: string, role?: string | null, visibility: SimpleProjectVisibility, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string } | null, modelCount: { __typename?: 'ModelCollection', totalCount: number }, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; +export type ProjectPageLatestItemsModelsFragment = { __typename?: 'Project', id: string, role?: string | null, visibility: ProjectVisibility, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string } | null, modelCount: { __typename?: 'ModelCollection', totalCount: number }, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; export type ProjectPageLatestItemsCommentsFragment = { __typename?: 'Project', id: string, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number } }; @@ -5815,14 +5814,14 @@ export type CreateProjectMutationVariables = Exact<{ }>; -export type CreateProjectMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', create: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, allowPublicComments: boolean, visibility: SimpleProjectVisibility, updatedAt: string, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string, name: string, logo?: string | null, role?: string | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, id: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, versions: { __typename?: 'VersionCollection', totalCount: number } } } }; +export type CreateProjectMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', create: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, updatedAt: string, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string, name: string, logo?: string | null, role?: string | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, id: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, versions: { __typename?: 'VersionCollection', totalCount: number } } } }; export type CreateWorkspaceProjectMutationVariables = Exact<{ input: WorkspaceProjectCreateInput; }>; -export type CreateWorkspaceProjectMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', projects: { __typename?: 'WorkspaceProjectMutations', create: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, allowPublicComments: boolean, visibility: SimpleProjectVisibility, updatedAt: string, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string, name: string, logo?: string | null, role?: string | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, id: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, versions: { __typename?: 'VersionCollection', totalCount: number } } } } }; +export type CreateWorkspaceProjectMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', projects: { __typename?: 'WorkspaceProjectMutations', create: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, updatedAt: string, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string, name: string, logo?: string | null, role?: string | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, id: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, versions: { __typename?: 'VersionCollection', totalCount: number } } } } }; export type UpdateModelMutationVariables = Exact<{ input: UpdateModelInput; @@ -5858,7 +5857,7 @@ export type InviteProjectUserMutationVariables = Exact<{ }>; -export type InviteProjectUserMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', invites: { __typename?: 'ProjectInviteMutations', batchCreate: { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: SimpleProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null } } } }; +export type InviteProjectUserMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', invites: { __typename?: 'ProjectInviteMutations', batchCreate: { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null } } } }; export type InviteWorkspaceProjectUserMutationVariables = Exact<{ projectId: Scalars['ID']['input']; @@ -5866,7 +5865,7 @@ export type InviteWorkspaceProjectUserMutationVariables = Exact<{ }>; -export type InviteWorkspaceProjectUserMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', invites: { __typename?: 'ProjectInviteMutations', createForWorkspace: { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: SimpleProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null } } } }; +export type InviteWorkspaceProjectUserMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', invites: { __typename?: 'ProjectInviteMutations', createForWorkspace: { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null } } } }; export type CancelProjectInviteMutationVariables = Exact<{ projectId: Scalars['ID']['input']; @@ -5874,14 +5873,14 @@ export type CancelProjectInviteMutationVariables = Exact<{ }>; -export type CancelProjectInviteMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', invites: { __typename?: 'ProjectInviteMutations', cancel: { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: SimpleProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null } } } }; +export type CancelProjectInviteMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', invites: { __typename?: 'ProjectInviteMutations', cancel: { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null } } } }; export type UpdateProjectMetadataMutationVariables = Exact<{ update: ProjectUpdateInput; }>; -export type UpdateProjectMetadataMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', update: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: SimpleProjectVisibility, allowPublicComments: boolean, permissions: { __typename?: 'ProjectPermissionChecks', canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdateAllowPublicComments: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canLeave: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } } }; +export type UpdateProjectMetadataMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', update: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, permissions: { __typename?: 'ProjectPermissionChecks', canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdateAllowPublicComments: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canLeave: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } } }; export type DeleteProjectMutationVariables = Exact<{ id: Scalars['String']['input']; @@ -6015,7 +6014,7 @@ export type ProjectsDashboardQueryQueryVariables = Exact<{ }>; -export type ProjectsDashboardQueryQuery = { __typename?: 'Query', activeUser?: { __typename?: 'User', id: string, projects: { __typename?: 'UserProjectCollection', cursor?: string | null, totalCount: number, numberOfHidden: number, items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: SimpleProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, expiredSsoSessions: Array<{ __typename?: 'LimitedWorkspace', id: string, slug: string, name: string, logo?: string | null }>, permissions: { __typename?: 'RootPermissionChecks', canCreatePersonalProject: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null }; +export type ProjectsDashboardQueryQuery = { __typename?: 'Query', activeUser?: { __typename?: 'User', id: string, projects: { __typename?: 'UserProjectCollection', cursor?: string | null, totalCount: number, numberOfHidden: number, items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, expiredSsoSessions: Array<{ __typename?: 'LimitedWorkspace', id: string, slug: string, name: string, logo?: string | null }>, permissions: { __typename?: 'RootPermissionChecks', canCreatePersonalProject: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null }; export type ProjectPageQueryQueryVariables = Exact<{ id: Scalars['String']['input']; @@ -6023,7 +6022,7 @@ export type ProjectPageQueryQueryVariables = Exact<{ }>; -export type ProjectPageQueryQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, allowPublicComments: boolean, visibility: SimpleProjectVisibility, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, role?: string | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, id: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, versions: { __typename?: 'VersionCollection', totalCount: number } }, projectInvite?: { __typename?: 'PendingStreamCollaborator', id: string, projectId: string, projectName: string, token?: string | null, invitedBy: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null }, user?: { __typename?: 'LimitedUser', id: string } | null } | null }; +export type ProjectPageQueryQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, role?: string | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, id: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, versions: { __typename?: 'VersionCollection', totalCount: number } }, projectInvite?: { __typename?: 'PendingStreamCollaborator', id: string, projectId: string, projectName: string, token?: string | null, invitedBy: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null }, user?: { __typename?: 'LimitedUser', id: string } | null } | null }; export type ProjectLatestModelsQueryVariables = Exact<{ projectId: Scalars['String']['input']; @@ -6090,7 +6089,7 @@ export type ProjectModelCheckQueryVariables = Exact<{ }>; -export type ProjectModelCheckQuery = { __typename?: 'Query', project: { __typename?: 'Project', visibility: SimpleProjectVisibility, model: { __typename?: 'Model', id: string } } }; +export type ProjectModelCheckQuery = { __typename?: 'Query', project: { __typename?: 'Project', visibility: ProjectVisibility, model: { __typename?: 'Model', id: string } } }; export type ProjectModelPageQueryVariables = Exact<{ projectId: Scalars['String']['input']; @@ -6099,7 +6098,7 @@ export type ProjectModelPageQueryVariables = Exact<{ }>; -export type ProjectModelPageQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: SimpleProjectVisibility, role?: string | null, model: { __typename?: 'Model', id: string, name: string, description?: string | null, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, versions: { __typename?: 'VersionCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Version', id: string, message?: string | null, createdAt: string, previewUrl: string, referencedObject?: string | null, sourceApplication?: string | null, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'VersionPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> } }, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string, name: string, logo?: string | null, role?: string | null } | null } }; +export type ProjectModelPageQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: ProjectVisibility, role?: string | null, model: { __typename?: 'Model', id: string, name: string, description?: string | null, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, versions: { __typename?: 'VersionCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Version', id: string, message?: string | null, createdAt: string, previewUrl: string, referencedObject?: string | null, sourceApplication?: string | null, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'VersionPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> } }, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string, name: string, logo?: string | null, role?: string | null } | null } }; export type ProjectModelVersionsQueryVariables = Exact<{ projectId: Scalars['String']['input']; @@ -6108,14 +6107,14 @@ export type ProjectModelVersionsQueryVariables = Exact<{ }>; -export type ProjectModelVersionsQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, visibility: SimpleProjectVisibility, role?: string | null, model: { __typename?: 'Model', id: string, versions: { __typename?: 'VersionCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Version', id: string, message?: string | null, createdAt: string, previewUrl: string, referencedObject?: string | null, sourceApplication?: string | null, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'VersionPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> } } } }; +export type ProjectModelVersionsQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, visibility: ProjectVisibility, role?: string | null, model: { __typename?: 'Model', id: string, versions: { __typename?: 'VersionCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Version', id: string, message?: string | null, createdAt: string, previewUrl: string, referencedObject?: string | null, sourceApplication?: string | null, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'VersionPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> } } } }; export type ProjectModelsPageQueryVariables = Exact<{ projectId: Scalars['String']['input']; }>; -export type ProjectModelsPageQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, name: string, sourceApps: Array, role?: string | null, visibility: SimpleProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, workspace?: { __typename?: 'Workspace', id: string, role?: string | null, slug: string, name: string, readOnly: boolean, plan?: { __typename?: 'WorkspacePlan', name: WorkspacePlans } | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, modelCount: { __typename?: 'ModelCollection', totalCount: number } } }; +export type ProjectModelsPageQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, name: string, sourceApps: Array, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, workspace?: { __typename?: 'Workspace', id: string, role?: string | null, slug: string, name: string, readOnly: boolean, plan?: { __typename?: 'WorkspacePlan', name: WorkspacePlans } | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, modelCount: { __typename?: 'ModelCollection', totalCount: number } } }; export type ProjectDiscussionsPageQueryVariables = Exact<{ projectId: Scalars['String']['input']; @@ -6146,7 +6145,7 @@ export type ProjectAutomationPageQueryVariables = Exact<{ }>; -export type ProjectAutomationPageQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, workspaceId?: string | null, role?: string | null, visibility: SimpleProjectVisibility, automation: { __typename?: 'Automation', id: string, name: string, enabled: boolean, isTestAutomation: boolean, permissions: { __typename?: 'AutomationPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, currentRevision?: { __typename?: 'AutomationRevision', id: string, triggerDefinitions: Array<{ __typename?: 'VersionCreatedTriggerDefinition', type: AutomateRunTriggerType, model?: { __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null }>, functions: Array<{ __typename?: 'AutomationRevisionFunction', parameters?: {} | null, release: { __typename?: 'AutomateFunctionRelease', id: string, inputSchema?: {} | null, versionTag: string, createdAt: string, function: { __typename?: 'AutomateFunction', id: string, name: string, isFeatured: boolean, description: string, logo?: string | null, releases: { __typename?: 'AutomateFunctionReleaseCollection', items: Array<{ __typename?: 'AutomateFunctionRelease', id: string }> }, repo: { __typename?: 'BasicGitRepositoryMetadata', id: string, url: string, owner: string, name: string } } } }> } | null, runs: { __typename?: 'AutomateRunCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'AutomateRun', id: string, status: AutomateRunStatus, createdAt: string, updatedAt: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', statusMessage?: string | null, id: string, status: AutomateRunStatus }>, trigger: { __typename?: 'VersionCreatedTrigger', version?: { __typename?: 'Version', id: string } | null, model?: { __typename?: 'Model', id: string } | null } }> } }, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null } }; +export type ProjectAutomationPageQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, workspaceId?: string | null, role?: string | null, visibility: ProjectVisibility, automation: { __typename?: 'Automation', id: string, name: string, enabled: boolean, isTestAutomation: boolean, permissions: { __typename?: 'AutomationPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, currentRevision?: { __typename?: 'AutomationRevision', id: string, triggerDefinitions: Array<{ __typename?: 'VersionCreatedTriggerDefinition', type: AutomateRunTriggerType, model?: { __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null }>, functions: Array<{ __typename?: 'AutomationRevisionFunction', parameters?: {} | null, release: { __typename?: 'AutomateFunctionRelease', id: string, inputSchema?: {} | null, versionTag: string, createdAt: string, function: { __typename?: 'AutomateFunction', id: string, name: string, isFeatured: boolean, description: string, logo?: string | null, releases: { __typename?: 'AutomateFunctionReleaseCollection', items: Array<{ __typename?: 'AutomateFunctionRelease', id: string }> }, repo: { __typename?: 'BasicGitRepositoryMetadata', id: string, url: string, owner: string, name: string } } } }> } | null, runs: { __typename?: 'AutomateRunCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'AutomateRun', id: string, status: AutomateRunStatus, createdAt: string, updatedAt: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', statusMessage?: string | null, id: string, status: AutomateRunStatus }>, trigger: { __typename?: 'VersionCreatedTrigger', version?: { __typename?: 'Version', id: string } | null, model?: { __typename?: 'Model', id: string } | null } }> } }, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null } }; export type ProjectAutomationPagePaginatedRunsQueryVariables = Exact<{ projectId: Scalars['String']['input']; @@ -6193,7 +6192,7 @@ export type OnProjectUpdatedSubscriptionVariables = Exact<{ }>; -export type OnProjectUpdatedSubscription = { __typename?: 'Subscription', projectUpdated: { __typename?: 'ProjectUpdatedMessage', id: string, type: ProjectUpdatedMessageType, project?: { __typename?: 'Project', id: string, createdAt: string, name: string, updatedAt: string, role?: string | null, description?: string | null, allowPublicComments: boolean, visibility: SimpleProjectVisibility, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, role?: string | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, id: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, versions: { __typename?: 'VersionCollection', totalCount: number } } | null } }; +export type OnProjectUpdatedSubscription = { __typename?: 'Subscription', projectUpdated: { __typename?: 'ProjectUpdatedMessage', id: string, type: ProjectUpdatedMessageType, project?: { __typename?: 'Project', id: string, createdAt: string, name: string, updatedAt: string, role?: string | null, description?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, role?: string | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, id: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, versions: { __typename?: 'VersionCollection', totalCount: number } } | null } }; export type OnProjectModelsUpdateSubscriptionVariables = Exact<{ id: Scalars['String']['input']; @@ -6314,7 +6313,7 @@ export type AdminPanelProjectsListQueryVariables = Exact<{ }>; -export type AdminPanelProjectsListQuery = { __typename?: 'Query', admin: { __typename?: 'AdminQueries', projectList: { __typename?: 'ProjectCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, visibility: SimpleProjectVisibility, createdAt: string, updatedAt: string, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', name: string, id: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null }> } }, activeUser?: { __typename?: 'User', permissions: { __typename?: 'RootPermissionChecks', canCreatePersonalProject: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null }; +export type AdminPanelProjectsListQuery = { __typename?: 'Query', admin: { __typename?: 'AdminQueries', projectList: { __typename?: 'ProjectCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, visibility: ProjectVisibility, createdAt: string, updatedAt: string, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', name: string, id: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null }> } }, activeUser?: { __typename?: 'User', permissions: { __typename?: 'RootPermissionChecks', canCreatePersonalProject: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null }; export type AdminPanelInvitesListQueryVariables = Exact<{ limit: Scalars['Int']['input']; @@ -6518,7 +6517,7 @@ export type SettingsWorkspacesProjectsQueryVariables = Exact<{ }>; -export type SettingsWorkspacesProjectsQuery = { __typename?: 'Query', workspaceBySlug: { __typename?: 'Workspace', id: string, name: string, slug: string, role?: string | null, projects: { __typename?: 'ProjectCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, visibility: SimpleProjectVisibility, createdAt: string, updatedAt: string, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', name: string, id: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null }> }, plan?: { __typename?: 'WorkspacePlan', name: WorkspacePlans } | null, permissions: { __typename?: 'WorkspacePermissionChecks', canCreateProject: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } }; +export type SettingsWorkspacesProjectsQuery = { __typename?: 'Query', workspaceBySlug: { __typename?: 'Workspace', id: string, name: string, slug: string, role?: string | null, projects: { __typename?: 'ProjectCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, visibility: ProjectVisibility, createdAt: string, updatedAt: string, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', name: string, id: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null }> }, plan?: { __typename?: 'WorkspacePlan', name: WorkspacePlans } | null, permissions: { __typename?: 'WorkspacePermissionChecks', canCreateProject: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } }; export type SettingsWorkspaceSecurityQueryVariables = Exact<{ slug: Scalars['String']['input']; @@ -6555,7 +6554,7 @@ export type UpdateLegacyProjectsExplainerMutation = { __typename?: 'Mutation', a export type OnUserProjectsUpdateSubscriptionVariables = Exact<{ [key: string]: never; }>; -export type OnUserProjectsUpdateSubscription = { __typename?: 'Subscription', userProjectsUpdated: { __typename?: 'UserProjectsUpdatedMessage', type: UserProjectsUpdatedMessageType, id: string, project?: { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: SimpleProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null } }; +export type OnUserProjectsUpdateSubscription = { __typename?: 'Subscription', userProjectsUpdated: { __typename?: 'UserProjectsUpdatedMessage', type: UserProjectsUpdatedMessageType, id: string, project?: { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null } }; export type UpdateUserMutationVariables = Exact<{ input: UserUpdateInput; @@ -6654,7 +6653,7 @@ export type ViewerLoadedResourcesQueryVariables = Exact<{ }>; -export type ViewerLoadedResourcesQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, role?: string | null, allowPublicComments: boolean, visibility: SimpleProjectVisibility, createdAt: string, name: string, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, updatedAt: string, loadedVersion: { __typename?: 'VersionCollection', items: Array<{ __typename?: 'Version', id: string, message?: string | null, referencedObject?: string | null, sourceApplication?: string | null, createdAt: string, previewUrl: string, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> }, versions: { __typename?: 'VersionCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'Version', id: string, message?: string | null, referencedObject?: string | null, sourceApplication?: string | null, createdAt: string, previewUrl: string, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> } }> }, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string, name: string, role?: string | null } | null, modelCount: { __typename?: 'ModelCollection', totalCount: number }, permissions: { __typename?: 'ProjectPermissionChecks', canCreateComment: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canBroadcastActivity: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRequestRender: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } }; +export type ViewerLoadedResourcesQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, role?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, createdAt: string, name: string, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, updatedAt: string, loadedVersion: { __typename?: 'VersionCollection', items: Array<{ __typename?: 'Version', id: string, message?: string | null, referencedObject?: string | null, sourceApplication?: string | null, createdAt: string, previewUrl: string, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> }, versions: { __typename?: 'VersionCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'Version', id: string, message?: string | null, referencedObject?: string | null, sourceApplication?: string | null, createdAt: string, previewUrl: string, authorUser?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> } }> }, workspace?: { __typename?: 'Workspace', id: string, readOnly: boolean, slug: string, name: string, role?: string | null } | null, modelCount: { __typename?: 'ModelCollection', totalCount: number }, permissions: { __typename?: 'ProjectPermissionChecks', canCreateComment: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canBroadcastActivity: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRequestRender: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } }; export type ViewerModelVersionsQueryVariables = Exact<{ projectId: Scalars['String']['input']; @@ -6727,7 +6726,7 @@ export type OnWorkspaceProjectsUpdateSubscriptionVariables = Exact<{ }>; -export type OnWorkspaceProjectsUpdateSubscription = { __typename?: 'Subscription', workspaceProjectsUpdated: { __typename?: 'WorkspaceProjectsUpdatedMessage', projectId: string, workspaceId: string, type: WorkspaceProjectsUpdatedMessageType, project?: { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: SimpleProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null } }; +export type OnWorkspaceProjectsUpdateSubscription = { __typename?: 'Subscription', workspaceProjectsUpdated: { __typename?: 'WorkspaceProjectsUpdatedMessage', projectId: string, workspaceId: string, type: WorkspaceProjectsUpdatedMessageType, project?: { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null } }; export type WorkspaceHasCustomDataResidency_WorkspaceFragment = { __typename?: 'Workspace', id: string, defaultRegion?: { __typename?: 'ServerRegionItem', id: string, name: string } | null }; @@ -6874,7 +6873,7 @@ export type WorkspaceProjectsQueryQueryVariables = Exact<{ }>; -export type WorkspaceProjectsQueryQuery = { __typename?: 'Query', workspaceBySlug: { __typename?: 'Workspace', id: string, projects: { __typename?: 'ProjectCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: SimpleProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> } } }; +export type WorkspaceProjectsQueryQuery = { __typename?: 'Query', workspaceBySlug: { __typename?: 'Workspace', id: string, projects: { __typename?: 'ProjectCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, readOnly: boolean } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }> } } }; export type WorkspaceFunctionsQueryQueryVariables = Exact<{ workspaceSlug: Scalars['String']['input']; @@ -7071,15 +7070,15 @@ export type AutomateFunctionPageWorkspaceQueryVariables = Exact<{ export type AutomateFunctionPageWorkspaceQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, name: string, slug: string } }; -export type ProjectPageProjectFragment = { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, allowPublicComments: boolean, visibility: SimpleProjectVisibility, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, role?: string | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, id: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, versions: { __typename?: 'VersionCollection', totalCount: number } }; +export type ProjectPageProjectFragment = { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number }, workspace?: { __typename?: 'Workspace', id: string, slug: string, name: string, logo?: string | null, role?: string | null } | null, permissions: { __typename?: 'ProjectPermissionChecks', canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canMoveToWorkspace: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, role: string, inviteId: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, team: Array<{ __typename?: 'ProjectCollaborator', role: string, seatType?: WorkspaceSeatType | null, workspaceRole?: string | null, id: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, versions: { __typename?: 'VersionCollection', totalCount: number } }; export type ProjectPageAutomationPage_AutomationFragment = { __typename?: 'Automation', id: string, name: string, enabled: boolean, isTestAutomation: boolean, permissions: { __typename?: 'AutomationPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, currentRevision?: { __typename?: 'AutomationRevision', id: string, triggerDefinitions: Array<{ __typename?: 'VersionCreatedTriggerDefinition', type: AutomateRunTriggerType, model?: { __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null, permissions: { __typename?: 'ModelPermissionChecks', canUpdate: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canCreateVersion: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } } | null }>, functions: Array<{ __typename?: 'AutomationRevisionFunction', parameters?: {} | null, release: { __typename?: 'AutomateFunctionRelease', id: string, inputSchema?: {} | null, versionTag: string, createdAt: string, function: { __typename?: 'AutomateFunction', id: string, name: string, isFeatured: boolean, description: string, logo?: string | null, releases: { __typename?: 'AutomateFunctionReleaseCollection', items: Array<{ __typename?: 'AutomateFunctionRelease', id: string }> }, repo: { __typename?: 'BasicGitRepositoryMetadata', id: string, url: string, owner: string, name: string } } } }> } | null, runs: { __typename?: 'AutomateRunCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'AutomateRun', id: string, status: AutomateRunStatus, createdAt: string, updatedAt: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', statusMessage?: string | null, id: string, status: AutomateRunStatus }>, trigger: { __typename?: 'VersionCreatedTrigger', version?: { __typename?: 'Version', id: string } | null, model?: { __typename?: 'Model', id: string } | null } }> } }; -export type ProjectPageAutomationPage_ProjectFragment = { __typename?: 'Project', id: string, workspaceId?: string | null, role?: string | null, visibility: SimpleProjectVisibility, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; +export type ProjectPageAutomationPage_ProjectFragment = { __typename?: 'Project', id: string, workspaceId?: string | null, role?: string | null, visibility: ProjectVisibility, permissions: { __typename?: 'ProjectPermissionChecks', canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', id: string, slug: string } | null }; export type ProjectPageSettingsTab_ProjectFragment = { __typename?: 'Project', id: string, name: string, permissions: { __typename?: 'ProjectPermissionChecks', canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; -export type SettingsServerProjects_ProjectCollectionFragment = { __typename?: 'ProjectCollection', totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, visibility: SimpleProjectVisibility, createdAt: string, updatedAt: string, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', name: string, id: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null }> }; +export type SettingsServerProjects_ProjectCollectionFragment = { __typename?: 'ProjectCollection', totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, visibility: ProjectVisibility, createdAt: string, updatedAt: string, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', name: string, id: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null }> }; export type SettingsServerProjects_UserFragment = { __typename?: 'User', permissions: { __typename?: 'RootPermissionChecks', canCreatePersonalProject: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; @@ -7092,7 +7091,7 @@ export type SettingsWorkspacesGeneral_WorkspaceFragment = { __typename?: 'Worksp export type SettingsWorkspacesMembersCounts_WorkspaceFragment = { __typename?: 'Workspace', id: string, role?: string | null, invitedTeam?: Array<{ __typename?: 'PendingWorkspaceCollaborator', id: string }> | null, adminWorkspacesJoinRequests?: { __typename?: 'WorkspaceJoinRequestCollection', items: Array<{ __typename?: 'WorkspaceJoinRequest', id: string, status: WorkspaceJoinRequestStatus }> } | null }; -export type SettingsWorkspacesProjects_ProjectCollectionFragment = { __typename?: 'ProjectCollection', totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, visibility: SimpleProjectVisibility, createdAt: string, updatedAt: string, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', name: string, id: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null }> }; +export type SettingsWorkspacesProjects_ProjectCollectionFragment = { __typename?: 'ProjectCollection', totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, visibility: ProjectVisibility, createdAt: string, updatedAt: string, role?: string | null, models: { __typename?: 'ModelCollection', totalCount: number }, versions: { __typename?: 'VersionCollection', totalCount: number }, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', name: string, id: string, avatar?: string | null } }>, permissions: { __typename?: 'ProjectPermissionChecks', canDelete: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null }, canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } }, workspace?: { __typename?: 'Workspace', slug: string, id: string } | null }> }; export type SettingsWorkspacesProjects_WorkspaceFragment = { __typename?: 'Workspace', id: string, name: string, slug: string, role?: string | null, plan?: { __typename?: 'WorkspacePlan', name: WorkspacePlans } | null, permissions: { __typename?: 'WorkspacePermissionChecks', canCreateProject: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: {} | null } } }; @@ -7167,7 +7166,7 @@ export const ProjectPageModelsCardDeleteDialogFragmentDoc = {"kind":"Document"," export const ProjectPageModelsActionsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageModelsActions"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Model"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canDelete"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canCreateVersion"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}}]} as unknown as DocumentNode; export const ProjectPageLatestItemsModelItemFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageLatestItemsModelItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Model"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","alias":{"kind":"Name","value":"versionCount"},"name":{"kind":"Name","value":"versions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"commentThreadCount"},"name":{"kind":"Name","value":"commentThreads"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"pendingImportedVersions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PendingFileUpload"}}]}},{"kind":"Field","name":{"kind":"Name","value":"previewUrl"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageModelsCardRenameDialog"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageModelsCardDeleteDialog"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageModelsActions"}},{"kind":"Field","name":{"kind":"Name","value":"automationsStatus"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AutomateRunsTriggerStatus_TriggeredAutomationsStatus"}}]}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canDelete"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FunctionRunStatusForSummary"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateFunctionRun"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TriggeredAutomationsStatusSummary"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TriggeredAutomationsStatus"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"automationRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"functionRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"FunctionRunStatusForSummary"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialogFunctionRun_AutomateFunctionRun"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateFunctionRun"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"results"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"statusMessage"}},{"kind":"Field","name":{"kind":"Name","value":"contextView"}},{"kind":"Field","name":{"kind":"Name","value":"function"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AutomationsStatusOrderedRuns_AutomationRun"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateRun"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"automation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"functionRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialogRunsRows_AutomateRun"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateRun"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"functionRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialogFunctionRun_AutomateFunctionRun"}}]}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AutomationsStatusOrderedRuns_AutomationRun"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialog_TriggeredAutomationsStatus"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TriggeredAutomationsStatus"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"automationRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialogRunsRows_AutomateRun"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PendingFileUpload"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FileUpload"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"projectId"}},{"kind":"Field","name":{"kind":"Name","value":"modelName"}},{"kind":"Field","name":{"kind":"Name","value":"convertedStatus"}},{"kind":"Field","name":{"kind":"Name","value":"convertedMessage"}},{"kind":"Field","name":{"kind":"Name","value":"uploadDate"}},{"kind":"Field","name":{"kind":"Name","value":"convertedLastUpdate"}},{"kind":"Field","name":{"kind":"Name","value":"fileType"}},{"kind":"Field","name":{"kind":"Name","value":"fileName"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageModelsCardRenameDialog"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Model"}},"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":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageModelsCardDeleteDialog"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Model"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageModelsActions"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Model"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canDelete"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canCreateVersion"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AutomateRunsTriggerStatus_TriggeredAutomationsStatus"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TriggeredAutomationsStatus"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"TriggeredAutomationsStatusSummary"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialog_TriggeredAutomationsStatus"}}]}}]} as unknown as DocumentNode; export const SingleLevelModelTreeItemFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleLevelModelTreeItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ModelsTreeItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"model"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageLatestItemsModelItem"}}]}},{"kind":"Field","name":{"kind":"Name","value":"hasChildren"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PendingFileUpload"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FileUpload"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"projectId"}},{"kind":"Field","name":{"kind":"Name","value":"modelName"}},{"kind":"Field","name":{"kind":"Name","value":"convertedStatus"}},{"kind":"Field","name":{"kind":"Name","value":"convertedMessage"}},{"kind":"Field","name":{"kind":"Name","value":"uploadDate"}},{"kind":"Field","name":{"kind":"Name","value":"convertedLastUpdate"}},{"kind":"Field","name":{"kind":"Name","value":"fileType"}},{"kind":"Field","name":{"kind":"Name","value":"fileName"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageModelsCardRenameDialog"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Model"}},"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":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageModelsCardDeleteDialog"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Model"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageModelsActions"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Model"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canDelete"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canCreateVersion"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FunctionRunStatusForSummary"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateFunctionRun"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TriggeredAutomationsStatusSummary"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TriggeredAutomationsStatus"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"automationRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"functionRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"FunctionRunStatusForSummary"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialogFunctionRun_AutomateFunctionRun"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateFunctionRun"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"results"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"statusMessage"}},{"kind":"Field","name":{"kind":"Name","value":"contextView"}},{"kind":"Field","name":{"kind":"Name","value":"function"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AutomationsStatusOrderedRuns_AutomationRun"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateRun"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"automation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"functionRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialogRunsRows_AutomateRun"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateRun"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"functionRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialogFunctionRun_AutomateFunctionRun"}}]}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AutomationsStatusOrderedRuns_AutomationRun"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialog_TriggeredAutomationsStatus"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TriggeredAutomationsStatus"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"automationRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialogRunsRows_AutomateRun"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AutomateRunsTriggerStatus_TriggeredAutomationsStatus"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TriggeredAutomationsStatus"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"TriggeredAutomationsStatusSummary"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AutomateRunsTriggerStatusDialog_TriggeredAutomationsStatus"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageLatestItemsModelItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Model"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","alias":{"kind":"Name","value":"versionCount"},"name":{"kind":"Name","value":"versions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"commentThreadCount"},"name":{"kind":"Name","value":"commentThreads"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"pendingImportedVersions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PendingFileUpload"}}]}},{"kind":"Field","name":{"kind":"Name","value":"previewUrl"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageModelsCardRenameDialog"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageModelsCardDeleteDialog"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageModelsActions"}},{"kind":"Field","name":{"kind":"Name","value":"automationsStatus"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AutomateRunsTriggerStatus_TriggeredAutomationsStatus"}}]}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canDelete"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}}]} as unknown as DocumentNode; -export const ProjectPageSettingsGeneralBlockAccess_ProjectFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockAccess_Project"},"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":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}}]} as unknown as DocumentNode; +export const ProjectPageSettingsGeneralBlockAccess_ProjectFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockAccess_Project"},"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":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}}]} as unknown as DocumentNode; export const ProjectsDeleteDialog_ProjectFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectsDeleteDialog_Project"},"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":"role"}},{"kind":"Field","name":{"kind":"Name","value":"models"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"workspace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"versions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; export const ProjectPageSettingsGeneralBlockDelete_ProjectFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockDelete_Project"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectsDeleteDialog_Project"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectsDeleteDialog_Project"},"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":"role"}},{"kind":"Field","name":{"kind":"Name","value":"models"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"workspace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"versions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}}]} as unknown as DocumentNode; export const ProjectPageSettingsGeneralBlockDiscussions_ProjectFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockDiscussions_Project"},"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":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"allowPublicComments"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdateAllowPublicComments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}}]} as unknown as DocumentNode; @@ -7295,7 +7294,7 @@ export const AutomationCreateDialogFunctionsSearchDocument = {"kind":"Document", export const InviteDialogProjectRowProjectCollaboratorsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"InviteDialogProjectRowProjectCollaborators"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","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":"InvitableCollaboratorsFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"invitableCollaborators"},"arguments":[{"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":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const ProjectPageCollaboratorsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProjectPageCollaborators"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceTeamFilter"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageTeamInternals_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"InviteDialogProject_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageCollaborators_Project"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"workspace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SettingsWorkspacesMembersTableHeader_Workspace"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"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":"ProjectPageCollaborators_WorkspaceCollaborator"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"LimitedUserAvatar"},"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":"avatar"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"InviteDialogWorkspace_Workspace"},"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":"domainBasedMembershipProtectionEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"domains"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"domain"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageTeamInternals_Project"},"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":"role"}},{"kind":"Field","name":{"kind":"Name","value":"invitedTeam"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"inviteId"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"seatType"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceRole"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"InviteDialogProject_Project"},"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":"workspaceId"}},{"kind":"Field","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":"role"}},{"kind":"Field","name":{"kind":"Name","value":"domainBasedMembershipProtectionEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"domains"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"domain"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageCollaborators_Project"},"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":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SettingsWorkspacesMembersTableHeader_Workspace"},"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":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"InviteDialogWorkspace_Workspace"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageCollaborators_WorkspaceCollaborator"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceCollaborator"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"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":"avatar"}}]}}]}}]} as unknown as DocumentNode; export const InvitableCollaboratorsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"InvitableCollaborators"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","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":"InvitableCollaboratorsFilter"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"invitableCollaborators"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceRole"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workspaceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}]}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; -export const ProjectPageSettingsGeneralDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProjectPageSettingsGeneral"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockProjectInfo_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockAccess_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockDiscussions_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockLeave_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockDelete_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageTeamInternals_Project"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"LimitedUserAvatar"},"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":"avatar"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectsDeleteDialog_Project"},"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":"role"}},{"kind":"Field","name":{"kind":"Name","value":"models"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"workspace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"versions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockProjectInfo_Project"},"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":"description"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockAccess_Project"},"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":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockDiscussions_Project"},"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":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"allowPublicComments"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdateAllowPublicComments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockLeave_Project"},"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":"role"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"workspace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canLeave"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockDelete_Project"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectsDeleteDialog_Project"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageTeamInternals_Project"},"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":"role"}},{"kind":"Field","name":{"kind":"Name","value":"invitedTeam"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"inviteId"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"seatType"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceRole"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}}]}}]}}]} as unknown as DocumentNode; +export const ProjectPageSettingsGeneralDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProjectPageSettingsGeneral"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockProjectInfo_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockAccess_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockDiscussions_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockLeave_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockDelete_Project"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageTeamInternals_Project"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"LimitedUserAvatar"},"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":"avatar"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectsDeleteDialog_Project"},"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":"role"}},{"kind":"Field","name":{"kind":"Name","value":"models"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"workspace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"versions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockProjectInfo_Project"},"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":"description"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockAccess_Project"},"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":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockDiscussions_Project"},"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":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"allowPublicComments"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdateAllowPublicComments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockLeave_Project"},"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":"role"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"workspace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canLeave"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageSettingsGeneralBlockDelete_Project"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectsDeleteDialog_Project"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canUpdate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageTeamInternals_Project"},"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":"role"}},{"kind":"Field","name":{"kind":"Name","value":"invitedTeam"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"inviteId"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"seatType"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceRole"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}}]}}]}}]} as unknown as DocumentNode; export const ActiveUserMainMetadataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveUserMainMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"emails"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"verified"}}]}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"bio"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"isOnboardingFinished"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"verified"}},{"kind":"Field","name":{"kind":"Name","value":"notificationPreferences"}},{"kind":"Field","name":{"kind":"Name","value":"versions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]}}]} as unknown as DocumentNode; export const ActiveUserProjectsToMoveDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveUserProjectsToMove"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UserProjectsFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"projects"},"arguments":[{"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":"totalCount"}}]}}]}}]}}]} as unknown as DocumentNode; export const FinishOnboardingDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"FinishOnboarding"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"OnboardingCompletionInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUserMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"finishOnboarding"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/frontend-2/lib/projects/helpers/visibility.ts b/packages/frontend-2/lib/projects/helpers/visibility.ts new file mode 100644 index 000000000..88a3acef7 --- /dev/null +++ b/packages/frontend-2/lib/projects/helpers/visibility.ts @@ -0,0 +1,26 @@ +import { throwUncoveredError } from '@speckle/shared' +import { ProjectVisibility } from '~/lib/common/generated/gql/graphql' + +export const SupportedProjectVisibility = { + Public: ProjectVisibility.Public, + Private: ProjectVisibility.Private, + Workspace: ProjectVisibility.Workspace +} + +export type SupportedProjectVisibility = + (typeof SupportedProjectVisibility)[keyof typeof SupportedProjectVisibility] + +export const castToSupportedVisibility = ( + visibility: ProjectVisibility +): SupportedProjectVisibility => { + switch (visibility) { + case ProjectVisibility.Public: + case ProjectVisibility.Unlisted: + return SupportedProjectVisibility.Public + case ProjectVisibility.Private: + case ProjectVisibility.Workspace: + return visibility + default: + throwUncoveredError(visibility) + } +} diff --git a/packages/frontend-2/middleware/requireValidModel.ts b/packages/frontend-2/middleware/requireValidModel.ts index cbaa3770a..47b57c12d 100644 --- a/packages/frontend-2/middleware/requireValidModel.ts +++ b/packages/frontend-2/middleware/requireValidModel.ts @@ -1,4 +1,7 @@ -import { SimpleProjectVisibility } from '~/lib/common/generated/gql/graphql' +import { + castToSupportedVisibility, + SupportedProjectVisibility +} from '~/lib/projects/helpers/visibility' import { WorkspaceSsoErrorCodes } from '~/lib/workspaces/helpers/types' import { useApolloClientFromNuxt } from '~~/lib/common/composables/graphql' import { @@ -43,10 +46,10 @@ export default defineNuxtRouteMiddleware(async (to) => { return } - // If project is public or link shareable, allow access + // If project is public, allow access if ( - // data.project.visibility === SimpleProjectVisibility.Public || - data.project.visibility === SimpleProjectVisibility.Unlisted + castToSupportedVisibility(data.project.visibility) === + SupportedProjectVisibility.Public ) { return } diff --git a/packages/server/assets/core/typedefs/projects.graphql b/packages/server/assets/core/typedefs/projects.graphql index d44cf3eb5..9272a02c2 100644 --- a/packages/server/assets/core/typedefs/projects.graphql +++ b/packages/server/assets/core/typedefs/projects.graphql @@ -7,17 +7,22 @@ extend type Query { } enum ProjectVisibility { + """ + Only accessible to explicit collaborators + """ PRIVATE + """ + Legacy - same as public + """ UNLISTED + """ + Accessible to everyone (even non-logged in users) + """ PUBLIC -} - -""" -Visibility without the "discoverable" option -""" -enum SimpleProjectVisibility { - PRIVATE - UNLISTED + """ + Accessible to everyone in the project's workspace + """ + WORKSPACE } """ @@ -175,7 +180,7 @@ type Project { id: ID! name: String! description: String - visibility: SimpleProjectVisibility! + visibility: ProjectVisibility! allowPublicComments: Boolean! """ Active user's role for this project. `null` if request is not authenticated, or the project is not explicitly shared with you. diff --git a/packages/server/assets/core/typedefs/streams.graphql b/packages/server/assets/core/typedefs/streams.graphql index d179e527c..2379a8796 100644 --- a/packages/server/assets/core/typedefs/streams.graphql +++ b/packages/server/assets/core/typedefs/streams.graphql @@ -61,6 +61,7 @@ type Stream { and searches """ isDiscoverable: Boolean! + @deprecated(reason: "Discoverability as a feature has been removed.") allowPublicComments: Boolean! """ Your role for this stream. `null` if request is not authenticated, or the stream is not explicitly shared with you. diff --git a/packages/server/modules/cli/commands/db/seed/commits.ts b/packages/server/modules/cli/commands/db/seed/commits.ts index 5e01cfc5e..d62e8726f 100644 --- a/packages/server/modules/cli/commands/db/seed/commits.ts +++ b/packages/server/modules/cli/commands/db/seed/commits.ts @@ -9,6 +9,7 @@ import { BasicTestCommit, createTestCommits } from '@/test/speckle-helpers/commi import dayjs from 'dayjs' import { times } from 'lodash' import { CommandModule } from 'yargs' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' const command: CommandModule< unknown, @@ -49,7 +50,7 @@ const command: CommandModule< if (!stream?.id) { throw new StreamNotFoundError(`Stream with ID ${streamId} not found`) } - if (!stream.isPublic && !stream.role) { + if (stream.visibility !== ProjectRecordVisibility.Public && !stream.role) { throw new ForbiddenError( `Commit author does not have access to the specified stream ${streamId}` ) diff --git a/packages/server/modules/comments/services/management.ts b/packages/server/modules/comments/services/management.ts index 839995369..a709644b0 100644 --- a/packages/server/modules/comments/services/management.ts +++ b/packages/server/modules/comments/services/management.ts @@ -1,7 +1,4 @@ -import { ensureError, Roles, SpeckleViewer } from '@speckle/shared' -import { AuthContext } from '@/modules/shared/authz' -import { ForbiddenError } from '@/modules/shared/errors' -import { StreamInvalidAccessError } from '@/modules/core/errors/stream' +import { ensureError, SpeckleViewer } from '@speckle/shared' import { CreateCommentInput, CreateCommentReplyInput, @@ -18,7 +15,6 @@ import { formatSerializedViewerState, inputToDataStruct } from '@/modules/comments/services/data' -import { adminOverrideEnabled } from '@/modules/shared/helpers/envHelper' import { ArchiveCommentAndNotify, CreateCommentReplyAndNotify, @@ -38,57 +34,6 @@ import { import { GetStream } from '@/modules/core/domain/streams/operations' import { EventBusEmit } from '@/modules/shared/services/eventBus' import { CommentEvents } from '@/modules/comments/domain/events' -import { authorizeResolver } from '@/modules/shared' - -type AuthorizeProjectCommentsAccessDeps = { - getStream: GetStream - adminOverrideEnabled: typeof adminOverrideEnabled -} - -export const authorizeProjectCommentsAccessFactory = - (deps: AuthorizeProjectCommentsAccessDeps) => - async (params: { - projectId: string - authCtx: AuthContext - requireProjectRole?: boolean - }) => { - const { projectId, authCtx, requireProjectRole } = params - if (authCtx.role === Roles.Server.ArchivedUser) { - throw new ForbiddenError('You are not authorized') - } - - const project = await deps.getStream({ - streamId: projectId, - userId: authCtx.userId - }) - if (!project) { - throw new StreamInvalidAccessError('Stream not found') - } - - let success = true - if (!project.isPublic && !authCtx.auth) success = false - if (!project.isPublic && !project.role) success = false - if (requireProjectRole && !project.role && !project.allowPublicComments) - success = false - if (deps.adminOverrideEnabled() && authCtx.role === Roles.Server.Admin) - success = true - - // TODO: Until we do canCommentCreate & canCommentRead, fallback: - if (authCtx.userId && (!requireProjectRole || project.allowPublicComments)) { - try { - await authorizeResolver(authCtx.userId, projectId, Roles.Stream.Reviewer, null) - success = true - } catch { - // suppress - } - } - - if (!success) { - throw new StreamInvalidAccessError('You are not authorized') - } - - return project - } export const createCommentThreadAndNotifyFactory = (deps: { diff --git a/packages/server/modules/comments/tests/comments.graph.spec.ts b/packages/server/modules/comments/tests/comments.graph.spec.ts index 60cf702f8..c161fe223 100644 --- a/packages/server/modules/comments/tests/comments.graph.spec.ts +++ b/packages/server/modules/comments/tests/comments.graph.spec.ts @@ -300,7 +300,11 @@ const testResult = ( ) => void ) => { if (shouldSucceed) { - expect(result.errors, 'This should not have failed').to.not.exist + expect( + result.errors, + 'This should not have failed and yet we found errors: ' + + JSON.stringify(result.errors) + ).to.not.exist successTests( // eslint-disable-next-line @typescript-eslint/no-explicit-any result as SetNonNullable>, 'data'> diff --git a/packages/server/modules/core/dbSchema.ts b/packages/server/modules/core/dbSchema.ts index cf02d1ab3..8056a470d 100644 --- a/packages/server/modules/core/dbSchema.ts +++ b/packages/server/modules/core/dbSchema.ts @@ -266,14 +266,13 @@ export const Streams = buildTableHelper( 'id', 'name', 'description', - 'isPublic', 'clonedFrom', 'createdAt', 'updatedAt', 'allowPublicComments', - 'isDiscoverable', 'workspaceId', - 'regionKey' + 'regionKey', + 'visibility' ], StreamsMeta ) diff --git a/packages/server/modules/core/domain/projects/operations.ts b/packages/server/modules/core/domain/projects/operations.ts index 11167950b..88a41f347 100644 --- a/packages/server/modules/core/domain/projects/operations.ts +++ b/packages/server/modules/core/domain/projects/operations.ts @@ -5,7 +5,7 @@ import { MaybeNullOrUndefined, StreamRoles } from '@speckle/shared' export type GetProject = (args: { projectId: string }) => Promise export type UpdateProject = (args: { - projectUpdate: Pick + projectUpdate: Pick & Partial }) => Promise export type StoreProjectRole = (args: { @@ -38,7 +38,7 @@ export type GetRolesByUserId = ({ workspaceId?: string }) => Promise[]> -export type ProjectVisibility = 'PRIVATE' | 'PUBLIC' | 'UNLISTED' +export type ProjectVisibility = 'PRIVATE' | 'PUBLIC' | 'UNLISTED' | 'WORKSPACE' export type ProjectCreateArgs = { description?: MaybeNullOrUndefined diff --git a/packages/server/modules/core/domain/streams/operations.ts b/packages/server/modules/core/domain/streams/operations.ts index 9588d1cd7..90220dba2 100644 --- a/packages/server/modules/core/domain/streams/operations.ts +++ b/packages/server/modules/core/domain/streams/operations.ts @@ -23,12 +23,13 @@ import type express from 'express' import { ProjectCreateArgs } from '@/modules/core/domain/projects/operations' import { ServerInviteRecord } from '@/modules/serverinvites/domain/types' import type { Logger } from 'pino' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' export type LegacyGetStreams = (params: { cursor?: string | Date | null | undefined limit: number orderBy?: string | null | undefined - visibility?: string | null | undefined + visibility?: ProjectRecordVisibility | 'all' | null | undefined searchQuery?: string | null | undefined streamIdWhitelist?: string[] | null | undefined workspaceIdWhitelist?: string[] | null | undefined diff --git a/packages/server/modules/core/graph/generated/graphql.ts b/packages/server/modules/core/graph/generated/graphql.ts index c3add11c1..ed3708335 100644 --- a/packages/server/modules/core/graph/generated/graphql.ts +++ b/packages/server/modules/core/graph/generated/graphql.ts @@ -2090,7 +2090,7 @@ export type Project = { versions: VersionCollection; /** Return metadata about resources being requested in the viewer */ viewerResources: Array; - visibility: SimpleProjectVisibility; + visibility: ProjectVisibility; webhooks: WebhookCollection; workspace?: Maybe; workspaceId?: Maybe; @@ -2711,9 +2711,14 @@ export const ProjectVersionsUpdatedMessageType = { export type ProjectVersionsUpdatedMessageType = typeof ProjectVersionsUpdatedMessageType[keyof typeof ProjectVersionsUpdatedMessageType]; export const ProjectVisibility = { + /** Only accessible to explicit collaborators */ Private: 'PRIVATE', + /** Accessible to everyone (even non-logged in users) */ Public: 'PUBLIC', - Unlisted: 'UNLISTED' + /** Legacy - same as public */ + Unlisted: 'UNLISTED', + /** Accessible to everyone in the project's workspace */ + Workspace: 'WORKSPACE' } as const; export type ProjectVisibility = typeof ProjectVisibility[keyof typeof ProjectVisibility]; @@ -3263,13 +3268,6 @@ export type SetPrimaryUserEmailInput = { id: Scalars['ID']['input']; }; -/** Visibility without the "discoverable" option */ -export const SimpleProjectVisibility = { - Private: 'PRIVATE', - Unlisted: 'UNLISTED' -} as const; - -export type SimpleProjectVisibility = typeof SimpleProjectVisibility[keyof typeof SimpleProjectVisibility]; export type SmartTextEditorValue = { __typename?: 'SmartTextEditorValue'; /** File attachments, if any */ @@ -3346,6 +3344,7 @@ export type Stream = { /** * Whether the stream (if public) can be found on public stream exploration pages * and searches + * @deprecated Discoverability as a feature has been removed. */ isDiscoverable: Scalars['Boolean']['output']; /** Whether the stream can be viewed by non-contributors */ @@ -5424,7 +5423,6 @@ export type ResolversTypes = { ServerWorkspacesInfo: ResolverTypeWrapper; SessionPaymentStatus: SessionPaymentStatus; SetPrimaryUserEmailInput: SetPrimaryUserEmailInput; - SimpleProjectVisibility: SimpleProjectVisibility; SmartTextEditorValue: ResolverTypeWrapper; SortDirection: SortDirection; Stream: ResolverTypeWrapper; @@ -6668,7 +6666,7 @@ export type ProjectResolvers>; versions?: Resolver>; viewerResources?: Resolver, ParentType, ContextType, RequireFields>; - visibility?: Resolver; + visibility?: Resolver; webhooks?: Resolver>; workspace?: Resolver, ParentType, ContextType>; workspaceId?: Resolver, ParentType, ContextType>; diff --git a/packages/server/modules/core/graph/resolvers/projects.ts b/packages/server/modules/core/graph/resolvers/projects.ts index c4880b738..9ffaf4ea9 100644 --- a/packages/server/modules/core/graph/resolvers/projects.ts +++ b/packages/server/modules/core/graph/resolvers/projects.ts @@ -7,7 +7,6 @@ import { } from '@/modules/comments/repositories/comments' import { RateLimitError } from '@/modules/core/errors/ratelimit' import { - ProjectVisibility, Resolvers, TokenResourceIdentifierType } from '@/modules/core/graph/generated/graphql' @@ -116,6 +115,8 @@ import { requestNewEmailVerificationFactory } from '@/modules/emails/services/ve import { deleteOldAndInsertNewVerificationFactory } from '@/modules/emails/repositories' import { renderEmail } from '@/modules/emails/services/emailRendering' import { sendEmail } from '@/modules/emails/services/sending' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' +import { mapDbToGqlProjectVisibility } from '@/modules/core/helpers/project' const getServerInfo = getServerInfoFactory({ db }) const getUsers = getUsersFactory({ db }) @@ -251,6 +252,12 @@ const getUserStreamsCount = getUserStreamsCountFactory({ db }) export = { Query: { async project(_parent, args, context) { + throwIfResourceAccessNotAllowed({ + resourceId: args.id, + resourceType: TokenResourceIdentifierType.Project, + resourceAccessRules: context.resourceAccessRules + }) + const canQuery = await context.authPolicies.project.canRead({ projectId: args.id, userId: context.userId @@ -259,8 +266,7 @@ export = { const project = await getStream({ streamId: args.id }) - // TODO: Should scopes & token resource access rules be checked in authz policy? - if (!project?.isPublic && !project?.isDiscoverable) { + if (project?.visibility !== ProjectRecordVisibility.Public) { await validateScopes(context.scopes, Scopes.Streams.Read) } @@ -614,12 +620,9 @@ export = { .streams.getSourceApps.load(parent.id) || [] ) }, - async visibility(parent) { - const { isPublic } = parent - - // Ignore discoverability for now - return isPublic ? ProjectVisibility.Unlisted : ProjectVisibility.Private + const { visibility } = parent + return mapDbToGqlProjectVisibility(visibility) } }, PendingStreamCollaborator: { diff --git a/packages/server/modules/core/graph/resolvers/streams.ts b/packages/server/modules/core/graph/resolvers/streams.ts index 4619cfed4..2511a3c58 100644 --- a/packages/server/modules/core/graph/resolvers/streams.ts +++ b/packages/server/modules/core/graph/resolvers/streams.ts @@ -36,12 +36,16 @@ import { updateStreamAndNotifyFactory, updateStreamRoleAndNotifyFactory } from '@/modules/core/services/streams/management' -import { Roles, Scopes } from '@speckle/shared' +import { Nullable, Roles, Scopes } from '@speckle/shared' import { StreamNotFoundError } from '@/modules/core/errors/stream' import { throwForNotHavingServerRole } from '@/modules/shared/authz' import { RateLimitError } from '@/modules/core/errors/ratelimit' -import { toProjectIdWhitelist, isResourceAllowed } from '@/modules/core/helpers/token' +import { + toProjectIdWhitelist, + isResourceAllowed, + throwIfResourceAccessNotAllowed +} from '@/modules/core/helpers/token' import { Resolvers, TokenResourceIdentifierType @@ -97,6 +101,7 @@ import { requestNewEmailVerificationFactory } from '@/modules/emails/services/ve import { deleteOldAndInsertNewVerificationFactory } from '@/modules/emails/repositories' import { renderEmail } from '@/modules/emails/services/emailRendering' import { sendEmail } from '@/modules/emails/services/sending' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' const getServerInfo = getServerInfoFactory({ db }) const getUsers = getUsersFactory({ db }) @@ -228,6 +233,12 @@ const getUserStreamsCount = getUserStreamsCountFactory({ db }) export = { Query: { async stream(_, args, context) { + throwIfResourceAccessNotAllowed({ + resourceId: args.id, + resourceType: TokenResourceIdentifierType.Project, + resourceAccessRules: context.resourceAccessRules + }) + const stream = await getStream({ streamId: args.id, userId: context.userId }) if (!stream) { throw new StreamNotFoundError('Stream not found') @@ -240,7 +251,7 @@ export = { context.resourceAccessRules ) - if (!stream.isPublic) { + if (stream.visibility !== ProjectRecordVisibility.Public) { await throwForNotHavingServerRole(context, Roles.Server.Guest) await validateScopes(context.scopes, Scopes.Streams.Read) } @@ -303,7 +314,7 @@ export = { orderBy: args.orderBy, publicOnly: null, searchQuery: args.query, - visibility: args.visibility, + visibility: args.visibility as Nullable, streamIdWhitelist: toProjectIdWhitelist(ctx.resourceAccessRules), cursor: null }) @@ -312,6 +323,10 @@ export = { }, Stream: { + isPublic(parent) { + return parent.visibility === ProjectRecordVisibility.Public + }, + isDiscoverable: () => false, async collaborators(parent, _args, ctx) { const collaborators = await ctx.loaders.streams.getCollaborators.load(parent.id) @@ -357,13 +372,6 @@ export = { return (await ctx.loaders.streams.getFavoritesCount.load(streamId)) || 0 }, - async isDiscoverable(parent) { - const { isPublic, isDiscoverable } = parent - - if (!isPublic) return false - return isDiscoverable - }, - async role(parent, _args, ctx) { // If role already resolved, return that const role = get(parent, 'role') as string | undefined diff --git a/packages/server/modules/core/graph/resolvers/users.ts b/packages/server/modules/core/graph/resolvers/users.ts index 0d339e42e..3b99094e9 100644 --- a/packages/server/modules/core/graph/resolvers/users.ts +++ b/packages/server/modules/core/graph/resolvers/users.ts @@ -50,6 +50,7 @@ import { metaHelpers } from '@/modules/core/helpers/meta' import { asOperation } from '@/modules/shared/command' import { setUserOnboardingChoicesFactory } from '@/modules/core/services/users/tracking' import { getMixpanelClient } from '@/modules/shared/utils/mixpanel' +import { throwIfAuthNotOk } from '@/modules/shared/helpers/errorHelper' const getUser = legacyGetUserFactory({ db }) const getUserByEmail = legacyGetUserByEmailFactory({ db }) @@ -147,7 +148,7 @@ export = { return { cursor, items: users } }, - async users(_parent, args) { + async users(_parent, args, context) { if (args.input.query.length < 1) throw new BadRequestError('Search query must be at least 1 character.') @@ -156,6 +157,14 @@ export = { 'Cannot return more than 100 items, please use pagination.' ) + if (args.input.projectId) { + const canRead = await context.authPolicies.project.canRead({ + projectId: args.input.projectId, + userId: context.userId + }) + throwIfAuthNotOk(canRead) + } + const { cursor, users } = await lookupUsers(args.input) return { cursor, items: users } }, diff --git a/packages/server/modules/core/helpers/project.ts b/packages/server/modules/core/helpers/project.ts new file mode 100644 index 000000000..fb2e8a114 --- /dev/null +++ b/packages/server/modules/core/helpers/project.ts @@ -0,0 +1,43 @@ +import { ProjectCreateArgs } from '@/modules/core/domain/projects/operations' +import { + ProjectVisibility, + StreamCreateInput +} from '@/modules/core/graph/generated/graphql' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' +import { throwUncoveredError } from '@speckle/shared' +import { has } from 'lodash' + +export const isProjectCreateInput = ( + i: StreamCreateInput | ProjectCreateArgs +): i is ProjectCreateArgs => has(i, 'visibility') + +export const mapGqlToDbProjectVisibility = ( + visibility: ProjectVisibility +): ProjectRecordVisibility => { + switch (visibility) { + case ProjectVisibility.Public: + case ProjectVisibility.Unlisted: + return ProjectRecordVisibility.Public + case ProjectVisibility.Private: + return ProjectRecordVisibility.Private + case ProjectVisibility.Workspace: + return ProjectRecordVisibility.Workspace + default: + throwUncoveredError(visibility) + } +} + +export const mapDbToGqlProjectVisibility = ( + visibility: ProjectRecordVisibility +): ProjectVisibility => { + switch (visibility) { + case ProjectRecordVisibility.Public: + return ProjectVisibility.Public + case ProjectRecordVisibility.Private: + return ProjectVisibility.Private + case ProjectRecordVisibility.Workspace: + return ProjectVisibility.Workspace + default: + throwUncoveredError(visibility) + } +} diff --git a/packages/server/modules/core/helpers/stream.ts b/packages/server/modules/core/helpers/stream.ts deleted file mode 100644 index 2355f4b59..000000000 --- a/packages/server/modules/core/helpers/stream.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ProjectCreateArgs } from '@/modules/core/domain/projects/operations' -import { StreamCreateInput } from '@/modules/core/graph/generated/graphql' -import { has } from 'lodash' - -export const isProjectCreateInput = ( - i: StreamCreateInput | ProjectCreateArgs -): i is ProjectCreateArgs => has(i, 'visibility') diff --git a/packages/server/modules/core/helpers/types.ts b/packages/server/modules/core/helpers/types.ts index ac22dabfe..13337ebf1 100644 --- a/packages/server/modules/core/helpers/types.ts +++ b/packages/server/modules/core/helpers/types.ts @@ -43,18 +43,34 @@ export type ServerAclRecord = { role: string } +export const ProjectRecordVisibility = { + Public: 'public', + Private: 'private', + Workspace: 'workspace' +} + +export type ProjectRecordVisibility = + (typeof ProjectRecordVisibility)[keyof typeof ProjectRecordVisibility] + export type StreamRecord = { id: string name: string description: Nullable - isPublic: boolean clonedFrom: Nullable createdAt: Date updatedAt: Date allowPublicComments: boolean - isDiscoverable: boolean workspaceId: Nullable regionKey: Nullable + visibility: ProjectRecordVisibility + /** + * @deprecated No longer used, about to be removed + */ + isDiscoverable: boolean + /** + * @deprecated No longer used, about to be removed + */ + isPublic: boolean } export type StreamAclRecord = { diff --git a/packages/server/modules/core/migrations/20250506114120_add_streams_visibility_col.ts b/packages/server/modules/core/migrations/20250506114120_add_streams_visibility_col.ts new file mode 100644 index 000000000..91e68a310 --- /dev/null +++ b/packages/server/modules/core/migrations/20250506114120_add_streams_visibility_col.ts @@ -0,0 +1,55 @@ +import { Knex } from 'knex' + +const tableName = 'streams' +const isPublicCol = 'isPublic' +// const isDiscoverableCol = 'isDiscoverable' +const visibilityCol = 'visibility' +const workspaceIdCol = 'workspaceId' + +export async function up(knex: Knex): Promise { + // Add new col + await knex.schema.alterTable(tableName, (table) => { + table.string(visibilityCol).defaultTo('private').notNullable() + }) + + // Migrate isPublic -> visibility + await knex.raw(` + UPDATE "${tableName}" + SET "${visibilityCol}" = + CASE + WHEN "${isPublicCol}" = true THEN 'public' + WHEN "${isPublicCol}" = false AND "${workspaceIdCol}" IS NULL THEN 'private' + WHEN "${isPublicCol}" = false AND "${workspaceIdCol}" IS NOT NULL THEN 'workspace' + END; + `) + + // // Drop old cols - Do this separately to avoid backwards incompatible changes + // await knex.schema.alterTable(tableName, (table) => { + // table.dropColumn(isPublicCol) + // table.dropColumn(isDiscoverableCol) + // }) +} + +export async function down(knex: Knex): Promise { + // // Re-introduce old cols + // await knex.schema.alterTable(tableName, (table) => { + // table.boolean(isPublicCol).defaultTo(true) + // table.boolean(isDiscoverableCol).defaultTo(false).notNullable() + // }) + + // Migrate visibility -> isPublic + await knex.raw(` + UPDATE "${tableName}" + SET "${isPublicCol}" = + CASE + WHEN "${visibilityCol}" = 'public' THEN true + WHEN "${visibilityCol}" = 'private' THEN false + WHEN "${visibilityCol}" = 'workspace' THEN false + END; + `) + + // Drop new col + await knex.schema.alterTable(tableName, (table) => { + table.dropColumn(visibilityCol) + }) +} diff --git a/packages/server/modules/core/repositories/commits.ts b/packages/server/modules/core/repositories/commits.ts index 2fab3a141..13274fb77 100644 --- a/packages/server/modules/core/repositories/commits.ts +++ b/packages/server/modules/core/repositories/commits.ts @@ -11,6 +11,7 @@ import { BranchCommitRecord, BranchRecord, CommitRecord, + ProjectRecordVisibility, StreamAclRecord, StreamCommitRecord } from '@/modules/core/helpers/types' @@ -527,7 +528,7 @@ export const getUserStreamCommitCountsFactory = if (publicOnly) { q.join(Streams.name, Streams.col.id, StreamAcl.col.resourceId) q.andWhere((q1) => { - q1.where(Streams.col.isPublic, true).orWhere(Streams.col.isDiscoverable, true) + q1.where(Streams.col.visibility, ProjectRecordVisibility.Public) }) } @@ -560,7 +561,7 @@ export const getUserAuthoredCommitCountsFactory = q.join(StreamCommits.name, StreamCommits.col.commitId, Commits.col.id) q.join(Streams.name, Streams.col.id, StreamCommits.col.streamId) q.andWhere((q1) => { - q1.where(Streams.col.isPublic, true).orWhere(Streams.col.isDiscoverable, true) + q1.where(Streams.col.visibility, ProjectRecordVisibility.Public) }) } @@ -610,7 +611,7 @@ const getCommitsByUserIdBaseFactory = .leftJoin('users', 'commits.author', 'users.id') .where('author', userId) - if (publicOnly) query.andWhere('streams.isPublic', true) + if (publicOnly) query.andWhere('streams.visibility', ProjectRecordVisibility.Public) if (streamIdWhitelist?.length) query.whereIn('streams.streamId', streamIdWhitelist) return query diff --git a/packages/server/modules/core/repositories/streams.ts b/packages/server/modules/core/repositories/streams.ts index 02cadc776..b08428f46 100644 --- a/packages/server/modules/core/repositories/streams.ts +++ b/packages/server/modules/core/repositories/streams.ts @@ -7,6 +7,7 @@ import _, { isObjectLike, isUndefined, mapValues, + omit, omitBy, reduce, toNumber @@ -25,6 +26,7 @@ import { import { InvalidArgumentError, LogicError } from '@/modules/shared/errors' import { Roles, StreamRoles } from '@/modules/core/helpers/mainConstants' import { + ProjectRecordVisibility, StreamAclRecord, StreamCommitRecord, StreamFavoriteRecord, @@ -47,7 +49,10 @@ import { import dayjs from 'dayjs' import cryptoRandomString from 'crypto-random-string' import { Knex } from 'knex' -import { isProjectCreateInput } from '@/modules/core/helpers/stream' +import { + isProjectCreateInput, + mapGqlToDbProjectVisibility +} from '@/modules/core/helpers/project' import { StreamAccessUpdateError, StreamNotFoundError, @@ -59,8 +64,7 @@ import { DeleteProjectRole, UpdateProject, GetRolesByUserId, - UpsertProjectRole, - ProjectVisibility + UpsertProjectRole } from '@/modules/core/domain/projects/operations' import { StreamWithCommitId, @@ -243,7 +247,9 @@ const getFavoritedStreamsQueryBaseFactory = .andOnVal(StreamAcl.col.userId, userId) ) .andWhere((q) => - q.where(Streams.col.isPublic, true).orWhereNotNull(StreamAcl.col.resourceId) + q + .where(Streams.col.visibility, ProjectRecordVisibility.Public) + .orWhereNotNull(StreamAcl.col.resourceId) ) if (streamIdWhitelist?.length) { @@ -406,7 +412,10 @@ export const canUserFavoriteStreamFactory = }) .where(Streams.col.id, streamId) .andWhere(function () { - this.where(Streams.col.isPublic, true).orWhereNotNull(StreamAcl.col.resourceId) + this.where( + Streams.col.visibility, + ProjectRecordVisibility.Public + ).orWhereNotNull(StreamAcl.col.resourceId) }) .limit(1) @@ -469,8 +478,8 @@ const buildDiscoverableStreamsBaseQueryFactory = const q = tables .streams(deps.db) .select(Streams.cols) - .where(Streams.col.isDiscoverable, true) - .andWhere(Streams.col.isPublic, true) + .andWhere(Streams.col.visibility, ProjectRecordVisibility.Public) + .andWhere(false) // TODO: No such thing as discoverability anymore, just return nothing if (params.streamIdWhitelist?.length) { q.whereIn(Streams.col.id, params.streamIdWhitelist) @@ -715,7 +724,9 @@ const getUserStreamsQueryBaseFactory = /** * implicit access rules: * 1. user must have an explicit stream role OR - * 2. user must be a non-guest member of the project's workspace + * 2. if project is in a workspace that the user is in: + * - user must be a workspace admin OR + * - project must not be fully private and user is non-workspace-guest */ query .leftJoin(WorkspaceAcl.name, (j2) => { @@ -726,11 +737,18 @@ const getUserStreamsQueryBaseFactory = }) .andWhere((w1) => { w1.whereNotNull(StreamAcl.col.role).orWhere((w2) => { - w2.whereNotNull(WorkspaceAcl.col.role).andWhere( - WorkspaceAcl.col.role, - '!=', - Roles.Workspace.Guest - ) + // Implicit workspace role conditions + w2.whereNotNull(WorkspaceAcl.col.role).andWhere((w2) => { + w2.andWhere(WorkspaceAcl.col.role, Roles.Workspace.Admin).orWhere( + (w4) => { + w4.where( + WorkspaceAcl.col.role, + '!=', + Roles.Workspace.Guest + ).andWhereNot(Streams.col.visibility, ProjectRecordVisibility.Private) + } + ) + }) }) }) } else { @@ -774,9 +792,8 @@ const getUserStreamsQueryBaseFactory = } if (forOtherUser) { - query - .andWhere(Streams.col.isDiscoverable, true) - .andWhere(Streams.col.isPublic, true) + // TODO: How did this work before discoverability? + query.andWhere(Streams.col.visibility, ProjectRecordVisibility.Public) } if (searchQuery) { @@ -876,15 +893,16 @@ export const createStreamFactory = const { name, description } = input const { ownerId, trx } = options || {} - let shouldBePublic: boolean, shouldBeDiscoverable: boolean + let visibility: ProjectRecordVisibility if (isProjectCreateInput(input)) { - shouldBeDiscoverable = input.visibility === 'PUBLIC' - const publicVisibilities: ProjectVisibility[] = ['PUBLIC', 'UNLISTED'] - shouldBePublic = - !input.visibility || publicVisibilities.includes(input.visibility) + visibility = mapGqlToDbProjectVisibility( + input.visibility || (input.workspaceId ? 'WORKSPACE' : 'PRIVATE') + ) } else { - shouldBePublic = input.isPublic !== false - shouldBeDiscoverable = input.isDiscoverable !== false && shouldBePublic + visibility = + input.isPublic !== false + ? ProjectRecordVisibility.Public + : ProjectRecordVisibility.Private } const workspaceId = 'workspaceId' in input ? input.workspaceId : null @@ -895,8 +913,7 @@ export const createStreamFactory = id, name: name || generateProjectName(), description: description || '', - isPublic: shouldBePublic, - isDiscoverable: shouldBeDiscoverable, + visibility, updatedAt: knex.fn.now(), workspaceId: workspaceId || null, regionKey @@ -945,7 +962,7 @@ export const getUserStreamCountsFactory = if (publicOnly) { q.join(Streams.name, Streams.col.id, StreamAcl.col.resourceId).andWhere((q1) => { - q1.where(Streams.col.isPublic, true).orWhere(Streams.col.isDiscoverable, true) + q1.where(Streams.col.visibility, ProjectRecordVisibility.Public) }) } @@ -1017,18 +1034,23 @@ export const updateStreamFactory = ) if (isProjectUpdateInput(update)) { - if (has(validUpdate, 'visibility')) { - validUpdate.isPublic = update.visibility !== 'PRIVATE' - validUpdate.isDiscoverable = update.visibility === 'PUBLIC' - delete validUpdate['visibility'] // cause it's not a real column + if (has(update, 'visibility')) { + validUpdate.visibility = mapGqlToDbProjectVisibility( + update.visibility || 'PRIVATE' + ) } } else { - if (has(validUpdate, 'isPublic') && !validUpdate.isPublic) { - validUpdate.isDiscoverable = false + if (has(update, 'isPublic')) { + validUpdate.visibility = update.isPublic + ? ProjectRecordVisibility.Public + : ProjectRecordVisibility.Private } } - if (has(validUpdate, 'isPublic') && !validUpdate.isPublic) { + if ( + has(validUpdate, 'visibility') && + validUpdate.visibility !== ProjectRecordVisibility.Public + ) { validUpdate.allowPublicComments = false } else if ( has(validUpdate, 'allowPublicComments') && @@ -1037,8 +1059,9 @@ export const updateStreamFactory = validUpdate.isPublic = true } - // Ignore discoverability for now + // Remove non-existant fields delete validUpdate['isDiscoverable'] + delete validUpdate['isPublic'] if (!Object.keys(validUpdate).length) return null @@ -1057,7 +1080,14 @@ export const updateStreamFactory = export const updateProjectFactory = ({ db }: { db: Knex }): UpdateProject => async ({ projectUpdate }) => { - const updatedStream = await updateStreamFactory({ db })(projectUpdate) + const [updatedStream] = await tables + .streams(db) + .returning('*') + .where({ id: projectUpdate.id }) + .update({ + ...omit(projectUpdate, ['id']), + updatedAt: knex.fn.now() + }) if (!updatedStream) { throw new StreamUpdateError('Stream was not updated.') @@ -1337,13 +1367,18 @@ export const legacyGetStreamsFactory = } if (visibility && visibility !== 'all') { - if (!['private', 'public'].includes(visibility)) + if ( + ![ + ProjectRecordVisibility.Private, + ProjectRecordVisibility.Public, + ProjectRecordVisibility.Workspace + ].includes(visibility) + ) throw new LogicError( - 'Stream visibility should be either private, public or all' + 'Stream visibility should be either private, public, workspace or all' ) - const isPublic = visibility === 'public' const publicFunc: Knex.QueryCallback = function () { - this.where({ isPublic }) + this.where({ visibility }) } query.andWhere(publicFunc) } diff --git a/packages/server/modules/core/repositories/users.ts b/packages/server/modules/core/repositories/users.ts index f347e9f5b..8a2b1964e 100644 --- a/packages/server/modules/core/repositories/users.ts +++ b/packages/server/modules/core/repositories/users.ts @@ -7,6 +7,7 @@ import { knex } from '@/modules/core/dbSchema' import { + ProjectRecordVisibility, ServerAclRecord, StreamAclRecord, StreamRecord, @@ -526,7 +527,9 @@ export const lookupUsersFactory = if (projectId) { // Workspace implicit roles logic: // - User must have an explicit stream acl OR - // - User must have a project workspace acl w/ non-guest role + // - User must have a project workspace acl AND: + // - must be a workspace admin + // - or must be a workspace member and the project must not be fully private query .innerJoin(Streams.name, (j1) => { j1.onVal(Streams.col.id, projectId) @@ -544,11 +547,20 @@ export const lookupUsersFactory = ) }) .andWhere((w1) => { - w1.whereNotNull(StreamAcl.col.role).orWhere( - WorkspaceAcl.col.role, - '!=', - Roles.Workspace.Guest - ) + w1.whereNotNull(StreamAcl.col.role).orWhere((w2) => { + // Implicit workspace role conditions + w2.whereNotNull(WorkspaceAcl.col.role).andWhere((w2) => { + w2.andWhere(WorkspaceAcl.col.role, Roles.Workspace.Admin).orWhere( + (w4) => { + w4.where( + WorkspaceAcl.col.role, + '!=', + Roles.Workspace.Guest + ).andWhereNot(Streams.col.visibility, ProjectRecordVisibility.Private) + } + ) + }) + }) }) } diff --git a/packages/server/modules/core/services/admin.ts b/packages/server/modules/core/services/admin.ts index 5518d8567..2aec05ce5 100644 --- a/packages/server/modules/core/services/admin.ts +++ b/packages/server/modules/core/services/admin.ts @@ -8,12 +8,14 @@ import { CountUsers, ListPaginatedUsersPage } from '@/modules/core/domain/users/operations' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' import { CountServerInvites, QueryServerInvites } from '@/modules/serverinvites/domain/operations' import { ServerInviteRecord } from '@/modules/serverinvites/domain/types' import { BaseError } from '@/modules/shared/errors/base' +import { Nullable } from '@speckle/shared' class CursorParsingError extends BaseError { static defaultMessage = 'Invalid cursor provided' @@ -86,6 +88,7 @@ export const adminProjectListFactory = const parsedCursor = args.cursor ? parseCursorToDate(args.cursor) : null const { streams, totalCount, cursorDate } = await deps.getStreams({ ...args, + visibility: args.visibility as Nullable, searchQuery: args.query, cursor: parsedCursor, streamIdWhitelist: args.streamIdWhitelist, diff --git a/packages/server/modules/core/services/projects.ts b/packages/server/modules/core/services/projects.ts index bd151794c..546d6bcce 100644 --- a/packages/server/modules/core/services/projects.ts +++ b/packages/server/modules/core/services/projects.ts @@ -4,7 +4,6 @@ import { CreateProject, DeleteProject, GetProject, - ProjectVisibility, StoreModel, StoreProject, StoreProjectRole @@ -12,6 +11,8 @@ import { import { Project } from '@/modules/core/domain/streams/types' import { RegionalProjectCreationError } from '@/modules/core/errors/projects' import { StreamNotFoundError } from '@/modules/core/errors/stream' +import { ProjectVisibility } from '@/modules/core/graph/generated/graphql' +import { mapGqlToDbProjectVisibility } from '@/modules/core/helpers/project' import { isTestEnv } from '@/modules/shared/helpers/envHelper' import { EventBusEmit } from '@/modules/shared/services/eventBus' import { retry } from '@lifeomic/attempt' @@ -35,24 +36,24 @@ export const createNewProjectFactory = storeModel: StoreModel }): CreateProject => async ({ description, name, regionKey, visibility, workspaceId, ownerId }) => { - const publicVisibilities: ProjectVisibility[] = ['PUBLIC', 'UNLISTED'] - const isPublic = !visibility || publicVisibilities.includes(visibility) - - // const isDiscoverable = visibility === 'PUBLIC' - const isDiscoverable = false // discoverability disabled for now + visibility = + visibility || + (workspaceId ? ProjectVisibility.Workspace : ProjectVisibility.Private) const project: Project = { id: cryptoRandomString({ length: 10 }), name: name || generateProjectName(), description: description || '', - isPublic, - isDiscoverable, + visibility: mapGqlToDbProjectVisibility(visibility), createdAt: new Date(), clonedFrom: null, updatedAt: new Date(), workspaceId: workspaceId || null, regionKey: regionKey || null, - allowPublicComments: false + allowPublicComments: false, + // TODO: Will be removed in a moment + isPublic: false, + isDiscoverable: false } await storeProject({ project }) @@ -94,7 +95,7 @@ export const createNewProjectFactory = input: { description: project.description, name: project.name, - visibility: isPublic ? 'PUBLIC' : isDiscoverable ? 'UNLISTED' : 'PRIVATE' + visibility } } }) diff --git a/packages/server/modules/core/services/streams/auth.ts b/packages/server/modules/core/services/streams/auth.ts index 0b225d210..d111fbb35 100644 --- a/packages/server/modules/core/services/streams/auth.ts +++ b/packages/server/modules/core/services/streams/auth.ts @@ -3,6 +3,7 @@ import { ValidatePermissionsReadStream, ValidatePermissionsWriteStream } from '@/modules/core/domain/streams/operations' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' import { throwForNotHavingServerRole } from '@/modules/shared/authz' import { AuthorizeResolver, ValidateScopes } from '@/modules/shared/domain/operations' import { DatabaseError } from '@/modules/shared/errors' @@ -16,7 +17,8 @@ export const validatePermissionsReadStreamFactory = }): ValidatePermissionsReadStream => async (streamId, req) => { const stream = await deps.getStream({ streamId, userId: req.context.userId }) - if (stream?.isPublic) return { result: true, status: 200 } + if (stream?.visibility === ProjectRecordVisibility.Public) + return { result: true, status: 200 } try { await throwForNotHavingServerRole(req.context, Roles.Server.Guest) @@ -28,31 +30,29 @@ export const validatePermissionsReadStreamFactory = if (!stream) return { result: false, status: 404 } - if (!stream.isPublic && req.context.auth === false) { + if (req.context.auth === false) { req.log.debug('User is not authenticated, so cannot read from non-public stream.') return { result: false, status: 401 } } - if (!stream.isPublic) { - try { - await deps.validateScopes(req.context.scopes, Scopes.Streams.Read) - } catch (e) { - req.log.info({ err: e }, 'Error while validating scopes') - return { result: false, status: 401 } - } + try { + await deps.validateScopes(req.context.scopes, Scopes.Streams.Read) + } catch (e) { + req.log.info({ err: e }, 'Error while validating scopes') + return { result: false, status: 401 } + } - try { - await deps.authorizeResolver( - req.context.userId, - streamId, - Roles.Stream.Reviewer, - req.context.resourceAccessRules - ) - } catch (e) { - if (e instanceof DatabaseError) return { result: false, status: 500 } - req.log.info({ err: e }, 'Error while checking stream contributor role') - return { result: false, status: 401 } - } + try { + await deps.authorizeResolver( + req.context.userId, + streamId, + Roles.Stream.Reviewer, + req.context.resourceAccessRules + ) + } catch (e) { + if (e instanceof DatabaseError) return { result: false, status: 500 } + req.log.info({ err: e }, 'Error while checking stream contributor role') + return { result: false, status: 401 } } return { result: true, status: 200 } } diff --git a/packages/server/modules/core/services/streams/clone.ts b/packages/server/modules/core/services/streams/clone.ts index b527bcb2c..56330a697 100644 --- a/packages/server/modules/core/services/streams/clone.ts +++ b/packages/server/modules/core/services/streams/clone.ts @@ -43,6 +43,7 @@ import { import { GetUser } from '@/modules/core/domain/users/operations' import { EventBusEmit } from '@/modules/shared/services/eventBus' import { ProjectEvents } from '@/modules/core/domain/projects/events' +import { mapDbToGqlProjectVisibility } from '@/modules/core/helpers/project' type CloneStreamInitialState = { user: UserWithOptionalRole @@ -124,8 +125,7 @@ const cloneStreamEntityFactory = { name: targetStream.name, description: targetStream.description, - isPublic: targetStream.isPublic, - isDiscoverable: targetStream.isDiscoverable + visibility: mapDbToGqlProjectVisibility(targetStream.visibility) }, { ownerId: user.id, diff --git a/packages/server/modules/core/services/streams/management.ts b/packages/server/modules/core/services/streams/management.ts index a813f0f36..7976fdd74 100644 --- a/packages/server/modules/core/services/streams/management.ts +++ b/packages/server/modules/core/services/streams/management.ts @@ -11,7 +11,7 @@ import { StreamNotFoundError, StreamUpdateError } from '@/modules/core/errors/stream' -import { isProjectCreateInput } from '@/modules/core/helpers/stream' +import { isProjectCreateInput } from '@/modules/core/helpers/project' import { has } from 'lodash' import { isNewResourceAllowed } from '@/modules/core/helpers/token' import { diff --git a/packages/server/modules/core/tests/discoverableStreams.spec.ts b/packages/server/modules/core/tests/discoverableStreams.spec.ts deleted file mode 100644 index 8bf44e3d4..000000000 --- a/packages/server/modules/core/tests/discoverableStreams.spec.ts +++ /dev/null @@ -1,384 +0,0 @@ -import { buildApolloServer } from '@/app' -import { db } from '@/db/knex' -import { Streams, Users } from '@/modules/core/dbSchema' -import { - getStreamFactory, - setStreamFavoritedFactory -} from '@/modules/core/repositories/streams' -import { Nullable, Optional } from '@/modules/shared/helpers/typeHelper' -import { BasicTestUser, createTestUsers } from '@/test/authHelper' -import { - DiscoverableStreamsSortType, - SortDirection -} from '@/test/graphql/generated/graphql' -import { - createStream, - readDiscoverableStreams, - updateStream -} from '@/test/graphql/streams' -import { - createAuthedTestContext, - createTestContext, - ServerAndContext -} from '@/test/graphqlHelper' -import { truncateTables } from '@/test/hooks' -import { BasicTestStream, createTestStream } from '@/test/speckle-helpers/streamHelper' -import { wait } from '@speckle/shared' -import { expect } from 'chai' -import dayjs from 'dayjs' -import { shuffle } from 'lodash' - -const READABLE_DISCOVERABLE_STREAM_COUNT = 15 - -const cleanup = async () => await truncateTables([Streams.name, Users.name]) -const getStream = getStreamFactory({ db }) -const setStreamFavorited = setStreamFavoritedFactory({ db }) - -// Discoverability currently disabled -describe.skip('Discoverable streams', () => { - let apollo: ServerAndContext - - const me: BasicTestUser = { - name: 'itsaa meeee', - email: 'me@gimail.com', - password: 'whateveridontcare', - id: '' - } - - const otherGuy: BasicTestUser = { - name: 'otherr guyyyy1', - email: 'otherguy1@gimail.com', - password: 'whateveridontcare', - id: '' - } - - const favoriterGuy1: BasicTestUser = { - name: 'favoriter guy1', - email: 'favoriterguy1@gimail.com', - password: 'whateveridontcare', - id: '' - } - - const favoriterGuy2: BasicTestUser = { - name: 'favoriter guy2', - email: 'favoriterguy2@gimail.com', - password: 'whateveridontcare', - id: '' - } - - const favoriterGuy3: BasicTestUser = { - name: 'favoriter guy3', - email: 'favoriterguy3@gimail.com', - password: 'whateveridontcare', - id: '' - } - - const allUsers = [me, otherGuy, favoriterGuy1, favoriterGuy2, favoriterGuy3] - - const readableDiscoverableStreams: BasicTestStream[] = [] - - before(async () => { - await cleanup() - - // Seeding users - await createTestUsers(allUsers) - - // Seeding streams (sequentially to ensure different created dates) - for (let i = 0; i < READABLE_DISCOVERABLE_STREAM_COUNT; i++) { - const owner = i % 2 === 0 ? me : otherGuy - const newStream: BasicTestStream = { - name: 'Readable Discoverable Stream ' + i, - isPublic: true, - isDiscoverable: true, - id: '', - ownerId: '' - } - readableDiscoverableStreams.push(newStream) - await createTestStream(newStream, owner) - await wait(5) - } - - // Favoriting some of them - stream with 5 favorites, stream with 4 favorites, then 3 and so on... - const favoriters = shuffle(allUsers.slice()) - const favoritableStreams = shuffle(readableDiscoverableStreams.slice()) - - for (let i = favoriters.length; i > 0; i--) { - const currentFavoriters = favoriters.slice(0, i) - const currentStream = favoritableStreams.pop() - - while (currentStream && currentFavoriters.length > 0) { - const favoriter = currentFavoriters.pop() - if (!favoriter) break - - await setStreamFavorited({ - streamId: currentStream.id, - userId: favoriter.id, - favorited: true - }) - await wait(5) - } - } - - apollo = { - apollo: await buildApolloServer(), - context: await createTestContext() - } - }) - - after(async () => { - await cleanup() - }) - - it('can be retrieved', async () => { - const { data, errors } = await readDiscoverableStreams(apollo, { - limit: READABLE_DISCOVERABLE_STREAM_COUNT - }) - - expect(errors).to.be.not.ok - expect(data?.discoverableStreams).to.be.ok - expect(data?.discoverableStreams?.totalCount).to.eq( - READABLE_DISCOVERABLE_STREAM_COUNT - ) - expect(data?.discoverableStreams?.items?.length).to.eq( - READABLE_DISCOVERABLE_STREAM_COUNT - ) - expect(data?.discoverableStreams?.cursor).to.be.ok - - const someItem = data?.discoverableStreams?.items?.[0] - expect(someItem?.id).to.be.ok - expect(someItem?.isDiscoverable).to.be.ok - }) - - const sortTypeDataset = [ - { display: 'created date', sortType: DiscoverableStreamsSortType.CreatedDate }, - { display: 'favorites count', sortType: DiscoverableStreamsSortType.FavoritesCount } - ] - const sortDirectionDataset = [ - { display: 'ascending', sortDir: SortDirection.Asc }, - { display: 'descending', sortDir: SortDirection.Desc } - ] - - sortTypeDataset.forEach(({ display: sortTypeDisplay, sortType }) => { - sortDirectionDataset.forEach(({ display: sortDirDisplay, sortDir }) => { - it(`can be retrieved properly paginated & sorted by ${sortDirDisplay} ${sortTypeDisplay}`, async () => { - const limit = Math.max(Math.floor(READABLE_DISCOVERABLE_STREAM_COUNT / 3), 1) - - const collectedItems = [] - let currentSortByValue: Optional = undefined - let cursor: Nullable = null - - const retrieveAndTestPage = async (cursor: Nullable) => { - const { data, errors } = await readDiscoverableStreams(apollo, { - limit, - cursor, - sort: { - type: sortType, - direction: sortDir - } - }) - - expect(errors).to.be.not.ok - expect(data?.discoverableStreams?.totalCount).to.eq( - READABLE_DISCOVERABLE_STREAM_COUNT - ) - - const items = data?.discoverableStreams?.items || [] - const hasMorePages = items.length === limit - const newCursor = data?.discoverableStreams?.cursor - - for (const currentItem of items) { - collectedItems.push(currentItem) - - let sortByValue: string | number - if (sortType === DiscoverableStreamsSortType.CreatedDate) { - sortByValue = currentItem.createdAt - } else if (sortType === DiscoverableStreamsSortType.FavoritesCount) { - sortByValue = currentItem.favoritesCount - } else { - throw new Error('Unexpected sort type') - } - - if (!currentSortByValue) { - currentSortByValue = sortByValue - continue - } - - const previousValue = currentSortByValue - const currentValue = sortByValue - if (sortType === DiscoverableStreamsSortType.CreatedDate) { - if (sortDir === SortDirection.Asc) { - expect(dayjs(currentValue).isAfter(dayjs(previousValue))).to.be.true - } else { - expect(dayjs(previousValue).isAfter(dayjs(currentValue))).to.be.true - } - } else if (sortType === DiscoverableStreamsSortType.FavoritesCount) { - if (sortDir === SortDirection.Asc) { - expect(currentValue).is.greaterThanOrEqual(previousValue as number) - } else { - expect(previousValue).is.greaterThanOrEqual(currentValue as number) - } - } else { - throw new Error('Unexpected sort type') - } - } - - return { hasMorePages, newCursor } - } - - let failsafe = 10 - while (failsafe > 0) { - const testResult = await retrieveAndTestPage(cursor) - cursor = testResult.newCursor as Nullable - - if (!testResult.hasMorePages) break - failsafe-- - } - - if (failsafe <= 0) - throw new Error( - 'Pagination failsafe triggered! Possible infinite loop encountered.' - ) - - expect(collectedItems.length).to.eq(READABLE_DISCOVERABLE_STREAM_COUNT) - }) - }) - }) - - describe('when authenticated', () => { - let apollo: ServerAndContext - - before(async () => { - apollo = { - apollo: await buildApolloServer(), - context: await createAuthedTestContext(me.id) - } - }) - - it('can be retrieved with role properly filled out', async () => { - const { data, errors } = await readDiscoverableStreams(apollo, { - limit: READABLE_DISCOVERABLE_STREAM_COUNT - }) - - expect(errors).to.be.not.ok - expect(data?.discoverableStreams?.totalCount).to.eq( - READABLE_DISCOVERABLE_STREAM_COUNT - ) - - const items = data?.discoverableStreams?.items || [] - const someHaveRole = items.some((i) => !!i.role) - expect(someHaveRole).to.be.true - }) - - it('can be created', async () => { - const { errors, data } = await createStream(apollo, { - stream: { - name: 'some rando stream', - isPublic: true, - isDiscoverable: true - } - }) - - expect(errors).to.not.be.ok - expect(data).to.be.ok - expect(data?.streamCreate).to.be.ok - - const streamId = data?.streamCreate as string - const streamData = await getStream({ streamId }) - - expect(streamData).to.be.ok - expect(streamData?.isDiscoverable).to.be.true - expect(streamData?.isPublic).to.be.true - }) - - const cantMakeDiscoverableDataset = [ - { display: 'isDiscoverable set to false', isDiscoverable: false, isPublic: true }, - { display: 'isPublic is set to false', isDiscoverable: true, isPublic: false } - ] - cantMakeDiscoverableDataset.forEach(({ display, isDiscoverable, isPublic }) => { - it(`cant be created discoverable if ${display}`, async () => { - const { errors, data } = await createStream(apollo, { - stream: { - isPublic, - isDiscoverable - } - }) - - expect(errors).to.not.be.ok - expect(data).to.be.ok - expect(data?.streamCreate).to.be.ok - - const streamId = data?.streamCreate as string - const streamData = await getStream({ streamId }) - - expect(streamData).to.be.ok - expect(streamData?.isDiscoverable).to.be.false - expect(streamData?.isPublic).to.eq(isPublic) - }) - }) - - describe('and being updated', () => { - const updateableStream: BasicTestStream = { - name: 'ill be getting updated a lot', - isPublic: false, - isDiscoverable: false, - id: '', - ownerId: '' - } - - beforeEach(async () => { - // re-create for each test - await createTestStream(updateableStream, me) - }) - - it('can be updated to be discoverable or not', async () => { - const testWithDiscoverable = async (val: boolean) => { - const { errors, data } = await updateStream(apollo, { - stream: { - id: updateableStream.id, - isPublic: val, - isDiscoverable: val - } - }) - - expect(errors).to.not.be.ok - expect(data).to.be.ok - expect(data?.streamUpdate).to.be.ok - - const streamData = await getStream({ streamId: updateableStream.id }) - - expect(streamData).to.be.ok - expect(streamData?.isDiscoverable).to.eq(val) - expect(streamData?.isPublic).to.eq(val) - } - - // Toggle on - await testWithDiscoverable(true) - - // Toggle off - await testWithDiscoverable(false) - }) - - cantMakeDiscoverableDataset.forEach(({ display, isDiscoverable, isPublic }) => { - it(`cant be updated to be discoverable if ${display}`, async () => { - const { errors, data } = await updateStream(apollo, { - stream: { - id: updateableStream.id, - isPublic, - isDiscoverable - } - }) - - expect(errors).to.not.be.ok - expect(data).to.be.ok - expect(data?.streamUpdate).to.be.ok - - const streamData = await getStream({ streamId: updateableStream.id }) - - expect(streamData).to.be.ok - expect(streamData?.isDiscoverable).to.be.false - expect(streamData?.isPublic).to.eq(isPublic) - }) - }) - }) - }) -}) diff --git a/packages/server/modules/core/tests/integration/projectRepositories.spec.ts b/packages/server/modules/core/tests/integration/projectRepositories.spec.ts index 90472155d..63becda62 100644 --- a/packages/server/modules/core/tests/integration/projectRepositories.spec.ts +++ b/packages/server/modules/core/tests/integration/projectRepositories.spec.ts @@ -1,5 +1,6 @@ import { db } from '@/db/knex' import { Project } from '@/modules/core/domain/streams/types' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' import { deleteProjectFactory, getProjectFactory, @@ -22,11 +23,12 @@ const createTestProject = (overrides?: Partial): Project => { createdAt: new Date(), updatedAt: new Date(), description: 'a test project', - isDiscoverable: true, - isPublic: true, + visibility: ProjectRecordVisibility.Public, name: cryptoRandomString({ length: 10 }), regionKey: null, - workspaceId: null + workspaceId: null, + isPublic: true, + isDiscoverable: true } return assign(defaults, overrides || {}) } diff --git a/packages/server/modules/core/tests/integration/projects.graph.spec.ts b/packages/server/modules/core/tests/integration/projects.graph.spec.ts index f3c925275..33119bc20 100644 --- a/packages/server/modules/core/tests/integration/projects.graph.spec.ts +++ b/packages/server/modules/core/tests/integration/projects.graph.spec.ts @@ -1,246 +1,43 @@ -import { createTestWorkspace } from '@/modules/workspaces/tests/helpers/creation' -import { BasicTestUser, createTestUser, login } from '@/test/authHelper' +import { BasicTestUser, createTestUser } from '@/test/authHelper' import { - ActiveUserProjectsDocument, CreateProjectDocument, - CreateWorkspaceProjectDocument, - GetWorkspaceDocument + ProjectVisibility } from '@/test/graphql/generated/graphql' import { Roles } from '@/modules/core/helpers/mainConstants' import { expect } from 'chai' -import cryptoRandomString from 'crypto-random-string' -import { getFeatureFlags } from '@/modules/shared/helpers/envHelper' -import { createRandomEmail } from '@/modules/core/helpers/testHelpers' -import { db } from '@/db/knex' -import { StreamAcl } from '@/modules/core/dbSchema' +import { beforeEachContext } from '@/test/hooks' +import { TestApolloServer, testApolloServer } from '@/test/graphqlHelper' -const { FF_WORKSPACES_MODULE_ENABLED } = getFeatureFlags() +describe('Projects GraphQL @core (outside of workspaces)', () => { + let apollo: TestApolloServer + const me: BasicTestUser = { + id: '', + name: 'me', + email: '', + role: Roles.Server.Admin + } -describe('Projects GraphQL @core', () => { - describe('query user.projects', () => { - ;(FF_WORKSPACES_MODULE_ENABLED ? it : it.skip)( - 'should return projects not in a workspace', - async () => { - const testAdminUser: BasicTestUser = { - id: '', - name: 'test', - email: createRandomEmail(), - role: Roles.Server.Admin, - verified: true - } - await createTestUser(testAdminUser) - const workspace = { - id: '', - name: 'test ws', - slug: cryptoRandomString({ length: 10 }), - ownerId: '' - } - await createTestWorkspace(workspace, testAdminUser) + before(async () => { + await beforeEachContext() + await createTestUser(me) + apollo = await testApolloServer({ authUserId: me.id }) + }) - const session = await login(testAdminUser) - const getWorkspaceRes = await session.execute(GetWorkspaceDocument, { - workspaceId: workspace.id - }) + describe('when being created', () => { + it('should use private visibility by default ', async () => { + const res = await apollo.execute( + CreateProjectDocument, + { + input: { + name: 'Test Default Visibility Project' + } + }, + { assertNoErrors: true } + ) - expect(getWorkspaceRes).to.not.haveGraphQLErrors() - const workspaceId = getWorkspaceRes.data!.workspace.id - - const createProjectInWorkspaceRes = await session.execute( - CreateWorkspaceProjectDocument, - { input: { name: 'project', workspaceId } } - ) - expect(createProjectInWorkspaceRes).to.not.haveGraphQLErrors() - - const createProjectNonInWorkspaceRes = await session.execute( - CreateProjectDocument, - { input: { name: 'project' } } - ) - expect(createProjectNonInWorkspaceRes).to.not.haveGraphQLErrors() - const projectNonInWorkspace = - createProjectNonInWorkspaceRes.data!.projectMutations.create - - const userProjectsRes = await session.execute(ActiveUserProjectsDocument, { - filter: { personalOnly: true } - }) - expect(userProjectsRes).to.not.haveGraphQLErrors() - - const projects = userProjectsRes.data!.activeUser!.projects.items - - expect(projects).to.have.length(1) - expect(projects[0].id).to.eq(projectNonInWorkspace.id) - } - ) - ;(FF_WORKSPACES_MODULE_ENABLED ? it : it.skip)( - 'should return projects in workspace', - async () => { - const testAdminUser: BasicTestUser = { - id: '', - name: 'test', - email: createRandomEmail(), - role: Roles.Server.Admin, - verified: true - } - await createTestUser(testAdminUser) - const workspace = { - id: '', - name: 'test ws', - slug: cryptoRandomString({ length: 10 }), - ownerId: '' - } - await createTestWorkspace(workspace, testAdminUser) - - const session = await login(testAdminUser) - const getWorkspaceRes = await session.execute(GetWorkspaceDocument, { - workspaceId: workspace.id - }) - - expect(getWorkspaceRes).to.not.haveGraphQLErrors() - const workspaceId = getWorkspaceRes.data!.workspace.id - - const createProjectInWorkspaceRes = await session.execute( - CreateWorkspaceProjectDocument, - { input: { name: 'project', workspaceId } } - ) - expect(createProjectInWorkspaceRes).to.not.haveGraphQLErrors() - const projectInWorkspace = - createProjectInWorkspaceRes.data!.workspaceMutations.projects.create - - const createProjectNonInWorkspaceRes = await session.execute( - CreateProjectDocument, - { input: { name: 'project' } } - ) - expect(createProjectNonInWorkspaceRes).to.not.haveGraphQLErrors() - - const userProjectsRes = await session.execute(ActiveUserProjectsDocument, { - filter: { workspaceId } - }) - expect(userProjectsRes).to.not.haveGraphQLErrors() - - const projects = userProjectsRes.data!.activeUser!.projects.items - - expect(projects).to.have.length(1) - expect(projects[0].id).to.eq(projectInWorkspace.id) - } - ) - ;(FF_WORKSPACES_MODULE_ENABLED ? it : it.skip)( - 'should return all user projects', - async () => { - const testAdminUser: BasicTestUser = { - id: '', - name: 'test', - email: createRandomEmail(), - role: Roles.Server.Admin, - verified: true - } - await createTestUser(testAdminUser) - const workspace = { - id: '', - name: 'test ws', - slug: cryptoRandomString({ length: 10 }), - ownerId: '' - } - await createTestWorkspace(workspace, testAdminUser) - - const session = await login(testAdminUser) - const getWorkspaceRes = await session.execute(GetWorkspaceDocument, { - workspaceId: workspace.id - }) - - expect(getWorkspaceRes).to.not.haveGraphQLErrors() - const workspaceId = getWorkspaceRes.data!.workspace.id - - const createProjectInWorkspaceRes = await session.execute( - CreateWorkspaceProjectDocument, - { input: { name: 'project', workspaceId } } - ) - expect(createProjectInWorkspaceRes).to.not.haveGraphQLErrors() - - const createProjectNonInWorkspaceRes = await session.execute( - CreateProjectDocument, - { input: { name: 'project' } } - ) - expect(createProjectNonInWorkspaceRes).to.not.haveGraphQLErrors() - - const userProjectsRes = await session.execute(ActiveUserProjectsDocument, { - filter: {} - }) - expect(userProjectsRes).to.not.haveGraphQLErrors() - - const projects = userProjectsRes.data!.activeUser!.projects.items - - expect(projects).to.have.length(2) - } - ) - ;(FF_WORKSPACES_MODULE_ENABLED ? it : it.skip)( - 'should return all user projects sorted by user role', - async () => { - const testAdminUser: BasicTestUser = { - id: '', - name: 'test', - email: createRandomEmail(), - role: Roles.Server.Admin, - verified: true - } - await createTestUser(testAdminUser) - const workspace = { - id: '', - name: 'test ws', - slug: cryptoRandomString({ length: 10 }), - ownerId: '' - } - await createTestWorkspace(workspace, testAdminUser) - - const session = await login(testAdminUser) - const getWorkspaceRes = await session.execute(GetWorkspaceDocument, { - workspaceId: workspace.id - }) - - expect(getWorkspaceRes).to.not.haveGraphQLErrors() - const workspaceId = getWorkspaceRes.data!.workspace.id - - const createProjectInWorkspaceAsOwnerRes = await session.execute( - CreateWorkspaceProjectDocument, - { input: { name: 'project', workspaceId } } - ) - expect(createProjectInWorkspaceAsOwnerRes).to.not.haveGraphQLErrors() - const createProjectInWorkspaceAsContributorRes = await session.execute( - CreateWorkspaceProjectDocument, - { input: { name: 'project 2', workspaceId } } - ) - expect(createProjectInWorkspaceAsContributorRes).to.not.haveGraphQLErrors() - const projectContributorId = - createProjectInWorkspaceAsContributorRes.data?.workspaceMutations.projects - .create.id - await db(StreamAcl.name) - .update({ role: Roles.Stream.Contributor }) - .where({ userId: testAdminUser.id, resourceId: projectContributorId }) - const createProjectInWorkspaceAsReviewerRes = await session.execute( - CreateWorkspaceProjectDocument, - { input: { name: 'project 3', workspaceId } } - ) - expect(createProjectInWorkspaceAsReviewerRes).to.not.haveGraphQLErrors() - const projectReviewerId = - createProjectInWorkspaceAsReviewerRes.data?.workspaceMutations.projects.create - .id - await db(StreamAcl.name) - .update({ role: Roles.Stream.Reviewer }) - .where({ userId: testAdminUser.id, resourceId: projectReviewerId }) - - const userProjectsRes = await session.execute(ActiveUserProjectsDocument, { - filter: {}, - sortBy: ['role'] - }) - expect(userProjectsRes).to.not.haveGraphQLErrors() - - const projects = userProjectsRes.data!.activeUser!.projects.items - - expect(projects).to.have.length(3) - expect(projects[0].id).to.eq( - createProjectInWorkspaceAsOwnerRes.data?.workspaceMutations.projects.create.id - ) - expect(projects[1].id).to.eq(projectContributorId) - expect(projects[2].id).to.eq(projectReviewerId) - } - ) + const project = res.data?.projectMutations.create + expect(project).to.be.ok + expect(project?.visibility).to.eq(ProjectVisibility.Private) + }) }) }) diff --git a/packages/server/modules/core/tests/integration/users.graph.spec.ts b/packages/server/modules/core/tests/integration/users.graph.spec.ts index 2a271385c..ea2711ffd 100644 --- a/packages/server/modules/core/tests/integration/users.graph.spec.ts +++ b/packages/server/modules/core/tests/integration/users.graph.spec.ts @@ -1,3 +1,4 @@ +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' import { getFeatureFlags } from '@/modules/shared/helpers/envHelper' import { assignToWorkspaces, @@ -19,7 +20,8 @@ import { waitForRegionUsers } from '@/test/speckle-helpers/regions' import { addAllToStream, BasicTestStream, - createTestStream + createTestStream, + createTestStreams } from '@/test/speckle-helpers/streamHelper' import { Roles } from '@speckle/shared' import { expect } from 'chai' @@ -68,11 +70,26 @@ describe('Users @graphql', () => { id: '', slug: '' } + const myWorkspaceCollaboratorProject: BasicTestStream = { name: 'My Workspace Collaborator Project #1', ownerId: '', id: '', - isPublic: true + visibility: ProjectRecordVisibility.Workspace + } + + const myPrivateWorkspaceCollaboratorProject: BasicTestStream = { + name: 'My Private Workspace Collaborator Project #1', + ownerId: '', + id: '', + visibility: ProjectRecordVisibility.Private + } + + const myNoCollaboratorProject: BasicTestStream = { + name: 'My No Collaborator Project #1', + ownerId: '', + id: '', + visibility: ProjectRecordVisibility.Private } const myBasicCollaboratorProject: BasicTestStream = { @@ -95,11 +112,18 @@ describe('Users @graphql', () => { before(async () => { await Promise.all([ createTestStream(myBasicCollaboratorProject, me), + createTestStream(myNoCollaboratorProject, me), createTestWorkspace(myWorkspace, me, { regionKey: getMainTestRegionKeyIfMultiRegion() - }).then(() => (myWorkspaceCollaboratorProject.workspaceId = myWorkspace.id)) + }) + ]) + + myWorkspaceCollaboratorProject.workspaceId = myWorkspace.id + myPrivateWorkspaceCollaboratorProject.workspaceId = myWorkspace.id + await createTestStreams([ + [myWorkspaceCollaboratorProject, me], + [myPrivateWorkspaceCollaboratorProject, me] ]) - await createTestStream(myWorkspaceCollaboratorProject, me) // Seed in users let remainingBasicProjectCollaborators = BASIC_COLLABORATOR_PROJECT_USER_COUNT @@ -164,6 +188,15 @@ describe('Users @graphql', () => { } ) } + + // Add specific user to myPrivateWorkspaceCollaboratorProject + await addAllToStream( + myPrivateWorkspaceCollaboratorProject, + [{ user: secondSpecificUser, role: Roles.Stream.Reviewer }], + { + owner: me + } + ) }) it('works with basic query', async () => { @@ -235,7 +268,7 @@ describe('Users @graphql', () => { ]) }) - it('works with a projectId from a workspace', async () => { + it('works with a workspace visibility projectId from a workspace', async () => { const res = await search( { query: 'user', @@ -245,6 +278,7 @@ describe('Users @graphql', () => { { assertNoErrors: true } ) + // workspace visibility, so: find all members (implicit access) - guests cause none have explicit access + 1 explicit access user expect(res.data?.users.items || []).to.have.lengthOf( WORKSPACE_COLLABORATOR_USER_COUNT - WORKSPACE_GUEST_USER_COUNT + 1 // +1 for the secondSpecificUser ) @@ -254,6 +288,37 @@ describe('Users @graphql', () => { ]) }) + it('works with a private visibility projectId from a workspace', async () => { + const res = await search( + { + query: 'user', + projectId: myPrivateWorkspaceCollaboratorProject.id, + limit: 100 + }, + { assertNoErrors: true } + ) + + // private visibility, so: only 1 explicit access user + expect(res.data?.users.items || []).to.have.lengthOf(1) + expect((res.data?.users.items || []).map((u) => u.id)).to.deep.equal([ + secondSpecificUser.id + ]) + }) + + it('doesnt work if user doesnt have access to the project specified', async () => { + const res = await search( + { + query: 'user', + projectId: myNoCollaboratorProject.id, + limit: 100 + }, + { authUserId: firstSpecificUser.id } + ) + + expect(res).to.haveGraphQLErrors('You do not have access to the project') + expect(res.data?.users).to.not.be.ok + }) + it('works with pagination', async () => { const totalUserCount = RANDOMIZED_USER_COUNT + 2 // +2 for the specific users const firstLimit = Math.floor(totalUserCount / 2) diff --git a/packages/server/modules/core/tests/projects.spec.ts b/packages/server/modules/core/tests/projects.spec.ts index df0bb6bb6..1ff648711 100644 --- a/packages/server/modules/core/tests/projects.spec.ts +++ b/packages/server/modules/core/tests/projects.spec.ts @@ -8,7 +8,8 @@ import { BatchDeleteProjectsDocument, CreateProjectDocument, GetProjectObjectDocument, - ProjectCreateInput + ProjectCreateInput, + ProjectVisibility } from '@/test/graphql/generated/graphql' import { createTestObject } from '@/test/speckle-helpers/commitHelper' import { times } from 'lodash' @@ -54,6 +55,9 @@ describe('Projects', () => { expect(res.data?.projectMutations.create.id).to.be.ok expect(res.data?.projectMutations.create.name).to.equal(input.name) expect(res.data?.projectMutations.create.description).to.equal(input.description) + expect(res.data?.projectMutations.create.visibility).to.equal( + ProjectVisibility.Private // private by default + ) }) describe('after creation', () => { diff --git a/packages/server/modules/core/tests/streams.spec.ts b/packages/server/modules/core/tests/streams.spec.ts index b482495fb..aa89562d7 100644 --- a/packages/server/modules/core/tests/streams.spec.ts +++ b/packages/server/modules/core/tests/streams.spec.ts @@ -602,7 +602,7 @@ describe('Streams @core-streams', () => { const TOTAL_OWN_STREAM_COUNT = OWNED_STREAM_COUNT + SHARED_STREAM_COUNT const PUBLIC_STREAM_COUNT = 15 - const DISCOVERABLE_STREAM_COUNT = PUBLIC_STREAM_COUNT - 5 + const DISCOVERABLE_STREAM_COUNT = PUBLIC_STREAM_COUNT let userOneStreams: BasicTestStream[] let userTwoStreams: BasicTestStream[] @@ -613,7 +613,6 @@ describe('Streams @core-streams', () => { async function setupStreams(user: BasicTestUser): Promise { let remainingPublicStreams = PUBLIC_STREAM_COUNT - let remainingDiscoverableStreams = DISCOVERABLE_STREAM_COUNT // creating test streams const streamDefinitions = times( @@ -621,7 +620,6 @@ describe('Streams @core-streams', () => { (i): BasicTestStream => ({ name: `${user.name} test stream #${i}`, isPublic: remainingPublicStreams-- > 0, - isDiscoverable: remainingDiscoverableStreams-- > 0, id: '', ownerId: '' }) @@ -683,7 +681,7 @@ describe('Streams @core-streams', () => { ) => { const { limitedUserQuery } = options const expectedTotalCount = isOtherUser - ? SHARED_STREAM_COUNT + DISCOVERABLE_STREAM_COUNT // only shared streams + discoverable ones + ? SHARED_STREAM_COUNT + DISCOVERABLE_STREAM_COUNT // only public : TOTAL_OWN_STREAM_COUNT // all owned & shared streams const requestPage = async (cursor?: Nullable) => { diff --git a/packages/server/modules/core/tests/unit/projects.spec.ts b/packages/server/modules/core/tests/unit/projects.spec.ts index 0a53c6f58..4d87705e2 100644 --- a/packages/server/modules/core/tests/unit/projects.spec.ts +++ b/packages/server/modules/core/tests/unit/projects.spec.ts @@ -2,6 +2,7 @@ import { ProjectEvents } from '@/modules/core/domain/projects/events' import { Project } from '@/modules/core/domain/streams/types' import { RegionalProjectCreationError } from '@/modules/core/errors/projects' import { StreamNotFoundError } from '@/modules/core/errors/stream' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' import { createNewProjectFactory } from '@/modules/core/services/projects' import { isSpecificEventPayload } from '@/modules/shared/services/eventBus' import { expectToThrow } from '@/test/assertionHelper' @@ -31,13 +32,11 @@ describe('project services @core', () => { const project = await createNewProject({ ownerId }) expect(project).deep.equal(storedProject) - expect(storedProject!.isPublic).to.be.true - expect(storedProject!.isDiscoverable).to.be.false + expect(storedProject!.visibility).to.eq(ProjectRecordVisibility.Private) expect(storedProject!.allowPublicComments).to.be.false }) - // Discoverability currently disabled - it.skip(`makes PUBLIC projects public and discoverable`, async () => { + it(`makes PUBLIC projects public`, async () => { const visibility = 'PUBLIC' const ownerId = cryptoRandomString({ length: 10 }) @@ -60,12 +59,11 @@ describe('project services @core', () => { const project = await createNewProject({ ownerId, visibility }) expect(project).deep.equal(storedProject) - expect(storedProject!.isPublic).to.be.true - expect(storedProject!.isDiscoverable).to.be.true + expect(storedProject!.visibility).to.eq(ProjectRecordVisibility.Public) expect(storedProject!.allowPublicComments).to.be.false }) - it(`makes UNLISTED projects public but not discoverable`, async () => { + it(`makes UNLISTED projects public`, async () => { const visibility = 'UNLISTED' const ownerId = cryptoRandomString({ length: 10 }) @@ -88,11 +86,10 @@ describe('project services @core', () => { const project = await createNewProject({ ownerId, visibility }) expect(project).deep.equal(storedProject) - expect(storedProject!.isPublic).to.be.true - expect(storedProject!.isDiscoverable).to.be.false + expect(storedProject!.visibility).to.eq(ProjectRecordVisibility.Public) expect(storedProject!.allowPublicComments).to.be.false }) - // ) + it('creates a private project', async () => { const ownerId = cryptoRandomString({ length: 10 }) let storedProject: Project | undefined = undefined @@ -113,8 +110,7 @@ describe('project services @core', () => { const project = await createNewProject({ ownerId, visibility: 'PRIVATE' }) expect(project).deep.equal(storedProject) - expect(storedProject!.isPublic).to.be.false - expect(storedProject!.isDiscoverable).to.be.false + expect(storedProject!.visibility).to.eq(ProjectRecordVisibility.Private) expect(storedProject!.allowPublicComments).to.be.false }) it('deletes the created project if getProject throws StreamNotFoundError', async () => { @@ -253,7 +249,7 @@ describe('project services @core', () => { expect(eventPayload).deep.equal({ ownerId, project, - input: { description: '', name: project.name, visibility: 'PUBLIC' } + input: { description: '', name: project.name, visibility: 'PRIVATE' } }) }) it('successfully creates a project', async () => { @@ -317,7 +313,7 @@ describe('project services @core', () => { expect(eventPayload).deep.equal({ ownerId, project, - input: { description: '', name: project.name, visibility: 'PUBLIC' } + input: { description: '', name: project.name, visibility: 'PRIVATE' } }) }) }) 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 0a51ac5fa..240f9ce66 100644 --- a/packages/server/modules/cross-server-sync/graph/generated/graphql.ts +++ b/packages/server/modules/cross-server-sync/graph/generated/graphql.ts @@ -2070,7 +2070,7 @@ export type Project = { versions: VersionCollection; /** Return metadata about resources being requested in the viewer */ viewerResources: Array; - visibility: SimpleProjectVisibility; + visibility: ProjectVisibility; webhooks: WebhookCollection; workspace?: Maybe; workspaceId?: Maybe; @@ -2691,9 +2691,14 @@ export const ProjectVersionsUpdatedMessageType = { export type ProjectVersionsUpdatedMessageType = typeof ProjectVersionsUpdatedMessageType[keyof typeof ProjectVersionsUpdatedMessageType]; export const ProjectVisibility = { + /** Only accessible to explicit collaborators */ Private: 'PRIVATE', + /** Accessible to everyone (even non-logged in users) */ Public: 'PUBLIC', - Unlisted: 'UNLISTED' + /** Legacy - same as public */ + Unlisted: 'UNLISTED', + /** Accessible to everyone in the project's workspace */ + Workspace: 'WORKSPACE' } as const; export type ProjectVisibility = typeof ProjectVisibility[keyof typeof ProjectVisibility]; @@ -3243,13 +3248,6 @@ export type SetPrimaryUserEmailInput = { id: Scalars['ID']['input']; }; -/** Visibility without the "discoverable" option */ -export const SimpleProjectVisibility = { - Private: 'PRIVATE', - Unlisted: 'UNLISTED' -} as const; - -export type SimpleProjectVisibility = typeof SimpleProjectVisibility[keyof typeof SimpleProjectVisibility]; export type SmartTextEditorValue = { __typename?: 'SmartTextEditorValue'; /** File attachments, if any */ @@ -3326,6 +3324,7 @@ export type Stream = { /** * Whether the stream (if public) can be found on public stream exploration pages * and searches + * @deprecated Discoverability as a feature has been removed. */ isDiscoverable: Scalars['Boolean']['output']; /** Whether the stream can be viewed by non-contributors */ @@ -5168,7 +5167,7 @@ export type CrossSyncProjectMetadataQueryVariables = Exact<{ }>; -export type CrossSyncProjectMetadataQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: SimpleProjectVisibility, versions: { __typename?: 'VersionCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'Version', id: string, createdAt: string, model: { __typename?: 'Model', id: string, name: string } }> } } }; +export type CrossSyncProjectMetadataQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: ProjectVisibility, versions: { __typename?: 'VersionCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'Version', id: string, createdAt: string, model: { __typename?: 'Model', id: string, name: string } }> } } }; export type CrossSyncClientTestQueryVariables = Exact<{ [key: string]: never; }>; diff --git a/packages/server/modules/notifications/tests/activityDigest.spec.ts b/packages/server/modules/notifications/tests/activityDigest.spec.ts index 1a3d31fa9..083cc2860 100644 --- a/packages/server/modules/notifications/tests/activityDigest.spec.ts +++ b/packages/server/modules/notifications/tests/activityDigest.spec.ts @@ -8,7 +8,11 @@ import { StreamScopeActivity, AllActivityTypes } from '@/modules/activitystream/helpers/types' -import { ServerInfo, UserRecord } from '@/modules/core/helpers/types' +import { + ProjectRecordVisibility, + ServerInfo, + UserRecord +} from '@/modules/core/helpers/types' import { renderEmail } from '@/modules/emails/services/emailRendering' import { digestMostActiveStream, @@ -116,14 +120,15 @@ describe('Activity digest notifications @notifications', () => { id: streamName, description: 'tester', name: streamName, - isPublic: true, + visibility: ProjectRecordVisibility.Public, clonedFrom: null, createdAt: new Date(), updatedAt: new Date(), allowPublicComments: true, - isDiscoverable: true, workspaceId: null, - regionKey: null + regionKey: null, + isPublic: true, + isDiscoverable: true }, activity: activities ?? [createActivity()] }) diff --git a/packages/server/modules/previews/services/management.ts b/packages/server/modules/previews/services/management.ts index cf6b8eb4f..2fa94a958 100644 --- a/packages/server/modules/previews/services/management.ts +++ b/packages/server/modules/previews/services/management.ts @@ -14,6 +14,7 @@ import { disablePreviews } from '@/modules/shared/helpers/envHelper' import { Roles, Scopes } from '@speckle/shared' import type { Logger } from 'pino' import { PreviewPriority, PreviewStatus } from '@/modules/previews/domain/consts' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' const noPreviewImage = require.resolve('#/assets/previews/images/no_preview.png') const previewErrorImage = require.resolve('#/assets/previews/images/preview_error.png') @@ -164,11 +165,14 @@ export const checkStreamPermissionsFactory = return { hasPermissions: false, httpErrorCode: 404 } } - if (!stream.isPublic && req.context.auth === false) { + if ( + stream.visibility !== ProjectRecordVisibility.Public && + req.context.auth === false + ) { return { hasPermissions: false, httpErrorCode: 401 } } - if (!stream.isPublic) { + if (stream.visibility !== ProjectRecordVisibility.Public) { try { await deps.validateScopes(req.context.scopes, Scopes.Streams.Read) } catch { diff --git a/packages/server/modules/shared/authz.ts b/packages/server/modules/shared/authz.ts index ce0ef3d7f..145f5d548 100644 --- a/packages/server/modules/shared/authz.ts +++ b/packages/server/modules/shared/authz.ts @@ -32,6 +32,7 @@ import { } from '@/modules/shared/domain/authz/operations' import { GetRoles } from '@/modules/shared/domain/rolesAndScopes/operations' import { ValidateUserServerRole } from '@/modules/shared/domain/operations' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' import { moduleAuthLoaders } from '@/modules/index' export { AuthContext, AuthParams } @@ -267,20 +268,25 @@ export const allowForServerAdmins: AuthPipelineFunction = async ({ export const allowForRegisteredUsersOnPublicStreamsEvenWithoutRole: AuthPipelineFunction = async ({ context, authResult }) => - context.auth && context.stream?.isPublic + context.auth && context.stream?.visibility === ProjectRecordVisibility.Public ? authSuccess(context) : { context, authResult } export const allowForAllRegisteredUsersOnPublicStreamsWithPublicComments: AuthPipelineFunction = async ({ context, authResult }) => - context.auth && context.stream?.isPublic && context.stream?.allowPublicComments + context.auth && + context.stream?.visibility === ProjectRecordVisibility.Public && + context.stream?.allowPublicComments ? authSuccess(context) : { context, authResult } export const allowAnonymousUsersOnPublicStreams: AuthPipelineFunction = async ({ context, authResult -}) => (context.stream?.isPublic ? authSuccess(context) : { context, authResult }) +}) => + context.stream?.visibility === ProjectRecordVisibility.Public + ? authSuccess(context) + : { context, authResult } export const authPipelineCreator = ( steps: AuthPipelineFunction[] diff --git a/packages/server/modules/shared/services/auth.ts b/packages/server/modules/shared/services/auth.ts index 4b5d17946..d19cd063b 100644 --- a/packages/server/modules/shared/services/auth.ts +++ b/packages/server/modules/shared/services/auth.ts @@ -4,6 +4,7 @@ import { RoleResourceTargets, roleResourceTypeToTokenResourceType } from '@/modules/core/helpers/token' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' import { AuthorizeResolver, GetUserAclRole, @@ -32,10 +33,16 @@ export const validateScopesFactory = (): ValidateScopes => async (scopes, scope) throw new ForbiddenError(errMsg, { info: { scope } }) } -const workspaceRoleImplicitProjectRoleMap = { - [Roles.Workspace.Admin]: Roles.Stream.Owner, - [Roles.Workspace.Member]: Roles.Stream.Reviewer, - [Roles.Workspace.Guest]: null +const workspaceRoleImplicitProjectRoleMap = ( + projectVisibility: ProjectRecordVisibility | null +) => { + const isFullyPrivate = projectVisibility === ProjectRecordVisibility.Private + + return { + [Roles.Workspace.Admin]: Roles.Stream.Owner, + [Roles.Workspace.Member]: isFullyPrivate ? null : Roles.Stream.Reviewer, + [Roles.Workspace.Guest]: null + } } /** @@ -82,6 +89,7 @@ export const authorizeResolverFactory = } let targetWorkspaceId: string | null = null + let streamVisibility: ProjectRecordVisibility | null = null if (role.resourceTarget === RoleResourceTargets.Streams) { const stream = await deps.getStream({ @@ -96,8 +104,9 @@ export const authorizeResolverFactory = } targetWorkspaceId = stream.workspaceId + streamVisibility = stream.visibility - const isPublic = !!stream?.isPublic + const isPublic = streamVisibility === ProjectRecordVisibility.Public if (isPublic && role.weight < 200) return } @@ -114,9 +123,7 @@ export const authorizeResolverFactory = : null if (!userAclRole) { - // TODO: Could be more optimized (caching?) but we're moving away from this towards - // auth policies anyway - // Check if workspace role allows for stream actions + // Implicit workspace project access if ( role.resourceTarget === RoleResourceTargets.Streams && targetWorkspaceId && @@ -128,7 +135,9 @@ export const authorizeResolverFactory = }) const implicitStreamRole = workspaceRoleAndSeat?.role.role && - workspaceRoleImplicitProjectRoleMap[workspaceRoleAndSeat.role.role] + workspaceRoleImplicitProjectRoleMap(streamVisibility)[ + workspaceRoleAndSeat.role.role + ] userAclRole = implicitStreamRole } diff --git a/packages/server/modules/shared/test/authz.spec.js b/packages/server/modules/shared/test/authz.spec.js index 376ddbd5d..c8ac64622 100644 --- a/packages/server/modules/shared/test/authz.spec.js +++ b/packages/server/modules/shared/test/authz.spec.js @@ -22,6 +22,7 @@ const { Roles } = require('@speckle/shared') const { TokenResourceIdentifierType } = require('@/modules/core/graph/generated/graphql') +const { ProjectRecordVisibility } = require('@/modules/core/helpers/types') describe('AuthZ @shared', () => { describe('Auth pipeline', () => { @@ -411,7 +412,10 @@ describe('AuthZ @shared', () => { expect(result).to.deep.equal(input) }) it('public stream, no auth returns same context ', async () => { - const input = { context: { stream: { isPublic: true } }, authResult: 'fake' } + const input = { + context: { stream: { visibility: ProjectRecordVisibility.Public } }, + authResult: 'fake' + } const result = await allowForRegisteredUsersOnPublicStreamsEvenWithoutRole( input ) @@ -419,7 +423,10 @@ describe('AuthZ @shared', () => { }) it('not public stream, with auth returns same context ', async () => { const input = { - context: { auth: true, stream: { isPublic: false } }, + context: { + auth: true, + stream: { visibility: ProjectRecordVisibility.Private } + }, authResult: 'fake' } const result = await allowForRegisteredUsersOnPublicStreamsEvenWithoutRole( @@ -429,7 +436,10 @@ describe('AuthZ @shared', () => { }) it('public stream, with auth returns authSuccess', async () => { const input = { - context: { auth: true, stream: { isPublic: true } }, + context: { + auth: true, + stream: { visibility: ProjectRecordVisibility.Public } + }, authResult: 'fake' } const result = await allowForRegisteredUsersOnPublicStreamsEvenWithoutRole( @@ -447,7 +457,10 @@ describe('AuthZ @shared', () => { { context: { auth: true, - stream: { isPublic: false, allowPublicComments: false } + stream: { + visibility: ProjectRecordVisibility.Private, + allowPublicComments: false + } }, authResult: 'fake' } @@ -457,7 +470,10 @@ describe('AuthZ @shared', () => { { context: { auth: true, - stream: { isPublic: false, allowPublicComments: true } + stream: { + visibility: ProjectRecordVisibility.Private, + allowPublicComments: true + } }, authResult: 'fake' } @@ -467,7 +483,10 @@ describe('AuthZ @shared', () => { { context: { auth: true, - stream: { isPublic: false, allowPublicComments: true } + stream: { + visibility: ProjectRecordVisibility.Private, + allowPublicComments: true + } }, authResult: 'fake' } @@ -477,7 +496,10 @@ describe('AuthZ @shared', () => { { context: { auth: false, - stream: { isPublic: false, allowPublicComments: false } + stream: { + visibility: ProjectRecordVisibility.Private, + allowPublicComments: false + } }, authResult: 'fake' } @@ -487,7 +509,10 @@ describe('AuthZ @shared', () => { { context: { auth: false, - stream: { isPublic: true, allowPublicComments: false } + stream: { + visibility: ProjectRecordVisibility.Public, + allowPublicComments: false + } }, authResult: 'fake' } @@ -497,7 +522,10 @@ describe('AuthZ @shared', () => { { context: { auth: false, - stream: { isPublic: true, allowPublicComments: true } + stream: { + visibility: ProjectRecordVisibility.Public, + allowPublicComments: true + } }, authResult: 'fake' } @@ -507,7 +535,10 @@ describe('AuthZ @shared', () => { { context: { auth: false, - stream: { isPublic: true, allowPublicComments: false } + stream: { + visibility: ProjectRecordVisibility.Public, + allowPublicComments: false + } }, authResult: 'fake' } @@ -517,7 +548,10 @@ describe('AuthZ @shared', () => { { context: { auth: false, - stream: { isPublic: true, allowPublicComments: false } + stream: { + visibility: ProjectRecordVisibility.Public, + allowPublicComments: false + } }, authResult: 'fake' } @@ -534,7 +568,10 @@ describe('AuthZ @shared', () => { const input = { context: { auth: true, - stream: { isPublic: true, allowPublicComments: true } + stream: { + visibility: ProjectRecordVisibility.Public, + allowPublicComments: true + } }, authResult: 'fake' } diff --git a/packages/server/modules/workspaces/repositories/workspaces.ts b/packages/server/modules/workspaces/repositories/workspaces.ts index c5c36b151..fa9065b57 100644 --- a/packages/server/modules/workspaces/repositories/workspaces.ts +++ b/packages/server/modules/workspaces/repositories/workspaces.ts @@ -44,7 +44,8 @@ import { ServerAclRecord, BranchRecord, StreamAclRecord, - StreamRecord + StreamRecord, + ProjectRecordVisibility } from '@/modules/core/helpers/types' import { WorkspaceInvalidRoleError } from '@/modules/workspaces/errors/workspace' import { @@ -564,8 +565,11 @@ const getPaginatedWorkspaceProjectsBaseQueryFactory = /** * If userId is set: * - If no workspace role, user should be server admin w/ admin override enabled - * - If workspace role is guest, user should have explicit stream roles - * - If workspace role other than guest, just get all workspace streams + * - If workspace role is admin: user can get all workspace streams + * - If workspace role is guest: user should have explicit stream roles + * - If workspace role is member: + * - Public/Workspace visibility: get stream + * - Private visibility: user should have explicit stream roles * * If withProjectRoleOnly is set: Require project role always */ @@ -590,10 +594,21 @@ const getPaginatedWorkspaceProjectsBaseQueryFactory = } w.orWhere((w2) => { - // Ensure workspace role exists and its not guest or the user has explicit stream roles + // Ensure workspace role exists and: + // user has explicit stream role or is admin or is a non-guest in a non-private project w2.whereNotNull(DbWorkspaceAcl.col.role).andWhere((w3) => { if (!withProjectRoleOnly) { - w3.whereNot(DbWorkspaceAcl.col.role, Roles.Workspace.Guest) + w3.where(DbWorkspaceAcl.col.role, Roles.Workspace.Admin).orWhere( + (w4) => { + w4.whereNot( + DbWorkspaceAcl.col.role, + Roles.Workspace.Guest + ).andWhereNot( + Streams.col.visibility, + ProjectRecordVisibility.Private + ) + } + ) } w3.orWhereExists( diff --git a/packages/server/modules/workspaces/services/projects.ts b/packages/server/modules/workspaces/services/projects.ts index 06b4a225a..27517dcc7 100644 --- a/packages/server/modules/workspaces/services/projects.ts +++ b/packages/server/modules/workspaces/services/projects.ts @@ -1,4 +1,4 @@ -import { StreamRecord } from '@/modules/core/helpers/types' +import { ProjectRecordVisibility, StreamRecord } from '@/modules/core/helpers/types' import { GetDefaultRegion, GetWorkspaceDomains, @@ -211,7 +211,17 @@ export const moveProjectToWorkspaceFactory = } // Assign project to workspace - return await updateProject({ projectUpdate: { id: projectId, workspaceId } }) + return await updateProject({ + projectUpdate: { + id: projectId, + workspaceId, + visibility: + // Migrate from Private -> Workspace visibility + project.visibility === ProjectRecordVisibility.Private + ? ProjectRecordVisibility.Workspace + : project.visibility + } + }) } export const getWorkspaceRoleToDefaultProjectRoleMappingFactory = diff --git a/packages/server/modules/workspaces/tests/helpers/invites.ts b/packages/server/modules/workspaces/tests/helpers/invites.ts index 20427aa1c..ccd5ae5de 100644 --- a/packages/server/modules/workspaces/tests/helpers/invites.ts +++ b/packages/server/modules/workspaces/tests/helpers/invites.ts @@ -32,6 +32,7 @@ import { expect } from 'chai' import { MaybeAsync, StreamRoles, WorkspaceRoles } from '@speckle/shared' import { expectToThrow } from '@/test/assertionHelper' import { ForbiddenError } from '@/modules/shared/errors' +import { isBoolean } from 'lodash' export const buildInvitesGraphqlOperations = (deps: { apollo: TestApolloServer }) => { const { apollo } = deps @@ -80,7 +81,7 @@ export const buildInvitesGraphqlOperations = (deps: { apollo: TestApolloServer } ) => apollo.execute(UseWorkspaceProjectInviteDocument, args, options) const validateResourceAccess = async (params: { - shouldHaveAccess: boolean + shouldHaveAccess: boolean | { workspace: boolean; project: boolean } userId: string workspaceId: string streamId?: string @@ -88,8 +89,17 @@ export const buildInvitesGraphqlOperations = (deps: { apollo: TestApolloServer } expectedProjectRole?: StreamRoles }) => { const { shouldHaveAccess, userId, workspaceId, streamId } = params + const shouldHaveWorkspaceAccess = isBoolean(shouldHaveAccess) + ? shouldHaveAccess + : shouldHaveAccess.workspace + const shouldHaveProjectAccess = isBoolean(shouldHaveAccess) + ? shouldHaveAccess + : shouldHaveAccess.project - const wrapAccessCheck = async (fn: () => MaybeAsync) => { + const wrapAccessCheck = async ( + fn: () => MaybeAsync, + shouldHaveAccess: boolean + ) => { if (shouldHaveAccess) { await fn() } else { @@ -113,7 +123,7 @@ export const buildInvitesGraphqlOperations = (deps: { apollo: TestApolloServer } `Unexpected workspace role! Expected: ${params.expectedWorkspaceRole}, real: ${workspace.role}` ) } - }) + }, shouldHaveWorkspaceAccess) if (streamId?.length) { await wrapAccessCheck(async () => { @@ -133,7 +143,7 @@ export const buildInvitesGraphqlOperations = (deps: { apollo: TestApolloServer } `Unexpected project role! Expected: ${params.expectedProjectRole}, real: ${project?.role}` ) } - }) + }, shouldHaveProjectAccess) } } diff --git a/packages/server/modules/workspaces/tests/integration/invites.graph.spec.ts b/packages/server/modules/workspaces/tests/integration/invites.graph.spec.ts index 62570699c..9d8280704 100644 --- a/packages/server/modules/workspaces/tests/integration/invites.graph.spec.ts +++ b/packages/server/modules/workspaces/tests/integration/invites.graph.spec.ts @@ -67,6 +67,7 @@ import { } from '@/modules/workspaces/tests/helpers/invites' import { getEventBus } from '@/modules/shared/services/eventBus' import { WorkspaceSeatType } from '@/modules/workspacesCore/domain/types' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' enum InviteByTarget { Email = 'email', @@ -1017,7 +1018,14 @@ describe('Workspaces Invites GQL', () => { name: 'My Invite Target Workspace Stream 1', id: '', ownerId: '', - isPublic: false + visibility: ProjectRecordVisibility.Workspace + } + + const myInviteTargetPrivateWorkspaceStream1: BasicTestStream = { + name: 'My Invite Target Private Workspace Stream 1', + id: '', + ownerId: '', + visibility: ProjectRecordVisibility.Private } const processableWorkspaceInvite = { @@ -1050,15 +1058,16 @@ describe('Workspaces Invites GQL', () => { } const validateResourceAccess = async (params: { - shouldHaveAccess: boolean + shouldHaveAccess: boolean | { workspace: boolean; project: boolean } expectedWorkspaceRole?: WorkspaceRoles expectedProjectRole?: StreamRoles + streamId: string }) => { return gqlHelpers.validateResourceAccess({ ...params, userId: otherGuy.id, workspaceId: myInviteTargetWorkspace.id, - streamId: myInviteTargetWorkspaceStream1.id + streamId: params.streamId }) } @@ -1067,7 +1076,11 @@ describe('Workspaces Invites GQL', () => { await createTestWorkspaces([[myInviteTargetWorkspace, me]]) myInviteTargetWorkspaceStream1.workspaceId = myInviteTargetWorkspace.id - await createTestStreams([[myInviteTargetWorkspaceStream1, me]]) + myInviteTargetPrivateWorkspaceStream1.workspaceId = myInviteTargetWorkspace.id + await createTestStreams([ + [myInviteTargetWorkspaceStream1, me], + [myInviteTargetPrivateWorkspaceStream1, me] + ]) }) beforeEach(async () => { @@ -1392,7 +1405,15 @@ describe('Workspaces Invites GQL', () => { }) expect(invite).to.be.not.ok - await validateResourceAccess({ shouldHaveAccess: accept }) + // Should have access to workspace visibility stream, not the other one + await validateResourceAccess({ + shouldHaveAccess: accept, + streamId: myInviteTargetWorkspaceStream1.id + }) + await validateResourceAccess({ + shouldHaveAccess: { workspace: accept, project: false }, + streamId: myInviteTargetPrivateWorkspaceStream1.id + }) } ) @@ -1440,7 +1461,10 @@ describe('Workspaces Invites GQL', () => { expect(res).to.not.haveGraphQLErrors() expect(res.data?.workspaceMutations.invites.use).to.be.ok - await validateResourceAccess({ shouldHaveAccess: accept }) + await validateResourceAccess({ + shouldHaveAccess: accept, + streamId: myInviteTargetWorkspaceStream1.id + }) const verifiedEmails = await findVerifiedEmailsByUserIdFactory({ db @@ -1487,7 +1511,8 @@ describe('Workspaces Invites GQL', () => { await validateResourceAccess({ shouldHaveAccess: true, - expectedWorkspaceRole: Roles.Workspace.Member + expectedWorkspaceRole: Roles.Workspace.Member, + streamId: myInviteTargetWorkspaceStream1.id }) const targetInvite = roleChanged @@ -1516,7 +1541,8 @@ describe('Workspaces Invites GQL', () => { shouldHaveAccess: true, expectedWorkspaceRole: roleChanged ? Roles.Workspace.Admin - : Roles.Workspace.Member + : Roles.Workspace.Member, + streamId: myInviteTargetWorkspaceStream1.id }) const email = targetInvite.email @@ -1610,7 +1636,8 @@ describe('Workspaces Invites GQL', () => { await validateResourceAccess({ shouldHaveAccess: true, expectedWorkspaceRole: Roles.Workspace.Guest, - expectedProjectRole: Roles.Stream.Reviewer + expectedProjectRole: Roles.Stream.Reviewer, + streamId: myInviteTargetWorkspaceStream1.id }) }) @@ -1666,7 +1693,14 @@ describe('Workspaces Invites GQL', () => { expectedWorkspaceRole: withRole ? Roles.Workspace.Admin : Roles.Workspace.Guest, - expectedProjectRole: withRole ? Roles.Stream.Owner : Roles.Stream.Reviewer + expectedProjectRole: withRole ? Roles.Stream.Owner : Roles.Stream.Reviewer, + streamId: myInviteTargetWorkspaceStream1.id + }) + + // ws admin will have access to everything + await validateResourceAccess({ + shouldHaveAccess: { workspace: true, project: withRole ? true : false }, + streamId: myInviteTargetPrivateWorkspaceStream1.id }) } ) diff --git a/packages/server/modules/workspaces/tests/integration/projects.graph.spec.ts b/packages/server/modules/workspaces/tests/integration/projects.graph.spec.ts index 8efcfa527..ecee3df98 100644 --- a/packages/server/modules/workspaces/tests/integration/projects.graph.spec.ts +++ b/packages/server/modules/workspaces/tests/integration/projects.graph.spec.ts @@ -1,4 +1,6 @@ import { db } from '@/db/knex' +import { StreamAcl } from '@/modules/core/dbSchema' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' import { grantStreamPermissionsFactory } from '@/modules/core/repositories/streams' import { WorkspaceSeatType } from '@/modules/gatekeeper/domain/billing' import { getWorkspaceUserSeatsFactory } from '@/modules/gatekeeper/repositories/workspaceSeat' @@ -10,16 +12,25 @@ import { createTestWorkspace } from '@/modules/workspaces/tests/helpers/creation' import { describeEach, itEach } from '@/test/assertionHelper' -import { BasicTestUser, createTestUser, createTestUsers } from '@/test/authHelper' import { + BasicTestUser, + createTestUser, + createTestUsers, + login +} from '@/test/authHelper' +import { + ActiveUserProjectsDocument, ActiveUserProjectsWorkspaceDocument, + CreateProjectDocument, CreateWorkspaceProjectDocument, GetProjectDocument, + GetWorkspaceDocument, GetWorkspaceProjectsDocument, GetWorkspaceProjectsQuery, GetWorkspaceTeamDocument, MoveProjectToWorkspaceDocument, ProjectUpdateRoleInput, + ProjectVisibility, UpdateProjectRoleDocument, UpdateWorkspaceProjectRoleDocument } from '@/test/graphql/generated/graphql' @@ -41,7 +52,8 @@ import { Nullable, Optional, PaidWorkspacePlans, - Roles + Roles, + WorkspacePlans } from '@speckle/shared' import { expect } from 'chai' import cryptoRandomString from 'crypto-random-string' @@ -97,6 +109,48 @@ describe('Workspace project GQL CRUD', () => { ) }) + describe('when creating project', () => { + it('should have workspace visibility by default', async () => { + const res = await apollo.execute( + CreateWorkspaceProjectDocument, + { + input: { + name: 'Test Default Project', + workspaceId: workspace.id + } + }, + { assertNoErrors: true } + ) + + const project = res.data?.workspaceMutations?.projects.create + expect(project).to.be.ok + expect(project?.visibility).to.equal(ProjectVisibility.Workspace) + }) + + it('should create the project in that workspace', async () => { + const projectName = cryptoRandomString({ length: 6 }) + + const createRes = await apollo.execute(CreateWorkspaceProjectDocument, { + input: { + name: projectName, + workspaceId: workspace.id + } + }) + + const getRes = await apollo.execute(GetWorkspaceProjectsDocument, { + id: workspace.id + }) + + const workspaceProject = getRes.data?.workspace.projects.items.find( + (project) => project.name === projectName + ) + + expect(createRes).to.not.haveGraphQLErrors() + expect(getRes).to.not.haveGraphQLErrors() + expect(workspaceProject).to.exist + }) + }) + describe('when changing workspace project roles', () => { const workspaceGuest: BasicTestUser = { id: '', @@ -240,31 +294,6 @@ describe('Workspace project GQL CRUD', () => { }) }) - describe('when specifying a workspace id during project creation', () => { - it('should create the project in that workspace', async () => { - const projectName = cryptoRandomString({ length: 6 }) - - const createRes = await apollo.execute(CreateWorkspaceProjectDocument, { - input: { - name: projectName, - workspaceId: workspace.id - } - }) - - const getRes = await apollo.execute(GetWorkspaceProjectsDocument, { - id: workspace.id - }) - - const workspaceProject = getRes.data?.workspace.projects.items.find( - (project) => project.name === projectName - ) - - expect(createRes).to.not.haveGraphQLErrors() - expect(getRes).to.not.haveGraphQLErrors() - expect(workspaceProject).to.exist - }) - }) - describe('when querying projects', () => { const PAGE_SIZE = 5 const PAGE_COUNT = 3 @@ -285,18 +314,36 @@ describe('Workspace project GQL CRUD', () => { email: '', name: 'Query Workspace Guest' } + const workspaceAdmin = serverMemberUser + const workspaceAdmin2: BasicTestUser = { + id: '', + email: '', + name: 'Query Workspace Admin 2' + } + const workspaceMember: BasicTestUser = { id: '', email: '', name: 'Query Workspace Member' } + const workspaceMemberNoExplicitRoles: BasicTestUser = { + id: '', + email: '', + name: 'Query Workspace Member w/ No Explicit Project Roles' + } + let wsProjects: BasicTestStream[] let nonWorkspaceProjects: BasicTestStream[] let apollo: TestApolloServer before(async () => { - await createTestUsers([workspaceGuest, workspaceMember]) + await createTestUsers([ + workspaceGuest, + workspaceMember, + workspaceAdmin2, + workspaceMemberNoExplicitRoles + ]) await createTestWorkspace(queryWorkspace, workspaceAdmin, { addPlan: { name: 'team', status: 'valid' } }) @@ -312,6 +359,18 @@ describe('Workspace project GQL CRUD', () => { workspaceMember, Roles.Workspace.Member, WorkspaceSeatType.Editor + ], + [ + queryWorkspace, + workspaceAdmin2, + Roles.Workspace.Admin, + WorkspaceSeatType.Editor + ], + [ + queryWorkspace, + workspaceMemberNoExplicitRoles, + Roles.Workspace.Member, + WorkspaceSeatType.Editor ] ]) wsProjects = times( @@ -320,7 +379,11 @@ describe('Workspace project GQL CRUD', () => { id: '', ownerId: '', name: `Query Workspace Project - #${i}`, - isPublic: false, // have to be private for tests below + // Make all except the very last one workspace visibility + visibility: + i === TOTAL_WS_PROJECT_COUNT - 1 + ? ProjectRecordVisibility.Private + : ProjectRecordVisibility.Workspace, workspaceId: queryWorkspace.id }) ) @@ -330,7 +393,7 @@ describe('Workspace project GQL CRUD', () => { id: '', ownerId: '', name: `Non Workspace Project - #${i}`, - isPublic: false + visibility: ProjectRecordVisibility.Private }) ) @@ -351,8 +414,9 @@ describe('Workspace project GQL CRUD', () => { ) await Promise.all([ - // Add explicit single assignment to workspaceMember to 1st non-workspace project + // Add explicit single assignment to workspaceMember & workspaceAdmin to 1st non-workspace project addToStream(nonWorkspaceProjects[0], workspaceMember, Roles.Stream.Contributor), + addToStream(nonWorkspaceProjects[0], workspaceAdmin, Roles.Stream.Contributor), // Add explicit single assignment to workspaceMember to 1st workspace project addToStream(wsProjects[0], workspaceMember, Roles.Stream.Contributor) ]) @@ -362,12 +426,18 @@ describe('Workspace project GQL CRUD', () => { }) }) + // projects at the end have no explicit project assignments (and very last one is fully private), + // and first X ones are explicitly assigned to guest user + const implicitPrivateProject = () => wsProjects.at(-1)! + const implicitWorkspaceVisibilityProject = () => wsProjects.at(-2)! + const explicitGuestProject = () => wsProjects.at(0)! + afterEach(async () => { adminOverrideMock.disable() }) describe('through Workspace.projects', () => { - it('should return all projects for workspace members', async () => { + it('should return all projects for workspace admin', async () => { const res = await apollo.execute(GetWorkspaceProjectsDocument, { id: queryWorkspace.id, limit: 999 // get everything @@ -443,6 +513,24 @@ describe('Workspace project GQL CRUD', () => { expect(collection?.totalCount).to.equal(GUEST_PROJECT_COUNT) }) + it('should return all non-private for members who may not even have any explicit project roles', async () => { + const apollo = await testApolloServer({ + authUserId: workspaceMemberNoExplicitRoles.id + }) + const res = await apollo.execute(GetWorkspaceProjectsDocument, { + id: queryWorkspace.id, + limit: 999 // get everything + }) + + const nonPrivateCount = TOTAL_WS_PROJECT_COUNT - 1 // -1 for the fully private one + + expect(res).to.not.haveGraphQLErrors() + const collection = res.data?.workspace.projects + expect(collection?.items.length).to.equal(nonPrivateCount) + expect(collection?.cursor).to.be.ok + expect(collection?.totalCount).to.equal(nonPrivateCount) + }) + it('should respect limits', async () => { const res = await apollo.execute(GetWorkspaceProjectsDocument, { id: queryWorkspace.id, @@ -542,17 +630,36 @@ describe('Workspace project GQL CRUD', () => { await createTestUser(randomServerGuy) }) - // projects at the end have no explicit project assignments, - // and first X ones are explicitly assigned to guest user - const implicitProject = () => wsProjects.at(-1)! - const explicitGuestProject = () => wsProjects.at(0)! - - it('it should be accessible to workspace member', async () => { + it('workspace visibility should be accessible to workspace member', async () => { const apollo = await testApolloServer({ authUserId: workspaceMember.id }) const res = await apollo.execute(GetProjectDocument, { - id: implicitProject().id + id: implicitWorkspaceVisibilityProject().id + }) + + expect(res).to.not.haveGraphQLErrors() + expect(res.data?.project.id).to.be.ok + }) + + it('private visibility should not be accessible to workspace member w/o explicit role', async () => { + const apollo = await testApolloServer({ + authUserId: workspaceMember.id + }) + const res = await apollo.execute(GetProjectDocument, { + id: implicitPrivateProject().id + }) + + expect(res).to.haveGraphQLErrors() + expect(res.data?.project).to.not.be.ok + }) + + it('private visibility should be accessible to workspace admin w/o explicit role', async () => { + const apollo = await testApolloServer({ + authUserId: workspaceAdmin2.id + }) + const res = await apollo.execute(GetProjectDocument, { + id: implicitPrivateProject().id }) expect(res).to.not.haveGraphQLErrors() @@ -564,7 +671,7 @@ describe('Workspace project GQL CRUD', () => { authUserId: randomServerGuy.id }) const res = await apollo.execute(GetProjectDocument, { - id: implicitProject().id + id: implicitWorkspaceVisibilityProject().id }) expect(res).to.haveGraphQLErrors() @@ -582,7 +689,9 @@ describe('Workspace project GQL CRUD', () => { authUserId: workspaceGuest.id }) const res = await apollo.execute(GetProjectDocument, { - id: explicit ? explicitGuestProject().id : implicitProject().id + id: explicit + ? explicitGuestProject().id + : implicitWorkspaceVisibilityProject().id }) if (explicit) { @@ -599,8 +708,8 @@ describe('Workspace project GQL CRUD', () => { [{ adminOverrideEnabled: true }, { adminOverrideEnabled: false }], ({ adminOverrideEnabled }) => adminOverrideEnabled - ? 'it should return project for server admins if override enabled' - : 'it should not return project for server admins if override disabled', + ? 'it should return fully private project for server admins if override enabled' + : 'it should not return fully private project for server admins if override disabled', async ({ adminOverrideEnabled }) => { const apollo = await testApolloServer({ authUserId: serverAdminUser.id @@ -608,7 +717,7 @@ describe('Workspace project GQL CRUD', () => { adminOverrideMock.enable(adminOverrideEnabled) const res = await apollo.execute(GetProjectDocument, { - id: implicitProject().id + id: implicitPrivateProject().id }) if (adminOverrideEnabled) { @@ -671,28 +780,41 @@ describe('Workspace project GQL CRUD', () => { ]).to.deep.equalInAnyOrder([nonWorkspaceProjects[0].id, wsProjects[0].id]) }) - it('should return all projects user is explicitly or implicitly assigned to, if flag set', async () => { - const apolloMember = await testApolloServer({ - authUserId: workspaceMember.id - }) - const memberRes = await apolloMember.execute( - ActiveUserProjectsWorkspaceDocument, - { limit: 999, filter: { includeImplicitAccess: true } }, - { assertNoErrors: true } - ) - const memberCollection = memberRes.data?.activeUser?.projects + itEach( + [{ admin: true }, { admin: false }], + ({ admin }) => + `should return all projects ${ + admin ? 'ws admin' : 'ws member' + } is explicitly or implicitly assigned to, if flag set`, + async ({ admin }) => { + const apollo = await testApolloServer({ + authUserId: admin ? workspaceAdmin.id : workspaceMember.id + }) + const res = await apollo.execute( + ActiveUserProjectsWorkspaceDocument, + { limit: 999, filter: { includeImplicitAccess: true } }, + { assertNoErrors: true } + ) + const projects = res.data?.activeUser?.projects - // 1 non-workspace assignment + all workspace projects - const expectedMemberCount = TOTAL_WS_PROJECT_COUNT + 1 + // 1 non-workspace assignment + all workspace projects + // (except the last one thats fully private, if not admin) + let expectedCount = TOTAL_WS_PROJECT_COUNT + 1 + if (!admin) { + expectedCount -= 1 + } - expect(memberCollection).to.be.ok - expect(memberCollection!.totalCount).to.equal(expectedMemberCount) - expect(memberCollection!.items.length).to.equal(expectedMemberCount) - expect(memberCollection!.items.map((i) => i.id)).to.deep.equalInAnyOrder([ - nonWorkspaceProjects[0].id, - ...wsProjects.map((p) => p.id) - ]) - }) + expect(projects).to.be.ok + expect(projects!.totalCount).to.equal(expectedCount) + expect(projects!.items.length).to.equal(expectedCount) + expect(projects!.items.map((i) => i.id)).to.deep.equalInAnyOrder([ + nonWorkspaceProjects[0].id, + ...wsProjects + .filter((p) => (admin ? true : p.id !== implicitPrivateProject().id)) + .map((p) => p.id) + ]) + } + ) it('should only return workspace projects if filter set', async () => { const res = await apollo.execute(ActiveUserProjectsWorkspaceDocument, { @@ -739,7 +861,7 @@ describe('Workspace project GQL CRUD', () => { id: '', ownerId: '', name: 'Test Project', - isPublic: false + visibility: ProjectRecordVisibility.Private } const targetWorkspace: BasicTestWorkspace = { @@ -750,7 +872,9 @@ describe('Workspace project GQL CRUD', () => { } before(async () => { - await createTestWorkspace(targetWorkspace, serverAdminUser) + await createTestWorkspace(targetWorkspace, serverAdminUser, { + addPlan: WorkspacePlans.Unlimited + }) }) beforeEach(async () => { @@ -762,17 +886,38 @@ describe('Workspace project GQL CRUD', () => { }) }) - it('should move the project to the target workspace', async () => { + it('should move the project to the target workspace and update visibility', async () => { const res = await apollo.execute(MoveProjectToWorkspaceDocument, { projectId: testProject.id, workspaceId: targetWorkspace.id }) - const { workspaceId } = - res.data?.workspaceMutations.projects.moveToWorkspace ?? {} + const project = res.data?.workspaceMutations.projects.moveToWorkspace expect(res).to.not.haveGraphQLErrors() - expect(workspaceId).to.equal(targetWorkspace.id) + expect(project?.workspaceId).to.equal(targetWorkspace.id) + expect(project?.visibility).to.equal(ProjectVisibility.Workspace) + }) + + it('should move a public project to the target workspace and keep same visibility', async () => { + const publicProject: BasicTestStream = { + id: '', + ownerId: '', + name: 'Test Public Project', + visibility: ProjectRecordVisibility.Public + } + await createTestStream(publicProject, serverAdminUser) + + const res = await apollo.execute(MoveProjectToWorkspaceDocument, { + projectId: publicProject.id, + workspaceId: targetWorkspace.id + }) + + const project = res.data?.workspaceMutations.projects.moveToWorkspace + + expect(res).to.not.haveGraphQLErrors() + expect(project?.workspaceId).to.equal(targetWorkspace.id) + expect(project?.visibility).to.equal(ProjectVisibility.Public) }) it('should preserve project roles for project members with editor seats', async () => { @@ -839,4 +984,224 @@ describe('Workspace project GQL CRUD', () => { expect(adminWorkspaceRole?.role).to.equal(Roles.Workspace.Admin) }) }) + + // moved over Alessandro's tests from core to here, since they are all related to workspaces + // they're kind of a mess and need to be cleaned up + describe('query user.projects', () => { + it('should return projects not in a workspace', async () => { + const testAdminUser: BasicTestUser = { + id: '', + name: 'test', + email: '', + role: Roles.Server.Admin, + verified: true + } + await createTestUser(testAdminUser) + const workspace = { + id: '', + name: 'test ws', + slug: cryptoRandomString({ length: 10 }), + ownerId: '' + } + await createTestWorkspace(workspace, testAdminUser) + + const session = await login(testAdminUser) + const getWorkspaceRes = await session.execute(GetWorkspaceDocument, { + workspaceId: workspace.id + }) + + expect(getWorkspaceRes).to.not.haveGraphQLErrors() + const workspaceId = getWorkspaceRes.data!.workspace.id + + const createProjectInWorkspaceRes = await session.execute( + CreateWorkspaceProjectDocument, + { input: { name: 'project', workspaceId } } + ) + expect(createProjectInWorkspaceRes).to.not.haveGraphQLErrors() + + const createProjectNonInWorkspaceRes = await session.execute( + CreateProjectDocument, + { input: { name: 'project' } } + ) + expect(createProjectNonInWorkspaceRes).to.not.haveGraphQLErrors() + const projectNonInWorkspace = + createProjectNonInWorkspaceRes.data!.projectMutations.create + + const userProjectsRes = await session.execute(ActiveUserProjectsDocument, { + filter: { personalOnly: true } + }) + expect(userProjectsRes).to.not.haveGraphQLErrors() + + const projects = userProjectsRes.data!.activeUser!.projects.items + + expect(projects).to.have.length(1) + expect(projects[0].id).to.eq(projectNonInWorkspace.id) + }) + + it('should return projects in workspace', async () => { + const testAdminUser: BasicTestUser = { + id: '', + name: 'test', + email: '', + role: Roles.Server.Admin, + verified: true + } + await createTestUser(testAdminUser) + const workspace = { + id: '', + name: 'test ws', + slug: cryptoRandomString({ length: 10 }), + ownerId: '' + } + await createTestWorkspace(workspace, testAdminUser) + + const session = await login(testAdminUser) + const getWorkspaceRes = await session.execute(GetWorkspaceDocument, { + workspaceId: workspace.id + }) + + expect(getWorkspaceRes).to.not.haveGraphQLErrors() + const workspaceId = getWorkspaceRes.data!.workspace.id + + const createProjectInWorkspaceRes = await session.execute( + CreateWorkspaceProjectDocument, + { input: { name: 'project', workspaceId } } + ) + expect(createProjectInWorkspaceRes).to.not.haveGraphQLErrors() + const projectInWorkspace = + createProjectInWorkspaceRes.data!.workspaceMutations.projects.create + + const createProjectNonInWorkspaceRes = await session.execute( + CreateProjectDocument, + { input: { name: 'project' } } + ) + expect(createProjectNonInWorkspaceRes).to.not.haveGraphQLErrors() + + const userProjectsRes = await session.execute(ActiveUserProjectsDocument, { + filter: { workspaceId } + }) + expect(userProjectsRes).to.not.haveGraphQLErrors() + + const projects = userProjectsRes.data!.activeUser!.projects.items + + expect(projects).to.have.length(1) + expect(projects[0].id).to.eq(projectInWorkspace.id) + }) + + it('should return all user projects', async () => { + const testAdminUser: BasicTestUser = { + id: '', + name: 'test', + email: '', + role: Roles.Server.Admin, + verified: true + } + await createTestUser(testAdminUser) + const workspace = { + id: '', + name: 'test ws', + slug: cryptoRandomString({ length: 10 }), + ownerId: '' + } + await createTestWorkspace(workspace, testAdminUser) + + const session = await login(testAdminUser) + const getWorkspaceRes = await session.execute(GetWorkspaceDocument, { + workspaceId: workspace.id + }) + + expect(getWorkspaceRes).to.not.haveGraphQLErrors() + const workspaceId = getWorkspaceRes.data!.workspace.id + + const createProjectInWorkspaceRes = await session.execute( + CreateWorkspaceProjectDocument, + { input: { name: 'project', workspaceId } } + ) + expect(createProjectInWorkspaceRes).to.not.haveGraphQLErrors() + + const createProjectNonInWorkspaceRes = await session.execute( + CreateProjectDocument, + { input: { name: 'project' } } + ) + expect(createProjectNonInWorkspaceRes).to.not.haveGraphQLErrors() + + const userProjectsRes = await session.execute(ActiveUserProjectsDocument, { + filter: {} + }) + expect(userProjectsRes).to.not.haveGraphQLErrors() + + const projects = userProjectsRes.data!.activeUser!.projects.items + + expect(projects).to.have.length(2) + }) + + it('should return all user projects sorted by user role', async () => { + const testAdminUser: BasicTestUser = { + id: '', + name: 'test', + email: '', + role: Roles.Server.Admin, + verified: true + } + await createTestUser(testAdminUser) + const workspace = { + id: '', + name: 'test ws', + slug: cryptoRandomString({ length: 10 }), + ownerId: '' + } + await createTestWorkspace(workspace, testAdminUser) + + const session = await login(testAdminUser) + const getWorkspaceRes = await session.execute(GetWorkspaceDocument, { + workspaceId: workspace.id + }) + + expect(getWorkspaceRes).to.not.haveGraphQLErrors() + const workspaceId = getWorkspaceRes.data!.workspace.id + + const createProjectInWorkspaceAsOwnerRes = await session.execute( + CreateWorkspaceProjectDocument, + { input: { name: 'project', workspaceId } } + ) + expect(createProjectInWorkspaceAsOwnerRes).to.not.haveGraphQLErrors() + const createProjectInWorkspaceAsContributorRes = await session.execute( + CreateWorkspaceProjectDocument, + { input: { name: 'project 2', workspaceId } } + ) + expect(createProjectInWorkspaceAsContributorRes).to.not.haveGraphQLErrors() + const projectContributorId = + createProjectInWorkspaceAsContributorRes.data?.workspaceMutations.projects + .create.id + await db(StreamAcl.name) + .update({ role: Roles.Stream.Contributor }) + .where({ userId: testAdminUser.id, resourceId: projectContributorId }) + const createProjectInWorkspaceAsReviewerRes = await session.execute( + CreateWorkspaceProjectDocument, + { input: { name: 'project 3', workspaceId } } + ) + expect(createProjectInWorkspaceAsReviewerRes).to.not.haveGraphQLErrors() + const projectReviewerId = + createProjectInWorkspaceAsReviewerRes.data?.workspaceMutations.projects.create + .id + await db(StreamAcl.name) + .update({ role: Roles.Stream.Reviewer }) + .where({ userId: testAdminUser.id, resourceId: projectReviewerId }) + + const userProjectsRes = await session.execute(ActiveUserProjectsDocument, { + filter: {}, + sortBy: ['role'] + }) + expect(userProjectsRes).to.not.haveGraphQLErrors() + + const projects = userProjectsRes.data!.activeUser!.projects.items + + expect(projects).to.have.length(3) + expect(projects[0].id).to.eq( + createProjectInWorkspaceAsOwnerRes.data?.workspaceMutations.projects.create.id + ) + expect(projects[1].id).to.eq(projectContributorId) + expect(projects[2].id).to.eq(projectReviewerId) + }) + }) }) diff --git a/packages/server/modules/workspaces/tests/integration/roles.graph.spec.ts b/packages/server/modules/workspaces/tests/integration/roles.graph.spec.ts index e929a6183..ec8434f92 100644 --- a/packages/server/modules/workspaces/tests/integration/roles.graph.spec.ts +++ b/packages/server/modules/workspaces/tests/integration/roles.graph.spec.ts @@ -1,5 +1,6 @@ import { Streams } from '@/modules/core/dbSchema' import { AllScopes } from '@/modules/core/helpers/mainConstants' +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' import { assignToWorkspace, BasicTestWorkspace, @@ -283,7 +284,6 @@ describe('Workspaces Roles/Seats GQL', () => { }) }) - // TODO: Viewer vs Editor describe('in a workspace with projects', () => { const workspace: BasicTestWorkspace = { id: '', @@ -326,35 +326,43 @@ describe('Workspaces Roles/Seats GQL', () => { id: '', ownerId: '', name: 'Project A', - isPublic: false + visibility: ProjectRecordVisibility.Workspace } const workspaceProjectB: BasicTestStream = { id: '', ownerId: '', name: 'Project B', - isPublic: false + visibility: ProjectRecordVisibility.Workspace } const workspaceProjectC: BasicTestStream = { id: '', ownerId: '', name: 'Project C', - isPublic: false + visibility: ProjectRecordVisibility.Workspace } const workspaceProjectD: BasicTestStream = { id: '', ownerId: '', name: 'Project D', - isPublic: false + visibility: ProjectRecordVisibility.Workspace + } + + const workspaceProjectE: BasicTestStream = { + id: '', + ownerId: '', + name: 'Project E (Fully private)', + visibility: ProjectRecordVisibility.Private } const workspaceProjects = [ workspaceProjectA, workspaceProjectB, workspaceProjectC, - workspaceProjectD + workspaceProjectD, + workspaceProjectE ] before(async () => { @@ -424,13 +432,13 @@ describe('Workspaces Roles/Seats GQL', () => { * * Initial explicit workspace project roles: * - * | | Project A | Project B | Project C | Project D | - * |---------------------------|-------------|-------------|-----------|-----------| - * | workspaceAdminUser | Owner | None | None | None | - * | workspaceMemberUser | Owner | Contributor | Reviewer | None | - * | workspaceGuestUser | Contributor | Reviewer | None | None | - * | workspaceMemberViewerUser | Reviewer | None | None | None | - * | workspaceGuestViewerUser | None | Reviewer | None | None | + * | | Project A | Project B | Project C | Project D | Project E (private) | + * |---------------------------|-------------|-------------|-----------|-----------|---------------------| + * | workspaceAdminUser | Owner | None | None | None | None + * | workspaceMemberUser | Owner | Contributor | Reviewer | None | None + * | workspaceGuestUser | Contributor | Reviewer | None | None | Reviewer + * | workspaceMemberViewerUser | Reviewer | None | None | None | Reviewer + * | workspaceGuestViewerUser | None | Reviewer | None | None | Reviewer */ await Promise.all([ @@ -448,7 +456,15 @@ describe('Workspaces Roles/Seats GQL', () => { addToStream(workspaceProjectB, workspaceGuestUser, Roles.Stream.Reviewer), addToStream(workspaceProjectB, workspaceGuestViewerUser, Roles.Stream.Reviewer), // C - addToStream(workspaceProjectC, workspaceMemberUser, Roles.Stream.Reviewer) + addToStream(workspaceProjectC, workspaceMemberUser, Roles.Stream.Reviewer), + // E + addToStream(workspaceProjectE, workspaceGuestUser, Roles.Stream.Reviewer), + addToStream( + workspaceProjectE, + workspaceMemberViewerUser, + Roles.Stream.Reviewer + ), + addToStream(workspaceProjectE, workspaceGuestViewerUser, Roles.Stream.Reviewer) ]) }) @@ -470,15 +486,16 @@ describe('Workspaces Roles/Seats GQL', () => { user: workspaceAdminUser }) - expect(projects.length).to.eq(4) + expect(projects.length).to.eq(5) expect(checkAllProjects((p) => p.isOwner)).to.be.ok expect(checkProject(workspaceProjectA).isExplicitOwner).to.be.ok expect(checkProject(workspaceProjectB).hasExplicitRole).to.be.not.ok expect(checkProject(workspaceProjectC).hasExplicitRole).to.be.not.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.be.not.ok + expect(checkProject(workspaceProjectE).hasExplicitRole).to.be.not.ok }) - it('workspaceMemberUser is implicit reviewer in all of them, and also has explicit roles in some', async () => { + it('workspaceMemberUser is implicit reviewer in all of them, except E, and also has explicit roles in some', async () => { const { projects, checkAllProjects, checkProject } = await getProjects({ user: workspaceMemberUser }) @@ -489,42 +506,46 @@ describe('Workspaces Roles/Seats GQL', () => { expect(checkProject(workspaceProjectB).isExplicitContributor).to.be.ok expect(checkProject(workspaceProjectC).isExplicitReviewer).to.be.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.be.not.ok + expect(checkProject(workspaceProjectE).hasAccess).to.be.not.ok }) - it('workspaceGuestUser only has explicit roles in 2 projects', async () => { + it('workspaceGuestUser only has explicit roles in 3 projects', async () => { const { projects, checkProject } = await getProjects({ user: workspaceGuestUser }) - expect(projects.length).to.eq(2) + expect(projects.length).to.eq(3) expect(checkProject(workspaceProjectA).isExplicitContributor).to.be.ok expect(checkProject(workspaceProjectB).isExplicitReviewer).to.be.ok - expect(checkProject(workspaceProjectC).hasExplicitRole).to.be.not.ok - expect(checkProject(workspaceProjectD).hasExplicitRole).to.be.not.ok + expect(checkProject(workspaceProjectC).hasAccess).to.be.not.ok + expect(checkProject(workspaceProjectD).hasAccess).to.be.not.ok + expect(checkProject(workspaceProjectE).isExplicitReviewer).to.be.ok }) - it('workspaceMemberViewerUser is only explicit reviewer in 1 project, and has implicit roles elsewhere', async () => { + it('workspaceMemberViewerUser is only explicit reviewer in 2 projects, and has implicit roles elsewhere', async () => { const { projects, checkAllProjects, checkProject } = await getProjects({ user: workspaceMemberViewerUser }) - expect(projects.length).to.eq(4) + expect(projects.length).to.eq(5) expect(checkAllProjects((p) => p.isReviewer)).to.be.ok expect(checkProject(workspaceProjectA).isExplicitReviewer).to.be.ok expect(checkProject(workspaceProjectB).hasExplicitRole).to.be.not.ok expect(checkProject(workspaceProjectC).hasExplicitRole).to.be.not.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.be.not.ok + expect(checkProject(workspaceProjectE).isExplicitReviewer).to.be.ok }) - it('workspaceGuestViewerUser is only explicit reviewer in 1 project', async () => { + it('workspaceGuestViewerUser is only explicit reviewer in 2 projects', async () => { const { projects, checkProject } = await getProjects({ user: workspaceGuestViewerUser }) - expect(projects.length).to.eq(1) + expect(projects.length).to.eq(2) expect(checkProject(workspaceProjectB).isExplicitReviewer).to.be.ok expect(checkProject(workspaceProjectA).hasExplicitRole).to.be.not.ok expect(checkProject(workspaceProjectC).hasExplicitRole).to.be.not.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.be.not.ok + expect(checkProject(workspaceProjectE).isExplicitReviewer).to.be.ok }) }) @@ -582,9 +603,10 @@ describe('Workspaces Roles/Seats GQL', () => { user: workspaceGuestUser }) - expect(projects.length).to.eq(2) + expect(projects.length).to.eq(3) expect(checkProject(workspaceProjectA).isExplicitReviewer).to.be.ok expect(checkProject(workspaceProjectB).isExplicitReviewer).to.be.ok + expect(checkProject(workspaceProjectE).isExplicitReviewer).to.be.ok }) }) @@ -605,17 +627,18 @@ describe('Workspaces Roles/Seats GQL', () => { ) }) - it('should still remain explicit owner and be implicit reviewer elsewhere', async () => { + it('should still remain explicit owner and be implicit reviewer elsewhere, except private E', async () => { const { projects, checkAllProjects, checkProject } = await getProjects({ user: workspaceAdminUser }) expect(projects.length).to.eq(4) + expect(checkAllProjects((p) => p.isReviewer)).to.be.ok expect(checkProject(workspaceProjectA).isExplicitOwner).to.be.ok expect(checkProject(workspaceProjectB).hasExplicitRole).to.be.not.ok expect(checkProject(workspaceProjectC).hasExplicitRole).to.be.not.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.be.not.ok - expect(checkAllProjects((p) => p.isReviewer)).to.be.ok + expect(checkProject(workspaceProjectE).hasAccess).to.be.not.ok }) }) @@ -670,12 +693,13 @@ describe('Workspaces Roles/Seats GQL', () => { user: workspaceMemberUser }) - expect(projects.length).to.eq(4) + expect(projects.length).to.eq(5) expect(checkAllProjects((p) => p.isOwner)).to.be.ok expect(checkProject(workspaceProjectA).isExplicitOwner).to.be.ok expect(checkProject(workspaceProjectB).isExplicitOwner).to.be.ok expect(checkProject(workspaceProjectC).isExplicitOwner).to.be.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.not.be.ok + expect(checkProject(workspaceProjectE).hasExplicitRole).to.not.be.ok }) }) @@ -704,6 +728,7 @@ describe('Workspaces Roles/Seats GQL', () => { expect(checkProject(workspaceProjectB).isExplicitContributor).to.be.ok expect(checkProject(workspaceProjectC).isExplicitReviewer).to.be.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.be.not.ok + expect(checkProject(workspaceProjectE).hasExplicitRole).to.be.not.ok }) }) }) @@ -729,12 +754,13 @@ describe('Workspaces Roles/Seats GQL', () => { user: workspaceGuestUser }) - expect(projects.length).to.eq(4) + expect(projects.length).to.eq(5) expect(checkAllProjects((p) => p.isOwner)).to.be.ok expect(checkProject(workspaceProjectA).isExplicitOwner).to.be.ok expect(checkProject(workspaceProjectB).isExplicitOwner).to.be.ok expect(checkProject(workspaceProjectC).hasExplicitRole).to.not.be.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.be.not.ok + expect(checkProject(workspaceProjectE).isExplicitOwner).to.be.ok }) }) @@ -758,12 +784,13 @@ describe('Workspaces Roles/Seats GQL', () => { user: workspaceGuestUser }) - expect(projects.length).to.eq(4) + expect(projects.length).to.eq(5) expect(checkAllProjects((p) => p.isReviewer)).to.be.ok expect(checkProject(workspaceProjectA).isExplicitContributor).to.be.ok expect(checkProject(workspaceProjectB).isExplicitReviewer).to.be.ok expect(checkProject(workspaceProjectC).hasExplicitRole).to.be.not.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.be.not.ok + expect(checkProject(workspaceProjectE).isExplicitReviewer).to.be.ok }) }) }) @@ -791,12 +818,13 @@ describe('Workspaces Roles/Seats GQL', () => { }) expect(workspace.seatType).to.eq(WorkspaceSeatType.Editor) - expect(projects.length).to.eq(4) + expect(projects.length).to.eq(5) expect(checkAllProjects((p) => p.isOwner)).to.be.ok expect(checkProject(workspaceProjectA).isExplicitOwner).to.be.ok expect(checkProject(workspaceProjectB).hasExplicitRole).to.not.be.ok expect(checkProject(workspaceProjectC).hasExplicitRole).to.not.be.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.not.be.ok + expect(checkProject(workspaceProjectE).isExplicitOwner).to.be.ok }) }) @@ -821,8 +849,9 @@ describe('Workspaces Roles/Seats GQL', () => { }) expect(workspace.seatType).to.eq(WorkspaceSeatType.Viewer) - expect(projects.length).to.eq(1) + expect(projects.length).to.eq(2) expect(checkProject(workspaceProjectA).isExplicitReviewer).to.be.ok + expect(checkProject(workspaceProjectE).isExplicitReviewer).to.be.ok }) }) }) @@ -850,12 +879,13 @@ describe('Workspaces Roles/Seats GQL', () => { }) expect(workspace.seatType).to.eq(WorkspaceSeatType.Editor) - expect(projects.length).to.eq(4) + expect(projects.length).to.eq(5) expect(checkAllProjects((p) => p.isOwner)).to.be.ok expect(checkProject(workspaceProjectA).hasExplicitRole).to.not.be.ok expect(checkProject(workspaceProjectB).isExplicitOwner).to.be.ok expect(checkProject(workspaceProjectC).hasExplicitRole).to.not.be.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.be.not.ok + expect(checkProject(workspaceProjectE).isExplicitOwner).to.be.ok }) }) @@ -874,19 +904,20 @@ describe('Workspaces Roles/Seats GQL', () => { ) }) - it('should retain viewer seat, same explicit access and get full implicit acccess', async () => { + it('should retain viewer seat, same explicit access and get full workspace visibility implicit acccess', async () => { const { workspace, projects, checkProject, checkAllProjects } = await getProjects({ user: workspaceGuestViewerUser }) expect(workspace.seatType).to.eq(WorkspaceSeatType.Viewer) - expect(projects.length).to.eq(4) + expect(projects.length).to.eq(5) expect(checkAllProjects((p) => p.isReviewer)).to.be.ok expect(checkProject(workspaceProjectA).hasExplicitRole).to.be.not.ok expect(checkProject(workspaceProjectB).isExplicitReviewer).to.be.ok expect(checkProject(workspaceProjectC).hasExplicitRole).to.be.not.ok expect(checkProject(workspaceProjectD).hasExplicitRole).to.be.not.ok + expect(checkProject(workspaceProjectE).isExplicitReviewer).to.be.ok }) }) }) diff --git a/packages/server/modules/workspaces/tests/integration/sso.graph.spec.ts b/packages/server/modules/workspaces/tests/integration/sso.graph.spec.ts index 79846e8f8..c7be7516f 100644 --- a/packages/server/modules/workspaces/tests/integration/sso.graph.spec.ts +++ b/packages/server/modules/workspaces/tests/integration/sso.graph.spec.ts @@ -1,3 +1,4 @@ +import { ProjectRecordVisibility } from '@/modules/core/helpers/types' import { getFeatureFlags } from '@/modules/shared/helpers/envHelper' import { assignToWorkspaces, @@ -110,9 +111,9 @@ const { FF_WORKSPACES_SSO_ENABLED } = getFeatureFlags() const testProject: BasicTestStream = { id: '', ownerId: '', - isPublic: false, name: 'Workspace Project', - workspaceId: testWorkspaceWithSso.id + workspaceId: testWorkspaceWithSso.id, + visibility: ProjectRecordVisibility.Workspace } await createTestStream(testProject, workspaceAdmin) diff --git a/packages/server/test/authHelper.ts b/packages/server/test/authHelper.ts index e70209891..c4ae62e90 100644 --- a/packages/server/test/authHelper.ts +++ b/packages/server/test/authHelper.ts @@ -1,5 +1,6 @@ import { db } from '@/db/knex' import { AllScopes, ServerRoles } from '@/modules/core/helpers/mainConstants' +import { createRandomEmail } from '@/modules/core/helpers/testHelpers' import { UserRecord } from '@/modules/core/helpers/types' import { getServerInfoFactory } from '@/modules/core/repositories/server' import { @@ -36,7 +37,7 @@ import { createTestContext, testApolloServer } from '@/test/graphqlHelper' import { faker } from '@faker-js/faker' import { ServerScope, wait } from '@speckle/shared' import cryptoRandomString from 'crypto-random-string' -import { isArray, isNumber, kebabCase, omit, times } from 'lodash' +import { isArray, isNumber, omit, times } from 'lodash' const getServerInfo = getServerInfoFactory({ db }) const findEmail = findEmailFactory({ db }) @@ -120,7 +121,7 @@ export async function createTestUser(userObj?: Partial) { } if (!baseUser.email) { - setVal('email', `${kebabCase(baseUser.name)}@example.org`) + setVal('email', createRandomEmail().toLowerCase()) } const id = await createUser(omit(baseUser, ['id', 'allowPersonalEmail']), { diff --git a/packages/server/test/graphql/generated/graphql.ts b/packages/server/test/graphql/generated/graphql.ts index 96742d948..ffbbc689e 100644 --- a/packages/server/test/graphql/generated/graphql.ts +++ b/packages/server/test/graphql/generated/graphql.ts @@ -2071,7 +2071,7 @@ export type Project = { versions: VersionCollection; /** Return metadata about resources being requested in the viewer */ viewerResources: Array; - visibility: SimpleProjectVisibility; + visibility: ProjectVisibility; webhooks: WebhookCollection; workspace?: Maybe; workspaceId?: Maybe; @@ -2692,9 +2692,14 @@ export const ProjectVersionsUpdatedMessageType = { export type ProjectVersionsUpdatedMessageType = typeof ProjectVersionsUpdatedMessageType[keyof typeof ProjectVersionsUpdatedMessageType]; export const ProjectVisibility = { + /** Only accessible to explicit collaborators */ Private: 'PRIVATE', + /** Accessible to everyone (even non-logged in users) */ Public: 'PUBLIC', - Unlisted: 'UNLISTED' + /** Legacy - same as public */ + Unlisted: 'UNLISTED', + /** Accessible to everyone in the project's workspace */ + Workspace: 'WORKSPACE' } as const; export type ProjectVisibility = typeof ProjectVisibility[keyof typeof ProjectVisibility]; @@ -3244,13 +3249,6 @@ export type SetPrimaryUserEmailInput = { id: Scalars['ID']['input']; }; -/** Visibility without the "discoverable" option */ -export const SimpleProjectVisibility = { - Private: 'PRIVATE', - Unlisted: 'UNLISTED' -} as const; - -export type SimpleProjectVisibility = typeof SimpleProjectVisibility[keyof typeof SimpleProjectVisibility]; export type SmartTextEditorValue = { __typename?: 'SmartTextEditorValue'; /** File attachments, if any */ @@ -3327,6 +3325,7 @@ export type Stream = { /** * Whether the stream (if public) can be found on public stream exploration pages * and searches + * @deprecated Discoverability as a feature has been removed. */ isDiscoverable: Scalars['Boolean']['output']; /** Whether the stream can be viewed by non-contributors */ @@ -5466,7 +5465,7 @@ export type UpdateWorkspaceProjectRoleMutationVariables = Exact<{ }>; -export type UpdateWorkspaceProjectRoleMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', projects: { __typename?: 'WorkspaceProjectMutations', updateRole: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: SimpleProjectVisibility, allowPublicComments: boolean, role?: string | null, createdAt: string, updatedAt: string } } } }; +export type UpdateWorkspaceProjectRoleMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', projects: { __typename?: 'WorkspaceProjectMutations', updateRole: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, role?: string | null, createdAt: string, updatedAt: string } } } }; export type UpdateWorkspaceSeatTypeMutationVariables = Exact<{ input: WorkspaceUpdateSeatTypeInput; @@ -5854,7 +5853,7 @@ export type EditProjectCommentMutationVariables = Exact<{ export type EditProjectCommentMutation = { __typename?: 'Mutation', commentMutations: { __typename?: 'CommentMutations', edit: { __typename?: 'Comment', id: string, rawText?: string | null, authorId: string, text?: { __typename?: 'SmartTextEditorValue', doc?: Record | null } | null } } }; -export type BasicProjectFieldsFragment = { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: SimpleProjectVisibility, allowPublicComments: boolean, role?: string | null, createdAt: string, updatedAt: string }; +export type BasicProjectFieldsFragment = { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, role?: string | null, createdAt: string, updatedAt: string }; export type AdminProjectListQueryVariables = Exact<{ query?: InputMaybe; @@ -5865,7 +5864,7 @@ export type AdminProjectListQueryVariables = Exact<{ }>; -export type AdminProjectListQuery = { __typename?: 'Query', admin: { __typename?: 'AdminQueries', projectList: { __typename?: 'ProjectCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, description?: string | null, visibility: SimpleProjectVisibility, allowPublicComments: boolean, role?: string | null, createdAt: string, updatedAt: string }> } } }; +export type AdminProjectListQuery = { __typename?: 'Query', admin: { __typename?: 'AdminQueries', projectList: { __typename?: 'ProjectCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, role?: string | null, createdAt: string, updatedAt: string }> } } }; export type GetProjectObjectQueryVariables = Exact<{ projectId: Scalars['String']['input']; @@ -5880,14 +5879,14 @@ export type GetProjectQueryVariables = Exact<{ }>; -export type GetProjectQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, name: string, workspaceId?: string | null, role?: string | null, description?: string | null, visibility: SimpleProjectVisibility, allowPublicComments: boolean, createdAt: string, updatedAt: string } }; +export type GetProjectQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, name: string, workspaceId?: string | null, role?: string | null, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, createdAt: string, updatedAt: string } }; export type CreateProjectMutationVariables = Exact<{ input: ProjectCreateInput; }>; -export type CreateProjectMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', create: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: SimpleProjectVisibility, allowPublicComments: boolean, role?: string | null, createdAt: string, updatedAt: string } } }; +export type CreateProjectMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', create: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, role?: string | null, createdAt: string, updatedAt: string } } }; export type BatchDeleteProjectsMutationVariables = Exact<{ ids: Array | Scalars['String']['input']; @@ -5901,7 +5900,7 @@ export type UpdateProjectRoleMutationVariables = Exact<{ }>; -export type UpdateProjectRoleMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', updateRole: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: SimpleProjectVisibility, allowPublicComments: boolean, role?: string | null, createdAt: string, updatedAt: string } } }; +export type UpdateProjectRoleMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', updateRole: { __typename?: 'Project', id: string, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, role?: string | null, createdAt: string, updatedAt: string } } }; export type GetProjectCollaboratorsQueryVariables = Exact<{ projectId: Scalars['String']['input']; @@ -6167,7 +6166,7 @@ export type TestWorkspaceFragment = { __typename?: 'Workspace', id: string, name export type TestWorkspaceCollaboratorFragment = { __typename?: 'WorkspaceCollaborator', id: string, role: string, user: { __typename?: 'LimitedUser', name: string }, projectRoles: Array<{ __typename?: 'ProjectRole', role: string, project: { __typename?: 'Project', id: string, name: string } }> }; -export type TestWorkspaceProjectFragment = { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string }> }; +export type TestWorkspaceProjectFragment = { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string }> }; export type CreateWorkspaceMutationVariables = Exact<{ input: WorkspaceCreateInput; @@ -6226,7 +6225,7 @@ export type CreateWorkspaceProjectMutationVariables = Exact<{ }>; -export type CreateWorkspaceProjectMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', projects: { __typename?: 'WorkspaceProjectMutations', create: { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string }> } } } }; +export type CreateWorkspaceProjectMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', projects: { __typename?: 'WorkspaceProjectMutations', create: { __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string }> } } } }; export type GetWorkspaceProjectsQueryVariables = Exact<{ id: Scalars['String']['input']; @@ -6236,7 +6235,7 @@ export type GetWorkspaceProjectsQueryVariables = Exact<{ }>; -export type GetWorkspaceProjectsQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', projects: { __typename?: 'ProjectCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string }> }> } } }; +export type GetWorkspaceProjectsQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', projects: { __typename?: 'ProjectCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string }> }> } } }; export type GetWorkspaceSsoQueryVariables = Exact<{ id: Scalars['String']['input']; @@ -6282,7 +6281,7 @@ export type MoveProjectToWorkspaceMutationVariables = Exact<{ }>; -export type MoveProjectToWorkspaceMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', projects: { __typename?: 'WorkspaceProjectMutations', moveToWorkspace: { __typename?: 'Project', id: string, workspaceId?: string | null, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string }> } } } }; +export type MoveProjectToWorkspaceMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', projects: { __typename?: 'WorkspaceProjectMutations', moveToWorkspace: { __typename?: 'Project', id: string, workspaceId?: string | null, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string }> } } } }; export const BasicWorkspaceFragmentDoc = {"kind":"Document","definitions":[{"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":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]} as unknown as DocumentNode; export const BasicPendingWorkspaceCollaboratorFragmentDoc = {"kind":"Document","definitions":[{"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; @@ -6305,7 +6304,7 @@ export const BaseUserFieldsFragmentDoc = {"kind":"Document","definitions":[{"kin 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":"slug"}},{"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":"Field","name":{"kind":"Name","value":"readOnly"}},{"kind":"Field","name":{"kind":"Name","value":"discoverabilityEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]} as unknown as DocumentNode; export const TestWorkspaceCollaboratorFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspaceCollaborator"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceCollaborator"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"projectRoles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"project"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} 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"}},{"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"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"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 CreateObjectDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateObject"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ObjectCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objectCreate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"objectInput"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const PingPongDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"PingPong"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ping"}}]}}]} as unknown as DocumentNode; export const OnUserProjectsUpdatedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"OnUserProjectsUpdated"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userProjectsUpdated"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"project"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; @@ -6454,11 +6453,11 @@ export const GetActiveUserDiscoverableWorkspacesDocument = {"kind":"Document","d 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":"slug"}},{"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":"Field","name":{"kind":"Name","value":"readOnly"}},{"kind":"Field","name":{"kind":"Name","value":"discoverabilityEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]} 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":"slug"}},{"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":"Field","name":{"kind":"Name","value":"readOnly"}},{"kind":"Field","name":{"kind":"Name","value":"discoverabilityEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]} 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":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspaceCollaborator"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspaceCollaborator"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceCollaborator"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"projectRoles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"project"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} 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":"WorkspaceProjectCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projects"},"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"}},{"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 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"}},{"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":"WorkspaceProjectCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projects"},"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"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"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 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"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"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 GetWorkspaceSsoDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspaceSso"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"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":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sso"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"provider"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"session"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const GetWorkspaceTeamDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspaceTeam"},"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":"filter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceTeamFilter"}}},{"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"}}}],"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":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}},{"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"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspaceCollaborator"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspaceCollaborator"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceCollaborator"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"projectRoles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"project"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; export const ActiveUserLeaveWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ActiveUserLeaveWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"leave"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}]}}]}}]} as unknown as DocumentNode; export const ActiveUserProjectsWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveUserProjectsWorkspace"},"variableDefinitions":[{"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":"UserProjectsFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}},{"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"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"workspace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const ActiveUserExpiredSsoSessionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveUserExpiredSsoSessions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"expiredSsoSessions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode; -export const MoveProjectToWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MoveProjectToWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"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":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projects"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"moveToWorkspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"projectId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}},{"kind":"Argument","name":{"kind":"Name","value":"workspaceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"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; \ No newline at end of file +export const MoveProjectToWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MoveProjectToWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"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":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projects"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"moveToWorkspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"projectId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}},{"kind":"Argument","name":{"kind":"Name","value":"workspaceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"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; \ No newline at end of file diff --git a/packages/server/test/graphql/workspaces.ts b/packages/server/test/graphql/workspaces.ts index 7fdd080dd..26105796c 100644 --- a/packages/server/test/graphql/workspaces.ts +++ b/packages/server/test/graphql/workspaces.ts @@ -38,6 +38,7 @@ export const workspaceProjectFragment = gql` name createdAt updatedAt + visibility team { id role @@ -271,6 +272,7 @@ export const moveProjectToWorkspaceMutation = gql` moveToWorkspace(projectId: $projectId, workspaceId: $workspaceId) { id workspaceId + visibility team { id role diff --git a/packages/server/test/speckle-helpers/streamHelper.ts b/packages/server/test/speckle-helpers/streamHelper.ts index 2af82afe4..3891570ed 100644 --- a/packages/server/test/speckle-helpers/streamHelper.ts +++ b/packages/server/test/speckle-helpers/streamHelper.ts @@ -1,5 +1,6 @@ import { db } from '@/db/knex' import { StreamAcl } from '@/modules/core/dbSchema' +import { mapDbToGqlProjectVisibility } from '@/modules/core/helpers/project' import { StreamAclRecord, StreamRecord } from '@/modules/core/helpers/types' import { createBranchFactory } from '@/modules/core/repositories/branches' import { getServerInfoFactory } from '@/modules/core/repositories/server' @@ -161,7 +162,10 @@ const addOrUpdateStreamCollaborator = addOrUpdateStreamCollaboratorFactory({ export type BasicTestStream = { name: string - isPublic: boolean + /** + * @deprecated Use visibility instead + */ + isPublic?: boolean /** * The ID of the owner user. Will be filled in by createTestStream(). */ @@ -189,6 +193,13 @@ export async function createTestStream( owner: BasicTestUser ) { let id: string + + const visibility = streamObj.isPublic + ? ProjectVisibility.Public + : (streamObj.visibility + ? mapDbToGqlProjectVisibility(streamObj.visibility) + : undefined) || ProjectVisibility.Private + if (streamObj.workspaceId) { const createWorkspaceProject = createWorkspaceProjectFactory({ getDefaultRegion: getDefaultRegionFactory({ db }) @@ -197,9 +208,7 @@ export async function createTestStream( input: { name: streamObj.name || faker.commerce.productName(), description: streamObj.description, - visibility: streamObj.isPublic - ? ProjectVisibility.Public - : ProjectVisibility.Private, + visibility, workspaceId: streamObj.workspaceId }, ownerId: owner.id @@ -207,7 +216,8 @@ export async function createTestStream( id = newProject.id } else { id = await createStream({ - ...omit(streamObj, ['id', 'ownerId']), + ...omit(streamObj, ['id', 'ownerId', 'visibility']), + isPublic: visibility === ProjectVisibility.Public, ownerId: owner.id }) } diff --git a/packages/shared/src/authz/checks/projects.spec.ts b/packages/shared/src/authz/checks/projects.spec.ts index 4e4e56dab..87e99b58f 100644 --- a/packages/shared/src/authz/checks/projects.spec.ts +++ b/packages/shared/src/authz/checks/projects.spec.ts @@ -3,6 +3,7 @@ import { isPubliclyReadableProject, hasMinimumProjectRole } from './projects.js' import cryptoRandomString from 'crypto-random-string' import { Roles } from '../../core/index.js' import { getProjectFake } from '../../tests/fakes.js' +import { ProjectVisibility } from '../domain/projects/types.js' describe('project checks', () => { describe('isPubliclyReadableProject returns a function, that', () => { @@ -14,13 +15,7 @@ describe('project checks', () => { }) it('returns true for public projects', async () => { const result = await isPubliclyReadableProject({ - getProject: getProjectFake({ isPublic: true }) - })({ projectId: cryptoRandomString({ length: 10 }) }) - expect(result).toEqual(true) - }) - it('returns true for discoverable projects', async () => { - const result = await isPubliclyReadableProject({ - getProject: getProjectFake({ isDiscoverable: true }) + getProject: getProjectFake({ visibility: ProjectVisibility.Public }) })({ projectId: cryptoRandomString({ length: 10 }) }) expect(result).toEqual(true) }) diff --git a/packages/shared/src/authz/checks/projects.ts b/packages/shared/src/authz/checks/projects.ts index 4708fc97f..9c9fd73b2 100644 --- a/packages/shared/src/authz/checks/projects.ts +++ b/packages/shared/src/authz/checks/projects.ts @@ -2,6 +2,7 @@ import { StreamRoles } from '../../core/index.js' import { AuthPolicyCheck } from '../domain/policies.js' import { isMinimumProjectRole } from '../domain/logic/roles.js' import { ProjectContext, UserContext } from '../domain/context.js' +import { ProjectVisibility } from '../domain/projects/types.js' export const hasMinimumProjectRole: AuthPolicyCheck< 'getProjectRole', @@ -19,5 +20,5 @@ export const isPubliclyReadableProject: AuthPolicyCheck<'getProject', ProjectCon async ({ projectId }) => { const project = await loaders.getProject({ projectId }) if (!project) return false - return project.isPublic || project.isDiscoverable + return project.visibility === ProjectVisibility.Public } diff --git a/packages/shared/src/authz/domain/projects/types.ts b/packages/shared/src/authz/domain/projects/types.ts index 9e0be219d..6a464ce7c 100644 --- a/packages/shared/src/authz/domain/projects/types.ts +++ b/packages/shared/src/authz/domain/projects/types.ts @@ -1,12 +1,15 @@ +export const ProjectVisibility = { + Public: 'public', + Private: 'private', + Workspace: 'workspace' +} + +export type ProjectVisibility = + (typeof ProjectVisibility)[keyof typeof ProjectVisibility] + export type Project = { id: string - /** - * @deprecated - */ - isDiscoverable: boolean - isPublic: boolean + visibility: ProjectVisibility workspaceId: string | null allowPublicComments: boolean } - -export type ProjectVisibility = 'public' | 'linkShareable' | 'private' diff --git a/packages/shared/src/authz/fragments/projects.spec.ts b/packages/shared/src/authz/fragments/projects.spec.ts index bab3503f2..1928637e7 100644 --- a/packages/shared/src/authz/fragments/projects.spec.ts +++ b/packages/shared/src/authz/fragments/projects.spec.ts @@ -21,15 +21,14 @@ import { import { OverridesOf } from '../../tests/helpers/types.js' import { getProjectFake } from '../../tests/fakes.js' import { TIME_MS } from '../../core/index.js' +import { ProjectVisibility } from '../domain/projects/types.js' describe('ensureMinimumProjectRoleFragment', () => { const buildSUT = (overrides?: OverridesOf) => ensureMinimumProjectRoleFragment({ getProject: getProjectFake({ id: 'projectId', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getWorkspace: async () => null, getWorkspaceSsoProvider: async () => null, @@ -48,8 +47,7 @@ describe('ensureMinimumProjectRoleFragment', () => { getProject: getProjectFake({ id: 'projectId', workspaceId: 'workspaceId', - isDiscoverable: false, - isPublic: false + visibility: ProjectVisibility.Workspace }), getWorkspace: async () => ({ id: 'workspaceId', @@ -143,6 +141,44 @@ describe('ensureMinimumProjectRoleFragment', () => { expect(result).toBeAuthOKResult() }) + it('succeeds if user has implicit owner role even in private project', async () => { + const result = await buildWorkspaceSUT({ + getWorkspaceRole: async () => Roles.Workspace.Admin, + getProjectRole: async () => null, + getProject: getProjectFake({ + id: 'projectId', + workspaceId: 'workspaceId', + visibility: ProjectVisibility.Private + }) + })({ + userId: 'userId', + projectId: 'projectId', + role: Roles.Stream.Reviewer + }) + + expect(result).toBeAuthOKResult() + }) + + it('fails if user doesnt have explicit project role and project is private', async () => { + const result = await buildWorkspaceSUT({ + getWorkspaceRole: async () => Roles.Workspace.Member, + getProjectRole: async () => null, + getProject: getProjectFake({ + id: 'projectId', + workspaceId: 'workspaceId', + visibility: ProjectVisibility.Private + }) + })({ + userId: 'userId', + projectId: 'projectId', + role: Roles.Stream.Reviewer + }) + + expect(result).toBeAuthErrorResult({ + code: ProjectNoAccessError.code + }) + }) + it('fails if implicit role is not enough', async () => { const result = await buildWorkspaceSUT({ getWorkspaceRole: async () => Roles.Workspace.Member, @@ -167,9 +203,7 @@ describe('checkIfPubliclyReadableProjectFragment', () => { checkIfPubliclyReadableProjectFragment({ getProject: getProjectFake({ id: 'projectId', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getEnv: async () => parseFeatureFlags({}), ...overrides @@ -200,8 +234,7 @@ describe('checkIfPubliclyReadableProjectFragment', () => { getProject: getProjectFake({ id: 'projectId', workspaceId: null, - isDiscoverable: false, - isPublic: true + visibility: ProjectVisibility.Public }) }) @@ -216,9 +249,7 @@ describe('checkIfPubliclyReadableProjectFragment', () => { const sut = buildSUT({ getProject: getProjectFake({ id: 'projectId', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }) }) const result = await sut({ @@ -235,9 +266,7 @@ describe('ensureProjectWorkspaceAccessFragment', () => { ensureProjectWorkspaceAccessFragment({ getProject: getProjectFake({ id: 'projectId', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getEnv: async () => parseFeatureFlags({}), getWorkspace: async () => null, @@ -253,9 +282,7 @@ describe('ensureProjectWorkspaceAccessFragment', () => { buildSUT({ getProject: getProjectFake({ id: 'projectId', - workspaceId: 'workspaceId', - isDiscoverable: false, - isPublic: false + workspaceId: 'workspaceId' }), getWorkspace: async () => ({ id: 'workspaceId', @@ -391,9 +418,7 @@ describe('ensureImplicitProjectMemberWithReadAccessFragment', async () => { ensureImplicitProjectMemberWithReadAccessFragment({ getProject: getProjectFake({ id: 'projectId', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getAdminOverrideEnabled: async () => false, getServerRole: async () => Roles.Server.User, @@ -413,8 +438,7 @@ describe('ensureImplicitProjectMemberWithReadAccessFragment', async () => { getProject: getProjectFake({ id: 'projectId', workspaceId: 'workspaceId', - isDiscoverable: false, - isPublic: false + visibility: ProjectVisibility.Workspace }), getProjectRole: async () => null, getWorkspace: async () => ({ @@ -537,6 +561,27 @@ describe('ensureImplicitProjectMemberWithReadAccessFragment', async () => { expect(result).toBeAuthOKResult() }) + it('fails w/o explicit project role if private project', async () => { + const sut = buildWorkspaceSUT({ + getProjectRole: async () => null, + getProject: getProjectFake({ + id: 'projectId', + workspaceId: 'workspaceId', + visibility: ProjectVisibility.Private + }) + }) + + const result = await sut({ + userId: 'userId', + projectId: 'projectId', + role: Roles.Stream.Reviewer + }) + + expect(result).toBeAuthErrorResult({ + code: ProjectNoAccessError.code + }) + }) + it('succeeds w/o sso session, if workspace guest w/ explicit project role', async () => { const sut = buildWorkspaceSUT({ getWorkspaceRole: async () => Roles.Workspace.Guest, @@ -612,9 +657,7 @@ describe('ensureImplicitProjectMemberWithWriteAccessFragment', () => { ensureImplicitProjectMemberWithWriteAccessFragment({ getProject: getProjectFake({ id: 'projectId', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getServerRole: async () => Roles.Server.User, getProjectRole: async () => Roles.Stream.Contributor, @@ -633,8 +676,7 @@ describe('ensureImplicitProjectMemberWithWriteAccessFragment', () => { getProject: getProjectFake({ id: 'projectId', workspaceId: 'workspaceId', - isDiscoverable: false, - isPublic: false + visibility: ProjectVisibility.Workspace }), getProjectRole: async () => null, getWorkspace: async () => ({ diff --git a/packages/shared/src/authz/fragments/projects.ts b/packages/shared/src/authz/fragments/projects.ts index c2c8bb7d2..d35b166d1 100644 --- a/packages/shared/src/authz/fragments/projects.ts +++ b/packages/shared/src/authz/fragments/projects.ts @@ -24,11 +24,16 @@ import { checkIfAdminOverrideEnabledFragment, ensureMinimumServerRoleFragment } from './server.js' +import { ProjectVisibility } from '../domain/projects/types.js' -const workspaceRoleImplicitProjectRoleMap = { - [Roles.Workspace.Admin]: Roles.Stream.Owner, - [Roles.Workspace.Member]: Roles.Stream.Reviewer, - [Roles.Workspace.Guest]: null +const workspaceRoleImplicitProjectRoleMap = (projectVisibility: ProjectVisibility) => { + const isFullyPrivate = projectVisibility === ProjectVisibility.Private + + return { + [Roles.Workspace.Admin]: Roles.Stream.Owner, + [Roles.Workspace.Member]: isFullyPrivate ? null : Roles.Stream.Reviewer, + [Roles.Workspace.Guest]: null + } } /** @@ -79,13 +84,14 @@ export const ensureMinimumProjectRoleFragment: AuthPolicyEnsureFragment< // Now check if there's an implicit one const { workspaceId } = project + if (env.FF_WORKSPACES_MODULE_ENABLED && !!workspaceId) { // Check for implicit workspace project role const userWorkspaceRole = await loaders.getWorkspaceRole({ userId, workspaceId }) if (userWorkspaceRole) { const implicitProjectRole = explicit ? null - : workspaceRoleImplicitProjectRoleMap[userWorkspaceRole] + : workspaceRoleImplicitProjectRoleMap(project.visibility)[userWorkspaceRole] if (implicitProjectRole) { // Does it fit minimum? if (isMinimumProjectRole(implicitProjectRole, requiredProjectRole)) { diff --git a/packages/shared/src/authz/policies/project/automation/canCreate.spec.ts b/packages/shared/src/authz/policies/project/automation/canCreate.spec.ts index f56654991..e77c3a2cc 100644 --- a/packages/shared/src/authz/policies/project/automation/canCreate.spec.ts +++ b/packages/shared/src/authz/policies/project/automation/canCreate.spec.ts @@ -13,6 +13,7 @@ import { WorkspaceSsoSessionNoAccessError } from '../../../domain/authErrors.js' import { TIME_MS } from '../../../../core/index.js' +import { ProjectVisibility } from '../../../domain/projects/types.js' const buildCanCreatePolicy = ( overrides?: Partial[0]> @@ -22,8 +23,7 @@ const buildCanCreatePolicy = ( getProject: async () => ({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: false, + visibility: ProjectVisibility.Private, allowPublicComments: false }), getProjectRole: async () => Roles.Stream.Owner, @@ -131,8 +131,7 @@ describe('canCreateAutomation', () => { getProject: async () => ({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false, + visibility: ProjectVisibility.Private, allowPublicComments: false }), getWorkspace: async () => ({ @@ -176,6 +175,21 @@ describe('canCreateAutomation', () => { expect(result).toBeAuthOKResult() }) + it('returns error with implicit member role', async () => { + const canCreateAutomation = buildCanCreatePolicy({ + ...overrides, + getWorkspaceRole: async () => Roles.Workspace.Member, + getProjectRole: async () => null + }) + const result = await canCreateAutomation({ + userId: 'user-id', + projectId: 'project-id' + }) + expect(result).toBeAuthErrorResult({ + code: ProjectNoAccessError.code + }) + }) + it('returns error if no workspace role, even w/ valid project role', async () => { const canCreateAutomation = buildCanCreatePolicy({ ...overrides, diff --git a/packages/shared/src/authz/policies/project/automation/canDelete.spec.ts b/packages/shared/src/authz/policies/project/automation/canDelete.spec.ts index 26809e00e..887c254b9 100644 --- a/packages/shared/src/authz/policies/project/automation/canDelete.spec.ts +++ b/packages/shared/src/authz/policies/project/automation/canDelete.spec.ts @@ -13,6 +13,7 @@ import { WorkspaceSsoSessionNoAccessError } from '../../../domain/authErrors.js' import { TIME_MS } from '../../../../core/index.js' +import { ProjectVisibility } from '../../../domain/projects/types.js' const buildCanDeletePolicy = ( overrides?: Partial[0]> @@ -22,9 +23,8 @@ const buildCanDeletePolicy = ( getProject: async () => ({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: false, - allowPublicComments: false + allowPublicComments: false, + visibility: ProjectVisibility.Private }), getProjectRole: async () => Roles.Stream.Owner, getServerRole: async () => Roles.Server.User, @@ -131,8 +131,7 @@ describe('canDeleteAutomation', () => { getProject: async () => ({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false, + visibility: ProjectVisibility.Private, allowPublicComments: false }), getWorkspace: async () => ({ diff --git a/packages/shared/src/authz/policies/project/automation/canRead.spec.ts b/packages/shared/src/authz/policies/project/automation/canRead.spec.ts index a9bf88283..a3fa55eae 100644 --- a/packages/shared/src/authz/policies/project/automation/canRead.spec.ts +++ b/packages/shared/src/authz/policies/project/automation/canRead.spec.ts @@ -13,6 +13,7 @@ import { WorkspaceSsoSessionNoAccessError } from '../../../domain/authErrors.js' import { TIME_MS } from '../../../../core/index.js' +import { ProjectVisibility } from '../../../domain/projects/types.js' const buildCanReadAutomationPolicy = ( overrides?: OverridesOf @@ -20,9 +21,7 @@ const buildCanReadAutomationPolicy = ( canReadAutomationPolicy({ getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isPublic: false, - isDiscoverable: false + workspaceId: null }), getProjectRole: async () => Roles.Stream.Reviewer, getAdminOverrideEnabled: async () => false, @@ -125,8 +124,7 @@ describe('canReadAutomationPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isPublic: false, - isDiscoverable: false + visibility: ProjectVisibility.Workspace }), getWorkspace: getWorkspaceFake({ id: 'workspace-id' diff --git a/packages/shared/src/authz/policies/project/automation/canUpdate.spec.ts b/packages/shared/src/authz/policies/project/automation/canUpdate.spec.ts index 1e29ed311..1441fd981 100644 --- a/packages/shared/src/authz/policies/project/automation/canUpdate.spec.ts +++ b/packages/shared/src/authz/policies/project/automation/canUpdate.spec.ts @@ -13,6 +13,7 @@ import { WorkspaceSsoSessionNoAccessError } from '../../../domain/authErrors.js' import { TIME_MS } from '../../../../core/index.js' +import { ProjectVisibility } from '../../../domain/projects/types.js' const buildCanUpdatePolicy = ( overrides?: Partial[0]> @@ -22,8 +23,7 @@ const buildCanUpdatePolicy = ( getProject: async () => ({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: false, + visibility: ProjectVisibility.Private, allowPublicComments: false }), getProjectRole: async () => Roles.Stream.Owner, @@ -131,8 +131,7 @@ describe('canUpdateAutomation', () => { getProject: async () => ({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false, + visibility: ProjectVisibility.Private, allowPublicComments: false }), getWorkspace: async () => ({ diff --git a/packages/shared/src/authz/policies/project/canBroadcastActivity.spec.ts b/packages/shared/src/authz/policies/project/canBroadcastActivity.spec.ts index d2842b351..a633f8a04 100644 --- a/packages/shared/src/authz/policies/project/canBroadcastActivity.spec.ts +++ b/packages/shared/src/authz/policies/project/canBroadcastActivity.spec.ts @@ -13,6 +13,7 @@ import { WorkspaceSsoSessionNoAccessError } from '../../domain/authErrors.js' import { TIME_MS } from '../../../core/helpers/timeConstants.js' +import { ProjectVisibility } from '../../domain/projects/types.js' describe('canBroadcastProjectActivityPolicy', () => { const buildSUT = ( @@ -22,9 +23,7 @@ describe('canBroadcastProjectActivityPolicy', () => { getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getAdminOverrideEnabled: async () => false, getProjectRole: async () => Roles.Stream.Reviewer, @@ -43,8 +42,7 @@ describe('canBroadcastProjectActivityPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false + visibility: ProjectVisibility.Workspace }), getProjectRole: async () => null, getWorkspace: async () => ({ @@ -79,8 +77,7 @@ describe('canBroadcastProjectActivityPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: true + visibility: ProjectVisibility.Public }), getProjectRole: async () => null }) @@ -187,8 +184,7 @@ describe('canBroadcastProjectActivityPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: true + visibility: ProjectVisibility.Public }) }) diff --git a/packages/shared/src/authz/policies/project/canDelete.spec.ts b/packages/shared/src/authz/policies/project/canDelete.spec.ts index 12fc2198a..4a49af9e7 100644 --- a/packages/shared/src/authz/policies/project/canDelete.spec.ts +++ b/packages/shared/src/authz/policies/project/canDelete.spec.ts @@ -13,9 +13,7 @@ describe('canDeleteProjectPolicy', () => { getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getProjectRole: async () => Roles.Stream.Owner, getServerRole: async () => Roles.Server.User, @@ -32,9 +30,7 @@ describe('canDeleteProjectPolicy', () => { buildSUT({ getProject: getProjectFake({ id: 'project-id', - workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false + workspaceId: 'workspace-id' }), getWorkspace: async () => ({ id: 'workspace-id', diff --git a/packages/shared/src/authz/policies/project/canLeave.spec.ts b/packages/shared/src/authz/policies/project/canLeave.spec.ts index ff46b135e..f0b35bc4f 100644 --- a/packages/shared/src/authz/policies/project/canLeave.spec.ts +++ b/packages/shared/src/authz/policies/project/canLeave.spec.ts @@ -20,9 +20,7 @@ describe('canLeaveProjectPolicy', () => { getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getProjectRole: async () => Roles.Stream.Reviewer, getServerRole: async () => Roles.Server.Guest, @@ -38,9 +36,7 @@ describe('canLeaveProjectPolicy', () => { buildSUT({ getProject: getProjectFake({ id: 'project-id', - workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false + workspaceId: 'workspace-id' }), getProjectRole: async () => Roles.Stream.Reviewer, getWorkspace: async () => ({ diff --git a/packages/shared/src/authz/policies/project/canLoad.spec.ts b/packages/shared/src/authz/policies/project/canLoad.spec.ts index 250ab7b00..930a32d0a 100644 --- a/packages/shared/src/authz/policies/project/canLoad.spec.ts +++ b/packages/shared/src/authz/policies/project/canLoad.spec.ts @@ -12,6 +12,7 @@ import { WorkspaceSsoSessionNoAccessError } from '../../domain/authErrors.js' import { TIME_MS } from '../../../core/index.js' +import { ProjectVisibility } from '../../domain/projects/types.js' const buildCanLoadPolicy = (overrides?: Partial[0]>) => canLoadPolicy({ @@ -19,8 +20,7 @@ const buildCanLoadPolicy = (overrides?: Partial getProject: async () => ({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: false, + visibility: ProjectVisibility.Private, allowPublicComments: false }), getProjectRole: async () => Roles.Stream.Owner, @@ -114,8 +114,7 @@ describe('canLoad', () => { getProject: async () => ({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false, + visibility: ProjectVisibility.Workspace, allowPublicComments: false }), getWorkspace: async () => ({ diff --git a/packages/shared/src/authz/policies/project/canPublish.spec.ts b/packages/shared/src/authz/policies/project/canPublish.spec.ts index cfd4c31fa..7b73aff80 100644 --- a/packages/shared/src/authz/policies/project/canPublish.spec.ts +++ b/packages/shared/src/authz/policies/project/canPublish.spec.ts @@ -12,6 +12,7 @@ import { WorkspaceSsoSessionNoAccessError } from '../../domain/authErrors.js' import { TIME_MS } from '../../../core/index.js' +import { ProjectVisibility } from '../../domain/projects/types.js' const buildCanPublishPolicy = ( overrides?: Partial[0]> @@ -21,8 +22,7 @@ const buildCanPublishPolicy = ( getProject: async () => ({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: false, + visibility: ProjectVisibility.Private, allowPublicComments: false }), getProjectRole: async () => Roles.Stream.Owner, @@ -116,8 +116,7 @@ describe('canPublish', () => { getProject: async () => ({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false, + visibility: ProjectVisibility.Workspace, allowPublicComments: false }), getWorkspace: async () => ({ diff --git a/packages/shared/src/authz/policies/project/canRead.spec.ts b/packages/shared/src/authz/policies/project/canRead.spec.ts index 209c2f962..2060eef80 100644 --- a/packages/shared/src/authz/policies/project/canRead.spec.ts +++ b/packages/shared/src/authz/policies/project/canRead.spec.ts @@ -14,6 +14,7 @@ import { import { getProjectFake } from '../../../tests/fakes.js' import cryptoRandomString from 'crypto-random-string' import { AuthCheckContextLoaders } from '../../domain/loaders.js' +import { ProjectVisibility } from '../../domain/projects/types.js' const canReadProjectArgs = () => { const projectId = crs({ length: 10 }) @@ -61,7 +62,7 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { const canReadProject = canReadProjectPolicy({ getAdminOverrideEnabled: async () => false, getEnv: async () => parseFeatureFlags({}), - getProject: getProjectFake({ isPublic: true }), + getProject: getProjectFake({ visibility: ProjectVisibility.Public }), getProjectRole: () => { assert.fail() }, @@ -83,31 +84,6 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { const canQuery = await canReadProject(canReadProjectArgs()) expect(canQuery).toBeAuthOKResult() }) - it('allows anyone on a linkShareable project', async () => { - const canReadProject = canReadProjectPolicy({ - getAdminOverrideEnabled: async () => false, - getEnv: async () => parseFeatureFlags({}), - getProject: getProjectFake({ isDiscoverable: true }), - getProjectRole: () => { - assert.fail() - }, - getServerRole: () => { - assert.fail() - }, - getWorkspace, - getWorkspaceRole: () => { - assert.fail() - }, - getWorkspaceSsoSession: () => { - assert.fail() - }, - getWorkspaceSsoProvider: () => { - assert.fail() - } - }) - const canQuery = await canReadProject(canReadProjectArgs()) - expect(canQuery).toBeAuthOKResult() - }) }) describe('server roles', () => { @@ -116,7 +92,7 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { getAdminOverrideEnabled: async () => false, getEnv: async () => parseFeatureFlags({ FF_WORKSPACES_MODULE_ENABLED: 'false' }), - getProject: getProjectFake({ isDiscoverable: false, isPublic: true }), + getProject: getProjectFake({ visibility: ProjectVisibility.Public }), getProjectRole: async () => Roles.Stream.Owner, getServerRole: async () => Roles.Server.ArchivedUser, getWorkspace, @@ -138,7 +114,7 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { getAdminOverrideEnabled: async () => false, getEnv: async () => parseFeatureFlags({ FF_WORKSPACES_MODULE_ENABLED: 'false' }), - getProject: getProjectFake({ isDiscoverable: false, isPublic: false }), + getProject: getProjectFake({}), getProjectRole: async () => Roles.Stream.Owner, getServerRole: async () => Roles.Server.ArchivedUser, getWorkspace, @@ -162,7 +138,7 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { getAdminOverrideEnabled: async () => false, getEnv: async () => parseFeatureFlags({ FF_WORKSPACES_MODULE_ENABLED: 'false' }), - getProject: getProjectFake({ isDiscoverable: false, isPublic: false }), + getProject: getProjectFake({}), getProjectRole: async () => Roles.Stream.Owner, getServerRole: async () => null, getWorkspace, @@ -192,7 +168,7 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { getAdminOverrideEnabled: async () => false, getEnv: async () => parseFeatureFlags({ FF_WORKSPACES_MODULE_ENABLED: 'false' }), - getProject: getProjectFake({ isDiscoverable: false, isPublic: false }), + getProject: getProjectFake({}), getProjectRole: async () => role, getServerRole: async () => Roles.Server.User, getWorkspace, @@ -216,7 +192,7 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { getAdminOverrideEnabled: async () => false, getEnv: async () => parseFeatureFlags({ FF_WORKSPACES_MODULE_ENABLED: 'false' }), - getProject: getProjectFake({ isDiscoverable: false, isPublic: false }), + getProject: getProjectFake({}), getProjectRole: async () => null, getWorkspace, getServerRole: async () => Roles.Server.Admin, @@ -241,7 +217,7 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { const result = canReadProjectPolicy({ getAdminOverrideEnabled: async () => true, getEnv: async () => parseFeatureFlags({}), - getProject: getProjectFake({ isDiscoverable: false, isPublic: false }), + getProject: getProjectFake({}), getServerRole: async () => Roles.Server.Admin, getProjectRole: () => { assert.fail() @@ -268,7 +244,7 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { parseFeatureFlags({ FF_WORKSPACES_MODULE_ENABLED: 'false' }), - getProject: getProjectFake({ isDiscoverable: false, isPublic: false }), + getProject: getProjectFake({}), getServerRole: async () => Roles.Server.Admin, getProjectRole: async () => null, getWorkspace, @@ -296,8 +272,6 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { getEnv: async () => parseFeatureFlags({ FF_WORKSPACES_MODULE_ENABLED: 'false' }), getProject: getProjectFake({ - isDiscoverable: false, - isPublic: false, workspaceId: crs({ length: 10 }) }), getProjectRole: async () => Roles.Stream.Contributor, @@ -325,8 +299,6 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { FF_WORKSPACES_MODULE_ENABLED: 'true' }), getProject: getProjectFake({ - isDiscoverable: false, - isPublic: false, workspaceId: crs({ length: 10 }) }), getProjectRole: async () => Roles.Stream.Contributor, @@ -347,7 +319,7 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { }) }) - it('allows project access via workspace role if user does not have project role', async () => { + it('allows project access via workspace admin role if user does not have project role, even if private project', async () => { const result = canReadProjectPolicy({ getAdminOverrideEnabled: async () => false, getEnv: async () => @@ -355,9 +327,8 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { FF_WORKSPACES_MODULE_ENABLED: 'true' }), getProject: getProjectFake({ - isDiscoverable: false, - isPublic: false, - workspaceId: crs({ length: 10 }) + workspaceId: crs({ length: 10 }), + visibility: ProjectVisibility.Private }), getProjectRole: async () => null, getServerRole: async () => Roles.Server.User, @@ -371,6 +342,31 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { await expect(result).resolves.toBeAuthOKResult() }) + + it('allows project access via workspace role if user does not have project role on workspace visibility', async () => { + const result = canReadProjectPolicy({ + getAdminOverrideEnabled: async () => false, + getEnv: async () => + parseFeatureFlags({ + FF_WORKSPACES_MODULE_ENABLED: 'true' + }), + getProject: getProjectFake({ + workspaceId: crs({ length: 10 }), + visibility: ProjectVisibility.Workspace + }), + getProjectRole: async () => null, + getServerRole: async () => Roles.Server.User, + getWorkspaceRole: async () => Roles.Workspace.Member, + getWorkspaceSsoSession: () => { + assert.fail() + }, + getWorkspace, + getWorkspaceSsoProvider: async () => null + })(canReadProjectArgs()) + + await expect(result).resolves.toBeAuthOKResult() + }) + it('does not check SSO sessions if user is workspace guest', async () => { const result = canReadProjectPolicy({ getAdminOverrideEnabled: async () => false, @@ -379,8 +375,6 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { FF_WORKSPACES_MODULE_ENABLED: 'true' }), getProject: getProjectFake({ - isDiscoverable: false, - isPublic: false, workspaceId: crs({ length: 10 }) }), getProjectRole: async () => Roles.Stream.Contributor, @@ -405,8 +399,6 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { FF_WORKSPACES_MODULE_ENABLED: 'true' }), getProject: getProjectFake({ - isDiscoverable: false, - isPublic: false, workspaceId: crs({ length: 10 }) }), getProjectRole: async () => Roles.Stream.Contributor, @@ -429,8 +421,6 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { FF_WORKSPACES_MODULE_ENABLED: 'true' }), getProject: getProjectFake({ - isDiscoverable: false, - isPublic: false, workspaceId: crs({ length: 10 }) }), getProjectRole: async () => Roles.Stream.Contributor, @@ -457,8 +447,6 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { FF_WORKSPACES_MODULE_ENABLED: 'true' }), getProject: getProjectFake({ - isDiscoverable: false, - isPublic: false, workspaceId: crs({ length: 10 }) }), getProjectRole: async () => Roles.Stream.Contributor, @@ -485,8 +473,6 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { FF_WORKSPACES_MODULE_ENABLED: 'true' }), getProject: getProjectFake({ - isDiscoverable: false, - isPublic: false, workspaceId: crs({ length: 10 }) }), getProjectRole: async () => Roles.Stream.Contributor, @@ -517,8 +503,6 @@ describe('canReadProjectPolicy creates a function, that handles ', () => { FF_WORKSPACES_MODULE_ENABLED: 'true' }), getProject: getProjectFake({ - isDiscoverable: false, - isPublic: false, workspaceId: crs({ length: 10 }) }), getProjectRole: async () => Roles.Stream.Contributor, diff --git a/packages/shared/src/authz/policies/project/canReadSettings.spec.ts b/packages/shared/src/authz/policies/project/canReadSettings.spec.ts index 48805184f..9775da2b9 100644 --- a/packages/shared/src/authz/policies/project/canReadSettings.spec.ts +++ b/packages/shared/src/authz/policies/project/canReadSettings.spec.ts @@ -12,6 +12,7 @@ import { } from '../../domain/authErrors.js' import { getProjectFake } from '../../../tests/fakes.js' import { TIME_MS } from '../../../core/helpers/timeConstants.js' +import { ProjectVisibility } from '../../domain/projects/types.js' describe('canReadProjectSettingsPolicy', () => { const buildSUT = (overrides?: OverridesOf) => @@ -19,9 +20,7 @@ describe('canReadProjectSettingsPolicy', () => { getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getAdminOverrideEnabled: async () => false, getProjectRole: async () => Roles.Stream.Reviewer, @@ -40,8 +39,7 @@ describe('canReadProjectSettingsPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false + visibility: ProjectVisibility.Workspace }), getProjectRole: async () => null, getWorkspace: async () => ({ diff --git a/packages/shared/src/authz/policies/project/canReadWebhooks.spec.ts b/packages/shared/src/authz/policies/project/canReadWebhooks.spec.ts index af70bdbd5..71d335e63 100644 --- a/packages/shared/src/authz/policies/project/canReadWebhooks.spec.ts +++ b/packages/shared/src/authz/policies/project/canReadWebhooks.spec.ts @@ -13,6 +13,7 @@ import { import { canReadProjectWebhooksPolicy } from './canReadWebhooks.js' import { getProjectFake } from '../../../tests/fakes.js' import { TIME_MS } from '../../../core/helpers/timeConstants.js' +import { ProjectVisibility } from '../../domain/projects/types.js' describe('canReadProjectWebhooksPolicy', () => { const buildSUT = (overrides?: OverridesOf) => @@ -20,9 +21,7 @@ describe('canReadProjectWebhooksPolicy', () => { getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getAdminOverrideEnabled: async () => false, getProjectRole: async () => Roles.Stream.Owner, @@ -41,8 +40,7 @@ describe('canReadProjectWebhooksPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false + visibility: ProjectVisibility.Workspace }), getProjectRole: async () => null, getWorkspace: async () => ({ diff --git a/packages/shared/src/authz/policies/project/canUpdate.spec.ts b/packages/shared/src/authz/policies/project/canUpdate.spec.ts index 5bcae5760..24bb96318 100644 --- a/packages/shared/src/authz/policies/project/canUpdate.spec.ts +++ b/packages/shared/src/authz/policies/project/canUpdate.spec.ts @@ -21,9 +21,7 @@ const buildSUT = (overrides?: Partial[ getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getProjectRole: async () => Roles.Stream.Owner, getServerRole: async () => Roles.Server.User, @@ -40,9 +38,7 @@ const buildWorkspaceSUT = ( buildSUT({ getProject: getProjectFake({ id: 'project-id', - workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false + workspaceId: 'workspace-id' }), getWorkspace: async () => ({ id: 'workspace-id', diff --git a/packages/shared/src/authz/policies/project/canUpdateAllowPublicComments.spec.ts b/packages/shared/src/authz/policies/project/canUpdateAllowPublicComments.spec.ts index 9d0b6d57b..eb4a465e0 100644 --- a/packages/shared/src/authz/policies/project/canUpdateAllowPublicComments.spec.ts +++ b/packages/shared/src/authz/policies/project/canUpdateAllowPublicComments.spec.ts @@ -5,6 +5,7 @@ import { parseFeatureFlags } from '../../../environment/index.js' import { Roles } from '../../../core/constants.js' import { ProjectNoAccessError } from '../../domain/authErrors.js' import { getProjectFake } from '../../../tests/fakes.js' +import { ProjectVisibility } from '../../domain/projects/types.js' describe('canUpdateProjectAllowPublicCommentsPolicy', () => { const buildSUT = ( @@ -15,8 +16,7 @@ describe('canUpdateProjectAllowPublicCommentsPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: true + visibility: ProjectVisibility.Public }), getProjectRole: async () => Roles.Stream.Owner, getServerRole: async () => Roles.Server.User, @@ -38,24 +38,6 @@ describe('canUpdateProjectAllowPublicCommentsPolicy', () => { expect(result).toBeOKResult() }) - it('succeeds if discoverable project', async () => { - const sut = buildSUT({ - getProject: getProjectFake({ - id: 'project-id', - workspaceId: null, - isDiscoverable: true, - isPublic: false - }) - }) - - const result = await sut({ - userId: 'user-id', - projectId: 'project-id' - }) - - expect(result).toBeOKResult() - }) - it("fails if can't update at all", async () => { const sut = buildSUT({ getProjectRole: async () => null @@ -71,13 +53,12 @@ describe('canUpdateProjectAllowPublicCommentsPolicy', () => { }) }) - it('fails if project is neither public nor discoverable', async () => { + it('fails if project is not public', async () => { const sut = buildSUT({ getProject: getProjectFake({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: false + visibility: ProjectVisibility.Private }) }) diff --git a/packages/shared/src/authz/policies/project/canUpdateAllowPublicComments.ts b/packages/shared/src/authz/policies/project/canUpdateAllowPublicComments.ts index 74a94399a..d9ca32838 100644 --- a/packages/shared/src/authz/policies/project/canUpdateAllowPublicComments.ts +++ b/packages/shared/src/authz/policies/project/canUpdateAllowPublicComments.ts @@ -14,6 +14,7 @@ import { WorkspaceSsoSessionNoAccessError } from '../../domain/authErrors.js' import { canUpdateProjectPolicy } from './canUpdate.js' +import { ProjectVisibility } from '../../domain/projects/types.js' export const canUpdateProjectAllowPublicCommentsPolicy: AuthPolicy< | typeof Loaders.getProject @@ -54,7 +55,7 @@ export const canUpdateProjectAllowPublicCommentsPolicy: AuthPolicy< return err(new ProjectNotFoundError()) } - const isPublic = project.isPublic || project.isDiscoverable + const isPublic = project.visibility === ProjectVisibility.Public return isPublic ? ok() : err( diff --git a/packages/shared/src/authz/policies/project/comment/canArchive.spec.ts b/packages/shared/src/authz/policies/project/comment/canArchive.spec.ts index df27e2f10..6a6fe00e1 100644 --- a/packages/shared/src/authz/policies/project/comment/canArchive.spec.ts +++ b/packages/shared/src/authz/policies/project/comment/canArchive.spec.ts @@ -13,6 +13,7 @@ import { WorkspaceSsoSessionNoAccessError } from '../../../domain/authErrors.js' import { TIME_MS } from '../../../../core/helpers/timeConstants.js' +import { ProjectVisibility } from '../../../domain/projects/types.js' describe('canArchiveProjectCommentPolicy', () => { const buildSUT = (overrides?: OverridesOf) => @@ -20,9 +21,7 @@ describe('canArchiveProjectCommentPolicy', () => { getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getProjectRole: async () => Roles.Stream.Reviewer, getServerRole: async () => Roles.Server.User, @@ -45,9 +44,8 @@ describe('canArchiveProjectCommentPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false, - allowPublicComments: false + allowPublicComments: false, + visibility: ProjectVisibility.Workspace }), getProjectRole: async () => null, getWorkspace: async () => ({ diff --git a/packages/shared/src/authz/policies/project/comment/canCreate.spec.ts b/packages/shared/src/authz/policies/project/comment/canCreate.spec.ts index 9c09bc4c9..4a72ae657 100644 --- a/packages/shared/src/authz/policies/project/comment/canCreate.spec.ts +++ b/packages/shared/src/authz/policies/project/comment/canCreate.spec.ts @@ -12,6 +12,7 @@ import { WorkspaceSsoSessionNoAccessError } from '../../../domain/authErrors.js' import { TIME_MS } from '../../../../core/helpers/timeConstants.js' +import { ProjectVisibility } from '../../../domain/projects/types.js' describe('canCreateProjectCommentPolicy', () => { const buildSUT = (overrides?: OverridesOf) => @@ -19,9 +20,7 @@ describe('canCreateProjectCommentPolicy', () => { getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getProjectRole: async () => Roles.Stream.Reviewer, getServerRole: async () => Roles.Server.User, @@ -39,9 +38,8 @@ describe('canCreateProjectCommentPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false, - allowPublicComments: false + allowPublicComments: false, + visibility: ProjectVisibility.Workspace }), getProjectRole: async () => null, getWorkspace: async () => ({ @@ -76,8 +74,7 @@ describe('canCreateProjectCommentPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: true, + visibility: ProjectVisibility.Public, allowPublicComments: true }), getProjectRole: async () => null @@ -112,8 +109,7 @@ describe('canCreateProjectCommentPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: true, + visibility: ProjectVisibility.Public, allowPublicComments: false }) }) diff --git a/packages/shared/src/authz/policies/project/comment/canCreate.ts b/packages/shared/src/authz/policies/project/comment/canCreate.ts index c8b3e4469..aabb90a05 100644 --- a/packages/shared/src/authz/policies/project/comment/canCreate.ts +++ b/packages/shared/src/authz/policies/project/comment/canCreate.ts @@ -16,6 +16,7 @@ import { } from '../../../domain/authErrors.js' import { ensureImplicitProjectMemberWithWriteAccessFragment } from '../../../fragments/projects.js' import { Roles } from '../../../../core/constants.js' +import { ProjectVisibility } from '../../../domain/projects/types.js' export const canCreateProjectCommentPolicy: AuthPolicy< | typeof Loaders.getProject @@ -53,7 +54,7 @@ export const canCreateProjectCommentPolicy: AuthPolicy< const project = await loaders.getProject({ projectId }) if (!project) return err(new ProjectNotFoundError()) const allowPublicCommenting = - (project.isPublic || project.isDiscoverable) && project.allowPublicComments + project.visibility === ProjectVisibility.Public && project.allowPublicComments if (allowPublicCommenting) return ok() // Not public, ensure proper project write access diff --git a/packages/shared/src/authz/policies/project/comment/canEdit.spec.ts b/packages/shared/src/authz/policies/project/comment/canEdit.spec.ts index 068ac2100..102f3b9bc 100644 --- a/packages/shared/src/authz/policies/project/comment/canEdit.spec.ts +++ b/packages/shared/src/authz/policies/project/comment/canEdit.spec.ts @@ -14,6 +14,7 @@ import { } from '../../../domain/authErrors.js' import { canEditProjectCommentPolicy } from './canEdit.js' import { TIME_MS } from '../../../../core/helpers/timeConstants.js' +import { ProjectVisibility } from '../../../domain/projects/types.js' describe('canEditProjectCommentPolicy', () => { const buildSUT = (overrides?: OverridesOf) => @@ -21,9 +22,7 @@ describe('canEditProjectCommentPolicy', () => { getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getProjectRole: async () => Roles.Stream.Reviewer, getServerRole: async () => Roles.Server.User, @@ -46,9 +45,8 @@ describe('canEditProjectCommentPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false, - allowPublicComments: false + allowPublicComments: false, + visibility: ProjectVisibility.Workspace }), getProjectRole: async () => null, getWorkspace: async () => ({ @@ -84,8 +82,7 @@ describe('canEditProjectCommentPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: true, + visibility: ProjectVisibility.Public, allowPublicComments: true }), getProjectRole: async () => null @@ -160,8 +157,7 @@ describe('canEditProjectCommentPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: null, - isDiscoverable: false, - isPublic: true, + visibility: ProjectVisibility.Public, allowPublicComments: false }) }) diff --git a/packages/shared/src/authz/policies/project/model/canCreate.spec.ts b/packages/shared/src/authz/policies/project/model/canCreate.spec.ts index 3727f436a..882c7773e 100644 --- a/packages/shared/src/authz/policies/project/model/canCreate.spec.ts +++ b/packages/shared/src/authz/policies/project/model/canCreate.spec.ts @@ -23,8 +23,6 @@ const buildCanCreateModelPolicy = ( getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: cryptoRandomString({ length: 9 }), - isPublic: false, - isDiscoverable: false, workspaceId: cryptoRandomString({ length: 9 }) }), getProjectRole: async () => { diff --git a/packages/shared/src/authz/policies/project/model/canDelete.spec.ts b/packages/shared/src/authz/policies/project/model/canDelete.spec.ts index b07789a94..3bd1c94f1 100644 --- a/packages/shared/src/authz/policies/project/model/canDelete.spec.ts +++ b/packages/shared/src/authz/policies/project/model/canDelete.spec.ts @@ -20,9 +20,7 @@ const buildSUT = (overrides?: Partial[0] getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getModel: getModelFake({ id: 'model-id', @@ -45,9 +43,7 @@ const buildWorkspaceSUT = ( buildSUT({ getProject: getProjectFake({ id: 'project-id', - workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false + workspaceId: 'workspace-id' }), getWorkspace: async () => ({ id: 'workspace-id', diff --git a/packages/shared/src/authz/policies/project/model/canUpdate.spec.ts b/packages/shared/src/authz/policies/project/model/canUpdate.spec.ts index c1d7d6ec6..56387f3bc 100644 --- a/packages/shared/src/authz/policies/project/model/canUpdate.spec.ts +++ b/packages/shared/src/authz/policies/project/model/canUpdate.spec.ts @@ -18,9 +18,7 @@ const buildSUT = (overrides?: Partial[0] getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getProjectRole: async () => Roles.Stream.Contributor, getServerRole: async () => Roles.Server.User, @@ -37,9 +35,7 @@ const buildWorkspaceSUT = ( buildSUT({ getProject: getProjectFake({ id: 'project-id', - workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false + workspaceId: 'workspace-id' }), getWorkspace: async () => ({ id: 'workspace-id', diff --git a/packages/shared/src/authz/policies/project/version/canCreate.spec.ts b/packages/shared/src/authz/policies/project/version/canCreate.spec.ts index 68c74f997..60246166d 100644 --- a/packages/shared/src/authz/policies/project/version/canCreate.spec.ts +++ b/packages/shared/src/authz/policies/project/version/canCreate.spec.ts @@ -14,15 +14,14 @@ import { } from '../../../domain/authErrors.js' import { canCreateProjectVersionPolicy } from './canCreate.js' import { TIME_MS } from '../../../../core/index.js' +import { ProjectVisibility } from '../../../domain/projects/types.js' -describe('canReceiveProjectVersionPolicy', () => { +describe('canCreateProjectVersionPolicy', () => { const buildSUT = (overrides?: OverridesOf) => canCreateProjectVersionPolicy({ getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isPublic: false, - isDiscoverable: false + workspaceId: null }), getProjectRole: async () => Roles.Stream.Contributor, getEnv: async () => parseFeatureFlags({}), @@ -41,8 +40,7 @@ describe('canReceiveProjectVersionPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isPublic: false, - isDiscoverable: false + visibility: ProjectVisibility.Workspace }), getWorkspace: getWorkspaceFake({ id: 'workspace-id' diff --git a/packages/shared/src/authz/policies/project/version/canReceive.spec.ts b/packages/shared/src/authz/policies/project/version/canReceive.spec.ts index b69a392ae..bb469ec28 100644 --- a/packages/shared/src/authz/policies/project/version/canReceive.spec.ts +++ b/packages/shared/src/authz/policies/project/version/canReceive.spec.ts @@ -13,15 +13,14 @@ import { } from '../../../domain/authErrors.js' import { canReceiveProjectVersionPolicy } from './canReceive.js' import { TIME_MS } from '../../../../core/index.js' +import { ProjectVisibility } from '../../../domain/projects/types.js' describe('canReceiveProjectVersionPolicy', () => { const buildSUT = (overrides?: OverridesOf) => canReceiveProjectVersionPolicy({ getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isPublic: false, - isDiscoverable: false + workspaceId: null }), getProjectRole: async () => Roles.Stream.Reviewer, getEnv: async () => parseFeatureFlags({}), @@ -40,8 +39,7 @@ describe('canReceiveProjectVersionPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isPublic: false, - isDiscoverable: false + visibility: ProjectVisibility.Workspace }), getWorkspace: getWorkspaceFake({ id: 'workspace-id' diff --git a/packages/shared/src/authz/policies/project/version/canRequestRender.spec.ts b/packages/shared/src/authz/policies/project/version/canRequestRender.spec.ts index 47e0d4a31..c11357cc0 100644 --- a/packages/shared/src/authz/policies/project/version/canRequestRender.spec.ts +++ b/packages/shared/src/authz/policies/project/version/canRequestRender.spec.ts @@ -13,6 +13,7 @@ import { WorkspaceSsoSessionNoAccessError } from '../../../domain/authErrors.js' import { TIME_MS } from '../../../../core/index.js' +import { ProjectVisibility } from '../../../domain/projects/types.js' describe('canRequestProjectVersionRenderPolicy', () => { const buildSUT = ( @@ -21,9 +22,7 @@ describe('canRequestProjectVersionRenderPolicy', () => { canRequestProjectVersionRenderPolicy({ getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isPublic: false, - isDiscoverable: false + workspaceId: null }), getProjectRole: async () => Roles.Stream.Reviewer, getAdminOverrideEnabled: async () => false, @@ -43,8 +42,7 @@ describe('canRequestProjectVersionRenderPolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isPublic: false, - isDiscoverable: false + visibility: ProjectVisibility.Workspace }), getWorkspace: getWorkspaceFake({ id: 'workspace-id' diff --git a/packages/shared/src/authz/policies/project/version/canUpdate.spec.ts b/packages/shared/src/authz/policies/project/version/canUpdate.spec.ts index a8aa405b0..9d4ec59d1 100644 --- a/packages/shared/src/authz/policies/project/version/canUpdate.spec.ts +++ b/packages/shared/src/authz/policies/project/version/canUpdate.spec.ts @@ -22,9 +22,7 @@ const buildSUT = (overrides?: OverridesOf) getEnv: async () => parseFeatureFlags({}), getProject: getProjectFake({ id: 'project-id', - workspaceId: null, - isDiscoverable: false, - isPublic: false + workspaceId: null }), getVersion: getVersionFake({ id: 'version-id', @@ -46,9 +44,7 @@ const buildWorkspaceSUT = ( buildSUT({ getProject: getProjectFake({ id: 'project-id', - workspaceId: 'workspace-id', - isDiscoverable: false, - isPublic: false + workspaceId: 'workspace-id' }), getWorkspace: async () => ({ id: 'workspace-id', diff --git a/packages/shared/src/authz/policies/workspace/canReceiveProjectsUpdatedMessage.spec.ts b/packages/shared/src/authz/policies/workspace/canReceiveProjectsUpdatedMessage.spec.ts index 05f321f89..c9388dfe5 100644 --- a/packages/shared/src/authz/policies/workspace/canReceiveProjectsUpdatedMessage.spec.ts +++ b/packages/shared/src/authz/policies/workspace/canReceiveProjectsUpdatedMessage.spec.ts @@ -10,6 +10,7 @@ import { ServerNoSessionError, WorkspaceNoAccessError } from '../../domain/authErrors.js' +import { ProjectVisibility } from '../../domain/projects/types.js' describe('canReceiveWorkspaceProjectsUpdatedMessagePolicy', () => { const buildSUT = ( @@ -20,8 +21,7 @@ describe('canReceiveWorkspaceProjectsUpdatedMessagePolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: 'workspace-id', - isDiscoverable: true, - isPublic: true + visibility: ProjectVisibility.Public }), getProjectRole: async () => Roles.Stream.Reviewer, getServerRole: async () => Roles.Server.Guest, @@ -73,8 +73,7 @@ describe('canReceiveWorkspaceProjectsUpdatedMessagePolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: null, - isDiscoverable: true, - isPublic: true + visibility: ProjectVisibility.Public }), getProjectRole: async () => null }) @@ -95,8 +94,7 @@ describe('canReceiveWorkspaceProjectsUpdatedMessagePolicy', () => { getProject: getProjectFake({ id: 'project-id', workspaceId: null, - isDiscoverable: true, - isPublic: true + visibility: ProjectVisibility.Public }), getServerRole: async () => null }) diff --git a/packages/shared/src/tests/fakes.ts b/packages/shared/src/tests/fakes.ts index 6bf2dcf47..2d5d86b32 100644 --- a/packages/shared/src/tests/fakes.ts +++ b/packages/shared/src/tests/fakes.ts @@ -1,5 +1,5 @@ import { merge } from '#lodash' -import { Project } from '../authz/domain/projects/types.js' +import { Project, ProjectVisibility } from '../authz/domain/projects/types.js' import { Comment } from '../authz/domain/comments/types.js' import { nanoid } from 'nanoid' import { Model } from '../authz/domain/models/types.js' @@ -19,8 +19,7 @@ export const fakeGetFactory = export const getProjectFake = fakeGetFactory(() => ({ id: nanoid(10), - isPublic: false, - isDiscoverable: false, + visibility: ProjectVisibility.Private, workspaceId: null, allowPublicComments: false }))