fix(fe2): project delete btn not following auth policy (#4770)
This commit is contained in:
committed by
GitHub
parent
7573e74d83
commit
7d64667ea0
@@ -44,8 +44,10 @@ import { LayoutDialog, type LayoutDialogButton } from '@speckle/ui-components'
|
||||
import { useDeleteProject } from '~~/lib/projects/composables/projectManagement'
|
||||
import { useMixpanel } from '~~/lib/core/composables/mp'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type { ProjectsDeleteDialog_ProjectFragment } from '~~/lib/common/generated/gql/graphql'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import type {
|
||||
FullPermissionCheckResultFragment,
|
||||
ProjectsDeleteDialog_ProjectFragment
|
||||
} from '~~/lib/common/generated/gql/graphql'
|
||||
|
||||
graphql(`
|
||||
fragment ProjectsDeleteDialog_Project on Project {
|
||||
@@ -62,6 +64,11 @@ graphql(`
|
||||
versions(limit: 0) {
|
||||
totalCount
|
||||
}
|
||||
permissions {
|
||||
canDelete {
|
||||
...FullPermissionCheckResult
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
@@ -75,7 +82,6 @@ const isOpen = defineModel<boolean>('open', { required: true })
|
||||
|
||||
const deleteProject = useDeleteProject()
|
||||
const mixpanel = useMixpanel()
|
||||
const { isAdmin } = useActiveUser()
|
||||
|
||||
const projectNameInput = ref('')
|
||||
|
||||
@@ -91,6 +97,18 @@ const versionsText = computed(
|
||||
props.project.versions.totalCount === 1 ? 'version' : 'versions'
|
||||
}`
|
||||
)
|
||||
|
||||
const canDelete = computed((): FullPermissionCheckResultFragment => {
|
||||
if (projectNameInput.value !== props.project.name)
|
||||
return {
|
||||
authorized: false,
|
||||
code: 'NAME_MISMATCH',
|
||||
message: 'Entered project name does not match the actual project name'
|
||||
}
|
||||
|
||||
return props.project.permissions.canDelete
|
||||
})
|
||||
|
||||
const dialogButtons = computed<LayoutDialogButton[]>(() => [
|
||||
{
|
||||
text: 'Cancel',
|
||||
@@ -105,27 +123,25 @@ const dialogButtons = computed<LayoutDialogButton[]>(() => [
|
||||
props: {
|
||||
color: 'danger',
|
||||
|
||||
disabled: projectNameInput.value !== props.project.name
|
||||
disabled: !canDelete.value.authorized
|
||||
},
|
||||
disabledMessage: canDelete.value.message,
|
||||
onClick: async () => {
|
||||
if (
|
||||
projectNameInput.value === props.project.name &&
|
||||
(props.project.role === Roles.Stream.Owner || isAdmin.value)
|
||||
) {
|
||||
const options = {
|
||||
goHome: props.redirectOnComplete,
|
||||
workspaceSlug: props.project.workspace?.slug
|
||||
}
|
||||
if (!canDelete.value.authorized) return
|
||||
|
||||
await deleteProject(props.project.id, options)
|
||||
isOpen.value = false
|
||||
mixpanel.track('Stream Action', {
|
||||
type: 'action',
|
||||
name: 'delete',
|
||||
// eslint-disable-next-line camelcase
|
||||
workspace_id: props.project.workspace?.id
|
||||
})
|
||||
const options = {
|
||||
goHome: props.redirectOnComplete,
|
||||
workspaceSlug: props.project.workspace?.slug
|
||||
}
|
||||
|
||||
await deleteProject(props.project.id, options)
|
||||
isOpen.value = false
|
||||
mixpanel.track('Stream Action', {
|
||||
type: 'action',
|
||||
name: 'delete',
|
||||
// eslint-disable-next-line camelcase
|
||||
workspace_id: props.project.workspace?.id
|
||||
})
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
@@ -99,7 +99,7 @@ type Documents = {
|
||||
"\n fragment ProjectsDashboard_User on User {\n permissions {\n canCreatePersonalProject {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.ProjectsDashboard_UserFragmentDoc,
|
||||
"\n fragment ProjectsDashboardFilledProject on ProjectCollection {\n items {\n ...ProjectDashboardItem\n }\n }\n": typeof types.ProjectsDashboardFilledProjectFragmentDoc,
|
||||
"\n fragment ProjectsDashboardFilledUser on UserProjectCollection {\n items {\n ...ProjectDashboardItem\n }\n }\n": typeof types.ProjectsDashboardFilledUserFragmentDoc,
|
||||
"\n fragment ProjectsDeleteDialog_Project on Project {\n id\n name\n role\n models(limit: 0) {\n totalCount\n }\n workspace {\n slug\n id\n }\n versions(limit: 0) {\n totalCount\n }\n }\n": typeof types.ProjectsDeleteDialog_ProjectFragmentDoc,
|
||||
"\n fragment ProjectsDeleteDialog_Project on Project {\n id\n name\n role\n models(limit: 0) {\n totalCount\n }\n workspace {\n slug\n id\n }\n versions(limit: 0) {\n totalCount\n }\n permissions {\n canDelete {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.ProjectsDeleteDialog_ProjectFragmentDoc,
|
||||
"\n fragment ProjectsHiddenProjectWarning_User on User {\n id\n expiredSsoSessions {\n id\n slug\n name\n logo\n }\n }\n": typeof types.ProjectsHiddenProjectWarning_UserFragmentDoc,
|
||||
"\n fragment ProjectsWorkspaceSelect_Workspace on Workspace {\n id\n role\n name\n logo\n readOnly\n slug\n }\n": typeof 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": typeof types.ProjectsInviteBannerFragmentDoc,
|
||||
@@ -512,7 +512,7 @@ const documents: Documents = {
|
||||
"\n fragment ProjectsDashboard_User on User {\n permissions {\n canCreatePersonalProject {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.ProjectsDashboard_UserFragmentDoc,
|
||||
"\n fragment ProjectsDashboardFilledProject on ProjectCollection {\n items {\n ...ProjectDashboardItem\n }\n }\n": types.ProjectsDashboardFilledProjectFragmentDoc,
|
||||
"\n fragment ProjectsDashboardFilledUser on UserProjectCollection {\n items {\n ...ProjectDashboardItem\n }\n }\n": types.ProjectsDashboardFilledUserFragmentDoc,
|
||||
"\n fragment ProjectsDeleteDialog_Project on Project {\n id\n name\n role\n models(limit: 0) {\n totalCount\n }\n workspace {\n slug\n id\n }\n versions(limit: 0) {\n totalCount\n }\n }\n": types.ProjectsDeleteDialog_ProjectFragmentDoc,
|
||||
"\n fragment ProjectsDeleteDialog_Project on Project {\n id\n name\n role\n models(limit: 0) {\n totalCount\n }\n workspace {\n slug\n id\n }\n versions(limit: 0) {\n totalCount\n }\n permissions {\n canDelete {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.ProjectsDeleteDialog_ProjectFragmentDoc,
|
||||
"\n fragment ProjectsHiddenProjectWarning_User on User {\n id\n expiredSsoSessions {\n id\n slug\n name\n logo\n }\n }\n": types.ProjectsHiddenProjectWarning_UserFragmentDoc,
|
||||
"\n fragment ProjectsWorkspaceSelect_Workspace on Workspace {\n id\n role\n name\n logo\n readOnly\n slug\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,
|
||||
@@ -1197,7 +1197,7 @@ export function graphql(source: "\n fragment ProjectsDashboardFilledUser on Use
|
||||
/**
|
||||
* 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 ProjectsDeleteDialog_Project on Project {\n id\n name\n role\n models(limit: 0) {\n totalCount\n }\n workspace {\n slug\n id\n }\n versions(limit: 0) {\n totalCount\n }\n }\n"): (typeof documents)["\n fragment ProjectsDeleteDialog_Project on Project {\n id\n name\n role\n models(limit: 0) {\n totalCount\n }\n workspace {\n slug\n id\n }\n versions(limit: 0) {\n totalCount\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment ProjectsDeleteDialog_Project on Project {\n id\n name\n role\n models(limit: 0) {\n totalCount\n }\n workspace {\n slug\n id\n }\n versions(limit: 0) {\n totalCount\n }\n permissions {\n canDelete {\n ...FullPermissionCheckResult\n }\n }\n }\n"): (typeof documents)["\n fragment ProjectsDeleteDialog_Project on Project {\n id\n name\n role\n models(limit: 0) {\n totalCount\n }\n workspace {\n slug\n id\n }\n versions(limit: 0) {\n totalCount\n }\n permissions {\n canDelete {\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.
|
||||
*/
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { Result } from 'true-myth'
|
||||
import type { Result } from 'true-myth'
|
||||
import { AuthError } from '../domain/authErrors.js'
|
||||
|
||||
export type GraphqlPermissionCheckResult = {
|
||||
|
||||
Reference in New Issue
Block a user