move export to the rust side to make the interface way more clean (#5855)
* move export Signed-off-by: Jess Frazelle <github@jessfraz.com> testing Signed-off-by: Jess Frazelle <github@jessfraz.com> remove debugs Signed-off-by: Jess Frazelle <github@jessfraz.com> fix main Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> fices Signed-off-by: Jess Frazelle <github@jessfraz.com> get rid of logs Signed-off-by: Jess Frazelle <github@jessfraz.com> * Convert async actions anti-pattern to fromPromise actors * Fix tsc by removing a generic type * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * cleanup Signed-off-by: Jess Frazelle <github@jessfraz.com> * cleanup Signed-off-by: Jess Frazelle <github@jessfraz.com> * Update rustContext.ts * fix Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix; Signed-off-by: Jess Frazelle <github@jessfraz.com> * cleanup Signed-off-by: Jess Frazelle <github@jessfraz.com> * remove weird file Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: Frank Noirot <frankjohnson1993@gmail.com>
This commit is contained in:
@ -8,7 +8,6 @@ import React, {
|
||||
} from 'react'
|
||||
import {
|
||||
Actor,
|
||||
AnyStateMachine,
|
||||
ContextFrom,
|
||||
Prop,
|
||||
SnapshotFrom,
|
||||
@ -33,8 +32,12 @@ import {
|
||||
codeManager,
|
||||
editorManager,
|
||||
sceneEntitiesManager,
|
||||
rustContext,
|
||||
} from 'lib/singletons'
|
||||
import { MachineManagerContext } from 'components/MachineManagerProvider'
|
||||
import {
|
||||
MachineManager,
|
||||
MachineManagerContext,
|
||||
} from 'components/MachineManagerProvider'
|
||||
import { useHotkeys } from 'react-hotkeys-hook'
|
||||
import { applyConstraintHorzVertDistance } from './Toolbar/SetHorzVertDistance'
|
||||
import {
|
||||
@ -53,7 +56,10 @@ import {
|
||||
import { applyConstraintIntersect } from './Toolbar/Intersect'
|
||||
import { applyConstraintAbsDistance } from './Toolbar/SetAbsDistance'
|
||||
import useStateMachineCommands from 'hooks/useStateMachineCommands'
|
||||
import { modelingMachineCommandConfig } from 'lib/commandBarConfigs/modelingCommandConfig'
|
||||
import {
|
||||
ModelingCommandSchema,
|
||||
modelingMachineCommandConfig,
|
||||
} from 'lib/commandBarConfigs/modelingCommandConfig'
|
||||
import {
|
||||
SEGMENT_BODIES,
|
||||
getParentGroup,
|
||||
@ -84,21 +90,17 @@ import {
|
||||
isCursorInFunctionDefinition,
|
||||
traverse,
|
||||
} from 'lang/queryAst'
|
||||
import { exportFromEngine } from 'lib/exportFromEngine'
|
||||
import { Models } from '@kittycad/lib/dist/types/src'
|
||||
import toast from 'react-hot-toast'
|
||||
import { useLoaderData, useNavigate, useSearchParams } from 'react-router-dom'
|
||||
import { letEngineAnimateAndSyncCamAfter } from 'clientSideScene/CameraControls'
|
||||
import { err, reportRejection, trap, reject } from 'lib/trap'
|
||||
import {
|
||||
ExportIntent,
|
||||
EngineConnectionStateType,
|
||||
EngineConnectionEvents,
|
||||
} from 'lang/std/engineConnection'
|
||||
import { submitAndAwaitTextToKcl } from 'lib/textToCad'
|
||||
import { useFileContext } from 'hooks/useFileContext'
|
||||
import { platform, uuidv4 } from 'lib/utils'
|
||||
import { IndexLoaderData } from 'lib/types'
|
||||
import { Node } from '@rust/kcl-lib/bindings/Node'
|
||||
import {
|
||||
getFaceCodeRef,
|
||||
@ -111,15 +113,18 @@ import { commandBarActor } from 'machines/commandBarMachine'
|
||||
import { useToken } from 'machines/appMachine'
|
||||
import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils'
|
||||
import { useSettings } from 'machines/appMachine'
|
||||
|
||||
type MachineContext<T extends AnyStateMachine> = {
|
||||
state: StateFrom<T>
|
||||
context: ContextFrom<T>
|
||||
send: Prop<Actor<T>, 'send'>
|
||||
}
|
||||
import { IndexLoaderData } from 'lib/types'
|
||||
import { OutputFormat3d } from '@rust/kcl-lib/bindings/ModelingCmd'
|
||||
import { EXPORT_TOAST_MESSAGES, MAKE_TOAST_MESSAGES } from 'lib/constants'
|
||||
import { exportMake } from 'lib/exportMake'
|
||||
import { exportSave } from 'lib/exportSave'
|
||||
|
||||
export const ModelingMachineContext = createContext(
|
||||
{} as MachineContext<typeof modelingMachine>
|
||||
{} as {
|
||||
state: StateFrom<typeof modelingMachine>
|
||||
context: ContextFrom<typeof modelingMachine>
|
||||
send: Prop<Actor<typeof modelingMachine>, 'send'>
|
||||
}
|
||||
)
|
||||
|
||||
const commandBarIsClosedSelector = (
|
||||
@ -524,118 +529,6 @@ export const ModelingMachineProvider = ({
|
||||
return {}
|
||||
}
|
||||
),
|
||||
Make: ({ context, event }) => {
|
||||
if (event.type !== 'Make') return
|
||||
// Check if we already have an export intent.
|
||||
if (engineCommandManager.exportInfo) {
|
||||
toast.error('Already exporting')
|
||||
return
|
||||
}
|
||||
// Set the export intent.
|
||||
engineCommandManager.exportInfo = {
|
||||
intent: ExportIntent.Make,
|
||||
name: file?.name || '',
|
||||
}
|
||||
|
||||
// Set the current machine.
|
||||
// Due to our use of singeton pattern, we need to do this to reliably
|
||||
// update this object across React and non-React boundary.
|
||||
// We need to do this eagerly because of the exportToEngine call below.
|
||||
if (engineCommandManager.machineManager === null) {
|
||||
console.warn(
|
||||
"engineCommandManager.machineManager is null. It shouldn't be at this point. Aborting operation."
|
||||
)
|
||||
return
|
||||
} else {
|
||||
engineCommandManager.machineManager.currentMachine =
|
||||
event.data.machine
|
||||
}
|
||||
|
||||
// Update the rest of the UI that needs to know the current machine
|
||||
context.machineManager.setCurrentMachine(event.data.machine)
|
||||
|
||||
const format: Models['OutputFormat_type'] = {
|
||||
type: 'stl',
|
||||
coords: {
|
||||
forward: {
|
||||
axis: 'y',
|
||||
direction: 'negative',
|
||||
},
|
||||
up: {
|
||||
axis: 'z',
|
||||
direction: 'positive',
|
||||
},
|
||||
},
|
||||
storage: 'ascii',
|
||||
// Convert all units to mm since that is what the slicer expects.
|
||||
units: 'mm',
|
||||
selection: { type: 'default_scene' },
|
||||
}
|
||||
|
||||
exportFromEngine({
|
||||
format: format,
|
||||
}).catch(reportRejection)
|
||||
},
|
||||
'Engine export': ({ event }) => {
|
||||
if (event.type !== 'Export') return
|
||||
if (engineCommandManager.exportInfo) {
|
||||
toast.error('Already exporting')
|
||||
return
|
||||
}
|
||||
// Set the export intent.
|
||||
engineCommandManager.exportInfo = {
|
||||
intent: ExportIntent.Save,
|
||||
// This never gets used its only for make.
|
||||
name: file?.name?.replace('.kcl', `.${event.data.type}`) || '',
|
||||
}
|
||||
|
||||
const format = {
|
||||
...event.data,
|
||||
} as Partial<Models['OutputFormat_type']>
|
||||
|
||||
// Set all the un-configurable defaults here.
|
||||
if (format.type === 'gltf') {
|
||||
format.presentation = 'pretty'
|
||||
}
|
||||
|
||||
if (
|
||||
format.type === 'obj' ||
|
||||
format.type === 'ply' ||
|
||||
format.type === 'step' ||
|
||||
format.type === 'stl'
|
||||
) {
|
||||
// Set the default coords.
|
||||
// In the future we can make this configurable.
|
||||
// But for now, its probably best to keep it consistent with the
|
||||
// UI.
|
||||
format.coords = {
|
||||
forward: {
|
||||
axis: 'y',
|
||||
direction: 'negative',
|
||||
},
|
||||
up: {
|
||||
axis: 'z',
|
||||
direction: 'positive',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
format.type === 'obj' ||
|
||||
format.type === 'stl' ||
|
||||
format.type === 'ply'
|
||||
) {
|
||||
format.units = defaultUnit.current
|
||||
}
|
||||
|
||||
if (format.type === 'ply' || format.type === 'stl') {
|
||||
format.selection = { type: 'default_scene' }
|
||||
}
|
||||
|
||||
exportFromEngine({
|
||||
format: format as Models['OutputFormat_type'],
|
||||
}).catch(reportRejection)
|
||||
},
|
||||
'Submit to Text-to-CAD API': ({ event }) => {
|
||||
if (event.type !== 'Text-to-CAD') return
|
||||
const trimmedPrompt = event.data.prompt.trim()
|
||||
@ -696,14 +589,155 @@ export const ModelingMachineProvider = ({
|
||||
else if (kclManager.ast.body.length === 0)
|
||||
errorMessage += 'due to Empty Scene'
|
||||
console.error(errorMessage)
|
||||
toast.error(errorMessage, {
|
||||
id: kclManager.engineCommandManager.pendingExport?.toastId,
|
||||
})
|
||||
toast.error(errorMessage)
|
||||
return false
|
||||
}
|
||||
},
|
||||
},
|
||||
actors: {
|
||||
exportFromEngine: fromPromise(
|
||||
async ({ input }: { input?: ModelingCommandSchema['Export'] }) => {
|
||||
if (!input) {
|
||||
return new Error('No input provided')
|
||||
}
|
||||
|
||||
let fileName = file?.name?.replace('.kcl', `.${input.type}`) || ''
|
||||
console.log('fileName', fileName)
|
||||
// Ensure the file has an extension.
|
||||
if (!fileName.includes('.')) {
|
||||
fileName += `.${input.type}`
|
||||
}
|
||||
|
||||
const format = {
|
||||
...input,
|
||||
} as Partial<OutputFormat3d>
|
||||
|
||||
// Set all the un-configurable defaults here.
|
||||
if (format.type === 'gltf') {
|
||||
format.presentation = 'pretty'
|
||||
}
|
||||
|
||||
if (
|
||||
format.type === 'obj' ||
|
||||
format.type === 'ply' ||
|
||||
format.type === 'step' ||
|
||||
format.type === 'stl'
|
||||
) {
|
||||
// Set the default coords.
|
||||
// In the future we can make this configurable.
|
||||
// But for now, its probably best to keep it consistent with the
|
||||
// UI.
|
||||
format.coords = {
|
||||
forward: {
|
||||
axis: 'y',
|
||||
direction: 'negative',
|
||||
},
|
||||
up: {
|
||||
axis: 'z',
|
||||
direction: 'positive',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
format.type === 'obj' ||
|
||||
format.type === 'stl' ||
|
||||
format.type === 'ply'
|
||||
) {
|
||||
format.units = defaultUnit.current
|
||||
}
|
||||
|
||||
if (format.type === 'ply' || format.type === 'stl') {
|
||||
format.selection = { type: 'default_scene' }
|
||||
}
|
||||
|
||||
const toastId = toast.loading(EXPORT_TOAST_MESSAGES.START)
|
||||
const files = await rustContext.export(
|
||||
format,
|
||||
{
|
||||
settings: { modeling: { base_unit: defaultUnit.current } },
|
||||
},
|
||||
toastId
|
||||
)
|
||||
|
||||
if (files === undefined) {
|
||||
// We already sent the toast message in the export function.
|
||||
return
|
||||
}
|
||||
|
||||
await exportSave({ files, toastId, fileName })
|
||||
}
|
||||
),
|
||||
makeFromEngine: fromPromise(
|
||||
async ({
|
||||
input,
|
||||
}: {
|
||||
input?: {
|
||||
machineManager: MachineManager
|
||||
} & ModelingCommandSchema['Make']
|
||||
}) => {
|
||||
if (input === undefined) {
|
||||
return new Error('No input provided')
|
||||
}
|
||||
|
||||
const name = file?.name || ''
|
||||
|
||||
// Set the current machine.
|
||||
// Due to our use of singeton pattern, we need to do this to reliably
|
||||
// update this object across React and non-React boundary.
|
||||
// We need to do this eagerly because of the exportToEngine call below.
|
||||
if (engineCommandManager.machineManager === null) {
|
||||
console.warn(
|
||||
"engineCommandManager.machineManager is null. It shouldn't be at this point. Aborting operation."
|
||||
)
|
||||
return new Error('Machine manager is not set')
|
||||
} else {
|
||||
engineCommandManager.machineManager.currentMachine = input.machine
|
||||
}
|
||||
|
||||
// Update the rest of the UI that needs to know the current machine
|
||||
input.machineManager.setCurrentMachine(input.machine)
|
||||
|
||||
const format: OutputFormat3d = {
|
||||
type: 'stl',
|
||||
coords: {
|
||||
forward: {
|
||||
axis: 'y',
|
||||
direction: 'negative',
|
||||
},
|
||||
up: {
|
||||
axis: 'z',
|
||||
direction: 'positive',
|
||||
},
|
||||
},
|
||||
storage: 'ascii',
|
||||
// Convert all units to mm since that is what the slicer expects.
|
||||
units: 'mm',
|
||||
selection: { type: 'default_scene' },
|
||||
}
|
||||
|
||||
const toastId = toast.loading(MAKE_TOAST_MESSAGES.START)
|
||||
const files = await rustContext.export(
|
||||
format,
|
||||
{
|
||||
settings: { modeling: { base_unit: 'mm' } },
|
||||
},
|
||||
toastId
|
||||
)
|
||||
|
||||
if (files === undefined) {
|
||||
// We already sent the toast message in the export function.
|
||||
return
|
||||
}
|
||||
|
||||
await exportMake({
|
||||
files,
|
||||
toastId,
|
||||
name,
|
||||
machineManager: engineCommandManager.machineManager,
|
||||
})
|
||||
}
|
||||
),
|
||||
'AST-undo-startSketchOn': fromPromise(
|
||||
async ({ input: { sketchDetails } }) => {
|
||||
if (!sketchDetails) return
|
||||
|
Reference in New Issue
Block a user