BREAKING: KCL @settings are the source of truth for units (#5808)
This commit is contained in:
@ -1,11 +1,11 @@
|
||||
interface CommandBarOverwriteWarningProps {
|
||||
heading?: string
|
||||
message?: string
|
||||
heading: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export function CommandBarOverwriteWarning({
|
||||
heading = 'Overwrite current file and units?',
|
||||
message = 'This will permanently replace the current code in the editor, and overwrite your current units.',
|
||||
heading,
|
||||
message,
|
||||
}: CommandBarOverwriteWarningProps) {
|
||||
return (
|
||||
<>
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
import { fileMachine } from 'machines/fileMachine'
|
||||
import { isDesktop } from 'lib/isDesktop'
|
||||
import {
|
||||
DEFAULT_DEFAULT_LENGTH_UNIT,
|
||||
DEFAULT_FILE_NAME,
|
||||
DEFAULT_PROJECT_KCL_FILE,
|
||||
FILE_EXT,
|
||||
@ -29,11 +30,12 @@ import {
|
||||
} from 'lib/getKclSamplesManifest'
|
||||
import { markOnce } from 'lib/performance'
|
||||
import { commandBarActor } from 'machines/commandBarMachine'
|
||||
import { settingsActor, useSettings } from 'machines/appMachine'
|
||||
import { useSettings } from 'machines/appMachine'
|
||||
import { createRouteCommands } from 'lib/commandBarConfigs/routeCommandConfig'
|
||||
import { useToken } from 'machines/appMachine'
|
||||
import { createNamedViewsCommand } from 'lib/commandBarConfigs/namedViewsConfig'
|
||||
import { reportRejection } from 'lib/trap'
|
||||
import { err, reportRejection } from 'lib/trap'
|
||||
import { newKclFile } from 'lang/project'
|
||||
|
||||
type MachineContext<T extends AnyStateMachine> = {
|
||||
state: StateFrom<T>
|
||||
@ -237,7 +239,12 @@ export const FileMachineProvider = ({
|
||||
createdPath
|
||||
)
|
||||
} else {
|
||||
await window.electron.writeFile(createdPath, input.content ?? '')
|
||||
const codeToWrite = newKclFile(
|
||||
input.content,
|
||||
settings.modeling.defaultUnit.current
|
||||
)
|
||||
if (err(codeToWrite)) return Promise.reject(codeToWrite)
|
||||
await window.electron.writeFile(createdPath, codeToWrite)
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +273,12 @@ export const FileMachineProvider = ({
|
||||
})
|
||||
createdName = name
|
||||
createdPath = path
|
||||
await window.electron.writeFile(createdPath, input.content ?? '')
|
||||
const codeToWrite = newKclFile(
|
||||
input.content,
|
||||
settings.modeling.defaultUnit.current
|
||||
)
|
||||
if (err(codeToWrite)) return Promise.reject(codeToWrite)
|
||||
await window.electron.writeFile(createdPath, codeToWrite)
|
||||
}
|
||||
|
||||
return {
|
||||
@ -357,10 +369,16 @@ export const FileMachineProvider = ({
|
||||
const hasKclEntries =
|
||||
entries.filter((e: string) => e.endsWith('.kcl')).length !== 0
|
||||
if (!hasKclEntries) {
|
||||
await window.electron.writeFile(
|
||||
window.electron.path.join(project.path, DEFAULT_PROJECT_KCL_FILE),
|
||||
''
|
||||
const codeToWrite = newKclFile(
|
||||
undefined,
|
||||
settings.modeling.defaultUnit.current
|
||||
)
|
||||
if (err(codeToWrite)) return Promise.reject(codeToWrite)
|
||||
const path = window.electron.path.join(
|
||||
project.path,
|
||||
DEFAULT_PROJECT_KCL_FILE
|
||||
)
|
||||
await window.electron.writeFile(path, codeToWrite)
|
||||
// Refresh the route selected above because it's possible we're on
|
||||
// the same path on the navigate, which doesn't cause anything to
|
||||
// refresh, leaving a stale execution state.
|
||||
@ -401,7 +419,9 @@ export const FileMachineProvider = ({
|
||||
authToken: token ?? '',
|
||||
projectData,
|
||||
settings: {
|
||||
defaultUnit: settings.modeling.defaultUnit.current ?? 'mm',
|
||||
defaultUnit:
|
||||
settings.modeling.defaultUnit.current ??
|
||||
DEFAULT_DEFAULT_LENGTH_UNIT,
|
||||
},
|
||||
specialPropsForSampleCommand: {
|
||||
onSubmit: async (data) => {
|
||||
@ -419,18 +439,6 @@ export const FileMachineProvider = ({
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Either way, we want to overwrite the defaultUnit project setting
|
||||
// with the sample's setting.
|
||||
if (data.sampleUnits) {
|
||||
settingsActor.send({
|
||||
type: 'set.modeling.defaultUnit',
|
||||
data: {
|
||||
level: 'project',
|
||||
value: data.sampleUnits,
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
providedOptions: kclSamples.map((sample) => ({
|
||||
value: sample.pathFromProjectDirectoryToFirstFile,
|
||||
|
@ -32,6 +32,8 @@ import {
|
||||
} from 'lib/constants'
|
||||
import { codeManager, kclManager } from 'lib/singletons'
|
||||
import { Project } from 'lib/project'
|
||||
import { newKclFile } from 'lang/project'
|
||||
import { err } from 'lib/trap'
|
||||
|
||||
type MachineContext<T extends AnyStateMachine> = {
|
||||
state?: StateFrom<T>
|
||||
@ -120,7 +122,13 @@ const ProjectsContextWeb = ({ children }: { children: React.ReactNode }) => {
|
||||
createFile: fromPromise(async ({ input }) => {
|
||||
// Browser version doesn't navigate, just overwrites the current file
|
||||
clearImportSearchParams()
|
||||
codeManager.updateCodeStateEditor(input.code || '')
|
||||
|
||||
const codeToWrite = newKclFile(
|
||||
input.code,
|
||||
settings.modeling.defaultUnit.current
|
||||
)
|
||||
if (err(codeToWrite)) return Promise.reject(codeToWrite)
|
||||
codeManager.updateCodeStateEditor(codeToWrite)
|
||||
await codeManager.writeToFile()
|
||||
await kclManager.executeCode(true)
|
||||
|
||||
@ -388,8 +396,10 @@ const ProjectsContextDesktop = ({
|
||||
}
|
||||
|
||||
// Create the project around the file if newProject
|
||||
let fileLoaded = false
|
||||
if (input.method === 'newProject') {
|
||||
await createNewProjectDirectory(projectName, input.code)
|
||||
fileLoaded = true
|
||||
message = `Project "${projectName}" created successfully with link contents`
|
||||
} else {
|
||||
message = `File "${fileName}" created successfully`
|
||||
@ -406,8 +416,16 @@ const ProjectsContextDesktop = ({
|
||||
})
|
||||
|
||||
fileName = name
|
||||
await window.electron.writeFile(path, input.code || '')
|
||||
if (!fileLoaded) {
|
||||
const codeToWrite = newKclFile(
|
||||
input.code,
|
||||
settings.modeling.defaultUnit.current
|
||||
)
|
||||
if (err(codeToWrite)) return Promise.reject(codeToWrite)
|
||||
await window.electron.writeFile(path, codeToWrite)
|
||||
}
|
||||
|
||||
// TODO: Return the project's file name if one was created.
|
||||
return {
|
||||
message,
|
||||
fileName,
|
||||
|
@ -1,6 +1,11 @@
|
||||
import { Popover } from '@headlessui/react'
|
||||
import { settingsActor, useSettings } from 'machines/appMachine'
|
||||
import { changeKclSettings, unitLengthToUnitLen } from 'lang/wasm'
|
||||
import {
|
||||
changeKclSettings,
|
||||
unitAngleToUnitAng,
|
||||
unitLengthToUnitLen,
|
||||
} from 'lang/wasm'
|
||||
import { DEFAULT_DEFAULT_ANGLE_UNIT } from 'lib/constants'
|
||||
import { DEFAULT_DEFAULT_LENGTH_UNIT } from 'lib/constants'
|
||||
import { baseUnitLabels, baseUnitsUnion } from 'lib/settings/settingsTypes'
|
||||
import { codeManager, kclManager } from 'lib/singletons'
|
||||
import { err, reportRejection } from 'lib/trap'
|
||||
@ -8,24 +13,10 @@ import { useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
export function UnitsMenu() {
|
||||
const settings = useSettings()
|
||||
const [hasPerFileLengthUnit, setHasPerFileLengthUnit] = useState(
|
||||
Boolean(kclManager.fileSettings.defaultLengthUnit)
|
||||
)
|
||||
const [lengthSetting, setLengthSetting] = useState(
|
||||
kclManager.fileSettings.defaultLengthUnit ||
|
||||
settings.modeling.defaultUnit.current
|
||||
)
|
||||
const [fileSettings, setFileSettings] = useState(kclManager.fileSettings)
|
||||
useEffect(() => {
|
||||
setHasPerFileLengthUnit(Boolean(kclManager.fileSettings.defaultLengthUnit))
|
||||
setLengthSetting(
|
||||
kclManager.fileSettings.defaultLengthUnit ||
|
||||
settings.modeling.defaultUnit.current
|
||||
)
|
||||
}, [
|
||||
kclManager.fileSettings.defaultLengthUnit,
|
||||
settings.modeling.defaultUnit.current,
|
||||
])
|
||||
setFileSettings(kclManager.fileSettings)
|
||||
}, [kclManager.fileSettings])
|
||||
|
||||
return (
|
||||
<Popover className="relative pointer-events-auto">
|
||||
@ -41,7 +32,7 @@ export function UnitsMenu() {
|
||||
<div className="absolute w-[1px] h-[1em] bg-primary right-0 top-1/2 -translate-y-1/2"></div>
|
||||
</div>
|
||||
<span className="sr-only">Current units are: </span>
|
||||
{lengthSetting}
|
||||
{fileSettings.defaultLengthUnit ?? DEFAULT_DEFAULT_LENGTH_UNIT}
|
||||
</Popover.Button>
|
||||
<Popover.Panel
|
||||
className={`absolute bottom-full right-0 mb-2 w-48 bg-chalkboard-10 dark:bg-chalkboard-90
|
||||
@ -54,40 +45,35 @@ export function UnitsMenu() {
|
||||
<button
|
||||
className="flex items-center gap-2 m-0 py-1.5 px-2 cursor-pointer hover:bg-chalkboard-20 dark:hover:bg-chalkboard-80 border-none text-left"
|
||||
onClick={() => {
|
||||
if (hasPerFileLengthUnit) {
|
||||
const newCode = changeKclSettings(codeManager.code, {
|
||||
defaultLengthUnits: unitLengthToUnitLen(unit),
|
||||
defaultAngleUnits: { type: 'Degrees' },
|
||||
})
|
||||
if (err(newCode)) {
|
||||
toast.error(
|
||||
`Failed to set per-file units: ${newCode.message}`
|
||||
)
|
||||
} else {
|
||||
codeManager.updateCodeStateEditor(newCode)
|
||||
Promise.all([
|
||||
codeManager.writeToFile(),
|
||||
kclManager.executeCode(),
|
||||
])
|
||||
.then(() => {
|
||||
toast.success(`Updated per-file units to ${unit}`)
|
||||
})
|
||||
.catch(reportRejection)
|
||||
}
|
||||
const newCode = changeKclSettings(codeManager.code, {
|
||||
defaultLengthUnits: unitLengthToUnitLen(unit),
|
||||
defaultAngleUnits: unitAngleToUnitAng(
|
||||
fileSettings.defaultAngleUnit ??
|
||||
DEFAULT_DEFAULT_ANGLE_UNIT
|
||||
),
|
||||
})
|
||||
if (err(newCode)) {
|
||||
toast.error(
|
||||
`Failed to set per-file units: ${newCode.message}`
|
||||
)
|
||||
} else {
|
||||
settingsActor.send({
|
||||
type: 'set.modeling.defaultUnit',
|
||||
data: {
|
||||
level: 'project',
|
||||
value: unit,
|
||||
},
|
||||
})
|
||||
codeManager.updateCodeStateEditor(newCode)
|
||||
Promise.all([
|
||||
codeManager.writeToFile(),
|
||||
kclManager.executeCode(),
|
||||
])
|
||||
.then(() => {
|
||||
toast.success(`Updated per-file units to ${unit}`)
|
||||
})
|
||||
.catch(reportRejection)
|
||||
}
|
||||
close()
|
||||
}}
|
||||
>
|
||||
<span className="flex-1">{baseUnitLabels[unit]}</span>
|
||||
{unit === lengthSetting && (
|
||||
{unit ===
|
||||
(fileSettings.defaultLengthUnit ??
|
||||
DEFAULT_DEFAULT_LENGTH_UNIT) && (
|
||||
<span className="text-chalkboard-60">current</span>
|
||||
)}
|
||||
</button>
|
||||
|
33
src/lang/project.ts
Normal file
33
src/lang/project.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { UnitLength } from '@rust/kcl-lib/bindings/ModelingCmd'
|
||||
import {
|
||||
changeKclSettings,
|
||||
unitAngleToUnitAng,
|
||||
unitLengthToUnitLen,
|
||||
} from './wasm'
|
||||
import { DEFAULT_DEFAULT_ANGLE_UNIT } from 'lib/constants'
|
||||
import { DEFAULT_DEFAULT_LENGTH_UNIT } from 'lib/constants'
|
||||
|
||||
/**
|
||||
* Create a new KCL file with the given initial content and default length unit.
|
||||
* @returns KCL string
|
||||
*/
|
||||
export function newKclFile(
|
||||
initialContent: string | undefined,
|
||||
defaultLengthUnit: UnitLength
|
||||
): string | Error {
|
||||
// If we're given initial content, we're loading a file that should already
|
||||
// have units in it. Don't modify it.
|
||||
if (initialContent !== undefined) {
|
||||
return initialContent
|
||||
}
|
||||
// If the default length unit is the same as the default default length unit,
|
||||
// there's no need to add the attribute.
|
||||
if (defaultLengthUnit === DEFAULT_DEFAULT_LENGTH_UNIT) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return changeKclSettings('', {
|
||||
defaultLengthUnits: unitLengthToUnitLen(defaultLengthUnit),
|
||||
defaultAngleUnits: unitAngleToUnitAng(DEFAULT_DEFAULT_ANGLE_UNIT),
|
||||
})
|
||||
}
|
@ -18,6 +18,7 @@ import {
|
||||
serialize_project_configuration,
|
||||
serialize_configuration,
|
||||
reloadModule,
|
||||
is_kcl_empty_or_only_settings,
|
||||
} from 'lib/wasm_lib_wrapper'
|
||||
|
||||
import { KCLError } from './errors'
|
||||
@ -55,6 +56,10 @@ import { UnitAngle as UnitAng } from '@rust/kcl-lib/bindings/UnitAngle'
|
||||
import { ModulePath } from '@rust/kcl-lib/bindings/ModulePath'
|
||||
import { DefaultPlanes } from '@rust/kcl-lib/bindings/DefaultPlanes'
|
||||
import { isArray } from 'lib/utils'
|
||||
import {
|
||||
DEFAULT_DEFAULT_ANGLE_UNIT,
|
||||
DEFAULT_DEFAULT_LENGTH_UNIT,
|
||||
} from 'lib/constants'
|
||||
|
||||
export type { Artifact } from '@rust/kcl-lib/bindings/Artifact'
|
||||
export type { ArtifactCommand } from '@rust/kcl-lib/bindings/Artifact'
|
||||
@ -607,7 +612,27 @@ export function changeKclSettings(
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a `UnitLength_type` to a `UnitLen`
|
||||
* Returns true if the given KCL is empty or only contains settings that would
|
||||
* be auto-generated.
|
||||
*/
|
||||
export function isKclEmptyOrOnlySettings(kcl: string): boolean {
|
||||
if (kcl === '') {
|
||||
// Fast path.
|
||||
return true
|
||||
}
|
||||
|
||||
try {
|
||||
return is_kcl_empty_or_only_settings(kcl)
|
||||
} catch (e) {
|
||||
console.debug('Caught error checking if KCL is empty', e)
|
||||
// If there's a parse error, it can't be empty or auto-generated.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a `UnitLength` (used in settings and modeling commands) to a
|
||||
* `UnitLen` (used in execution).
|
||||
*/
|
||||
export function unitLengthToUnitLen(input: UnitLength): UnitLen {
|
||||
switch (input) {
|
||||
@ -627,7 +652,8 @@ export function unitLengthToUnitLen(input: UnitLength): UnitLen {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert `UnitLen` to `UnitLength_type`.
|
||||
* Convert `UnitLen` (used in execution) to `UnitLength` (used in settings
|
||||
* and modeling commands).
|
||||
*/
|
||||
export function unitLenToUnitLength(input: UnitLen): UnitLength {
|
||||
switch (input.type) {
|
||||
@ -642,19 +668,33 @@ export function unitLenToUnitLength(input: UnitLen): UnitLength {
|
||||
case 'Inches':
|
||||
return 'in'
|
||||
default:
|
||||
return 'mm'
|
||||
return DEFAULT_DEFAULT_LENGTH_UNIT
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert `UnitAngle` to `UnitAngle_type`.
|
||||
* Convert a `UnitAngle` (used in modeling commands) to a `UnitAng` (used in
|
||||
* execution).
|
||||
*/
|
||||
export function unitAngleToUnitAng(input: UnitAngle): UnitAng {
|
||||
switch (input) {
|
||||
case 'radians':
|
||||
return { type: 'Radians' }
|
||||
default:
|
||||
return { type: 'Degrees' }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert `UnitAng` (used in execution) to `UnitAngle` (used in modeling
|
||||
* commands).
|
||||
*/
|
||||
export function unitAngToUnitAngle(input: UnitAng): UnitAngle {
|
||||
switch (input.type) {
|
||||
case 'Radians':
|
||||
return 'radians'
|
||||
default:
|
||||
return 'degrees'
|
||||
return DEFAULT_DEFAULT_ANGLE_UNIT
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Models } from '@kittycad/lib/dist/types/src'
|
||||
import { UnitAngle, UnitLength } from '@rust/kcl-lib/bindings/ModelingCmd'
|
||||
|
||||
export const APP_NAME = 'Modeling App'
|
||||
/** Search string in new project names to increment as an index */
|
||||
@ -168,6 +169,18 @@ export const ZOO_STUDIO_PROTOCOL = 'zoo-studio'
|
||||
*/
|
||||
export const ASK_TO_OPEN_QUERY_PARAM = 'ask-open-desktop'
|
||||
|
||||
/**
|
||||
* When no annotation is in the KCL file to specify the defaults, we use these
|
||||
* default units.
|
||||
*/
|
||||
export const DEFAULT_DEFAULT_ANGLE_UNIT: UnitAngle = 'degrees'
|
||||
|
||||
/**
|
||||
* When no annotation is in the KCL file to specify the defaults, we use these
|
||||
* default units.
|
||||
*/
|
||||
export const DEFAULT_DEFAULT_LENGTH_UNIT: UnitLength = 'mm'
|
||||
|
||||
/** Real execution. */
|
||||
export const EXECUTION_TYPE_REAL = 'real'
|
||||
/** Mock execution. */
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
parseProjectSettings,
|
||||
} from 'lang/wasm'
|
||||
import {
|
||||
DEFAULT_DEFAULT_LENGTH_UNIT,
|
||||
PROJECT_ENTRYPOINT,
|
||||
PROJECT_FOLDER,
|
||||
PROJECT_IMAGE_NAME,
|
||||
@ -21,6 +22,7 @@ import {
|
||||
import { DeepPartial } from './types'
|
||||
import { ProjectConfiguration } from '@rust/kcl-lib/bindings/ProjectConfiguration'
|
||||
import { Configuration } from '@rust/kcl-lib/bindings/Configuration'
|
||||
import { newKclFile } from 'lang/project'
|
||||
|
||||
export async function renameProjectDirectory(
|
||||
projectPath: string,
|
||||
@ -113,7 +115,15 @@ export async function createNewProjectDirectory(
|
||||
}
|
||||
|
||||
const projectFile = window.electron.path.join(projectDir, PROJECT_ENTRYPOINT)
|
||||
await window.electron.writeFile(projectFile, initialCode ?? '')
|
||||
// When initialCode is present, we're loading existing code. If it's not
|
||||
// present, we're creating a new project, and we want to incorporate the
|
||||
// user's settings.
|
||||
const codeToWrite = newKclFile(
|
||||
initialCode,
|
||||
configuration?.settings?.modeling?.base_unit ?? DEFAULT_DEFAULT_LENGTH_UNIT
|
||||
)
|
||||
if (err(codeToWrite)) return Promise.reject(codeToWrite)
|
||||
await window.electron.writeFile(projectFile, codeToWrite)
|
||||
const metadata = await window.electron.stat(projectFile)
|
||||
|
||||
return {
|
||||
|
@ -2,11 +2,22 @@ import { CommandBarOverwriteWarning } from 'components/CommandBarOverwriteWarnin
|
||||
import { Command, CommandArgumentOption } from './commandTypes'
|
||||
import { codeManager, kclManager } from './singletons'
|
||||
import { isDesktop } from './isDesktop'
|
||||
import { FILE_EXT } from './constants'
|
||||
import {
|
||||
DEFAULT_DEFAULT_ANGLE_UNIT,
|
||||
DEFAULT_DEFAULT_LENGTH_UNIT,
|
||||
FILE_EXT,
|
||||
} from './constants'
|
||||
import { UnitLength_type } from '@kittycad/lib/dist/types/src/models'
|
||||
import { reportRejection } from './trap'
|
||||
import { err, reportRejection } from './trap'
|
||||
import { IndexLoaderData } from './types'
|
||||
import { copyFileShareLink } from './links'
|
||||
import { baseUnitsUnion } from './settings/settingsTypes'
|
||||
import toast from 'react-hot-toast'
|
||||
import {
|
||||
changeKclSettings,
|
||||
unitLengthToUnitLen,
|
||||
unitAngleToUnitAng,
|
||||
} from 'lang/wasm'
|
||||
|
||||
interface OnSubmitProps {
|
||||
sampleName: string
|
||||
@ -31,6 +42,59 @@ interface KclCommandConfig {
|
||||
|
||||
export function kclCommands(commandProps: KclCommandConfig): Command[] {
|
||||
return [
|
||||
{
|
||||
name: 'set-file-units',
|
||||
displayName: 'Set file units',
|
||||
description:
|
||||
'Set the length unit for all dimensions not given explicit units in the current file.',
|
||||
needsReview: false,
|
||||
groupId: 'code',
|
||||
icon: 'code',
|
||||
args: {
|
||||
unit: {
|
||||
required: true,
|
||||
inputType: 'options',
|
||||
defaultValue:
|
||||
kclManager.fileSettings.defaultLengthUnit ||
|
||||
DEFAULT_DEFAULT_LENGTH_UNIT,
|
||||
options: () =>
|
||||
Object.values(baseUnitsUnion).map((v) => {
|
||||
return {
|
||||
name: v,
|
||||
value: v,
|
||||
isCurrent: kclManager.fileSettings.defaultLengthUnit
|
||||
? v === kclManager.fileSettings.defaultLengthUnit
|
||||
: v === DEFAULT_DEFAULT_LENGTH_UNIT,
|
||||
}
|
||||
}),
|
||||
},
|
||||
},
|
||||
onSubmit: (data) => {
|
||||
if (typeof data === 'object' && 'unit' in data) {
|
||||
const newCode = changeKclSettings(codeManager.code, {
|
||||
defaultLengthUnits: unitLengthToUnitLen(data.unit),
|
||||
defaultAngleUnits: unitAngleToUnitAng(
|
||||
kclManager.fileSettings.defaultAngleUnit ??
|
||||
DEFAULT_DEFAULT_ANGLE_UNIT
|
||||
),
|
||||
})
|
||||
if (err(newCode)) {
|
||||
toast.error(`Failed to set per-file units: ${newCode.message}`)
|
||||
} else {
|
||||
codeManager.updateCodeStateEditor(newCode)
|
||||
Promise.all([codeManager.writeToFile(), kclManager.executeCode()])
|
||||
.then(() => {
|
||||
toast.success(`Updated per-file units to ${data.unit}`)
|
||||
})
|
||||
.catch(reportRejection)
|
||||
}
|
||||
} else {
|
||||
toast.error(
|
||||
'Failed to set per-file units: no value provided to submit function. This is a bug.'
|
||||
)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'format-code',
|
||||
displayName: 'Format Code',
|
||||
@ -49,12 +113,18 @@ export function kclCommands(commandProps: KclCommandConfig): Command[] {
|
||||
needsReview: true,
|
||||
icon: 'code',
|
||||
reviewMessage: ({ argumentsToSubmit }) =>
|
||||
argumentsToSubmit.method === 'newFile'
|
||||
? CommandBarOverwriteWarning({
|
||||
heading: 'Create a new file, overwrite project units?',
|
||||
message: `This will add the sample as a new file to your project, and replace your current project units with the sample's units.`,
|
||||
})
|
||||
: CommandBarOverwriteWarning({}),
|
||||
CommandBarOverwriteWarning({
|
||||
heading:
|
||||
'method' in argumentsToSubmit &&
|
||||
argumentsToSubmit.method === 'newFile'
|
||||
? 'Create a new file from sample?'
|
||||
: 'Overwrite current file with sample?',
|
||||
message:
|
||||
'method' in argumentsToSubmit &&
|
||||
argumentsToSubmit.method === 'newFile'
|
||||
? 'This will create a new file in the current project and open it.'
|
||||
: 'This will erase your current file and load the sample part.',
|
||||
}),
|
||||
groupId: 'code',
|
||||
onSubmit(data) {
|
||||
if (!data?.sample) {
|
||||
|
@ -22,6 +22,7 @@ import { CameraProjectionType } from '@rust/kcl-lib/bindings/CameraProjectionTyp
|
||||
import { OnboardingStatus } from '@rust/kcl-lib/bindings/OnboardingStatus'
|
||||
import { NamedView } from '@rust/kcl-lib/bindings/NamedView'
|
||||
import { CameraOrbitType } from '@rust/kcl-lib/bindings/CameraOrbitType'
|
||||
import { DEFAULT_DEFAULT_LENGTH_UNIT } from 'lib/constants'
|
||||
|
||||
/**
|
||||
* A setting that can be set at the user or project level
|
||||
@ -300,8 +301,9 @@ export function createSettings() {
|
||||
* The default unit to use in modeling dimensions
|
||||
*/
|
||||
defaultUnit: new Setting<BaseUnit>({
|
||||
defaultValue: 'mm',
|
||||
description: 'The default unit to use in modeling dimensions',
|
||||
defaultValue: DEFAULT_DEFAULT_LENGTH_UNIT,
|
||||
description:
|
||||
'Set the default length unit setting value to give any new files.',
|
||||
validate: (v) => baseUnitsUnion.includes(v),
|
||||
commandConfig: {
|
||||
inputType: 'options',
|
||||
|
@ -145,7 +145,7 @@ export type SaveSettingsPayload = RecursiveSettingsPayloads<typeof settings>
|
||||
|
||||
/**
|
||||
* Annotation names for default units are defined on rust side in
|
||||
* src/wasm-lib/kcl/src/execution/annotations.rs
|
||||
* rust/kcl-lib/src/execution/annotations.rs
|
||||
*/
|
||||
export interface KclSettingsAnnotation {
|
||||
defaultLengthUnit?: UnitLength_type
|
||||
|
@ -22,6 +22,7 @@ import {
|
||||
base64_decode as Base64Decode,
|
||||
kcl_settings as KclSettings,
|
||||
change_kcl_settings as ChangeKclSettings,
|
||||
is_kcl_empty_or_only_settings as IsKclEmptyOrOnlySettings,
|
||||
get_kcl_version as GetKclVersion,
|
||||
serialize_configuration as SerializeConfiguration,
|
||||
serialize_project_configuration as SerializeProjectConfiguration,
|
||||
@ -93,6 +94,11 @@ export const kcl_settings: typeof KclSettings = (...args) => {
|
||||
export const change_kcl_settings: typeof ChangeKclSettings = (...args) => {
|
||||
return getModule().change_kcl_settings(...args)
|
||||
}
|
||||
export const is_kcl_empty_or_only_settings: typeof IsKclEmptyOrOnlySettings = (
|
||||
...args
|
||||
) => {
|
||||
return getModule().is_kcl_empty_or_only_settings(...args)
|
||||
}
|
||||
export const get_kcl_version: typeof GetKclVersion = () => {
|
||||
return getModule().get_kcl_version()
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ export const fileMachine = setup({
|
||||
makeDir: boolean
|
||||
selectedDirectory: FileEntry
|
||||
targetPathToClone?: string
|
||||
content: string
|
||||
content?: string
|
||||
shouldSetToRename: boolean
|
||||
}
|
||||
}) => Promise.resolve({ message: '', path: '' })
|
||||
@ -152,7 +152,7 @@ export const fileMachine = setup({
|
||||
name: string
|
||||
makeDir: boolean
|
||||
selectedDirectory: FileEntry
|
||||
content: string
|
||||
content?: string
|
||||
}
|
||||
}) => Promise.resolve({ path: '' })
|
||||
),
|
||||
@ -238,7 +238,7 @@ export const fileMachine = setup({
|
||||
makeDir: event.data.makeDir,
|
||||
selectedDirectory: context.selectedDirectory,
|
||||
targetPathToClone: event.data.targetPathToClone,
|
||||
content: event.data.content ?? '',
|
||||
content: event.data.content,
|
||||
shouldSetToRename: event.data.shouldSetToRename ?? false,
|
||||
}
|
||||
},
|
||||
@ -417,7 +417,7 @@ export const fileMachine = setup({
|
||||
name: event.data.name,
|
||||
makeDir: event.data.makeDir,
|
||||
selectedDirectory: context.selectedDirectory,
|
||||
content: event.data.content ?? '',
|
||||
content: event.data.content,
|
||||
}
|
||||
},
|
||||
onDone: 'Reading files',
|
||||
|
@ -14,6 +14,7 @@ import { useFileContext } from 'hooks/useFileContext'
|
||||
import { useLspContext } from 'components/LspProvider'
|
||||
import { reportRejection } from 'lib/trap'
|
||||
import { useSettings } from 'machines/appMachine'
|
||||
import { isKclEmptyOrOnlySettings } from 'lang/wasm'
|
||||
|
||||
/**
|
||||
* Show either a welcome screen or a warning screen
|
||||
@ -21,7 +22,7 @@ import { useSettings } from 'machines/appMachine'
|
||||
*/
|
||||
export default function OnboardingIntroduction() {
|
||||
const [shouldShowWarning, setShouldShowWarning] = useState(
|
||||
codeManager.code !== '' && codeManager.code !== bracket
|
||||
!isKclEmptyOrOnlySettings(codeManager.code) && codeManager.code !== bracket
|
||||
)
|
||||
|
||||
return shouldShowWarning ? (
|
||||
|
Reference in New Issue
Block a user