fix(workspaces): make discoverable workspace dismiss sticky (#4189)

* fix(workspaces): make discoverable workspace dismiss sticky

* Modify cache instead of refetch

* Add to new cards

---------

Co-authored-by: Mike Tasset <mike.tasset@gmail.com>
This commit is contained in:
Chuck Driesler
2025-03-17 11:01:06 +00:00
committed by GitHub
parent c962d2c6fa
commit a8546e4e5f
9 changed files with 160 additions and 105 deletions
@@ -13,23 +13,20 @@
:invite="invite"
/>
<WorkspaceInviteDiscoverableWorkspaceBanner
v-for="workspace in filteredDiscoverableWorkspaces"
v-for="workspace in discoverableWorkspaces"
:key="workspace.id"
:workspace="workspace"
@dismiss="handleDismiss"
/>
</div>
</div>
</template>
<script setup lang="ts">
import type { MaybeNullOrUndefined } from '@speckle/shared'
import { useSynchronizedCookie } from '~/lib/common/composables/reactiveCookie'
import { graphql } from '~/lib/common/generated/gql'
import type {
ProjectsDashboardHeaderProjects_UserFragment,
ProjectsDashboardHeaderWorkspaces_UserFragment
} from '~/lib/common/generated/gql/graphql'
import { CookieKeys } from '~/lib/common/helpers/constants'
import { useDiscoverableWorkspaces } from '~/lib/workspaces/composables/discoverableWorkspaces'
graphql(`
@@ -53,35 +50,15 @@ const props = defineProps<{
workspacesInvites: MaybeNullOrUndefined<ProjectsDashboardHeaderWorkspaces_UserFragment>
}>()
const dismissedDiscoverableWorkspaces = useSynchronizedCookie<string[]>(
CookieKeys.DismissedDiscoverableWorkspaces,
{
default: () => []
}
)
const { discoverableWorkspaces } = useDiscoverableWorkspaces()
const workspaceInvites = computed(() => props.workspacesInvites?.workspaceInvites || [])
const filteredDiscoverableWorkspaces = computed(
() =>
discoverableWorkspaces.value?.filter(
(workspace) => !dismissedDiscoverableWorkspaces.value.includes(workspace.id)
) || []
)
const hasBanners = computed(() => {
return (
props.projectsInvites?.projectInvites?.length ||
workspaceInvites.value.length ||
filteredDiscoverableWorkspaces.value.length
discoverableWorkspaces.value?.length
)
})
const handleDismiss = (workspaceId: string) => {
dismissedDiscoverableWorkspaces.value = [
...dismissedDiscoverableWorkspaces.value,
workspaceId
]
}
</script>
@@ -12,23 +12,21 @@
{{ workspace.team?.totalCount === 1 ? 'member' : 'members' }}
</p>
</div>
<FormButton
v-if="workspace.requestStatus"
color="outline"
size="sm"
disabled
class="capitalize"
>
{{ workspace.requestStatus }}
</FormButton>
<FormButton
v-else
color="outline"
size="sm"
@click="() => onRequest(workspace.id)"
>
Request to join
</FormButton>
<div class="flex flex-col gap-y-2">
<FormButton
v-if="workspace.requestStatus"
color="outline"
size="sm"
disabled
class="capitalize"
>
{{ workspace.requestStatus }}
</FormButton>
<FormButton v-else color="outline" size="sm" @click="onRequest">
Request to join
</FormButton>
<FormButton color="subtle" size="sm" @click="onDismiss">Dismiss</FormButton>
</div>
</div>
</div>
</CommonCard>
@@ -42,13 +40,18 @@ type WorkspaceWithStatus = LimitedWorkspace & {
requestStatus: string | null
}
defineProps<{
const props = defineProps<{
workspace: WorkspaceWithStatus
}>()
const { processRequest } = useDiscoverableWorkspaces()
const { requestToJoinWorkspace, dismissDiscoverableWorkspace } =
useDiscoverableWorkspaces()
const onRequest = (workspaceId: string) => {
processRequest(true, workspaceId)
const onRequest = () => {
requestToJoinWorkspace(props.workspace.id)
}
const onDismiss = () => {
dismissDiscoverableWorkspace(props.workspace.id)
}
</script>
@@ -2,7 +2,11 @@
<LayoutDialog v-model:open="open" max-width="md" :buttons="dialogButtons">
<template #header>Join existing workspaces</template>
<p class="text-body-xs text-foreground-2 pb-3">
Workspaces that match your email domain
{{
hasDiscoverableWorkspacesOrJoinRequests
? 'Workspaces that match your email domain'
: 'You have no discoverable workspaces'
}}
</p>
<div class="flex flex-col gap-y-3">
<WorkspaceDiscoverableWorkspacesCard
@@ -17,7 +21,10 @@
import type { LayoutDialogButton } from '@speckle/ui-components'
import { useDiscoverableWorkspaces } from '~/lib/workspaces/composables/discoverableWorkspaces'
const { discoverableWorkspacesAndJoinRequests } = useDiscoverableWorkspaces()
const {
discoverableWorkspacesAndJoinRequests,
hasDiscoverableWorkspacesOrJoinRequests
} = useDiscoverableWorkspaces()
const open = defineModel<boolean>('open', { required: true })
@@ -17,9 +17,9 @@ const props = defineProps<{
workspace: LimitedWorkspace
}>()
const { processRequest } = useDiscoverableWorkspaces()
const { requestToJoinWorkspace, dismissDiscoverableWorkspace } =
useDiscoverableWorkspaces()
const mixpanel = useMixpanel()
const { triggerNotification } = useGlobalToast()
const invite = computed(() => ({
workspace: {
@@ -29,26 +29,17 @@ const invite = computed(() => ({
}
}))
const emit = defineEmits<{
(e: 'dismiss', workspaceId: string): void
}>()
const handleRequest = async (accept: boolean) => {
if (accept) {
await processRequest(true, props.workspace.id)
emit('dismiss', props.workspace.id)
await requestToJoinWorkspace(props.workspace.id)
} else {
emit('dismiss', props.workspace.id)
await dismissDiscoverableWorkspace(props.workspace.id)
mixpanel.track('Workspace Discovery Banner Dismissed', {
workspaceId: props.workspace.id,
location: 'discovery banner',
// eslint-disable-next-line camelcase
workspace_id: props.workspace.id
})
triggerNotification({
title: 'Discoverable workspace dismissed',
type: ToastNotificationType.Info
})
}
}
</script>
@@ -185,6 +185,7 @@ type Documents = {
"\n query ProjectModelsSelectorValues($projectId: String!, $cursor: String) {\n project(id: $projectId) {\n id\n models(limit: 100, cursor: $cursor) {\n cursor\n totalCount\n items {\n ...CommonModelSelectorModel\n }\n }\n }\n }\n": typeof types.ProjectModelsSelectorValuesDocument,
"\n query MainServerInfoData {\n serverInfo {\n adminContact\n canonicalUrl\n company\n description\n guestModeEnabled\n inviteOnly\n name\n termsOfService\n version\n automateUrl\n configuration {\n isEmailEnabled\n }\n }\n }\n": typeof types.MainServerInfoDataDocument,
"\n mutation DashboardRequestToJoinWorkspace($input: WorkspaceRequestToJoinInput!) {\n workspaceMutations {\n requestToJoin(input: $input)\n }\n }\n": typeof types.DashboardRequestToJoinWorkspaceDocument,
"\n mutation DashboardDismissDiscoverableWorkspace($input: WorkspaceDismissInput!) {\n workspaceMutations {\n dismiss(input: $input)\n }\n }\n": typeof types.DashboardDismissDiscoverableWorkspaceDocument,
"\n query DashboardProjectsPageQuery {\n activeUser {\n id\n projects(limit: 3) {\n items {\n ...DashboardProjectCard_Project\n }\n }\n ...ProjectsDashboardHeaderProjects_User\n }\n }\n": typeof types.DashboardProjectsPageQueryDocument,
"\n query DashboardProjectsPageWorkspaceQuery {\n activeUser {\n id\n ...ProjectsDashboardHeaderWorkspaces_User\n }\n }\n": typeof types.DashboardProjectsPageWorkspaceQueryDocument,
"\n mutation DeleteAccessToken($token: String!) {\n apiTokenRevoke(token: $token)\n }\n": typeof types.DeleteAccessTokenDocument,
@@ -584,6 +585,7 @@ const documents: Documents = {
"\n query ProjectModelsSelectorValues($projectId: String!, $cursor: String) {\n project(id: $projectId) {\n id\n models(limit: 100, cursor: $cursor) {\n cursor\n totalCount\n items {\n ...CommonModelSelectorModel\n }\n }\n }\n }\n": types.ProjectModelsSelectorValuesDocument,
"\n query MainServerInfoData {\n serverInfo {\n adminContact\n canonicalUrl\n company\n description\n guestModeEnabled\n inviteOnly\n name\n termsOfService\n version\n automateUrl\n configuration {\n isEmailEnabled\n }\n }\n }\n": types.MainServerInfoDataDocument,
"\n mutation DashboardRequestToJoinWorkspace($input: WorkspaceRequestToJoinInput!) {\n workspaceMutations {\n requestToJoin(input: $input)\n }\n }\n": types.DashboardRequestToJoinWorkspaceDocument,
"\n mutation DashboardDismissDiscoverableWorkspace($input: WorkspaceDismissInput!) {\n workspaceMutations {\n dismiss(input: $input)\n }\n }\n": types.DashboardDismissDiscoverableWorkspaceDocument,
"\n query DashboardProjectsPageQuery {\n activeUser {\n id\n projects(limit: 3) {\n items {\n ...DashboardProjectCard_Project\n }\n }\n ...ProjectsDashboardHeaderProjects_User\n }\n }\n": types.DashboardProjectsPageQueryDocument,
"\n query DashboardProjectsPageWorkspaceQuery {\n activeUser {\n id\n ...ProjectsDashboardHeaderWorkspaces_User\n }\n }\n": types.DashboardProjectsPageWorkspaceQueryDocument,
"\n mutation DeleteAccessToken($token: String!) {\n apiTokenRevoke(token: $token)\n }\n": types.DeleteAccessTokenDocument,
@@ -1510,6 +1512,10 @@ export function graphql(source: "\n query MainServerInfoData {\n serverInfo
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation DashboardRequestToJoinWorkspace($input: WorkspaceRequestToJoinInput!) {\n workspaceMutations {\n requestToJoin(input: $input)\n }\n }\n"): (typeof documents)["\n mutation DashboardRequestToJoinWorkspace($input: WorkspaceRequestToJoinInput!) {\n workspaceMutations {\n requestToJoin(input: $input)\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 mutation DashboardDismissDiscoverableWorkspace($input: WorkspaceDismissInput!) {\n workspaceMutations {\n dismiss(input: $input)\n }\n }\n"): (typeof documents)["\n mutation DashboardDismissDiscoverableWorkspace($input: WorkspaceDismissInput!) {\n workspaceMutations {\n dismiss(input: $input)\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -5397,6 +5397,13 @@ export type DashboardRequestToJoinWorkspaceMutationVariables = Exact<{
export type DashboardRequestToJoinWorkspaceMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', requestToJoin: boolean } };
export type DashboardDismissDiscoverableWorkspaceMutationVariables = Exact<{
input: WorkspaceDismissInput;
}>;
export type DashboardDismissDiscoverableWorkspaceMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', dismiss: boolean } };
export type DashboardProjectsPageQueryQueryVariables = Exact<{ [key: string]: never; }>;
@@ -7017,6 +7024,7 @@ export const ServerInfoAllScopesDocument = {"kind":"Document","definitions":[{"k
export const ProjectModelsSelectorValuesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProjectModelsSelectorValues"},"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":"cursor"}},"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":"Field","name":{"kind":"Name","value":"models"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"100"}},{"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":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommonModelSelectorModel"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommonModelSelectorModel"},"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"}}]}}]} as unknown as DocumentNode<ProjectModelsSelectorValuesQuery, ProjectModelsSelectorValuesQueryVariables>;
export const MainServerInfoDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MainServerInfoData"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"adminContact"}},{"kind":"Field","name":{"kind":"Name","value":"canonicalUrl"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"guestModeEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"inviteOnly"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"termsOfService"}},{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"automateUrl"}},{"kind":"Field","name":{"kind":"Name","value":"configuration"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"isEmailEnabled"}}]}}]}}]}}]} as unknown as DocumentNode<MainServerInfoDataQuery, MainServerInfoDataQueryVariables>;
export const DashboardRequestToJoinWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DashboardRequestToJoinWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceRequestToJoinInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"requestToJoin"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]}}]} as unknown as DocumentNode<DashboardRequestToJoinWorkspaceMutation, DashboardRequestToJoinWorkspaceMutationVariables>;
export const DashboardDismissDiscoverableWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DashboardDismissDiscoverableWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceDismissInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dismiss"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]}}]} as unknown as DocumentNode<DashboardDismissDiscoverableWorkspaceMutation, DashboardDismissDiscoverableWorkspaceMutationVariables>;
export const DashboardProjectsPageQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardProjectsPageQuery"},"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":"limit"},"value":{"kind":"IntValue","value":"3"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"DashboardProjectCard_Project"}}]}}]}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectsDashboardHeaderProjects_User"}}]}}]}},{"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":"ProjectsInviteBanner"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PendingStreamCollaborator"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"invitedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}},{"kind":"Field","name":{"kind":"Name","value":"projectId"}},{"kind":"Field","name":{"kind":"Name","value":"projectName"}},{"kind":"Field","name":{"kind":"Name","value":"token"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"DashboardProjectCard_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":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"models"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}}]}},{"kind":"Field","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":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectsDashboardHeaderProjects_User"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projectInvites"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectsInviteBanner"}}]}}]}}]} as unknown as DocumentNode<DashboardProjectsPageQueryQuery, DashboardProjectsPageQueryQueryVariables>;
export const DashboardProjectsPageWorkspaceQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardProjectsPageWorkspaceQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectsDashboardHeaderWorkspaces_User"}}]}}]}},{"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":"UseWorkspaceInviteManager_PendingWorkspaceCollaborator"},"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":"token"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceSlug"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkspaceInviteBanner_PendingWorkspaceCollaborator"},"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":"invitedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceName"}},{"kind":"Field","name":{"kind":"Name","value":"token"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"UseWorkspaceInviteManager_PendingWorkspaceCollaborator"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectsDashboardHeaderWorkspaces_User"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceInvites"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkspaceInviteBanner_PendingWorkspaceCollaborator"}}]}}]}}]} as unknown as DocumentNode<DashboardProjectsPageWorkspaceQueryQuery, DashboardProjectsPageWorkspaceQueryQueryVariables>;
export const DeleteAccessTokenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteAccessToken"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"token"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apiTokenRevoke"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"token"},"value":{"kind":"Variable","name":{"kind":"Name","value":"token"}}}]}]}}]} as unknown as DocumentNode<DeleteAccessTokenMutation, DeleteAccessTokenMutationVariables>;
@@ -4,9 +4,7 @@
export enum CookieKeys {
AuthToken = 'authn',
Theme = 'theme',
PostAuthRedirect = 'postAuthRedirect',
DismissedDiscoverableWorkspaces = 'dismissedDiscoverableWorkspaces',
DismissedWorkspaceBanner = 'dismissedWorkspaceBanner'
PostAuthRedirect = 'postAuthRedirect'
}
/**
@@ -7,3 +7,11 @@ export const dashboardRequestToJoinWorkspaceMutation = graphql(`
}
}
`)
export const dashboardDismissDiscoverableWorkspaceMutation = graphql(`
mutation DashboardDismissDiscoverableWorkspace($input: WorkspaceDismissInput!) {
workspaceMutations {
dismiss(input: $input)
}
}
`)
@@ -3,12 +3,17 @@ import {
discoverableWorkspacesQuery,
discoverableWorkspacesRequestsQuery
} from '../graphql/queries'
import { dashboardRequestToJoinWorkspaceMutation } from '~/lib/dashboard/graphql/mutations'
import {
dashboardDismissDiscoverableWorkspaceMutation,
dashboardRequestToJoinWorkspaceMutation
} from '~/lib/dashboard/graphql/mutations'
import { graphql } from '~/lib/common/generated/gql'
import { useMixpanel } from '~/lib/core/composables/mp'
import type { CacheObjectReference } from '~~/lib/common/helpers/graphql'
import {
convertThrowIntoFetchResult,
getFirstErrorMessage
getFirstErrorMessage,
getCacheId
} from '~~/lib/common/helpers/graphql'
graphql(`
@@ -60,16 +65,20 @@ export const useDiscoverableWorkspaces = () => {
undefined,
{ enabled: isWorkspacesEnabled }
)
const {
result: requestsResult,
refetch,
loading: joinRequestsLoading
} = useQuery(discoverableWorkspacesRequestsQuery, undefined, {
enabled: isWorkspacesEnabled
})
const { result: requestsResult, loading: joinRequestsLoading } = useQuery(
discoverableWorkspacesRequestsQuery,
undefined,
{
enabled: isWorkspacesEnabled
}
)
const { mutate: requestToJoin } = useMutation(dashboardRequestToJoinWorkspaceMutation)
const { mutate: dismissWorkspace } = useMutation(
dashboardDismissDiscoverableWorkspaceMutation
)
const { activeUser } = useActiveUser()
const mixpanel = useMixpanel()
const { triggerNotification } = useGlobalToast()
const apollo = useApolloClient().client
@@ -123,40 +132,88 @@ export const useDiscoverableWorkspaces = () => {
() => discoverableWorkspacesCount.value + discoverableJoinRequestsCount.value
)
const processRequest = async (accept: boolean, workspaceId: string) => {
const requestToJoinWorkspace = async (workspaceId: string) => {
const cache = apollo.cache
const activeUserId = activeUser.value?.id
if (accept) {
const result = await requestToJoin({
input: { workspaceId }
}).catch(convertThrowIntoFetchResult)
if (!activeUserId) return
if (result?.data) {
cache.evict({
id: getCacheId('LimitedWorkspace', workspaceId)
})
refetch()
const result = await requestToJoin({
input: { workspaceId }
}).catch(convertThrowIntoFetchResult)
mixpanel.track('Workspace Join Request Sent', {
workspaceId,
location: 'onboarding',
// eslint-disable-next-line camelcase
workspace_id: workspaceId
})
if (result?.data) {
cache.modify({
id: getCacheId('User', activeUserId),
fields: {
discoverableWorkspaces(existingRefs = [], { readField }) {
return existingRefs.filter(
(ref: CacheObjectReference<'LimitedWorkspace'>) => {
const id = readField('id', ref)
return id !== workspaceId
}
)
}
}
})
triggerNotification({
title: 'Request sent',
description: 'Your request to join the workspace has been sent.',
type: ToastNotificationType.Success
})
} else {
const errorMessage = getFirstErrorMessage(result?.errors)
triggerNotification({
title: 'Failed to send request',
description: errorMessage,
type: ToastNotificationType.Danger
})
}
mixpanel.track('Workspace Join Request Sent', {
workspaceId,
location: 'onboarding',
// eslint-disable-next-line camelcase
workspace_id: workspaceId
})
triggerNotification({
title: 'Request sent',
description: 'Your request to join the workspace has been sent.',
type: ToastNotificationType.Success
})
} else {
const errorMessage = getFirstErrorMessage(result?.errors)
triggerNotification({
title: 'Failed to send request',
description: errorMessage,
type: ToastNotificationType.Danger
})
}
}
const dismissDiscoverableWorkspace = async (workspaceId: string) => {
const result = await dismissWorkspace({
input: { workspaceId }
}).catch(convertThrowIntoFetchResult)
const cache = apollo.cache
const activeUserId = activeUser.value?.id
if (!activeUserId) return
if (result?.data) {
triggerNotification({
title: 'Discoverable workspace dismissed',
type: ToastNotificationType.Info
})
cache.modify({
id: getCacheId('User', activeUserId),
fields: {
discoverableWorkspaces(existingRefs = [], { readField }) {
return existingRefs.filter(
(ref: CacheObjectReference<'LimitedWorkspace'>) => {
const id = readField('id', ref)
return id !== workspaceId
}
)
}
}
})
} else {
const errorMessage = getFirstErrorMessage(result?.errors)
triggerNotification({
title: 'Failed to dismiss workspace',
description: errorMessage,
type: ToastNotificationType.Danger
})
}
}
@@ -172,10 +229,10 @@ export const useDiscoverableWorkspaces = () => {
discoverableWorkspacesCount,
discoverableWorkspacesAndJoinRequestsCount,
discoverableWorkspaces,
dismissDiscoverableWorkspace,
workspaceJoinRequests,
discoverableWorkspacesAndJoinRequests,
processRequest,
loading,
refetch
requestToJoinWorkspace,
loading
}
}