feat: initial model ingestion tests

This commit is contained in:
oguzhankoral
2026-01-27 02:01:29 +03:00
parent 8b60074992
commit e0b8ccd959
8 changed files with 212 additions and 25 deletions
+15 -3
View File
@@ -135,9 +135,12 @@ import {
canCreateVersionQuery,
setVersionMessageMutation
} from '~/lib/graphql/mutationsAndQueries'
import { useModelIngestion } from '~/lib/ingestion/composables/useModelIngestion'
const store = useHostAppStore()
const accountStore = useAccountStore()
const { startIngestion } = useModelIngestion()
const { trackEvent } = useMixpanel()
const app = useNuxtApp()
@@ -170,12 +173,21 @@ const canCreateVersion = computed(() => {
return canCreateVersionResult.value?.project.model.permissions.canCreateVersion
})
const sendOrCancel = () => {
const sendOrCancel = async () => {
if (!props.canEdit) {
return
}
if (props.modelCard.progress) store.sendModelCancel(props.modelCard.modelCardId)
else store.sendModel(props.modelCard.modelCardId, 'ModelCardButton')
if (props.modelCard.progress) {
store.sendModelCancel(props.modelCard.modelCardId)
// TODO: cancel ingestion
} else {
const sourceData = {
sourceApplicationSlug: store.hostAppName || 'unknown',
sourceApplicationVersion: store.hostAppVersion?.toString() || 'unknown'
}
await startIngestion(props.modelCard, 'Starting to publish', sourceData)
store.sendModel(props.modelCard.modelCardId, 'ModelCardButton')
}
hasSetVersionMessage.value = false
}
+34 -15
View File
@@ -19,6 +19,8 @@ import type {
ReceiveViaBrowserArgs,
CreateVersionArgs
} from '~/lib/bridge/server'
import { useModelIngestion } from '../ingestion/composables/useModelIngestion'
import type { ISenderModelCard } from '../models/card/send'
declare let sketchup: {
exec: (data: Record<string, unknown>) => void
@@ -309,28 +311,45 @@ export class SketchupBridge extends BaseBridge {
}
public async createVersion(args: CreateVersionArgs) {
const accountStore = useAccountStore()
// const accountStore = useAccountStore()
const hostAppStore = useHostAppStore()
const { accounts } = storeToRefs(accountStore)
const account = accounts.value.find((acc) => acc.accountInfo.id === args.accountId)
const { completeIngestionWithVersion } = useModelIngestion()
// const { accounts } = storeToRefs(accountStore)
// const account = accounts.value.find((acc) => acc.accountInfo.id === args.accountId)
const createVersion = provideApolloClient((account as DUIAccount).client)(() =>
useMutation(createVersionMutation)
// const createVersion = provideApolloClient((account as DUIAccount).client)(() =>
// useMutation(createVersionMutation)
// )
const modelCard = hostAppStore.models.find(
(model) => model.modelCardId === args.modelCardId
)
const ingestionId = hostAppStore.ingestionStatus[args.modelCardId]
if (!ingestionId) {
// TODO: fail ingestion
return
}
const res = await completeIngestionWithVersion(
modelCard as ISenderModelCard,
ingestionId,
args.referencedObjectId
)
// sketchup versions are provided as 2 digit. i.e. 22, 23, 24
// we are safe with this string concatanation for 77 years
const hostAppName = `SketchUp 20${hostAppStore.hostAppVersion}`
// const hostAppName = `SketchUp 20${hostAppStore.hostAppVersion}`
const result = await createVersion.mutate({
input: {
modelId: args.modelId,
objectId: args.referencedObjectId,
sourceApplication: hostAppName,
projectId: args.projectId
}
})
return result?.data?.versionMutations?.create?.id
// const result = await createVersion.mutate({
// input: {
// modelId: args.modelId,
// objectId: args.referencedObjectId,
// sourceApplication: hostAppName,
// projectId: args.projectId
// }
// })
return res?.statusData.versionId
}
public async create(): Promise<boolean> {
+3 -3
View File
@@ -57,7 +57,7 @@ type Documents = {
"\n subscription ProjectCommentsUpdated($target: ViewerUpdateTrackingTarget!) {\n projectCommentsUpdated(target: $target) {\n comment {\n author {\n avatar\n id\n name\n }\n id\n hasParent\n parent {\n id\n }\n }\n type\n }\n }\n": typeof types.ProjectCommentsUpdatedDocument,
"\n mutation CreateModelIngestion($input: ModelIngestionCreateInput!) {\n projectMutations {\n modelIngestionMutations {\n create(input: $input) {\n id\n }\n }\n }\n }\n": typeof types.CreateModelIngestionDocument,
"\n mutation UpdateModelIngestionProgress($input: ModelIngestionUpdateInput!) {\n projectMutations {\n modelIngestionMutations {\n updateProgress(input: $input) {\n id\n }\n }\n }\n }\n": typeof types.UpdateModelIngestionProgressDocument,
"\n mutation CompleteModelIngestionWithVersion($input: ModelIngestionSuccessInput!) {\n projectMutations {\n modelIngestionMutations {\n completeWithVersion(input: $input) {\n id\n }\n }\n }\n }\n": typeof types.CompleteModelIngestionWithVersionDocument,
"\n mutation CompleteModelIngestionWithVersion($input: ModelIngestionSuccessInput!) {\n projectMutations {\n modelIngestionMutations {\n completeWithVersion(input: $input) {\n id\n statusData {\n ... on ModelIngestionSuccessStatus {\n versionId\n }\n }\n }\n }\n }\n }\n": typeof types.CompleteModelIngestionWithVersionDocument,
"\n fragment IssuesItem on Issue {\n id\n status\n title\n priority\n viewerState\n identifier\n resourceIdString\n activities(input: { limit: 1, sortDirection: asc }) {\n totalCount\n items {\n actor {\n id\n user {\n name\n id\n avatar\n }\n }\n eventType\n createdAt\n }\n }\n replies {\n totalCount\n items {\n id\n author {\n id\n user {\n name\n id\n avatar\n }\n }\n createdAt\n description {\n doc\n }\n }\n }\n description {\n doc\n }\n labels {\n hexColor\n id\n name\n }\n author {\n id\n user {\n id\n name\n avatar\n }\n }\n dueDate\n assignee {\n id\n user {\n id\n avatar\n name\n }\n }\n }\n": typeof types.IssuesItemFragmentDoc,
"\n query IssuesList($projectId: String!) {\n project(id: $projectId) {\n id\n issues {\n totalCount\n items {\n ...IssuesItem\n }\n }\n }\n }\n": typeof types.IssuesListDocument,
};
@@ -105,7 +105,7 @@ const documents: Documents = {
"\n subscription ProjectCommentsUpdated($target: ViewerUpdateTrackingTarget!) {\n projectCommentsUpdated(target: $target) {\n comment {\n author {\n avatar\n id\n name\n }\n id\n hasParent\n parent {\n id\n }\n }\n type\n }\n }\n": types.ProjectCommentsUpdatedDocument,
"\n mutation CreateModelIngestion($input: ModelIngestionCreateInput!) {\n projectMutations {\n modelIngestionMutations {\n create(input: $input) {\n id\n }\n }\n }\n }\n": types.CreateModelIngestionDocument,
"\n mutation UpdateModelIngestionProgress($input: ModelIngestionUpdateInput!) {\n projectMutations {\n modelIngestionMutations {\n updateProgress(input: $input) {\n id\n }\n }\n }\n }\n": types.UpdateModelIngestionProgressDocument,
"\n mutation CompleteModelIngestionWithVersion($input: ModelIngestionSuccessInput!) {\n projectMutations {\n modelIngestionMutations {\n completeWithVersion(input: $input) {\n id\n }\n }\n }\n }\n": types.CompleteModelIngestionWithVersionDocument,
"\n mutation CompleteModelIngestionWithVersion($input: ModelIngestionSuccessInput!) {\n projectMutations {\n modelIngestionMutations {\n completeWithVersion(input: $input) {\n id\n statusData {\n ... on ModelIngestionSuccessStatus {\n versionId\n }\n }\n }\n }\n }\n }\n": types.CompleteModelIngestionWithVersionDocument,
"\n fragment IssuesItem on Issue {\n id\n status\n title\n priority\n viewerState\n identifier\n resourceIdString\n activities(input: { limit: 1, sortDirection: asc }) {\n totalCount\n items {\n actor {\n id\n user {\n name\n id\n avatar\n }\n }\n eventType\n createdAt\n }\n }\n replies {\n totalCount\n items {\n id\n author {\n id\n user {\n name\n id\n avatar\n }\n }\n createdAt\n description {\n doc\n }\n }\n }\n description {\n doc\n }\n labels {\n hexColor\n id\n name\n }\n author {\n id\n user {\n id\n name\n avatar\n }\n }\n dueDate\n assignee {\n id\n user {\n id\n avatar\n name\n }\n }\n }\n": types.IssuesItemFragmentDoc,
"\n query IssuesList($projectId: String!) {\n project(id: $projectId) {\n id\n issues {\n totalCount\n items {\n ...IssuesItem\n }\n }\n }\n }\n": types.IssuesListDocument,
};
@@ -299,7 +299,7 @@ export function graphql(source: "\n mutation UpdateModelIngestionProgress($inpu
/**
* 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 CompleteModelIngestionWithVersion($input: ModelIngestionSuccessInput!) {\n projectMutations {\n modelIngestionMutations {\n completeWithVersion(input: $input) {\n id\n }\n }\n }\n }\n"): (typeof documents)["\n mutation CompleteModelIngestionWithVersion($input: ModelIngestionSuccessInput!) {\n projectMutations {\n modelIngestionMutations {\n completeWithVersion(input: $input) {\n id\n }\n }\n }\n }\n"];
export function graphql(source: "\n mutation CompleteModelIngestionWithVersion($input: ModelIngestionSuccessInput!) {\n projectMutations {\n modelIngestionMutations {\n completeWithVersion(input: $input) {\n id\n statusData {\n ... on ModelIngestionSuccessStatus {\n versionId\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n mutation CompleteModelIngestionWithVersion($input: ModelIngestionSuccessInput!) {\n projectMutations {\n modelIngestionMutations {\n completeWithVersion(input: $input) {\n id\n statusData {\n ... on ModelIngestionSuccessStatus {\n versionId\n }\n }\n }\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
@@ -0,0 +1,124 @@
import { provideApolloClient, useMutation } from '@vue/apollo-composable'
import { useAccountStore } from '~/store/accounts'
import { useHostAppStore } from '~/store/hostApp'
import {
completeModelIngestionWithVersion,
createModelIngestion,
updateModelIngestionProgress
} from '../graphql/mutations'
import type { SourceDataInput } from '~~/lib/common/generated/gql/graphql'
import type { ISenderModelCard } from '~/lib/models/card/send'
import { storeToRefs } from 'pinia'
/**
* New way of creating versions.
* It is essential for server to track limits on versions.
* The flow is as follows:
* 0. Check if the user has enough limits to create a new version (this is handled outside of this composable)
* 1. Start a new ingestion
* 2. Update the ingestion with the new data when connector throws progress via 'setModelProgress' event
* 3. Complete the version with the root object id that passed by connector or server/sketchup bridges in JS
*/
export const useModelIngestion = () => {
const store = useHostAppStore()
const { ingestionStatus } = storeToRefs(store)
const { getAccountClient } = useAccountStore()
const startIngestion = async (
senderModelCard: ISenderModelCard,
progressMessage: string,
sourceData: SourceDataInput
) => {
const client = getAccountClient(senderModelCard.accountId)
const { mutate } = provideApolloClient(client)(() =>
useMutation(createModelIngestion)
)
const res = await mutate({
input: {
projectId: senderModelCard.projectId,
modelId: senderModelCard.modelId,
progressMessage,
sourceData
}
})
if (res?.errors?.length) {
throw new Error(res.errors[0].message)
}
const ingestionId = res?.data?.projectMutations.modelIngestionMutations.create.id
if (ingestionId) {
ingestionStatus.value[senderModelCard.modelCardId] = ingestionId
}
return res?.data?.projectMutations.modelIngestionMutations.create
}
const updateIngestion = async (
senderModelCard: ISenderModelCard,
ingestionId: string,
progressMessage: string,
progress?: number
) => {
const client = getAccountClient(senderModelCard.accountId)
const { mutate } = provideApolloClient(client)(() =>
useMutation(updateModelIngestionProgress)
)
const res = await mutate({
input: {
projectId: senderModelCard.projectId,
ingestionId,
progressMessage,
progress
}
})
if (res?.errors?.length) {
throw new Error(res.errors[0].message)
}
return res?.data?.projectMutations.modelIngestionMutations.updateProgress
}
// TODO: cancel ingestion
const completeIngestionWithVersion = async (
senderModelCard: ISenderModelCard,
ingestionId: string,
rootObjectId: string
) => {
const client = getAccountClient(senderModelCard.accountId)
const { mutate } = provideApolloClient(client)(() =>
useMutation(completeModelIngestionWithVersion)
)
const res = await mutate({
input: {
projectId: senderModelCard.projectId,
ingestionId,
rootObjectId
}
})
if (res?.errors?.length) {
throw new Error(res.errors[0].message)
}
// clean the completed ingestion
ingestionStatus.value = Object.fromEntries(
Object.entries(ingestionStatus.value).filter(
([key]) => key !== senderModelCard.modelCardId
)
)
return res?.data?.projectMutations.modelIngestionMutations.completeWithVersion
}
return {
startIngestion,
updateIngestion,
completeIngestionWithVersion
}
}
+5
View File
@@ -30,6 +30,11 @@ export const completeModelIngestionWithVersion = graphql(`
modelIngestionMutations {
completeWithVersion(input: $input) {
id
statusData {
... on ModelIngestionSuccessStatus {
versionId
}
}
}
}
}
+9
View File
@@ -294,6 +294,14 @@ export const useAccountStore = defineStore('accountStore', () => {
if (accountMatchWithServerUrl) return accountMatchWithServerUrl
}
const getAccountClient = (accountId: string) => {
return (
accounts.value.find(
(account) => account.accountInfo.id === accountId
) as DUIAccount
).client
}
const provideClients = () => {
provideApolloClients(apolloClients)
}
@@ -320,6 +328,7 @@ export const useAccountStore = defineStore('accountStore', () => {
return {
isLoading,
accounts,
getAccountClient,
defaultAccount,
activeAccount,
userSelectedAccount,
+20 -2
View File
@@ -28,6 +28,7 @@ import {
import { provideApolloClient, useMutation } from '@vue/apollo-composable'
import { createVersionMutation } from '~/lib/graphql/mutationsAndQueries'
import type { BaseBridge } from '~/lib/bridge/base'
import { useModelIngestion } from '~/lib/ingestion/composables/useModelIngestion'
export type ProjectModelGroup = {
projectId: string
@@ -43,6 +44,7 @@ export const useHostAppStore = defineStore('hostAppStore', () => {
const { $openUrl } = useNuxtApp()
const accountsStore = useAccountStore()
const { checkUpdate } = useUpdateConnector()
const { updateIngestion } = useModelIngestion()
const isDistributedBySpeckle = ref<boolean>(true)
const latestAvailableVersion = ref<Version | null>(null)
@@ -65,6 +67,9 @@ export const useHostAppStore = defineStore('hostAppStore', () => {
// Different host apps can have different kind of ISendFilterSelect send filters, and we collect them here to generalize the component we use in `ListSelect`
const availableSelectSendFilters = ref<Record<string, SendFilterSelect>>({})
// kvp for modelCardId - ingestionId
const ingestionStatus = ref<Record<string, string>>({})
const dismissNotification = () => {
currentNotification.value = null
}
@@ -479,7 +484,7 @@ export const useHostAppStore = defineStore('hostAppStore', () => {
app.$receiveBinding?.on('setModelReceiveResult', setModelReceiveResult)
// GENERIC STUFF
const handleModelProgressEvents = (args: {
const handleModelProgressEvents = async (args: {
modelCardId: string
progress?: ModelCardProgress
}) => {
@@ -487,6 +492,18 @@ export const useHostAppStore = defineStore('hostAppStore', () => {
(m) => m.modelCardId === args.modelCardId
) as IModelCard
model.progress = args.progress
if (model.typeDiscriminator.includes('SenderModelCard')) {
const ingestionId = ingestionStatus.value[args.modelCardId]
if (ingestionId) {
await updateIngestion(
model,
ingestionId,
args.progress?.status || 'Progressing',
args.progress?.progress || 0
)
}
}
}
const setModelError = (args: {
@@ -788,6 +805,7 @@ export const useHostAppStore = defineStore('hostAppStore', () => {
getSendSettings,
setModelSendResult,
setModelReceiveResult,
handleModelProgressEvents
handleModelProgressEvents,
ingestionStatus
}
})