From 7e4e66229a717d0cb2c4219fc4561268ef206fd9 Mon Sep 17 00:00:00 2001 From: astone123 Date: Tue, 16 Sep 2025 14:20:47 -0400 Subject: [PATCH 1/4] chore: (studio) pass UserProjectStatusStore to cloud studio --- packages/app/src/runner/SpecRunnerOpenMode.vue | 4 ++++ packages/app/src/studio/StudioPanel.vue | 2 ++ packages/app/src/studio/studio-app-types.ts | 3 +++ 3 files changed, 9 insertions(+) diff --git a/packages/app/src/runner/SpecRunnerOpenMode.vue b/packages/app/src/runner/SpecRunnerOpenMode.vue index 7973e56d0a9..8650dc8696e 100644 --- a/packages/app/src/runner/SpecRunnerOpenMode.vue +++ b/packages/app/src/runner/SpecRunnerOpenMode.vue @@ -98,6 +98,7 @@ :event-manager="eventManager" :studio-status="studioStatus" :aut-url-selector="autUrlSelector" + :user-project-status-store="userProjectStatusStore" /> @@ -136,6 +137,7 @@ import { runnerConstants } from './runner-constants' import { useStudioStore } from '../store/studio-store' import StudioPanel from '../studio/StudioPanel.vue' import { useSubscription } from '../graphql' +import { useUserProjectStatusStore } from '@packages/frontend-shared/src/store/user-project-status-store' // this is used by the StudioPanel to access the AUT URL input const autUrlSelector = '.aut-url-input' @@ -149,6 +151,8 @@ const { collapsedNavBarWidth, } = runnerConstants +const userProjectStatusStore = useUserProjectStatusStore() + gql` fragment SpecRunner_Preferences on Query { localSettings { diff --git a/packages/app/src/studio/StudioPanel.vue b/packages/app/src/studio/StudioPanel.vue index 2db464af37a..f7e80ea4777 100644 --- a/packages/app/src/studio/StudioPanel.vue +++ b/packages/app/src/studio/StudioPanel.vue @@ -53,6 +53,7 @@ const props = defineProps<{ studioStatus: string | null cloudStudioSessionId?: string autUrlSelector: string + userProjectStatusStore: UserProjectStatusStore }>() interface StudioApp { default: StudioAppDefaultShape } @@ -79,6 +80,7 @@ const maybeRenderReactComponent = () => { onStudioPanelClose: props.onStudioPanelClose, studioSessionId: props.cloudStudioSessionId, autUrlSelector: props.autUrlSelector, + userProjectStatusStore: props.userProjectStatusStore, }) // Store the react root in a weak map keyed by the container. We do this so that we have a reference diff --git a/packages/app/src/studio/studio-app-types.ts b/packages/app/src/studio/studio-app-types.ts index c8a529f0811..a6fef621854 100644 --- a/packages/app/src/studio/studio-app-types.ts +++ b/packages/app/src/studio/studio-app-types.ts @@ -2,6 +2,8 @@ // `studio` bundle. It is downloaded and copied to the app. // It should not be modified directly in the app. +import { UserProjectStatusStore } from '@cy/store/user-project-status-store' + export type RecordingState = 'recording' | 'paused' | 'disabled' export interface StudioPanelProps { @@ -13,6 +15,7 @@ export interface StudioPanelProps { useCypress?: CypressShape autUrlSelector?: string studioAiAvailable?: boolean + userProjectStatusStore: UserProjectStatusStore } export type StudioPanelShape = (props: StudioPanelProps) => JSX.Element From b4cd6c6da7c726993c3ebb08c2c2f02c853887ba Mon Sep 17 00:00:00 2001 From: astone123 Date: Tue, 23 Sep 2025 15:13:16 -0400 Subject: [PATCH 2/4] add project request access mutation --- .../app/src/runner/SpecRunnerOpenMode.vue | 36 ++++++++++++++++++- packages/app/src/studio/StudioPanel.vue | 6 +++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/app/src/runner/SpecRunnerOpenMode.vue b/packages/app/src/runner/SpecRunnerOpenMode.vue index 8650dc8696e..977d23718ca 100644 --- a/packages/app/src/runner/SpecRunnerOpenMode.vue +++ b/packages/app/src/runner/SpecRunnerOpenMode.vue @@ -99,6 +99,8 @@ :studio-status="studioStatus" :aut-url-selector="autUrlSelector" :user-project-status-store="userProjectStatusStore" + :has-requested-project-access="hasRequestedProjectAccess" + :request-project-access-mutation="requestProjectAccessMutation" /> @@ -123,7 +125,7 @@ import ScreenshotHelperPixels from './screenshot/ScreenshotHelperPixels.vue' import { useScreenshotStore } from '../store/screenshot-store' import ChooseExternalEditorModal from '@packages/frontend-shared/src/gql-components/ChooseExternalEditorModal.vue' import { useMutation, gql } from '@urql/vue' -import { SpecRunnerOpenMode_OpenFileInIdeDocument, StudioStatus_ChangeDocument } from '../generated/graphql' +import { SpecRunnerOpenMode_OpenFileInIdeDocument, StudioStatus_ChangeDocument, SpecRunner_Studio_RequestAccessDocument } from '../generated/graphql' import type { SpecRunnerFragment } from '../generated/graphql' import { usePreferences } from '../composables/usePreferences' import ScriptError from './ScriptError.vue' @@ -171,6 +173,32 @@ fragment SpecRunner_Preferences on Query { gql` fragment SpecRunner_Studio on Query { cloudStudioRequested + currentProject { + id + projectId + cloudProject { + __typename + ... on CloudProjectUnauthorized { + message + hasRequestedAccess + } + ... on CloudProject { + id + } + } + } +} +` + +gql` +mutation SpecRunner_Studio_RequestAccess( $projectId: String! ) { + cloudProjectRequestAccess(projectSlug: $projectId) { + __typename + ... on CloudProjectUnauthorized { + message + hasRequestedAccess + } + } } ` @@ -236,6 +264,12 @@ const { const studioStore = useStudioStore() +const hasRequestedProjectAccess = computed(() => { + return props.gql.currentProject?.cloudProject?.__typename === 'CloudProjectUnauthorized' && props.gql.currentProject?.cloudProject?.hasRequestedAccess +}) + +const requestProjectAccessMutation = useMutation(SpecRunner_Studio_RequestAccessDocument) + const handleStudioPanelClose = () => { eventManager.emit('studio:cancel', undefined) } diff --git a/packages/app/src/studio/StudioPanel.vue b/packages/app/src/studio/StudioPanel.vue index f7e80ea4777..55349fd8ad6 100644 --- a/packages/app/src/studio/StudioPanel.vue +++ b/packages/app/src/studio/StudioPanel.vue @@ -27,7 +27,7 @@