Feat: Mixpanel workspace groups add properties (#2904)
This commit is contained in:
@@ -146,18 +146,19 @@ const save = handleSubmit(async () => {
|
||||
const result = await updateMutation({ input }).catch(convertThrowIntoFetchResult)
|
||||
|
||||
if (result?.data) {
|
||||
triggerNotification({
|
||||
type: ToastNotificationType.Success,
|
||||
title: 'Workspace updated'
|
||||
})
|
||||
|
||||
mixpanel.track('Workspace General Settings Updated', {
|
||||
fields: (Object.keys(input) as Array<keyof WorkspaceUpdateInput>).filter(
|
||||
(key) => key !== 'id'
|
||||
),
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
workspace_id: props.workspaceId
|
||||
})
|
||||
|
||||
triggerNotification({
|
||||
type: ToastNotificationType.Success,
|
||||
title: 'Workspace updated'
|
||||
})
|
||||
} else {
|
||||
const errorMessage = getFirstErrorMessage(result?.errors)
|
||||
triggerNotification({
|
||||
|
||||
@@ -99,6 +99,7 @@ import type {
|
||||
} from '~~/lib/common/generated/gql/graphql'
|
||||
import { workspaceRoute } from '~/lib/common/helpers/route'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { useWorkspacesMixpanel } from '~/lib/workspaces/composables/mixpanel'
|
||||
import {
|
||||
SettingMenuKeys,
|
||||
type AvailableSettingsMenuKeys
|
||||
@@ -117,6 +118,7 @@ graphql(`
|
||||
const selectedRoles = ref(undefined as Optional<StreamRoles[]>)
|
||||
const openNewProject = ref(false)
|
||||
|
||||
const { workspaceMixpanelUpdateGroup } = useWorkspacesMixpanel()
|
||||
const areQueriesLoading = useQueryLoading()
|
||||
const route = useRoute()
|
||||
const {
|
||||
@@ -141,7 +143,7 @@ const token = computed(() => route.query.token as Optional<string>)
|
||||
|
||||
const pageFetchPolicy = usePageQueryStandardFetchPolicy()
|
||||
|
||||
const { result: initialQueryResult } = useQuery(
|
||||
const { result: initialQueryResult, onResult } = useQuery(
|
||||
workspacePageQuery,
|
||||
() => ({
|
||||
workspaceId: props.workspaceId,
|
||||
@@ -239,4 +241,10 @@ const onShowSettingsDialog = (target: AvailableSettingsMenuKeys) => {
|
||||
showSettingsDialog.value = true
|
||||
settingsDialogTarget.value = target
|
||||
}
|
||||
|
||||
onResult((queryResult) => {
|
||||
if (queryResult.data?.workspace) {
|
||||
workspaceMixpanelUpdateGroup(queryResult.data.workspace)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -299,12 +299,14 @@ const documents = {
|
||||
"\n subscription OnViewerCommentsUpdated($target: ViewerUpdateTrackingTarget!) {\n projectCommentsUpdated(target: $target) {\n id\n type\n comment {\n id\n parent {\n id\n }\n ...ViewerCommentThread\n }\n }\n }\n": types.OnViewerCommentsUpdatedDocument,
|
||||
"\n fragment LinkableComment on Comment {\n id\n viewerResources {\n modelId\n versionId\n objectId\n }\n }\n": types.LinkableCommentFragmentDoc,
|
||||
"\n fragment UseWorkspaceInviteManager_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n token\n workspaceId\n user {\n id\n }\n }\n": types.UseWorkspaceInviteManager_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\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 billing {\n cost {\n total\n }\n versionsCount {\n current\n max\n }\n }\n team {\n totalCount\n items {\n ...WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator\n }\n }\n }\n": types.WorkspaceMixpanelUpdateGroup_WorkspaceFragmentDoc,
|
||||
"\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,
|
||||
"\n mutation InviteToWorkspace(\n $workspaceId: String!\n $input: [WorkspaceInviteCreateInput!]!\n ) {\n workspaceMutations {\n invites {\n batchCreate(workspaceId: $workspaceId, input: $input) {\n id\n invitedTeam {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\n }\n }\n }\n }\n }\n": types.InviteToWorkspaceDocument,
|
||||
"\n mutation CreateWorkspace($input: WorkspaceCreateInput!) {\n workspaceMutations {\n create(input: $input) {\n id\n ...SettingsDialog_Workspace\n }\n }\n }\n": types.CreateWorkspaceDocument,
|
||||
"\n mutation ProcessWorkspaceInvite($input: WorkspaceInviteUseInput!) {\n workspaceMutations {\n invites {\n use(input: $input)\n }\n }\n }\n": types.ProcessWorkspaceInviteDocument,
|
||||
"\n query WorkspaceAccessCheck($id: String!) {\n workspace(id: $id) {\n id\n }\n }\n": types.WorkspaceAccessCheckDocument,
|
||||
"\n query WorkspacePageQuery(\n $workspaceId: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspace(id: $workspaceId) {\n id\n ...WorkspaceHeader_Workspace\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(workspaceId: $workspaceId, token: $token) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n": types.WorkspacePageQueryDocument,
|
||||
"\n query WorkspacePageQuery(\n $workspaceId: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspace(id: $workspaceId) {\n id\n ...WorkspaceHeader_Workspace\n ...WorkspaceMixpanelUpdateGroup_Workspace\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(workspaceId: $workspaceId, token: $token) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n": types.WorkspacePageQueryDocument,
|
||||
"\n query WorkspaceProjectsQuery(\n $workspaceId: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n ) {\n workspace(id: $workspaceId) {\n id\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n }\n": types.WorkspaceProjectsQueryDocument,
|
||||
"\n query WorkspaceInvite($workspaceId: String, $token: String) {\n workspaceInvite(workspaceId: $workspaceId, token: $token) {\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n": types.WorkspaceInviteDocument,
|
||||
"\n query LegacyBranchRedirectMetadata($streamId: String!, $branchName: String!) {\n project(id: $streamId) {\n modelByName(name: $branchName) {\n id\n }\n }\n }\n": types.LegacyBranchRedirectMetadataDocument,
|
||||
@@ -1479,6 +1481,14 @@ export function graphql(source: "\n fragment LinkableComment on Comment {\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 UseWorkspaceInviteManager_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n token\n workspaceId\n user {\n id\n }\n }\n"): (typeof documents)["\n fragment UseWorkspaceInviteManager_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n token\n workspaceId\n user {\n id\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 WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n }\n"): (typeof documents)["\n fragment WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\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 WorkspaceMixpanelUpdateGroup_Workspace on Workspace {\n id\n name\n description\n domainBasedMembershipProtectionEnabled\n discoverabilityEnabled\n billing {\n cost {\n total\n }\n versionsCount {\n current\n max\n }\n }\n team {\n totalCount\n items {\n ...WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator\n }\n }\n }\n"): (typeof documents)["\n fragment WorkspaceMixpanelUpdateGroup_Workspace on Workspace {\n id\n name\n description\n domainBasedMembershipProtectionEnabled\n discoverabilityEnabled\n billing {\n cost {\n total\n }\n versionsCount {\n current\n max\n }\n }\n team {\n totalCount\n items {\n ...WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -1502,7 +1512,7 @@ export function graphql(source: "\n query WorkspaceAccessCheck($id: String!) {\
|
||||
/**
|
||||
* 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 WorkspacePageQuery(\n $workspaceId: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspace(id: $workspaceId) {\n id\n ...WorkspaceHeader_Workspace\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(workspaceId: $workspaceId, token: $token) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n"): (typeof documents)["\n query WorkspacePageQuery(\n $workspaceId: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspace(id: $workspaceId) {\n id\n ...WorkspaceHeader_Workspace\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(workspaceId: $workspaceId, token: $token) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n"];
|
||||
export function graphql(source: "\n query WorkspacePageQuery(\n $workspaceId: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspace(id: $workspaceId) {\n id\n ...WorkspaceHeader_Workspace\n ...WorkspaceMixpanelUpdateGroup_Workspace\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(workspaceId: $workspaceId, token: $token) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n"): (typeof documents)["\n query WorkspacePageQuery(\n $workspaceId: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspace(id: $workspaceId) {\n id\n ...WorkspaceHeader_Workspace\n ...WorkspaceMixpanelUpdateGroup_Workspace\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(workspaceId: $workspaceId, token: $token) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\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
@@ -5,7 +5,14 @@ import type { Merge } from 'type-fest'
|
||||
export type MixpanelClient = Merge<
|
||||
Pick<
|
||||
OverridedMixpanel,
|
||||
'track' | 'init' | 'reset' | 'register' | 'identify' | 'people' | 'add_group'
|
||||
| 'track'
|
||||
| 'init'
|
||||
| 'reset'
|
||||
| 'register'
|
||||
| 'identify'
|
||||
| 'people'
|
||||
| 'add_group'
|
||||
| 'get_group'
|
||||
>,
|
||||
{
|
||||
people: Pick<OverridedMixpanel['people'], 'set' | 'set_once'>
|
||||
@@ -25,5 +32,6 @@ export const fakeMixpanelClient = (): MixpanelClient => ({
|
||||
set: noop,
|
||||
set_once: noop
|
||||
},
|
||||
add_group: noop
|
||||
add_group: noop,
|
||||
get_group: noop as MixpanelClient['get_group']
|
||||
})
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { useMixpanel } from '~/lib/core/composables/mp'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type {
|
||||
WorkspaceMixpanelUpdateGroup_WorkspaceFragment,
|
||||
WorkspaceMixpanelUpdateGroup_WorkspaceCollaboratorFragment
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { Roles, type WorkspaceRoles } from '@speckle/shared'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator on WorkspaceCollaborator {
|
||||
id
|
||||
role
|
||||
}
|
||||
`)
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceMixpanelUpdateGroup_Workspace on Workspace {
|
||||
id
|
||||
name
|
||||
description
|
||||
domainBasedMembershipProtectionEnabled
|
||||
discoverabilityEnabled
|
||||
billing {
|
||||
cost {
|
||||
total
|
||||
}
|
||||
versionsCount {
|
||||
current
|
||||
max
|
||||
}
|
||||
}
|
||||
team {
|
||||
totalCount
|
||||
items {
|
||||
...WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const useWorkspacesMixpanel = () => {
|
||||
const mixpanel = useMixpanel()
|
||||
|
||||
const workspaceMixpanelUpdateGroup = (
|
||||
workspace: WorkspaceMixpanelUpdateGroup_WorkspaceFragment
|
||||
) => {
|
||||
if (!workspace.id) return
|
||||
const roleCount = {
|
||||
[Roles.Workspace.Admin]: 0,
|
||||
[Roles.Workspace.Member]: 0,
|
||||
[Roles.Workspace.Guest]: 0
|
||||
}
|
||||
|
||||
workspace.team.items.forEach(
|
||||
(item: WorkspaceMixpanelUpdateGroup_WorkspaceCollaboratorFragment) => {
|
||||
roleCount[item.role as WorkspaceRoles] =
|
||||
(roleCount[item.role as WorkspaceRoles] ?? 0) + 1
|
||||
}
|
||||
)
|
||||
|
||||
const input = {
|
||||
name: workspace.name,
|
||||
description: workspace.description,
|
||||
domainBasedMembershipProtectionEnabled:
|
||||
workspace.domainBasedMembershipProtectionEnabled,
|
||||
discoverabilityEnabled: workspace.discoverabilityEnabled,
|
||||
costTotal: workspace.billing?.cost.total,
|
||||
versionsCountCurrent: workspace.billing?.versionsCount.current,
|
||||
versionsCountMax: workspace.billing?.versionsCount.max,
|
||||
teamTotalCount: workspace.team.totalCount,
|
||||
teamAdminCount: roleCount[Roles.Workspace.Admin],
|
||||
teamMemberCount: roleCount[Roles.Workspace.Member],
|
||||
teamGuestCount: roleCount[Roles.Workspace.Guest]
|
||||
}
|
||||
|
||||
mixpanel.get_group('workspace_id', workspace.id).set(input)
|
||||
}
|
||||
|
||||
return {
|
||||
workspaceMixpanelUpdateGroup
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ export const workspacePageQuery = graphql(`
|
||||
workspace(id: $workspaceId) {
|
||||
id
|
||||
...WorkspaceHeader_Workspace
|
||||
...WorkspaceMixpanelUpdateGroup_Workspace
|
||||
projects(filter: $filter, cursor: $cursor, limit: 10) {
|
||||
...WorkspaceProjectList_ProjectCollection
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const workspaceId = computed(() => route.params.id as string)
|
||||
|
||||
definePageMeta({
|
||||
middleware: ['requires-workspaces-enabled', 'require-valid-workspace']
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user