refactor(permissions): check canCreateVersion on action instead of polling
This commit is contained in:
@@ -4,10 +4,6 @@
|
||||
:model-card="modelCard"
|
||||
:project="project"
|
||||
:can-edit="canEdit"
|
||||
:cta-disabled="!canCreateVersion?.authorized"
|
||||
:cta-disabled-message="
|
||||
canCreateVersion?.authorized ? undefined : canCreateVersion?.message
|
||||
"
|
||||
@manual-publish-or-load="sendOrCancel"
|
||||
>
|
||||
<div class="flex max-[275px]:w-full overflow-hidden my-2">
|
||||
@@ -39,15 +35,9 @@
|
||||
<FormButton size="sm" color="outline" @click.stop="saveFilter()">
|
||||
Save
|
||||
</FormButton>
|
||||
<div v-tippy="canCreateVersion?.authorized ? '' : canCreateVersion?.message">
|
||||
<FormButton
|
||||
size="sm"
|
||||
:disabled="!canCreateVersion?.authorized"
|
||||
@click.stop="saveFilterAndSend()"
|
||||
>
|
||||
Save & Publish
|
||||
</FormButton>
|
||||
</div>
|
||||
<FormButton size="sm" @click.stop="saveFilterAndSend()">
|
||||
Save & Publish
|
||||
</FormButton>
|
||||
</div>
|
||||
</CommonDialog>
|
||||
|
||||
@@ -127,13 +117,9 @@ import type { ProjectModelGroup } from '~/store/hostApp'
|
||||
import { useHostAppStore } from '~/store/hostApp'
|
||||
import { useMixpanel } from '~/lib/core/composables/mixpanel'
|
||||
import { ToastNotificationType, ValidationHelpers } from '@speckle/ui-components'
|
||||
import { provideApolloClient, useMutation, useQuery } from '@vue/apollo-composable'
|
||||
import { provideApolloClient, useMutation } from '@vue/apollo-composable'
|
||||
import { useAccountStore, type DUIAccount } from '~/store/accounts'
|
||||
import {
|
||||
canCreateVersionQuery,
|
||||
setVersionMessageMutation
|
||||
} from '~/lib/graphql/mutationsAndQueries'
|
||||
import { useIntervalFn } from '@vueuse/core'
|
||||
import { setVersionMessageMutation } from '~/lib/graphql/mutationsAndQueries'
|
||||
|
||||
const store = useHostAppStore()
|
||||
const accountStore = useAccountStore()
|
||||
@@ -157,25 +143,6 @@ app.$baseBinding?.on('documentChanged', () => {
|
||||
openFilterDialog.value = false
|
||||
})
|
||||
|
||||
const { result: canCreateVersionResult, refetch: refetchCanCreateVersion } = useQuery(
|
||||
canCreateVersionQuery,
|
||||
() => ({ projectId: props.modelCard.projectId, modelId: props.modelCard.modelId }),
|
||||
() => ({
|
||||
clientId: account.accountInfo.id,
|
||||
fetchPolicy: 'network-only'
|
||||
})
|
||||
)
|
||||
|
||||
const canCreateVersion = computed(() => {
|
||||
return canCreateVersionResult.value?.project.model.permissions.canCreateVersion
|
||||
})
|
||||
|
||||
// poll canCreateVersion every 1s to reflect workspace limit changes.
|
||||
// No subscription available on a workspace level, so polling probably easiest approach?
|
||||
useIntervalFn(() => {
|
||||
refetchCanCreateVersion()
|
||||
}, 1000)
|
||||
|
||||
const sendOrCancel = () => {
|
||||
if (!props.canEdit) {
|
||||
return
|
||||
@@ -299,19 +266,12 @@ const expiredNotification = computed(() => {
|
||||
notification.cta = {
|
||||
name: ctaType,
|
||||
action: async () => {
|
||||
if (!canCreateVersion.value?.authorized) {
|
||||
return
|
||||
}
|
||||
hasSetVersionMessage.value = false
|
||||
if (props.modelCard.progress) {
|
||||
await store.sendModelCancel(props.modelCard.modelCardId)
|
||||
}
|
||||
store.sendModel(props.modelCard.modelCardId, ctaType)
|
||||
},
|
||||
disabled: !canCreateVersion.value?.authorized,
|
||||
tooltipText: canCreateVersion.value?.authorized
|
||||
? undefined
|
||||
: canCreateVersion.value?.message
|
||||
}
|
||||
}
|
||||
return notification
|
||||
})
|
||||
|
||||
@@ -45,15 +45,7 @@
|
||||
"
|
||||
/>
|
||||
<div class="mt-2">
|
||||
<div v-tippy="canCreateVersion?.authorized ? '' : canCreateVersion?.message">
|
||||
<FormButton
|
||||
full-width
|
||||
:disabled="!canCreateVersion?.authorized"
|
||||
@click="addModel"
|
||||
>
|
||||
Publish
|
||||
</FormButton>
|
||||
</div>
|
||||
<FormButton full-width @click="addModel">Publish</FormButton>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="urlParseError" class="p-2 text-danger">
|
||||
@@ -75,9 +67,6 @@ import { useMixpanel } from '~/lib/core/composables/mixpanel'
|
||||
import { useSettingsTracking } from '~/lib/core/composables/trackSettings'
|
||||
import type { CardSetting } from '~/lib/models/card/setting'
|
||||
import { useAddByUrl } from '~/lib/core/composables/addByUrl'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { canCreateVersionQuery } from '~/lib/graphql/mutationsAndQueries'
|
||||
import { useIntervalFn } from '@vueuse/core'
|
||||
|
||||
const { trackEvent } = useMixpanel()
|
||||
const { trackSettingsChange } = useSettingsTracking()
|
||||
@@ -150,31 +139,6 @@ watch(step, (newVal, oldVal) => {
|
||||
|
||||
const hostAppStore = useHostAppStore()
|
||||
|
||||
// check canCreateVersion permission when model is selected
|
||||
const { result: canCreateVersionResult, refetch: refetchCanCreateVersion } = useQuery(
|
||||
canCreateVersionQuery,
|
||||
() => ({
|
||||
projectId: selectedProject.value?.id as string,
|
||||
modelId: selectedModel.value?.id as string
|
||||
}),
|
||||
() => ({
|
||||
enabled: !!selectedProject.value?.id && !!selectedModel.value?.id,
|
||||
clientId: selectedAccountId.value,
|
||||
fetchPolicy: 'network-only'
|
||||
})
|
||||
)
|
||||
|
||||
const canCreateVersion = computed(() => {
|
||||
return canCreateVersionResult.value?.project.model.permissions.canCreateVersion
|
||||
})
|
||||
|
||||
useIntervalFn(() => {
|
||||
// poll on step 3 (where the Publish button is visible)
|
||||
if (step.value === 3) {
|
||||
refetchCanCreateVersion()
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
// accountId, serverUrl, projectId, modelId, sendFilter, settings
|
||||
const addModel = async () => {
|
||||
void trackEvent('DUI3 Action', {
|
||||
|
||||
+43
-1
@@ -14,6 +14,7 @@ import type {
|
||||
SendFilterSelect
|
||||
} from '~/lib/models/card/send'
|
||||
import type { ToastNotification } from '@speckle/ui-components'
|
||||
import { ToastNotificationType } from '@speckle/ui-components'
|
||||
import type { Nullable } from '@speckle/shared'
|
||||
import type { HostAppError } from '~/lib/bridge/errorHandler'
|
||||
import type { ConversionResult } from '~/lib/conversions/conversionResult'
|
||||
@@ -26,7 +27,10 @@ import {
|
||||
type Version
|
||||
} from '~/lib/core/composables/updateConnector'
|
||||
import { provideApolloClient, useMutation } from '@vue/apollo-composable'
|
||||
import { createVersionMutation } from '~/lib/graphql/mutationsAndQueries'
|
||||
import {
|
||||
canCreateVersionQuery,
|
||||
createVersionMutation
|
||||
} from '~/lib/graphql/mutationsAndQueries'
|
||||
import type { BaseBridge } from '~/lib/bridge/base'
|
||||
import { useModelIngestion } from '~/lib/ingestion/composables/useModelIngestion'
|
||||
|
||||
@@ -325,6 +329,31 @@ export const useHostAppStore = defineStore('hostAppStore', () => {
|
||||
* Send functionality
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks if user can create a version for the given model.
|
||||
* Used to validate before starting a publish operation.
|
||||
*/
|
||||
const checkCanCreateVersion = async (model: ISenderModelCard) => {
|
||||
const client = accountsStore.getAccountClient(model.accountId)
|
||||
|
||||
try {
|
||||
const result = await client.query({
|
||||
query: canCreateVersionQuery,
|
||||
variables: {
|
||||
projectId: model.projectId,
|
||||
modelId: model.modelId
|
||||
},
|
||||
fetchPolicy: 'network-only'
|
||||
})
|
||||
|
||||
return result.data.project.model.permissions.canCreateVersion
|
||||
} catch (error) {
|
||||
// If we can't check, allow the attempt - server will reject if not allowed
|
||||
console.error('Failed to check canCreateVersion:', error)
|
||||
return { authorized: true, message: null }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the host app to start sending a specific model card. This will reach inside the host application.
|
||||
* @param modelId
|
||||
@@ -333,6 +362,19 @@ export const useHostAppStore = defineStore('hostAppStore', () => {
|
||||
const model = documentModelStore.value.models.find(
|
||||
(m) => m.modelCardId === modelCardId
|
||||
) as ISenderModelCard
|
||||
|
||||
// Check if user can create version before starting publish.
|
||||
// We do this check on action rather than polling to avoid going ott on the server.
|
||||
const canCreate = await checkCanCreateVersion(model)
|
||||
if (!canCreate.authorized) {
|
||||
setNotification({
|
||||
type: ToastNotificationType.Warning,
|
||||
title: 'Cannot publish',
|
||||
description: canCreate.message || 'Workspace limits have been reached'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (model.expired) {
|
||||
// user sends via "Update" button
|
||||
void trackEvent(
|
||||
|
||||
Reference in New Issue
Block a user