feat(fe2): show custom data residency restriction disclaimer (#3605)
* move to workspace disclaimer * disclaimer added everywhere * cleanup * copy update * Update copy --------- Co-authored-by: Benjamin Ottensten <benjamin.ottensten@gmail.com>
This commit is contained in:
committed by
GitHub
parent
c68090a041
commit
16897b86cb
@@ -6,7 +6,7 @@
|
||||
:size-limit="maxSizeInBytes"
|
||||
:accept="accept"
|
||||
class="flex items-center h-full"
|
||||
@files-selected="onFilesSelected"
|
||||
@files-selected="triggerAction"
|
||||
>
|
||||
<div
|
||||
class="w-full h-full border-dashed border rounded-md p-4 flex items-center justify-center text-sm"
|
||||
@@ -42,6 +42,12 @@
|
||||
file here.
|
||||
</span>
|
||||
</div>
|
||||
<WorkspaceRegionStaticDataDisclaimer
|
||||
v-if="showRegionStaticDataDisclaimer"
|
||||
v-model:open="showRegionStaticDataDisclaimer"
|
||||
:variant="RegionStaticDataDisclaimerVariant.UploadModel"
|
||||
@confirm="onConfirmHandler"
|
||||
/>
|
||||
</FormFileUploadZone>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@@ -50,6 +56,10 @@ import { useFileUploadProgressCore } from '~~/lib/form/composables/fileUpload'
|
||||
import { ExclamationTriangleIcon } from '@heroicons/vue/24/solid'
|
||||
import { downloadManagerUrl } from '~/lib/common/helpers/route'
|
||||
import type { Nullable } from '@speckle/shared'
|
||||
import {
|
||||
useWorkspaceCustomDataResidencyDisclaimerQuery,
|
||||
RegionStaticDataDisclaimerVariant
|
||||
} from '~/lib/workspaces/composables/region'
|
||||
|
||||
const props = defineProps<{
|
||||
projectId: string
|
||||
@@ -58,12 +68,18 @@ const props = defineProps<{
|
||||
|
||||
const {
|
||||
maxSizeInBytes,
|
||||
onFilesSelected,
|
||||
onFilesSelected: onFilesSelectedInternal,
|
||||
accept,
|
||||
upload: fileUpload,
|
||||
isUploading
|
||||
} = useFileImport(toRefs(props))
|
||||
|
||||
const { showRegionStaticDataDisclaimer, triggerAction, onConfirmHandler } =
|
||||
useWorkspaceCustomDataResidencyDisclaimerQuery({
|
||||
projectId: computed(() => props.projectId),
|
||||
onConfirmAction: onFilesSelectedInternal
|
||||
})
|
||||
|
||||
const { errorMessage, progressBarClasses, progressBarStyle } =
|
||||
useFileUploadProgressCore({
|
||||
item: fileUpload
|
||||
|
||||
@@ -48,6 +48,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<WorkspaceRegionStaticDataDisclaimer
|
||||
v-if="showRegionStaticDataDisclaimer"
|
||||
v-model:open="showRegionStaticDataDisclaimer"
|
||||
:variant="RegionStaticDataDisclaimerVariant.MoveProjectIntoWorkspace"
|
||||
@confirm="onConfirmHandler"
|
||||
/>
|
||||
</LayoutDialog>
|
||||
</template>
|
||||
|
||||
@@ -57,12 +63,15 @@ import type {
|
||||
ProjectsMoveToWorkspaceDialog_WorkspaceFragment,
|
||||
ProjectsMoveToWorkspaceDialog_ProjectFragment
|
||||
} from '~~/lib/common/generated/gql/graphql'
|
||||
import { projectWorkspaceSelectQuery } from '~/lib/projects/graphql/queries'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { useMutationLoading, useQuery } from '@vue/apollo-composable'
|
||||
import { type LayoutDialogButton } from '@speckle/ui-components'
|
||||
import { useMoveProjectToWorkspace } from '~/lib/projects/composables/projectManagement'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { workspacesRoute } from '~/lib/common/helpers/route'
|
||||
import {
|
||||
useWorkspaceCustomDataResidencyDisclaimer,
|
||||
RegionStaticDataDisclaimerVariant
|
||||
} from '~/lib/workspaces/composables/region'
|
||||
|
||||
graphql(`
|
||||
fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {
|
||||
@@ -71,6 +80,8 @@ graphql(`
|
||||
name
|
||||
defaultLogoIndex
|
||||
logo
|
||||
...WorkspaceHasCustomDataResidency_Workspace
|
||||
...ProjectsWorkspaceSelect_Workspace
|
||||
}
|
||||
`)
|
||||
|
||||
@@ -97,6 +108,15 @@ graphql(`
|
||||
}
|
||||
`)
|
||||
|
||||
const query = graphql(`
|
||||
query ProjectsMoveToWorkspaceDialog {
|
||||
activeUser {
|
||||
id
|
||||
...ProjectsMoveToWorkspaceDialog_User
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
const props = defineProps<{
|
||||
project: ProjectsMoveToWorkspaceDialog_ProjectFragment
|
||||
workspace?: ProjectsMoveToWorkspaceDialog_WorkspaceFragment
|
||||
@@ -105,9 +125,10 @@ const props = defineProps<{
|
||||
const open = defineModel<boolean>('open', { required: true })
|
||||
|
||||
const isWorkspacesEnabled = useIsWorkspacesEnabled()
|
||||
const { result } = useQuery(projectWorkspaceSelectQuery, null, () => ({
|
||||
const { result } = useQuery(query, null, () => ({
|
||||
enabled: isWorkspacesEnabled.value
|
||||
}))
|
||||
const loading = useMutationLoading()
|
||||
const moveProject = useMoveProjectToWorkspace()
|
||||
|
||||
const selectedWorkspace = ref<ProjectsMoveToWorkspaceDialog_WorkspaceFragment>()
|
||||
@@ -134,9 +155,9 @@ const dialogButtons = computed<LayoutDialogButton[]>(() => {
|
||||
text: 'Move',
|
||||
props: {
|
||||
color: 'primary',
|
||||
disabled: !selectedWorkspace.value && !props.workspace
|
||||
disabled: (!selectedWorkspace.value && !props.workspace) || loading.value
|
||||
},
|
||||
onClick: () => onMoveProject()
|
||||
onClick: () => triggerAction()
|
||||
}
|
||||
]
|
||||
: [
|
||||
@@ -153,27 +174,31 @@ const dialogButtons = computed<LayoutDialogButton[]>(() => {
|
||||
const onMoveProject = async () => {
|
||||
const workspaceId = selectedWorkspace.value?.id ?? props.workspace?.id
|
||||
const workspaceName = selectedWorkspace.value?.name ?? props.workspace?.name
|
||||
if (!workspaceId || !workspaceName) return
|
||||
|
||||
if (workspaceId && workspaceName) {
|
||||
try {
|
||||
await moveProject({
|
||||
projectId: props.project.id,
|
||||
workspaceId,
|
||||
workspaceName,
|
||||
eventSource: props.eventSource
|
||||
})
|
||||
open.value = false
|
||||
} catch {
|
||||
// Do nothing on error, composable already shows notification
|
||||
}
|
||||
const res = await moveProject({
|
||||
projectId: props.project.id,
|
||||
workspaceId,
|
||||
workspaceName,
|
||||
eventSource: props.eventSource
|
||||
})
|
||||
if (res?.id) {
|
||||
open.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const { showRegionStaticDataDisclaimer, triggerAction, onConfirmHandler } =
|
||||
useWorkspaceCustomDataResidencyDisclaimer({
|
||||
workspace: computed(() => selectedWorkspace.value ?? props.workspace),
|
||||
onConfirmAction: onMoveProject
|
||||
})
|
||||
|
||||
watch(
|
||||
() => open.value,
|
||||
(isOpen, oldIsOpen) => {
|
||||
if (isOpen && isOpen !== oldIsOpen) {
|
||||
selectedWorkspace.value = undefined
|
||||
showRegionStaticDataDisclaimer.value = false
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<LayoutDialog
|
||||
v-model:open="open"
|
||||
max-width="xs"
|
||||
title="Data residency notice"
|
||||
:buttons="dialogButtons"
|
||||
>
|
||||
<template
|
||||
v-if="variant === RegionStaticDataDisclaimerVariant.MoveProjectIntoWorkspace"
|
||||
>
|
||||
Your workspace has custom data residency set up. However, we currently do not
|
||||
support moving projects between data regions, so the projects you move in to the
|
||||
workspace will remain in their previous location.
|
||||
</template>
|
||||
<template v-else-if="variant === RegionStaticDataDisclaimerVariant.UploadModel">
|
||||
The workspace where the project resides has custom data residency set up. However,
|
||||
we currently do not support custom data residency for file uploads. As a result,
|
||||
the uploaded file will be stored in the default location.
|
||||
</template>
|
||||
</LayoutDialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { LayoutDialogButton } from '@speckle/ui-components'
|
||||
import { RegionStaticDataDisclaimerVariant } from '~/lib/workspaces/composables/region'
|
||||
|
||||
const emit = defineEmits<{
|
||||
cancel: []
|
||||
confirm: []
|
||||
}>()
|
||||
|
||||
defineProps<{
|
||||
variant: RegionStaticDataDisclaimerVariant
|
||||
}>()
|
||||
|
||||
const open = defineModel<boolean>('open', { required: true })
|
||||
|
||||
const dialogButtons = computed((): LayoutDialogButton[] => [
|
||||
{
|
||||
text: 'Cancel',
|
||||
props: { color: 'outline' },
|
||||
onClick: () => {
|
||||
open.value = false
|
||||
emit('cancel')
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'I Understand',
|
||||
onClick: () => {
|
||||
open.value = false
|
||||
emit('confirm')
|
||||
}
|
||||
}
|
||||
])
|
||||
</script>
|
||||
@@ -98,9 +98,10 @@ const documents = {
|
||||
"\n fragment ProjectsDashboardHeaderProjects_User on User {\n projectInvites {\n ...ProjectsInviteBanner\n }\n }\n": types.ProjectsDashboardHeaderProjects_UserFragmentDoc,
|
||||
"\n fragment ProjectsDashboardHeaderWorkspaces_User on User {\n discoverableWorkspaces {\n ...WorkspaceInviteDiscoverableWorkspaceBanner_LimitedWorkspace\n }\n workspaceInvites {\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n }\n }\n": types.ProjectsDashboardHeaderWorkspaces_UserFragmentDoc,
|
||||
"\n fragment ProjectsHiddenProjectWarning_User on User {\n id\n expiredSsoSessions {\n id\n slug\n name\n logo\n defaultLogoIndex\n }\n }\n": types.ProjectsHiddenProjectWarning_UserFragmentDoc,
|
||||
"\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n name\n defaultLogoIndex\n logo\n }\n": types.ProjectsMoveToWorkspaceDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n name\n defaultLogoIndex\n logo\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n": types.ProjectsMoveToWorkspaceDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment ProjectsMoveToWorkspaceDialog_User on User {\n workspaces {\n items {\n ...ProjectsMoveToWorkspaceDialog_Workspace\n }\n }\n }\n": types.ProjectsMoveToWorkspaceDialog_UserFragmentDoc,
|
||||
"\n fragment ProjectsMoveToWorkspaceDialog_Project on Project {\n id\n name\n modelCount: models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n }\n": types.ProjectsMoveToWorkspaceDialog_ProjectFragmentDoc,
|
||||
"\n query ProjectsMoveToWorkspaceDialog {\n activeUser {\n id\n ...ProjectsMoveToWorkspaceDialog_User\n }\n }\n": types.ProjectsMoveToWorkspaceDialogDocument,
|
||||
"\n fragment ProjectsWorkspaceSelect_Workspace on Workspace {\n id\n role\n name\n defaultLogoIndex\n logo\n }\n": types.ProjectsWorkspaceSelect_WorkspaceFragmentDoc,
|
||||
"\n fragment ProjectsInviteBanner on PendingStreamCollaborator {\n id\n invitedBy {\n ...LimitedUserAvatar\n }\n projectId\n projectName\n token\n user {\n id\n }\n }\n": types.ProjectsInviteBannerFragmentDoc,
|
||||
"\n fragment SettingsDialog_Workspace on Workspace {\n ...WorkspaceAvatar_Workspace\n ...SettingsMenu_Workspace\n id\n slug\n role\n name\n plan {\n status\n }\n }\n": types.SettingsDialog_WorkspaceFragmentDoc,
|
||||
@@ -341,6 +342,8 @@ const documents = {
|
||||
"\n fragment WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n }\n": types.WorkspaceMixpanelUpdateGroup_WorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment WorkspaceMixpanelUpdateGroup_Workspace on Workspace {\n id\n name\n description\n domainBasedMembershipProtectionEnabled\n discoverabilityEnabled\n plan {\n status\n name\n }\n team {\n totalCount\n items {\n ...WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator\n }\n }\n }\n": types.WorkspaceMixpanelUpdateGroup_WorkspaceFragmentDoc,
|
||||
"\n subscription OnWorkspaceProjectsUpdate($slug: String!) {\n workspaceProjectsUpdated(workspaceId: null, workspaceSlug: $slug) {\n projectId\n workspaceId\n type\n project {\n ...ProjectDashboardItem\n }\n }\n }\n ": types.OnWorkspaceProjectsUpdateDocument,
|
||||
"\n fragment WorkspaceHasCustomDataResidency_Workspace on Workspace {\n id\n defaultRegion {\n id\n name\n }\n }\n": types.WorkspaceHasCustomDataResidency_WorkspaceFragmentDoc,
|
||||
"\n query CheckProjectWorkspaceDataResidency($projectId: String!) {\n project(id: $projectId) {\n id\n workspace {\n ...WorkspaceHasCustomDataResidency_Workspace\n }\n }\n }\n": types.CheckProjectWorkspaceDataResidencyDocument,
|
||||
"\n fragment WorkspaceSsoStatus_Workspace on Workspace {\n id\n sso {\n provider {\n id\n name\n clientId\n issuerUrl\n }\n session {\n validUntil\n }\n }\n }\n ": types.WorkspaceSsoStatus_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSsoStatus_User on User {\n expiredSsoSessions {\n id\n slug\n }\n }\n ": types.WorkspaceSsoStatus_UserFragmentDoc,
|
||||
"\n mutation UpdateRole($input: WorkspaceRoleUpdateInput!) {\n workspaceMutations {\n updateRole(input: $input) {\n team {\n items {\n id\n role\n }\n }\n }\n }\n }\n": types.UpdateRoleDocument,
|
||||
@@ -726,7 +729,7 @@ export function graphql(source: "\n fragment ProjectsHiddenProjectWarning_User
|
||||
/**
|
||||
* 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 ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n name\n defaultLogoIndex\n logo\n }\n"): (typeof documents)["\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n name\n defaultLogoIndex\n logo\n }\n"];
|
||||
export function graphql(source: "\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n name\n defaultLogoIndex\n logo\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n"): (typeof documents)["\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n name\n defaultLogoIndex\n logo\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -735,6 +738,10 @@ export function graphql(source: "\n fragment ProjectsMoveToWorkspaceDialog_User
|
||||
* 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 ProjectsMoveToWorkspaceDialog_Project on Project {\n id\n name\n modelCount: models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n }\n"): (typeof documents)["\n fragment ProjectsMoveToWorkspaceDialog_Project on Project {\n id\n name\n modelCount: models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query ProjectsMoveToWorkspaceDialog {\n activeUser {\n id\n ...ProjectsMoveToWorkspaceDialog_User\n }\n }\n"): (typeof documents)["\n query ProjectsMoveToWorkspaceDialog {\n activeUser {\n id\n ...ProjectsMoveToWorkspaceDialog_User\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -1695,6 +1702,14 @@ export function graphql(source: "\n fragment WorkspaceMixpanelUpdateGroup_Works
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n subscription OnWorkspaceProjectsUpdate($slug: String!) {\n workspaceProjectsUpdated(workspaceId: null, workspaceSlug: $slug) {\n projectId\n workspaceId\n type\n project {\n ...ProjectDashboardItem\n }\n }\n }\n "): (typeof documents)["\n subscription OnWorkspaceProjectsUpdate($slug: String!) {\n workspaceProjectsUpdated(workspaceId: null, workspaceSlug: $slug) {\n projectId\n workspaceId\n type\n project {\n ...ProjectDashboardItem\n }\n }\n }\n "];
|
||||
/**
|
||||
* 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 WorkspaceHasCustomDataResidency_Workspace on Workspace {\n id\n defaultRegion {\n id\n name\n }\n }\n"): (typeof documents)["\n fragment WorkspaceHasCustomDataResidency_Workspace on Workspace {\n id\n defaultRegion {\n id\n name\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query CheckProjectWorkspaceDataResidency($projectId: String!) {\n project(id: $projectId) {\n id\n workspace {\n ...WorkspaceHasCustomDataResidency_Workspace\n }\n }\n }\n"): (typeof documents)["\n query CheckProjectWorkspaceDataResidency($projectId: String!) {\n project(id: $projectId) {\n id\n workspace {\n ...WorkspaceHasCustomDataResidency_Workspace\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
import type { ApolloCache } from '@apollo/client/core'
|
||||
import type { Optional } from '@speckle/shared'
|
||||
import { useApolloClient, useSubscription } from '@vue/apollo-composable'
|
||||
import { useApolloClient, useMutation, useSubscription } from '@vue/apollo-composable'
|
||||
import type { MaybeRef } from '@vueuse/core'
|
||||
import type { Get } from 'type-fest'
|
||||
import { useActiveUser } from '~~/lib/auth/composables/activeUser'
|
||||
@@ -544,10 +544,9 @@ export function useLeaveProject() {
|
||||
}
|
||||
|
||||
export function useMoveProjectToWorkspace() {
|
||||
const apollo = useApolloClient().client
|
||||
|
||||
const { triggerNotification } = useGlobalToast()
|
||||
const mixpanel = useMixpanel()
|
||||
const { mutate } = useMutation(useMoveProjectToWorkspaceMutation)
|
||||
|
||||
return async (params: {
|
||||
projectId: string
|
||||
@@ -557,10 +556,9 @@ export function useMoveProjectToWorkspace() {
|
||||
}) => {
|
||||
const { projectId, workspaceId, workspaceName, eventSource } = params
|
||||
|
||||
const { data, errors } = await apollo
|
||||
.mutate({
|
||||
mutation: useMoveProjectToWorkspaceMutation,
|
||||
variables: { projectId, workspaceId },
|
||||
const res = await mutate(
|
||||
{ projectId, workspaceId },
|
||||
{
|
||||
update: (cache, { data }) => {
|
||||
if (!data?.workspaceMutations.projects.moveToWorkspace) return
|
||||
if (!workspaceId) return
|
||||
@@ -576,10 +574,10 @@ export function useMoveProjectToWorkspace() {
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
.catch(convertThrowIntoFetchResult)
|
||||
}
|
||||
).catch(convertThrowIntoFetchResult)
|
||||
|
||||
if (data?.workspaceMutations) {
|
||||
if (res?.data?.workspaceMutations.projects.moveToWorkspace.id) {
|
||||
triggerNotification({
|
||||
type: ToastNotificationType.Success,
|
||||
title: `Moved project to ${workspaceName}`
|
||||
@@ -592,13 +590,15 @@ export function useMoveProjectToWorkspace() {
|
||||
source: eventSource
|
||||
})
|
||||
} else {
|
||||
const errMsg = getFirstErrorMessage(errors)
|
||||
const errMsg = getFirstErrorMessage(res?.errors)
|
||||
triggerNotification({
|
||||
type: ToastNotificationType.Danger,
|
||||
title: "Couldn't move project",
|
||||
description: errMsg
|
||||
})
|
||||
}
|
||||
|
||||
return res?.data?.workspaceMutations.projects.moveToWorkspace
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import type { MaybeAsync, MaybeNullOrUndefined } from '@speckle/shared'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { graphql } from '~/lib/common/generated/gql'
|
||||
import type { WorkspaceHasCustomDataResidency_WorkspaceFragment } from '~/lib/common/generated/gql/graphql'
|
||||
|
||||
export enum RegionStaticDataDisclaimerVariant {
|
||||
MoveProjectIntoWorkspace = 'MoveProjectIntoWorkspace',
|
||||
UploadModel = 'UploadModel'
|
||||
}
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceHasCustomDataResidency_Workspace on Workspace {
|
||||
id
|
||||
defaultRegion {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
const checkProjectWorkspaceDataResidencyQuery = graphql(`
|
||||
query CheckProjectWorkspaceDataResidency($projectId: String!) {
|
||||
project(id: $projectId) {
|
||||
id
|
||||
workspace {
|
||||
...WorkspaceHasCustomDataResidency_Workspace
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const useWorkspaceCustomDataResidencyDisclaimer = <
|
||||
ConfirmArgs extends any[]
|
||||
>(params: {
|
||||
workspace: Ref<
|
||||
MaybeNullOrUndefined<WorkspaceHasCustomDataResidency_WorkspaceFragment>
|
||||
>
|
||||
onConfirmAction: (...args: ConfirmArgs) => MaybeAsync<void>
|
||||
}) => {
|
||||
const { onConfirmAction, workspace } = params
|
||||
const showRegionStaticDataDisclaimer = ref(false)
|
||||
const storedArgs = shallowRef<ConfirmArgs>()
|
||||
|
||||
const hasCustomDataResidency = computed(() => {
|
||||
return !!workspace.value?.defaultRegion
|
||||
})
|
||||
|
||||
/**
|
||||
* Trigger the actual action that requires the user to confirm the data residency disclaimer
|
||||
*/
|
||||
const triggerAction = (...args: ConfirmArgs) => {
|
||||
if (!hasCustomDataResidency.value) {
|
||||
onConfirmAction(...args)
|
||||
} else {
|
||||
storedArgs.value = args
|
||||
showRegionStaticDataDisclaimer.value = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disclaimer on-confirm handler
|
||||
*/
|
||||
const onConfirmHandler = () => {
|
||||
showRegionStaticDataDisclaimer.value = false
|
||||
onConfirmAction(...storedArgs.value!)
|
||||
}
|
||||
|
||||
return {
|
||||
hasCustomDataResidency,
|
||||
showRegionStaticDataDisclaimer,
|
||||
triggerAction,
|
||||
onConfirmHandler
|
||||
}
|
||||
}
|
||||
|
||||
export const useWorkspaceCustomDataResidencyDisclaimerQuery = <
|
||||
ConfirmArgs extends any[]
|
||||
>(params: {
|
||||
projectId: Ref<string>
|
||||
onConfirmAction: (...args: ConfirmArgs) => MaybeAsync<void>
|
||||
}) => {
|
||||
const { projectId, onConfirmAction } = params
|
||||
const { result } = useQuery(checkProjectWorkspaceDataResidencyQuery, () => ({
|
||||
projectId: projectId.value
|
||||
}))
|
||||
|
||||
return useWorkspaceCustomDataResidencyDisclaimer({
|
||||
workspace: computed(() => result.value?.project?.workspace),
|
||||
onConfirmAction
|
||||
})
|
||||
}
|
||||
@@ -506,9 +506,6 @@ describe('Core GraphQL Subscriptions (New)', () => {
|
||||
}
|
||||
)
|
||||
await meSubClient.waitForReadiness()
|
||||
await meSubClient.waitForReadiness()
|
||||
await meSubClient.waitForReadiness()
|
||||
await meSubClient.waitForReadiness()
|
||||
|
||||
await addOrUpdateStreamCollaborator(
|
||||
otherGuysProj.id,
|
||||
|
||||
Reference in New Issue
Block a user