Compare commits
4 Commits
codex/fix-
...
remove-old
Author | SHA1 | Date | |
---|---|---|---|
0f8dfe528f | |||
006663d83c | |||
8e248f43ab | |||
09ef1d5f10 |
@ -12,9 +12,10 @@ import { CmdBarFixture } from './cmdBarFixture'
|
||||
import { EditorFixture } from './editorFixture'
|
||||
import { ToolbarFixture } from './toolbarFixture'
|
||||
import { SceneFixture } from './sceneFixture'
|
||||
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
|
||||
import { HomePageFixture } from './homePageFixture'
|
||||
import { unsafeTypedKeys } from 'lib/utils'
|
||||
import { DeepPartial } from 'lib/types'
|
||||
import { Settings } from 'wasm-lib/kcl/bindings/Settings'
|
||||
|
||||
export class AuthenticatedApp {
|
||||
public readonly page: Page
|
||||
@ -78,7 +79,7 @@ export class AuthenticatedTronApp {
|
||||
fixtures: Partial<Fixtures>
|
||||
folderSetupFn?: (projectDirName: string) => Promise<void>
|
||||
cleanProjectDir?: boolean
|
||||
appSettings?: Partial<SaveSettingsPayload>
|
||||
appSettings?: DeepPartial<Settings>
|
||||
} = { fixtures: {} }
|
||||
) {
|
||||
const { electronApp, page, context, dir } = await setupElectron({
|
||||
|
@ -1,7 +1,12 @@
|
||||
import { test, expect } from './zoo-test'
|
||||
import { join } from 'path'
|
||||
import fsp from 'fs/promises'
|
||||
import { getUtils, executorInputPath, createProject } from './test-utils'
|
||||
import {
|
||||
getUtils,
|
||||
executorInputPath,
|
||||
createProject,
|
||||
settingsToToml,
|
||||
} from './test-utils'
|
||||
import { bracket } from 'lib/exampleKcl'
|
||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||
import {
|
||||
@ -10,7 +15,6 @@ import {
|
||||
TEST_SETTINGS_ONBOARDING_EXPORT,
|
||||
TEST_SETTINGS_ONBOARDING_USER_MENU,
|
||||
} from './storageStates'
|
||||
import * as TOML from '@iarna/toml'
|
||||
import { expectPixelColor } from './fixtures/sceneFixture'
|
||||
|
||||
// Because onboarding relies on an app setting we need to set it as incompletel
|
||||
@ -22,7 +26,7 @@ test.describe('Onboarding tests', () => {
|
||||
{
|
||||
appSettings: {
|
||||
app: {
|
||||
onboardingStatus: 'incomplete',
|
||||
onboarding_status: 'incomplete',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
@ -63,7 +67,7 @@ test.describe('Onboarding tests', () => {
|
||||
tag: '@electron',
|
||||
appSettings: {
|
||||
app: {
|
||||
onboardingStatus: 'incomplete',
|
||||
onboarding_status: 'incomplete',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
@ -108,7 +112,7 @@ test.describe('Onboarding tests', () => {
|
||||
{
|
||||
appSettings: {
|
||||
app: {
|
||||
onboardingStatus: 'incomplete',
|
||||
onboarding_status: 'incomplete',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
@ -158,7 +162,7 @@ test.describe('Onboarding tests', () => {
|
||||
{
|
||||
appSettings: {
|
||||
app: {
|
||||
onboardingStatus: 'incomplete',
|
||||
onboarding_status: 'incomplete',
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -172,7 +176,7 @@ test.describe('Onboarding tests', () => {
|
||||
},
|
||||
{
|
||||
settingsKey: TEST_SETTINGS_KEY,
|
||||
settings: TOML.stringify({
|
||||
settings: settingsToToml({
|
||||
settings: TEST_SETTINGS_ONBOARDING_START,
|
||||
}),
|
||||
}
|
||||
@ -208,7 +212,7 @@ test.describe('Onboarding tests', () => {
|
||||
{
|
||||
appSettings: {
|
||||
app: {
|
||||
onboardingStatus: '/export',
|
||||
onboarding_status: '/export',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
@ -225,7 +229,7 @@ test.describe('Onboarding tests', () => {
|
||||
},
|
||||
{
|
||||
settingsKey: TEST_SETTINGS_KEY,
|
||||
settings: TOML.stringify({
|
||||
settings: settingsToToml({
|
||||
settings: TEST_SETTINGS_ONBOARDING_EXPORT,
|
||||
}),
|
||||
}
|
||||
@ -263,7 +267,7 @@ test.describe('Onboarding tests', () => {
|
||||
{
|
||||
appSettings: {
|
||||
app: {
|
||||
onboardingStatus: '/parametric-modeling',
|
||||
onboarding_status: '/parametric-modeling',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
@ -313,7 +317,7 @@ test.describe('Onboarding tests', () => {
|
||||
{
|
||||
appSettings: {
|
||||
app: {
|
||||
onboardingStatus: 'incomplete',
|
||||
onboarding_status: 'incomplete',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
@ -326,7 +330,7 @@ test.describe('Onboarding tests', () => {
|
||||
},
|
||||
{
|
||||
settingsKey: TEST_SETTINGS_KEY,
|
||||
settings: TOML.stringify({
|
||||
settings: settingsToToml({
|
||||
settings: TEST_SETTINGS_ONBOARDING_USER_MENU,
|
||||
}),
|
||||
}
|
||||
@ -386,7 +390,7 @@ test.describe('Onboarding tests', () => {
|
||||
{
|
||||
appSettings: {
|
||||
app: {
|
||||
onboardingStatus: 'incomplete',
|
||||
onboarding_status: 'incomplete',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
@ -400,7 +404,7 @@ test.describe('Onboarding tests', () => {
|
||||
},
|
||||
{
|
||||
settingsKey: TEST_SETTINGS_KEY,
|
||||
settings: TOML.stringify({
|
||||
settings: settingsToToml({
|
||||
settings: TEST_SETTINGS_ONBOARDING_USER_MENU,
|
||||
}),
|
||||
}
|
||||
@ -442,7 +446,7 @@ test.fixme(
|
||||
{
|
||||
appSettings: {
|
||||
app: {
|
||||
onboardingStatus: 'dismissed',
|
||||
onboarding_status: 'dismissed',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
import { secrets } from './secrets'
|
||||
import { Paths, doExport, getUtils } from './test-utils'
|
||||
import { Paths, doExport, getUtils, settingsToToml } from './test-utils'
|
||||
import { Models } from '@kittycad/lib'
|
||||
import fsp from 'fs/promises'
|
||||
import { spawn } from 'child_process'
|
||||
@ -12,7 +12,6 @@ import {
|
||||
TEST_SETTINGS,
|
||||
TEST_SETTINGS_KEY,
|
||||
} from './storageStates'
|
||||
import * as TOML from '@iarna/toml'
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// reducedMotion kills animations, which speeds up tests and reduces flakiness
|
||||
@ -29,7 +28,7 @@ test.beforeEach(async ({ page }) => {
|
||||
{
|
||||
token: secrets.token,
|
||||
settingsKey: TEST_SETTINGS_KEY,
|
||||
settings: TOML.stringify({ settings: TEST_SETTINGS }),
|
||||
settings: settingsToToml({ settings: TEST_SETTINGS }),
|
||||
IS_PLAYWRIGHT_KEY: IS_PLAYWRIGHT_KEY,
|
||||
}
|
||||
)
|
||||
@ -704,12 +703,12 @@ test.describe(
|
||||
},
|
||||
{
|
||||
settingsKey: TEST_SETTINGS_KEY,
|
||||
settings: TOML.stringify({
|
||||
settings: settingsToToml({
|
||||
settings: {
|
||||
...TEST_SETTINGS,
|
||||
modeling: {
|
||||
...TEST_SETTINGS.modeling,
|
||||
defaultUnit: 'mm',
|
||||
base_unit: 'mm',
|
||||
},
|
||||
},
|
||||
}),
|
||||
@ -1062,12 +1061,12 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
|
||||
},
|
||||
{
|
||||
settingsKey: TEST_SETTINGS_KEY,
|
||||
settings: TOML.stringify({
|
||||
settings: settingsToToml({
|
||||
settings: {
|
||||
...TEST_SETTINGS,
|
||||
modeling: {
|
||||
...TEST_SETTINGS.modeling,
|
||||
showScaleGrid: true,
|
||||
show_scale_grid: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
@ -1,78 +1,83 @@
|
||||
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
|
||||
import { Themes } from 'lib/theme'
|
||||
import { DeepPartial } from 'lib/types'
|
||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||
import { Settings } from 'wasm-lib/kcl/bindings/Settings'
|
||||
|
||||
export const IS_PLAYWRIGHT_KEY = 'playwright'
|
||||
|
||||
export const TEST_SETTINGS_KEY = '/settings.toml'
|
||||
export const TEST_SETTINGS = {
|
||||
app: {
|
||||
onboarding_status: 'dismissed',
|
||||
appearance: {
|
||||
theme: Themes.Dark,
|
||||
onboardingStatus: 'dismissed',
|
||||
projectDirectory: '',
|
||||
enableSSAO: false,
|
||||
},
|
||||
show_debug_panel: true,
|
||||
},
|
||||
modeling: {
|
||||
defaultUnit: 'in',
|
||||
mouseControls: 'Zoo',
|
||||
cameraProjection: 'perspective',
|
||||
showDebugPanel: true,
|
||||
base_unit: 'in',
|
||||
mouse_controls: 'zoo',
|
||||
camera_projection: 'perspective',
|
||||
enable_ssao: false,
|
||||
},
|
||||
projects: {
|
||||
defaultProjectName: 'project-$nnn',
|
||||
project: {
|
||||
default_project_name: 'project-$nnn',
|
||||
directory: '',
|
||||
},
|
||||
textEditor: {
|
||||
textWrapping: true,
|
||||
text_editor: {
|
||||
text_wrapping: true,
|
||||
},
|
||||
} satisfies Partial<SaveSettingsPayload>
|
||||
} satisfies DeepPartial<Settings>
|
||||
|
||||
export const TEST_SETTINGS_ONBOARDING_USER_MENU = {
|
||||
...TEST_SETTINGS,
|
||||
app: { ...TEST_SETTINGS.app, onboardingStatus: onboardingPaths.USER_MENU },
|
||||
} satisfies Partial<SaveSettingsPayload>
|
||||
app: { ...TEST_SETTINGS.app, onboarding_status: onboardingPaths.USER_MENU },
|
||||
} satisfies DeepPartial<Settings>
|
||||
|
||||
export const TEST_SETTINGS_ONBOARDING_EXPORT = {
|
||||
...TEST_SETTINGS,
|
||||
app: { ...TEST_SETTINGS.app, onboardingStatus: onboardingPaths.EXPORT },
|
||||
} satisfies Partial<SaveSettingsPayload>
|
||||
app: { ...TEST_SETTINGS.app, onboarding_status: onboardingPaths.EXPORT },
|
||||
} satisfies DeepPartial<Settings>
|
||||
|
||||
export const TEST_SETTINGS_ONBOARDING_PARAMETRIC_MODELING = {
|
||||
...TEST_SETTINGS,
|
||||
app: {
|
||||
...TEST_SETTINGS.app,
|
||||
onboardingStatus: onboardingPaths.PARAMETRIC_MODELING,
|
||||
onboarding_status: onboardingPaths.PARAMETRIC_MODELING,
|
||||
},
|
||||
} satisfies Partial<SaveSettingsPayload>
|
||||
} satisfies DeepPartial<Settings>
|
||||
|
||||
export const TEST_SETTINGS_ONBOARDING_START = {
|
||||
...TEST_SETTINGS,
|
||||
app: { ...TEST_SETTINGS.app, onboardingStatus: '' },
|
||||
} satisfies Partial<SaveSettingsPayload>
|
||||
app: { ...TEST_SETTINGS.app, onboarding_status: '' },
|
||||
} satisfies DeepPartial<Settings>
|
||||
|
||||
export const TEST_SETTINGS_DEFAULT_THEME = {
|
||||
...TEST_SETTINGS,
|
||||
app: { ...TEST_SETTINGS.app, theme: Themes.System },
|
||||
} satisfies Partial<SaveSettingsPayload>
|
||||
app: { ...TEST_SETTINGS.app, appearance: { theme: Themes.System } },
|
||||
} satisfies DeepPartial<Settings>
|
||||
|
||||
export const TEST_SETTINGS_CORRUPTED = {
|
||||
app: {
|
||||
onboarding_status: 'dismissed',
|
||||
appearance: {
|
||||
theme: Themes.Dark,
|
||||
onboardingStatus: 'dismissed',
|
||||
projectDirectory: 123 as any,
|
||||
},
|
||||
show_debug_panel: true,
|
||||
},
|
||||
modeling: {
|
||||
defaultUnit: 'invalid' as any,
|
||||
mouseControls: `() => alert('hack the planet')` as any,
|
||||
cameraProjection: 'perspective',
|
||||
showDebugPanel: true,
|
||||
base_unit: 'invalid' as any,
|
||||
mouse_controls: `() => alert('hack the planet')` as any,
|
||||
camera_projection: 'perspective',
|
||||
},
|
||||
projects: {
|
||||
defaultProjectName: false as any,
|
||||
project: {
|
||||
default_project_name: false as any,
|
||||
directory: 123 as any,
|
||||
},
|
||||
textEditor: {
|
||||
textWrapping: true,
|
||||
text_editor: {
|
||||
text_wrapping: true,
|
||||
},
|
||||
} satisfies Partial<SaveSettingsPayload>
|
||||
} satisfies DeepPartial<Settings>
|
||||
|
||||
export const TEST_CODE_GIZMO = `part001 = startSketchOn('XZ')
|
||||
|> startProfileAt([20, 0], %)
|
||||
|
@ -23,11 +23,13 @@ import {
|
||||
IS_PLAYWRIGHT_KEY,
|
||||
} from './storageStates'
|
||||
import * as TOML from '@iarna/toml'
|
||||
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
|
||||
import { SETTINGS_FILE_NAME } from 'lib/constants'
|
||||
import { isErrorWhitelisted } from './lib/console-error-whitelist'
|
||||
import { isArray } from 'lib/utils'
|
||||
import { reportRejection } from 'lib/trap'
|
||||
import { Configuration } from 'lang/wasm'
|
||||
import { DeepPartial } from 'lib/types'
|
||||
import { Settings } from 'wasm-lib/kcl/bindings/Settings'
|
||||
|
||||
const toNormalizedCode = (text: string) => {
|
||||
return text.replace(/\s+/g, '')
|
||||
@ -884,19 +886,23 @@ export async function setup(
|
||||
{
|
||||
token: secrets.token,
|
||||
settingsKey: TEST_SETTINGS_KEY,
|
||||
settings: TOML.stringify({
|
||||
settings: settingsToToml({
|
||||
settings: {
|
||||
...TEST_SETTINGS,
|
||||
app: {
|
||||
...TEST_SETTINGS.projects,
|
||||
projectDirectory: TEST_SETTINGS.app.projectDirectory,
|
||||
onboardingStatus: 'dismissed',
|
||||
...TEST_SETTINGS.app,
|
||||
onboarding_status: 'dismissed',
|
||||
appearance: {
|
||||
theme: 'dark',
|
||||
},
|
||||
} as Partial<SaveSettingsPayload>,
|
||||
},
|
||||
project: {
|
||||
directory: TEST_SETTINGS.project.directory,
|
||||
},
|
||||
},
|
||||
}),
|
||||
IS_PLAYWRIGHT_KEY,
|
||||
PLAYWRIGHT_TEST_DIR: TEST_SETTINGS.app.projectDirectory,
|
||||
PLAYWRIGHT_TEST_DIR: TEST_SETTINGS.project.directory,
|
||||
PERSIST_MODELING_CONTEXT,
|
||||
}
|
||||
)
|
||||
@ -931,7 +937,7 @@ export async function setupElectron({
|
||||
testInfo: TestInfo
|
||||
folderSetupFn?: (projectDirName: string) => Promise<void>
|
||||
cleanProjectDir?: boolean
|
||||
appSettings?: Partial<SaveSettingsPayload>
|
||||
appSettings?: DeepPartial<Settings>
|
||||
}): Promise<{
|
||||
electronApp: ElectronApplication
|
||||
context: BrowserContext
|
||||
@ -978,7 +984,7 @@ export async function setupElectron({
|
||||
|
||||
if (cleanProjectDir) {
|
||||
const tempSettingsFilePath = path.join(projectDirName, SETTINGS_FILE_NAME)
|
||||
const settingsOverrides = TOML.stringify(
|
||||
const settingsOverrides = settingsToToml(
|
||||
appSettings
|
||||
? {
|
||||
settings: {
|
||||
@ -986,9 +992,11 @@ export async function setupElectron({
|
||||
...appSettings,
|
||||
app: {
|
||||
...TEST_SETTINGS.app,
|
||||
projectDirectory: projectDirName,
|
||||
...appSettings.app,
|
||||
},
|
||||
project: {
|
||||
directory: projectDirName,
|
||||
},
|
||||
},
|
||||
}
|
||||
: {
|
||||
@ -996,7 +1004,9 @@ export async function setupElectron({
|
||||
...TEST_SETTINGS,
|
||||
app: {
|
||||
...TEST_SETTINGS.app,
|
||||
projectDirectory: projectDirName,
|
||||
},
|
||||
project: {
|
||||
directory: projectDirName,
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -1190,3 +1200,7 @@ export async function pollEditorLinesSelectedLength(page: Page, lines: number) {
|
||||
})
|
||||
.toBe(lines)
|
||||
}
|
||||
|
||||
export function settingsToToml(settings: DeepPartial<Configuration>) {
|
||||
return TOML.stringify(settings)
|
||||
}
|
||||
|
@ -31,13 +31,13 @@ test.describe('Testing settings', () => {
|
||||
)
|
||||
) as { settings: SaveSettingsPayload }
|
||||
|
||||
expect(storedSettings.settings?.app?.theme).toBe('dark')
|
||||
expect(storedSettings.settings?.app?.appearance?.theme).toBe('dark')
|
||||
|
||||
// Check that the invalid settings were changed to good defaults
|
||||
expect(storedSettings.settings?.modeling?.defaultUnit).toBe('in')
|
||||
expect(storedSettings.settings?.modeling?.mouseControls).toBe('Zoo')
|
||||
expect(storedSettings.settings?.app?.projectDirectory).toBe('')
|
||||
expect(storedSettings.settings?.projects?.defaultProjectName).toBe(
|
||||
expect(storedSettings.settings?.modeling?.base_unit).toBe('in')
|
||||
expect(storedSettings.settings?.modeling?.mouse_controls).toBe('Zoo')
|
||||
expect(storedSettings.settings?.project?.directory).toBe('')
|
||||
expect(storedSettings.settings?.project?.default_project_name).toBe(
|
||||
'project-$nnn'
|
||||
)
|
||||
}
|
||||
@ -374,7 +374,9 @@ test.describe('Testing settings', () => {
|
||||
tag: '@electron',
|
||||
appSettings: {
|
||||
app: {
|
||||
themeColor: '259',
|
||||
appearance: {
|
||||
color: 259,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -400,9 +402,11 @@ test.describe('Testing settings', () => {
|
||||
tag: '@electron',
|
||||
appSettings: {
|
||||
app: {
|
||||
appearance: {
|
||||
// Doesn't matter what you set it to. It will
|
||||
// default to 264.5
|
||||
themeColor: '0',
|
||||
color: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -832,7 +836,7 @@ test.describe('Testing settings', () => {
|
||||
// but "show debug panel" set to false
|
||||
appSettings: {
|
||||
...TEST_SETTINGS,
|
||||
modeling: { ...TEST_SETTINGS.modeling, showDebugPanel: false },
|
||||
app: { ...TEST_SETTINGS.app, show_debug_panel: false },
|
||||
},
|
||||
},
|
||||
async ({ context, page, homePage }) => {
|
||||
|
@ -18,7 +18,8 @@ import {
|
||||
AuthenticatedApp,
|
||||
} from './fixtures/fixtureSetup'
|
||||
|
||||
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
|
||||
import { Settings } from 'wasm-lib/kcl/bindings/Settings'
|
||||
import { DeepPartial } from 'lib/types'
|
||||
export { expect } from '@playwright/test'
|
||||
|
||||
declare module '@playwright/test' {
|
||||
@ -45,7 +46,7 @@ export type BrowserContext = BrowserContextPlaywright
|
||||
export type Page = PagePlaywright
|
||||
export type TestDetails = TestDetailsPlaywright & {
|
||||
cleanProjectDir?: boolean
|
||||
appSettings?: Partial<SaveSettingsPayload>
|
||||
appSettings?: DeepPartial<Settings>
|
||||
}
|
||||
|
||||
// Our custom decorated Zoo test object. Makes it easier to add fixtures, and
|
||||
|
@ -54,7 +54,7 @@ export function App() {
|
||||
)
|
||||
|
||||
const {
|
||||
app: { onboardingStatus },
|
||||
app: { onboarding_status },
|
||||
} = settings.context
|
||||
|
||||
useHotkeys('backspace', (e) => {
|
||||
@ -69,7 +69,7 @@ export function App() {
|
||||
)
|
||||
|
||||
const paneOpacity = [onboardingPaths.CAMERA, onboardingPaths.STREAMING].some(
|
||||
(p) => p === onboardingStatus.current
|
||||
(p) => p === onboarding_status.current
|
||||
)
|
||||
? 'opacity-20'
|
||||
: ''
|
||||
|
@ -77,7 +77,7 @@ export const ClientSideScene = ({
|
||||
}: {
|
||||
cameraControls: ReturnType<
|
||||
typeof useSettingsAuthContext
|
||||
>['settings']['context']['modeling']['mouseControls']['current']
|
||||
>['settings']['context']['modeling']['mouse_controls']['current']
|
||||
}) => {
|
||||
const canvasRef = useRef<HTMLDivElement>(null)
|
||||
const { state, send, context } = useModelingContext()
|
||||
|
@ -5,21 +5,21 @@ import { useEffect, useState } from 'react'
|
||||
export function CameraProjectionToggle() {
|
||||
const { settings } = useSettingsAuthContext()
|
||||
const isCameraProjectionPerspective =
|
||||
settings.context.modeling.cameraProjection.current === 'perspective'
|
||||
settings.context.modeling.camera_projection.current === 'perspective'
|
||||
const [checked, setChecked] = useState(isCameraProjectionPerspective)
|
||||
|
||||
useEffect(() => {
|
||||
setChecked(
|
||||
settings.context.modeling.cameraProjection.current === 'perspective'
|
||||
settings.context.modeling.camera_projection.current === 'perspective'
|
||||
)
|
||||
}, [settings.context.modeling.cameraProjection.current])
|
||||
}, [settings.context.modeling.camera_projection.current])
|
||||
|
||||
return (
|
||||
<Switch
|
||||
checked={checked}
|
||||
onChange={(newValue) => {
|
||||
settings.send({
|
||||
type: 'set.modeling.cameraProjection',
|
||||
type: 'set.modeling.camera_projection',
|
||||
data: {
|
||||
level: 'user',
|
||||
value: newValue ? 'perspective' : 'orthographic',
|
||||
|
@ -115,9 +115,9 @@ function CommandBarKclInput({
|
||||
: defaultValue.length,
|
||||
},
|
||||
theme:
|
||||
settings.context.app.theme.current === 'system'
|
||||
settings.context.app.appearance.theme.current === 'system'
|
||||
? getSystemTheme()
|
||||
: settings.context.app.theme.current,
|
||||
: settings.context.app.appearance.theme.current,
|
||||
extensions: [
|
||||
varMentionsExtension,
|
||||
EditorView.updateListener.of((vu: ViewUpdate) => {
|
||||
|
@ -6,7 +6,7 @@ import { useState } from 'react'
|
||||
const DownloadAppBanner = () => {
|
||||
const { settings } = useSettingsAuthContext()
|
||||
const [isBannerDismissed, setIsBannerDismissed] = useState(
|
||||
settings.context.app.dismissWebBanner.current
|
||||
settings.context.app.dismiss_web_banner.current
|
||||
)
|
||||
|
||||
return (
|
||||
|
@ -315,7 +315,7 @@ export const FileMachineProvider = ({
|
||||
// with the sample's setting.
|
||||
if (data.sampleUnits) {
|
||||
settings.send({
|
||||
type: 'set.modeling.defaultUnit',
|
||||
type: 'set.modeling.base_unit',
|
||||
data: {
|
||||
level: 'project',
|
||||
value: data.sampleUnits,
|
||||
|
@ -107,7 +107,7 @@ export function HelpMenu(props: React.PropsWithChildren) {
|
||||
as="button"
|
||||
onClick={() => {
|
||||
settings.send({
|
||||
type: 'set.app.onboardingStatus',
|
||||
type: 'set.app.onboarding_status',
|
||||
data: {
|
||||
value: '',
|
||||
level: 'user',
|
||||
|
@ -111,12 +111,15 @@ export const ModelingMachineProvider = ({
|
||||
auth,
|
||||
settings: {
|
||||
context: {
|
||||
app: { theme, enableSSAO },
|
||||
app: {
|
||||
appearance: { theme },
|
||||
},
|
||||
modeling: {
|
||||
defaultUnit,
|
||||
cameraProjection,
|
||||
highlightEdges,
|
||||
showScaleGrid,
|
||||
base_unit,
|
||||
camera_projection,
|
||||
highlight_edges,
|
||||
show_scale_grid,
|
||||
enable_ssao,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -172,7 +175,7 @@ export const ModelingMachineProvider = ({
|
||||
|
||||
sceneInfra.camControls.syncDirection = 'clientToEngine'
|
||||
|
||||
if (cameraProjection.current === 'perspective') {
|
||||
if (camera_projection.current === 'perspective') {
|
||||
await sceneInfra.camControls.snapToPerspectiveBeforeHandingBackControlToEngine()
|
||||
}
|
||||
|
||||
@ -508,7 +511,7 @@ export const ModelingMachineProvider = ({
|
||||
format.type === 'stl' ||
|
||||
format.type === 'ply'
|
||||
) {
|
||||
format.units = defaultUnit.current
|
||||
format.units = base_unit.current
|
||||
}
|
||||
|
||||
if (format.type === 'ply' || format.type === 'stl') {
|
||||
@ -533,7 +536,7 @@ export const ModelingMachineProvider = ({
|
||||
token,
|
||||
settings: {
|
||||
theme: theme.current,
|
||||
highlightEdges: highlightEdges.current,
|
||||
highlightEdges: highlight_edges.current,
|
||||
},
|
||||
}).catch(reportRejection)
|
||||
},
|
||||
@ -1134,10 +1137,10 @@ export const ModelingMachineProvider = ({
|
||||
{
|
||||
pool: pool,
|
||||
theme: theme.current,
|
||||
highlightEdges: highlightEdges.current,
|
||||
enableSSAO: enableSSAO.current,
|
||||
showScaleGrid: showScaleGrid.current,
|
||||
cameraProjection: cameraProjection.current,
|
||||
highlightEdges: highlight_edges.current,
|
||||
enableSSAO: enable_ssao.current,
|
||||
showScaleGrid: show_scale_grid.current,
|
||||
cameraProjection: camera_projection.current,
|
||||
},
|
||||
token
|
||||
)
|
||||
|
@ -69,7 +69,7 @@ export const ModelingPane = ({
|
||||
...props
|
||||
}: ModelingPaneProps) => {
|
||||
const { settings } = useSettingsAuthContext()
|
||||
const onboardingStatus = settings.context.app.onboardingStatus
|
||||
const onboardingStatus = settings.context.app.onboarding_status
|
||||
const pointerEventsCssClass =
|
||||
onboardingStatus.current === onboardingPaths.CAMERA
|
||||
? 'pointer-events-none '
|
||||
|
@ -69,9 +69,9 @@ export const KclEditorPane = () => {
|
||||
const lastSelectionEvent = useSelector(kclEditorActor, selectionEventSelector)
|
||||
const editorIsMounted = useSelector(kclEditorActor, editorIsMountedSelector)
|
||||
const theme =
|
||||
context.app.theme.current === Themes.System
|
||||
context.app.appearance.theme.current === Themes.System
|
||||
? getSystemTheme()
|
||||
: context.app.theme.current
|
||||
: context.app.appearance.theme.current
|
||||
const { copilotLSP, kclLSP } = useLspContext()
|
||||
|
||||
// Since these already exist in the editor, we don't need to define them
|
||||
@ -104,8 +104,8 @@ export const KclEditorPane = () => {
|
||||
})
|
||||
}, [editorIsMounted, lastSelectionEvent])
|
||||
|
||||
const textWrapping = context.textEditor.textWrapping
|
||||
const cursorBlinking = context.textEditor.blinkingCursor
|
||||
const textWrapping = context.text_editor.text_wrapping
|
||||
const cursorBlinking = context.text_editor.blinking_cursor
|
||||
// DO NOT ADD THE CODEMIRROR HOTKEYS HERE TO THE DEPENDENCY ARRAY
|
||||
// It reloads the editor every time we do _anything_ in the editor
|
||||
// I have no idea why.
|
||||
|
@ -210,6 +210,6 @@ export const sidebarPanes: SidebarPane[] = [
|
||||
)
|
||||
},
|
||||
keybinding: 'Shift + D',
|
||||
hide: ({ settings }) => !settings.modeling.showDebugPanel.current,
|
||||
hide: ({ settings }) => !settings.app.show_debug_panel.current,
|
||||
},
|
||||
]
|
||||
|
@ -40,14 +40,14 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
|
||||
const { commandBarSend } = useCommandsContext()
|
||||
const kclContext = useKclContext()
|
||||
const { settings } = useSettingsAuthContext()
|
||||
const onboardingStatus = settings.context.app.onboardingStatus
|
||||
const onboardingStatus = settings.context.app.onboarding_status
|
||||
const { send, context } = useModelingContext()
|
||||
const pointerEventsCssClass =
|
||||
onboardingStatus.current === onboardingPaths.CAMERA ||
|
||||
context.store?.openPanes.length === 0
|
||||
? 'pointer-events-none '
|
||||
: 'pointer-events-auto '
|
||||
const showDebugPanel = settings.context.modeling.showDebugPanel
|
||||
const showDebugPanel = settings.context.app.show_debug_panel
|
||||
|
||||
const paneCallbackProps = useMemo(
|
||||
() => ({
|
||||
|
@ -79,11 +79,8 @@ const ProjectsContextDesktop = ({
|
||||
} = useSettingsAuthContext()
|
||||
|
||||
useEffect(() => {
|
||||
console.log(
|
||||
'project directory changed',
|
||||
settings.app.projectDirectory.current
|
||||
)
|
||||
}, [settings.app.projectDirectory.current])
|
||||
console.log('project directory changed', settings.project.directory.current)
|
||||
}, [settings.project.directory.current])
|
||||
|
||||
const [projectsLoaderTrigger, setProjectsLoaderTrigger] = useState(0)
|
||||
const { projectPaths, projectsDir } = useProjectsLoader([
|
||||
@ -192,7 +189,7 @@ const ProjectsContextDesktop = ({
|
||||
let name = (
|
||||
input && 'name' in input && input.name
|
||||
? input.name
|
||||
: settings.projects.defaultProjectName.current
|
||||
: settings.project.default_project_name.current
|
||||
).trim()
|
||||
|
||||
if (doesProjectNameNeedInterpolated(name)) {
|
||||
@ -257,8 +254,8 @@ const ProjectsContextDesktop = ({
|
||||
{
|
||||
input: {
|
||||
projects: projectPaths,
|
||||
defaultProjectName: settings.projects.defaultProjectName.current,
|
||||
defaultDirectory: settings.app.projectDirectory.current,
|
||||
defaultProjectName: settings.project.default_project_name.current,
|
||||
defaultDirectory: settings.project.directory.current,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
@ -61,7 +61,7 @@ export const AllSettingsFields = forwardRef(
|
||||
|
||||
function restartOnboarding() {
|
||||
send({
|
||||
type: `set.app.onboardingStatus`,
|
||||
type: `set.app.onboarding_status`,
|
||||
data: { level: 'user', value: '' },
|
||||
})
|
||||
}
|
||||
@ -73,7 +73,7 @@ export const AllSettingsFields = forwardRef(
|
||||
useEffect(() => {
|
||||
async function navigateToOnboardingStart() {
|
||||
if (
|
||||
state.context.app.onboardingStatus.user === '' &&
|
||||
state.context.app.onboarding_status.user === '' &&
|
||||
state.matches('idle')
|
||||
) {
|
||||
if (isFileSettings) {
|
||||
|
@ -122,18 +122,20 @@ export const SettingsAuthProviderBase = ({
|
||||
|
||||
setClientSideSceneUnits: ({ context, event }) => {
|
||||
const newBaseUnit =
|
||||
event.type === 'set.modeling.defaultUnit'
|
||||
event.type === 'set.modeling.base_unit'
|
||||
? (event.data.value as BaseUnit)
|
||||
: context.modeling.defaultUnit.current
|
||||
: context.modeling.base_unit.current
|
||||
sceneInfra.baseUnit = newBaseUnit
|
||||
},
|
||||
setEngineTheme: ({ context }) => {
|
||||
engineCommandManager
|
||||
.setTheme(context.app.theme.current)
|
||||
.setTheme(context.app.appearance.theme.current)
|
||||
.catch(reportRejection)
|
||||
},
|
||||
setClientTheme: ({ context }) => {
|
||||
const opposingTheme = getOppositeTheme(context.app.theme.current)
|
||||
const opposingTheme = getOppositeTheme(
|
||||
context.app.appearance.theme.current
|
||||
)
|
||||
sceneInfra.theme = opposingTheme
|
||||
sceneEntitiesManager.updateSegmentBaseColor(opposingTheme)
|
||||
},
|
||||
@ -164,12 +166,12 @@ export const SettingsAuthProviderBase = ({
|
||||
try {
|
||||
const relevantSetting = (s: typeof settings) => {
|
||||
return (
|
||||
s.modeling?.defaultUnit?.current !==
|
||||
context.modeling.defaultUnit.current ||
|
||||
s.modeling.showScaleGrid.current !==
|
||||
context.modeling.showScaleGrid.current ||
|
||||
s.modeling?.highlightEdges.current !==
|
||||
context.modeling.highlightEdges.current
|
||||
s.modeling?.base_unit.current !==
|
||||
context.modeling.base_unit.current ||
|
||||
s.modeling.show_scale_grid.current !==
|
||||
context.modeling.show_scale_grid.current ||
|
||||
s.modeling?.highlight_edges.current !==
|
||||
context.modeling.highlight_edges.current
|
||||
)
|
||||
}
|
||||
|
||||
@ -180,9 +182,9 @@ export const SettingsAuthProviderBase = ({
|
||||
event.type === 'Reset settings' && relevantSetting(settings)
|
||||
|
||||
if (
|
||||
event.type === 'set.modeling.defaultUnit' ||
|
||||
event.type === 'set.modeling.showScaleGrid' ||
|
||||
event.type === 'set.modeling.highlightEdges' ||
|
||||
event.type === 'set.modeling.base_unit' ||
|
||||
event.type === 'set.modeling.show_scale_grid' ||
|
||||
event.type === 'set.modeling.highlight_edges' ||
|
||||
allSettingsIncludesUnitChange ||
|
||||
resetSettingsIncludesUnitChange
|
||||
) {
|
||||
@ -258,7 +260,7 @@ export const SettingsAuthProviderBase = ({
|
||||
useEffect(() => {
|
||||
// If the user wants to hide the settings commands
|
||||
//from the command bar don't add them.
|
||||
if (settingsState.context.commandBar.includeSettings.current === false)
|
||||
if (settingsState.context.command_bar.include_settings.current === false)
|
||||
return
|
||||
|
||||
const commands = settingsWithCommandConfigs(settingsState.context)
|
||||
@ -334,7 +336,8 @@ export const SettingsAuthProviderBase = ({
|
||||
// events outside of the machine that also depend on the machine's context
|
||||
useEffect(() => {
|
||||
const listener = (e: MediaQueryListEvent) => {
|
||||
if (settingsState.context.app.theme.current !== 'system') return
|
||||
if (settingsState.context.app.appearance.theme.current !== 'system')
|
||||
return
|
||||
setThemeClass(e.matches ? Themes.Dark : Themes.Light)
|
||||
}
|
||||
|
||||
@ -349,9 +352,9 @@ export const SettingsAuthProviderBase = ({
|
||||
useEffect(() => {
|
||||
document.documentElement.style.setProperty(
|
||||
`--primary-hue`,
|
||||
settingsState.context.app.themeColor.current
|
||||
settingsState.context.app.appearance.color.current
|
||||
)
|
||||
}, [settingsState.context.app.themeColor.current])
|
||||
}, [settingsState.context.app.appearance.color.current])
|
||||
|
||||
/**
|
||||
* Update the --cursor-color CSS variable
|
||||
@ -360,11 +363,11 @@ export const SettingsAuthProviderBase = ({
|
||||
useEffect(() => {
|
||||
document.documentElement.style.setProperty(
|
||||
`--cursor-color`,
|
||||
settingsState.context.textEditor.blinkingCursor.current
|
||||
settingsState.context.text_editor.blinking_cursor.current
|
||||
? 'auto'
|
||||
: 'transparent'
|
||||
)
|
||||
}, [settingsState.context.textEditor.blinkingCursor.current])
|
||||
}, [settingsState.context.text_editor.blinking_cursor.current])
|
||||
|
||||
// Auth machine setup
|
||||
const [authState, authSend, authActor] = useMachine(
|
||||
|
@ -41,7 +41,7 @@ export const Stream = () => {
|
||||
const [streamState, setStreamState] = useState(StreamState.Unset)
|
||||
const { file } = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
|
||||
|
||||
const IDLE = settings.context.app.streamIdleMode.current
|
||||
const IDLE = settings.context.app.stream_idle_mode.current
|
||||
|
||||
const isNetworkOkay =
|
||||
overallState === NetworkHealthState.Ok ||
|
||||
@ -342,7 +342,7 @@ export const Stream = () => {
|
||||
id="video-stream"
|
||||
/>
|
||||
<ClientSideScene
|
||||
cameraControls={settings.context.modeling.mouseControls.current}
|
||||
cameraControls={settings.context.modeling.mouse_controls.current}
|
||||
/>
|
||||
{(streamState === StreamState.Paused ||
|
||||
streamState === StreamState.Resuming) && (
|
||||
|
@ -18,7 +18,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>
|
||||
{settings.context.modeling.defaultUnit.current}
|
||||
{settings.context.modeling.base_unit.current}
|
||||
</Popover.Button>
|
||||
<Popover.Panel
|
||||
className={`absolute bottom-full right-0 mb-2 w-48 bg-chalkboard-10 dark:bg-chalkboard-90
|
||||
@ -32,7 +32,7 @@ export function UnitsMenu() {
|
||||
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={() => {
|
||||
settings.send({
|
||||
type: 'set.modeling.defaultUnit',
|
||||
type: 'set.modeling.base_unit',
|
||||
data: {
|
||||
level: 'project',
|
||||
value: unit,
|
||||
@ -42,7 +42,7 @@ export function UnitsMenu() {
|
||||
}}
|
||||
>
|
||||
<span className="flex-1">{baseUnitLabels[unit]}</span>
|
||||
{unit === settings.context.modeling.defaultUnit.current && (
|
||||
{unit === settings.context.modeling.base_unit.current && (
|
||||
<span className="text-chalkboard-60">current</span>
|
||||
)}
|
||||
</button>
|
||||
|
@ -10,7 +10,7 @@ export function useResolvedTheme() {
|
||||
const {
|
||||
settings: { context },
|
||||
} = useSettingsAuthContext()
|
||||
return context.app.theme.current === Themes.System
|
||||
return context.app.appearance.theme.current === Themes.System
|
||||
? getSystemTheme()
|
||||
: context.app.theme.current
|
||||
: context.app.appearance.theme.current
|
||||
}
|
||||
|
@ -63,9 +63,7 @@ export async function renameProjectDirectory(
|
||||
export async function ensureProjectDirectoryExists(
|
||||
config: DeepPartial<Configuration>
|
||||
): Promise<string | undefined> {
|
||||
const projectDir =
|
||||
config.settings?.app?.project_directory ||
|
||||
config.settings?.project?.directory
|
||||
const projectDir = config.settings?.project?.directory
|
||||
if (!projectDir) {
|
||||
console.error('projectDir is falsey', config)
|
||||
return Promise.reject(new Error('projectDir is falsey'))
|
||||
@ -520,8 +518,7 @@ export const readAppSettingsFile = async () => {
|
||||
}
|
||||
|
||||
const hasProjectDirectorySetting =
|
||||
parsedAppConfig.settings?.project?.directory ||
|
||||
parsedAppConfig.settings?.app?.project_directory
|
||||
parsedAppConfig.settings?.project?.directory
|
||||
|
||||
if (hasProjectDirectorySetting) {
|
||||
return parsedAppConfig
|
||||
|
@ -86,8 +86,7 @@ export function kclCommands(
|
||||
sampleName: data.sample,
|
||||
code,
|
||||
method: data.method,
|
||||
sampleUnits:
|
||||
projectSettingsPayload.modeling?.defaultUnit || 'mm',
|
||||
sampleUnits: projectSettingsPayload.modeling?.base_unit || 'mm',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -55,7 +55,7 @@ export const telemetryLoader: LoaderFunction = async ({
|
||||
export const onboardingRedirectLoader: ActionFunction = async (args) => {
|
||||
const { settings } = await loadAndValidateSettings()
|
||||
const onboardingStatus: OnboardingStatus =
|
||||
settings.app.onboardingStatus.current || ''
|
||||
settings.app.onboarding_status.current || ''
|
||||
const notEnRouteToOnboarding = !args.request.url.includes(
|
||||
PATHS.ONBOARDING.INDEX
|
||||
)
|
||||
|
@ -128,6 +128,7 @@ export function createSettings() {
|
||||
/**
|
||||
* The overall appearance of the app: light, dark, or system
|
||||
*/
|
||||
appearance: {
|
||||
theme: new Setting<Themes>({
|
||||
hideOnLevel: 'project',
|
||||
defaultValue: Themes.System,
|
||||
@ -148,7 +149,7 @@ export function createSettings() {
|
||||
})),
|
||||
},
|
||||
}),
|
||||
themeColor: new Setting<string>({
|
||||
color: new Setting<string>({
|
||||
defaultValue: '264.5',
|
||||
description: 'The hue of the primary theme color for the app',
|
||||
validate: (v) => Number(v) >= 0 && Number(v) < 360,
|
||||
@ -172,17 +173,23 @@ export function createSettings() {
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
enableSSAO: new Setting<boolean>({
|
||||
defaultValue: true,
|
||||
description:
|
||||
'Whether or not Screen Space Ambient Occlusion (SSAO) is enabled',
|
||||
},
|
||||
/**
|
||||
* Whether to show the debug panel, which lets you see
|
||||
* various states of the app to aid in development
|
||||
*/
|
||||
show_debug_panel: new Setting<boolean>({
|
||||
defaultValue: false,
|
||||
description: 'Whether to show the debug panel, a development tool',
|
||||
validate: (v) => typeof v === 'boolean',
|
||||
hideOnPlatform: 'both', //for now
|
||||
commandConfig: {
|
||||
inputType: 'boolean',
|
||||
},
|
||||
}),
|
||||
/**
|
||||
* Stream resource saving behavior toggle
|
||||
*/
|
||||
streamIdleMode: new Setting<boolean>({
|
||||
stream_idle_mode: new Setting<boolean>({
|
||||
defaultValue: false,
|
||||
description: 'Toggle stream idling, saving bandwidth and battery',
|
||||
validate: (v) => typeof v === 'boolean',
|
||||
@ -190,7 +197,7 @@ export function createSettings() {
|
||||
inputType: 'boolean',
|
||||
},
|
||||
}),
|
||||
onboardingStatus: new Setting<OnboardingStatus>({
|
||||
onboarding_status: new Setting<OnboardingStatus>({
|
||||
defaultValue: '',
|
||||
// TODO: this could be better but we don't have a TS side real enum
|
||||
// for this yet
|
||||
@ -198,62 +205,13 @@ export function createSettings() {
|
||||
hideOnPlatform: 'both',
|
||||
}),
|
||||
/** Permanently dismiss the banner warning to download the desktop app. */
|
||||
dismissWebBanner: new Setting<boolean>({
|
||||
dismiss_web_banner: new Setting<boolean>({
|
||||
defaultValue: false,
|
||||
description:
|
||||
'Permanently dismiss the banner warning to download the desktop app.',
|
||||
validate: (v) => typeof v === 'boolean',
|
||||
hideOnPlatform: 'desktop',
|
||||
}),
|
||||
projectDirectory: new Setting<string>({
|
||||
defaultValue: '',
|
||||
description: 'The directory to save and load projects from',
|
||||
hideOnLevel: 'project',
|
||||
hideOnPlatform: 'web',
|
||||
validate: (v) =>
|
||||
typeof v === 'string' && (v.length > 0 || !isDesktop()),
|
||||
Component: ({ value, updateValue }) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
return (
|
||||
<div className="flex gap-4 p-1 border rounded-sm border-chalkboard-30">
|
||||
<input
|
||||
className="flex-grow text-xs px-2 bg-transparent"
|
||||
value={value}
|
||||
disabled
|
||||
data-testid="project-directory-input"
|
||||
ref={inputRef}
|
||||
/>
|
||||
<button
|
||||
onClick={toSync(async () => {
|
||||
// In desktop end-to-end tests we can't control the file picker,
|
||||
// so we seed the new directory value in the element's dataset
|
||||
const inputRefVal = inputRef.current?.dataset.testValue
|
||||
if (
|
||||
inputRef.current &&
|
||||
inputRefVal &&
|
||||
!Array.isArray(inputRefVal)
|
||||
) {
|
||||
updateValue(inputRefVal)
|
||||
} else {
|
||||
const newPath = await window.electron.open({
|
||||
properties: ['openDirectory', 'createDirectory'],
|
||||
defaultPath: value,
|
||||
title: 'Choose a new project directory',
|
||||
})
|
||||
if (newPath.canceled) return
|
||||
updateValue(newPath.filePaths[0])
|
||||
}
|
||||
}, reportRejection)}
|
||||
className="p-0 m-0 border-none hover:bg-primary/10 focus:bg-primary/10 dark:hover:bg-primary/20 dark:focus::bg-primary/20"
|
||||
data-testid="project-directory-button"
|
||||
>
|
||||
<CustomIcon name="folder" className="w-5 h-5" />
|
||||
<Tooltip position="top-right">Choose a folder</Tooltip>
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
}),
|
||||
},
|
||||
/**
|
||||
* Settings that affect the behavior while modeling.
|
||||
@ -262,7 +220,7 @@ export function createSettings() {
|
||||
/**
|
||||
* The default unit to use in modeling dimensions
|
||||
*/
|
||||
defaultUnit: new Setting<BaseUnit>({
|
||||
base_unit: new Setting<BaseUnit>({
|
||||
defaultValue: 'mm',
|
||||
description: 'The default unit to use in modeling dimensions',
|
||||
validate: (v) => baseUnitsUnion.includes(v as BaseUnit),
|
||||
@ -285,7 +243,7 @@ export function createSettings() {
|
||||
/**
|
||||
* The controls for how to navigate the 3D view
|
||||
*/
|
||||
mouseControls: new Setting<CameraSystem>({
|
||||
mouse_controls: new Setting<CameraSystem>({
|
||||
defaultValue: 'Zoo',
|
||||
description: 'The controls for how to navigate the 3D view',
|
||||
validate: (v) => cameraSystems.includes(v as CameraSystem),
|
||||
@ -345,7 +303,7 @@ export function createSettings() {
|
||||
/**
|
||||
* Projection method applied to the 3D view, perspective or orthographic
|
||||
*/
|
||||
cameraProjection: new Setting<CameraProjectionType>({
|
||||
camera_projection: new Setting<CameraProjectionType>({
|
||||
defaultValue: 'orthographic',
|
||||
hideOnLevel: 'project',
|
||||
description:
|
||||
@ -372,10 +330,17 @@ export function createSettings() {
|
||||
})),
|
||||
},
|
||||
}),
|
||||
enable_ssao: new Setting<boolean>({
|
||||
defaultValue: true,
|
||||
description:
|
||||
'Whether or not Screen Space Ambient Occlusion (SSAO) is enabled',
|
||||
validate: (v) => typeof v === 'boolean',
|
||||
hideOnPlatform: 'both', //for now
|
||||
}),
|
||||
/**
|
||||
* Whether to highlight edges of 3D objects
|
||||
*/
|
||||
highlightEdges: new Setting<boolean>({
|
||||
highlight_edges: new Setting<boolean>({
|
||||
defaultValue: true,
|
||||
description: 'Whether to highlight edges of 3D objects',
|
||||
validate: (v) => typeof v === 'boolean',
|
||||
@ -387,7 +352,7 @@ export function createSettings() {
|
||||
/**
|
||||
* Whether to show a scale grid in the 3D modeling view
|
||||
*/
|
||||
showScaleGrid: new Setting<boolean>({
|
||||
show_scale_grid: new Setting<boolean>({
|
||||
defaultValue: false,
|
||||
description: 'Whether to show a scale grid in the 3D modeling view',
|
||||
validate: (v) => typeof v === 'boolean',
|
||||
@ -396,18 +361,6 @@ export function createSettings() {
|
||||
},
|
||||
hideOnLevel: 'project',
|
||||
}),
|
||||
/**
|
||||
* Whether to show the debug panel, which lets you see
|
||||
* various states of the app to aid in development
|
||||
*/
|
||||
showDebugPanel: new Setting<boolean>({
|
||||
defaultValue: false,
|
||||
description: 'Whether to show the debug panel, a development tool',
|
||||
validate: (v) => typeof v === 'boolean',
|
||||
commandConfig: {
|
||||
inputType: 'boolean',
|
||||
},
|
||||
}),
|
||||
/**
|
||||
* TODO: This setting is not yet implemented.
|
||||
* Whether to turn off animations and other motion effects
|
||||
@ -438,11 +391,11 @@ export function createSettings() {
|
||||
/**
|
||||
* Settings that affect the behavior of the KCL text editor.
|
||||
*/
|
||||
textEditor: {
|
||||
text_editor: {
|
||||
/**
|
||||
* Whether to wrap text in the editor or overflow with scroll
|
||||
*/
|
||||
textWrapping: new Setting<boolean>({
|
||||
text_wrapping: new Setting<boolean>({
|
||||
defaultValue: true,
|
||||
description:
|
||||
'Whether to wrap text in the editor or overflow with scroll',
|
||||
@ -454,7 +407,7 @@ export function createSettings() {
|
||||
/**
|
||||
* Whether to make the cursor blink in the editor
|
||||
*/
|
||||
blinkingCursor: new Setting<boolean>({
|
||||
blinking_cursor: new Setting<boolean>({
|
||||
defaultValue: true,
|
||||
description: 'Whether to make the cursor blink in the editor',
|
||||
validate: (v) => typeof v === 'boolean',
|
||||
@ -466,11 +419,60 @@ export function createSettings() {
|
||||
/**
|
||||
* Settings that affect the behavior of project management.
|
||||
*/
|
||||
projects: {
|
||||
project: {
|
||||
directory: new Setting<string>({
|
||||
defaultValue: '',
|
||||
description: 'The directory to save and load projects from',
|
||||
hideOnLevel: 'project',
|
||||
hideOnPlatform: 'web',
|
||||
validate: (v) =>
|
||||
typeof v === 'string' && (v.length > 0 || !isDesktop()),
|
||||
Component: ({ value, updateValue }) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
return (
|
||||
<div className="flex gap-4 p-1 border rounded-sm border-chalkboard-30">
|
||||
<input
|
||||
className="flex-grow text-xs px-2 bg-transparent"
|
||||
value={value}
|
||||
disabled
|
||||
data-testid="project-directory-input"
|
||||
ref={inputRef}
|
||||
/>
|
||||
<button
|
||||
onClick={toSync(async () => {
|
||||
// In desktop end-to-end tests we can't control the file picker,
|
||||
// so we seed the new directory value in the element's dataset
|
||||
const inputRefVal = inputRef.current?.dataset.testValue
|
||||
if (
|
||||
inputRef.current &&
|
||||
inputRefVal &&
|
||||
!Array.isArray(inputRefVal)
|
||||
) {
|
||||
updateValue(inputRefVal)
|
||||
} else {
|
||||
const newPath = await window.electron.open({
|
||||
properties: ['openDirectory', 'createDirectory'],
|
||||
defaultPath: value,
|
||||
title: 'Choose a new project directory',
|
||||
})
|
||||
if (newPath.canceled) return
|
||||
updateValue(newPath.filePaths[0])
|
||||
}
|
||||
}, reportRejection)}
|
||||
className="p-0 m-0 border-none hover:bg-primary/10 focus:bg-primary/10 dark:hover:bg-primary/20 dark:focus::bg-primary/20"
|
||||
data-testid="project-directory-button"
|
||||
>
|
||||
<CustomIcon name="folder" className="w-5 h-5" />
|
||||
<Tooltip position="top-right">Choose a folder</Tooltip>
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
}),
|
||||
/**
|
||||
* The default project name to use when creating a new project
|
||||
*/
|
||||
defaultProjectName: new Setting<string>({
|
||||
default_project_name: new Setting<string>({
|
||||
defaultValue: DEFAULT_PROJECT_NAME,
|
||||
description:
|
||||
'The default project name to use when creating a new project',
|
||||
@ -504,11 +506,11 @@ export function createSettings() {
|
||||
/**
|
||||
* Settings that affect the behavior of the command bar.
|
||||
*/
|
||||
commandBar: {
|
||||
command_bar: {
|
||||
/**
|
||||
* Whether to include settings in the command bar
|
||||
*/
|
||||
includeSettings: new Setting<boolean>({
|
||||
include_settings: new Setting<boolean>({
|
||||
defaultValue: true,
|
||||
description: 'Whether to include settings in the command bar',
|
||||
validate: (v) => typeof v === 'boolean',
|
||||
|
@ -26,8 +26,8 @@ describe(`testing settings initialization`, () => {
|
||||
|
||||
setSettingsAtLevel(settings, 'user', appSettingsPayload)
|
||||
|
||||
expect(settings.app.theme.current).toBe('dark')
|
||||
expect(settings.app.themeColor.current).toBe('190')
|
||||
expect(settings.app.appearance.theme.current).toBe('dark')
|
||||
expect(settings.app.appearance.color.current).toBe('190')
|
||||
})
|
||||
|
||||
it(`doesn't read theme from project settings`, () => {
|
||||
@ -61,9 +61,9 @@ describe(`testing settings initialization`, () => {
|
||||
setSettingsAtLevel(settings, 'project', projectSettingsPayload)
|
||||
|
||||
// The 'project'-level for `theme` setting should be ignored completely
|
||||
expect(settings.app.theme.current).toBe('dark')
|
||||
expect(settings.app.appearance.theme.current).toBe('dark')
|
||||
// But the 'project'-level for `themeColor` setting should be applied
|
||||
expect(settings.app.themeColor.current).toBe('200')
|
||||
expect(settings.app.appearance.color.current).toBe('200')
|
||||
})
|
||||
})
|
||||
|
||||
@ -106,8 +106,8 @@ describe(`testing getAllCurrentSettings`, () => {
|
||||
const allCurrentSettings = getAllCurrentSettings(settings)
|
||||
// This one gets the 'user'-level theme because it's ignored at the project level
|
||||
// (see the test "doesn't read theme from project settings")
|
||||
expect(allCurrentSettings.app.theme).toBe('dark')
|
||||
expect(allCurrentSettings.app.themeColor).toBe('200')
|
||||
expect(allCurrentSettings.modeling.defaultUnit).toBe('ft')
|
||||
expect(allCurrentSettings.app.appearance?.theme).toBe('dark')
|
||||
expect(allCurrentSettings.app.appearance?.color).toBe('200')
|
||||
expect(allCurrentSettings.modeling.base_unit).toBe('ft')
|
||||
})
|
||||
})
|
||||
|
@ -34,36 +34,38 @@ export function configurationToSettingsPayload(
|
||||
): DeepPartial<SaveSettingsPayload> {
|
||||
return {
|
||||
app: {
|
||||
appearance: {
|
||||
theme: appThemeToTheme(configuration?.settings?.app?.appearance?.theme),
|
||||
themeColor: configuration?.settings?.app?.appearance?.color
|
||||
color: configuration?.settings?.app?.appearance?.color
|
||||
? configuration?.settings?.app?.appearance?.color.toString()
|
||||
: undefined,
|
||||
onboardingStatus: configuration?.settings?.app?.onboarding_status,
|
||||
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
||||
streamIdleMode: configuration?.settings?.app?.stream_idle_mode,
|
||||
projectDirectory: configuration?.settings?.project?.directory,
|
||||
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
||||
},
|
||||
onboarding_status: configuration?.settings?.app?.onboarding_status,
|
||||
dismiss_web_banner: configuration?.settings?.app?.dismiss_web_banner,
|
||||
stream_idle_mode: configuration?.settings?.app?.stream_idle_mode,
|
||||
show_debug_panel: configuration?.settings?.app?.show_debug_panel,
|
||||
},
|
||||
modeling: {
|
||||
defaultUnit: configuration?.settings?.modeling?.base_unit,
|
||||
cameraProjection: configuration?.settings?.modeling?.camera_projection,
|
||||
mouseControls: mouseControlsToCameraSystem(
|
||||
base_unit: configuration?.settings?.modeling?.base_unit,
|
||||
camera_projection: configuration?.settings?.modeling?.camera_projection,
|
||||
mouse_controls: mouseControlsToCameraSystem(
|
||||
configuration?.settings?.modeling?.mouse_controls
|
||||
),
|
||||
highlightEdges: configuration?.settings?.modeling?.highlight_edges,
|
||||
showDebugPanel: configuration?.settings?.modeling?.show_debug_panel,
|
||||
showScaleGrid: configuration?.settings?.modeling?.show_scale_grid,
|
||||
highlight_edges: configuration?.settings?.modeling?.highlight_edges,
|
||||
show_scale_grid: configuration?.settings?.modeling?.show_scale_grid,
|
||||
enable_ssao: configuration?.settings?.modeling?.enable_ssao,
|
||||
},
|
||||
textEditor: {
|
||||
textWrapping: configuration?.settings?.text_editor?.text_wrapping,
|
||||
blinkingCursor: configuration?.settings?.text_editor?.blinking_cursor,
|
||||
text_editor: {
|
||||
text_wrapping: configuration?.settings?.text_editor?.text_wrapping,
|
||||
blinking_cursor: configuration?.settings?.text_editor?.blinking_cursor,
|
||||
},
|
||||
projects: {
|
||||
defaultProjectName:
|
||||
project: {
|
||||
default_project_name:
|
||||
configuration?.settings?.project?.default_project_name,
|
||||
directory: configuration?.settings?.project?.directory,
|
||||
},
|
||||
commandBar: {
|
||||
includeSettings: configuration?.settings?.command_bar?.include_settings,
|
||||
command_bar: {
|
||||
include_settings: configuration?.settings?.command_bar?.include_settings,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -73,29 +75,28 @@ export function projectConfigurationToSettingsPayload(
|
||||
): DeepPartial<SaveSettingsPayload> {
|
||||
return {
|
||||
app: {
|
||||
appearance: {
|
||||
// do not read in `theme`, because it is blocked on the project level
|
||||
themeColor: configuration?.settings?.app?.appearance?.color
|
||||
color: configuration?.settings?.app?.appearance?.color
|
||||
? configuration?.settings?.app?.appearance?.color.toString()
|
||||
: undefined,
|
||||
onboardingStatus: configuration?.settings?.app?.onboarding_status,
|
||||
dismissWebBanner: configuration?.settings?.app?.dismiss_web_banner,
|
||||
streamIdleMode: configuration?.settings?.app?.stream_idle_mode,
|
||||
enableSSAO: configuration?.settings?.modeling?.enable_ssao,
|
||||
},
|
||||
onboarding_status: configuration?.settings?.app?.onboarding_status,
|
||||
dismiss_web_banner: configuration?.settings?.app?.dismiss_web_banner,
|
||||
stream_idle_mode: configuration?.settings?.app?.stream_idle_mode,
|
||||
show_debug_panel: configuration?.settings?.app?.show_debug_panel,
|
||||
},
|
||||
modeling: {
|
||||
defaultUnit: configuration?.settings?.modeling?.base_unit,
|
||||
mouseControls: mouseControlsToCameraSystem(
|
||||
configuration?.settings?.modeling?.mouse_controls
|
||||
),
|
||||
highlightEdges: configuration?.settings?.modeling?.highlight_edges,
|
||||
showDebugPanel: configuration?.settings?.modeling?.show_debug_panel,
|
||||
base_unit: configuration?.settings?.modeling?.base_unit,
|
||||
highlight_edges: configuration?.settings?.modeling?.highlight_edges,
|
||||
enable_ssao: configuration?.settings?.modeling?.enable_ssao,
|
||||
},
|
||||
textEditor: {
|
||||
textWrapping: configuration?.settings?.text_editor?.text_wrapping,
|
||||
blinkingCursor: configuration?.settings?.text_editor?.blinking_cursor,
|
||||
text_editor: {
|
||||
text_wrapping: configuration?.settings?.text_editor?.text_wrapping,
|
||||
blinking_cursor: configuration?.settings?.text_editor?.blinking_cursor,
|
||||
},
|
||||
commandBar: {
|
||||
includeSettings: configuration?.settings?.command_bar?.include_settings,
|
||||
command_bar: {
|
||||
include_settings: configuration?.settings?.command_bar?.include_settings,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -181,7 +182,7 @@ export async function loadAndValidateSettings(
|
||||
|
||||
// Because getting the default directory is async, we need to set it after
|
||||
if (onDesktop) {
|
||||
settings.app.projectDirectory.default = await getInitialDefaultDir()
|
||||
settings.project.directory.default = await getInitialDefaultDir()
|
||||
}
|
||||
|
||||
settingsNext = setSettingsAtLevel(
|
||||
|
@ -84,13 +84,13 @@ export const settingsMachine = setup({
|
||||
return newContext
|
||||
}),
|
||||
setThemeClass: ({ context }) => {
|
||||
const currentTheme = context.app.theme.current ?? Themes.System
|
||||
const currentTheme = context.app.appearance.theme.current ?? Themes.System
|
||||
setThemeClass(
|
||||
currentTheme === Themes.System ? getSystemTheme() : currentTheme
|
||||
)
|
||||
},
|
||||
setEngineCameraProjection: ({ context }) => {
|
||||
const newCurrentProjection = context.modeling.cameraProjection.current
|
||||
const newCurrentProjection = context.modeling.camera_projection.current
|
||||
sceneInfra.camControls.setEngineCameraProjection(newCurrentProjection)
|
||||
},
|
||||
},
|
||||
|
@ -79,13 +79,13 @@ const Home = () => {
|
||||
send({
|
||||
type: 'assign',
|
||||
data: {
|
||||
defaultProjectName: settings.projects.defaultProjectName.current,
|
||||
defaultDirectory: settings.app.projectDirectory.current,
|
||||
defaultProjectName: settings.project.default_project_name.current,
|
||||
defaultDirectory: settings.project.directory.current,
|
||||
},
|
||||
})
|
||||
}, [
|
||||
settings.app.projectDirectory.current,
|
||||
settings.projects.defaultProjectName.current,
|
||||
settings.project.directory.current,
|
||||
settings.project.default_project_name.current,
|
||||
send,
|
||||
])
|
||||
|
||||
@ -134,7 +134,7 @@ const Home = () => {
|
||||
groupId: 'projects',
|
||||
name: 'Create project',
|
||||
argDefaultValues: {
|
||||
name: settings.projects.defaultProjectName.current,
|
||||
name: settings.project.default_project_name.current,
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -207,7 +207,7 @@ const Home = () => {
|
||||
to={`${PATHS.HOME + PATHS.SETTINGS_USER}#projectDirectory`}
|
||||
className="text-chalkboard-90 dark:text-chalkboard-20 underline underline-offset-2"
|
||||
>
|
||||
{settings.app.projectDirectory.current}
|
||||
{settings.project.directory.current}
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
|
@ -16,7 +16,7 @@ export default function Units() {
|
||||
send,
|
||||
state: {
|
||||
context: {
|
||||
modeling: { mouseControls },
|
||||
modeling: { mouse_controls },
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -38,10 +38,10 @@ export default function Units() {
|
||||
<select
|
||||
id="camera-controls"
|
||||
className="block w-full px-3 py-1 bg-transparent border border-chalkboard-30"
|
||||
value={mouseControls.current}
|
||||
value={mouse_controls.current}
|
||||
onChange={(e) => {
|
||||
send({
|
||||
type: 'set.modeling.mouseControls',
|
||||
type: 'set.modeling.mouse_controls',
|
||||
data: {
|
||||
level: 'user',
|
||||
value: e.target.value as CameraSystem,
|
||||
@ -58,15 +58,15 @@ export default function Units() {
|
||||
<ul className="mx-4 my-2 text-sm leading-relaxed">
|
||||
<li>
|
||||
<strong>Pan:</strong>{' '}
|
||||
{cameraMouseDragGuards[mouseControls.current].pan.description}
|
||||
{cameraMouseDragGuards[mouse_controls.current].pan.description}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Zoom:</strong>{' '}
|
||||
{cameraMouseDragGuards[mouseControls.current].zoom.description}
|
||||
{cameraMouseDragGuards[mouse_controls.current].zoom.description}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Rotate:</strong>{' '}
|
||||
{cameraMouseDragGuards[mouseControls.current].rotate.description}
|
||||
{cameraMouseDragGuards[mouse_controls.current].rotate.description}
|
||||
</li>
|
||||
</ul>
|
||||
</SettingsSection>
|
||||
|
@ -126,7 +126,9 @@ function OnboardingIntroductionInner() {
|
||||
settings: {
|
||||
state: {
|
||||
context: {
|
||||
app: { theme },
|
||||
app: {
|
||||
appearance: { theme },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -11,10 +11,12 @@ export default function OnboardingParametricModeling() {
|
||||
settings: {
|
||||
context: {
|
||||
app: {
|
||||
appearance: {
|
||||
theme: { current: theme },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} = useSettingsAuthContext()
|
||||
const getImageTheme = () =>
|
||||
theme === Themes.Light ||
|
||||
|
@ -13,7 +13,7 @@ export default function Units() {
|
||||
settings: {
|
||||
send,
|
||||
context: {
|
||||
modeling: { defaultUnit },
|
||||
modeling: { base_unit },
|
||||
},
|
||||
},
|
||||
} = useSettingsAuthContext()
|
||||
@ -29,10 +29,10 @@ export default function Units() {
|
||||
<select
|
||||
id="base-unit"
|
||||
className="block w-full px-3 py-1 border border-chalkboard-30 bg-transparent"
|
||||
value={defaultUnit.user}
|
||||
value={base_unit.user}
|
||||
onChange={(e) => {
|
||||
send({
|
||||
type: 'set.modeling.defaultUnit',
|
||||
type: 'set.modeling.base_unit',
|
||||
data: {
|
||||
level: 'user',
|
||||
value: e.target.value as BaseUnit,
|
||||
|
@ -116,7 +116,7 @@ export function useNextClick(newStatus: string) {
|
||||
|
||||
return useCallback(() => {
|
||||
send({
|
||||
type: 'set.app.onboardingStatus',
|
||||
type: 'set.app.onboarding_status',
|
||||
data: { level: 'user', value: newStatus },
|
||||
})
|
||||
navigate(filePath + PATHS.ONBOARDING.INDEX.slice(0, -1) + newStatus)
|
||||
@ -132,7 +132,7 @@ export function useDismiss() {
|
||||
|
||||
const settingsCallback = useCallback(() => {
|
||||
send({
|
||||
type: 'set.app.onboardingStatus',
|
||||
type: 'set.app.onboarding_status',
|
||||
data: { level: 'user', value: 'dismissed' },
|
||||
})
|
||||
}, [send])
|
||||
@ -143,7 +143,7 @@ export function useDismiss() {
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (
|
||||
state.context.app.onboardingStatus.user === 'dismissed' &&
|
||||
state.context.app.onboarding_status.user === 'dismissed' &&
|
||||
state.matches('idle')
|
||||
) {
|
||||
navigate(filePath)
|
||||
|
@ -26,7 +26,9 @@ const SignIn = () => {
|
||||
settings: {
|
||||
state: {
|
||||
context: {
|
||||
app: { theme },
|
||||
app: {
|
||||
appearance: { theme },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -13,9 +13,7 @@ use tower_lsp::lsp_types::{
|
||||
MarkupKind, ParameterInformation, ParameterLabel, SignatureHelp, SignatureInformation,
|
||||
};
|
||||
|
||||
use crate::execution::Sketch;
|
||||
|
||||
use crate::std::Primitive;
|
||||
use crate::{execution::Sketch, std::Primitive};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, ts_rs::TS)]
|
||||
#[ts(export)]
|
||||
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||
|
||||
use async_recursion::async_recursion;
|
||||
|
||||
use super::cad_op::{OpArg, Operation};
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{
|
||||
@ -19,8 +20,6 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use super::cad_op::{OpArg, Operation};
|
||||
|
||||
const FLOAT_TO_INT_MAX_DELTA: f64 = 0.01;
|
||||
|
||||
impl BinaryPart {
|
||||
|
@ -31,6 +31,9 @@ mod exec_ast;
|
||||
mod function_param;
|
||||
mod kcl_value;
|
||||
|
||||
// Re-exports.
|
||||
pub use cad_op::Operation;
|
||||
|
||||
use crate::{
|
||||
engine::{EngineManager, ExecutionKind},
|
||||
errors::{KclError, KclErrorDetails},
|
||||
@ -47,9 +50,6 @@ use crate::{
|
||||
ExecError, Program,
|
||||
};
|
||||
|
||||
// Re-exports.
|
||||
pub use cad_op::Operation;
|
||||
|
||||
/// State for executing a program.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
|
@ -12,6 +12,7 @@ use winnow::{
|
||||
token::{any, one_of, take_till},
|
||||
};
|
||||
|
||||
use super::{ast::types::LabelledExpression, token::NumericSuffix};
|
||||
use crate::{
|
||||
docs::StdLibFn,
|
||||
errors::{CompilationError, Severity, Tag},
|
||||
@ -33,8 +34,6 @@ use crate::{
|
||||
SourceRange,
|
||||
};
|
||||
|
||||
use super::{ast::types::LabelledExpression, token::NumericSuffix};
|
||||
|
||||
thread_local! {
|
||||
/// The current `ParseContext`. `None` if parsing is not currently happening on this thread.
|
||||
static CTXT: RefCell<Option<ParseContext>> = const { RefCell::new(None) };
|
||||
|
@ -55,6 +55,11 @@ impl Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
if settings.settings.modeling.show_debug_panel && !settings.settings.app.show_debug_panel {
|
||||
settings.settings.app.show_debug_panel = settings.settings.modeling.show_debug_panel;
|
||||
settings.settings.modeling.show_debug_panel = Default::default();
|
||||
}
|
||||
|
||||
settings.validate()?;
|
||||
|
||||
Ok(settings)
|
||||
@ -121,6 +126,10 @@ pub struct AppSettings {
|
||||
/// When the user is idle, and this is true, the stream will be torn down.
|
||||
#[serde(default, alias = "streamIdleMode", skip_serializing_if = "is_default")]
|
||||
stream_idle_mode: bool,
|
||||
/// Whether to show the debug panel, which lets you see various states
|
||||
/// of the app to aid in development.
|
||||
#[serde(default, alias = "showDebugPanel", skip_serializing_if = "is_default")]
|
||||
pub show_debug_panel: bool,
|
||||
}
|
||||
|
||||
// TODO: When we remove backwards compatibility with the old settings file, we can remove this.
|
||||
@ -264,6 +273,7 @@ pub struct ModelingSettings {
|
||||
pub highlight_edges: DefaultTrue,
|
||||
/// Whether to show the debug panel, which lets you see various states
|
||||
/// of the app to aid in development.
|
||||
/// Remove this when we remove backwards compatibility with the old settings file.
|
||||
#[serde(default, alias = "showDebugPanel", skip_serializing_if = "is_default")]
|
||||
pub show_debug_panel: bool,
|
||||
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
|
||||
@ -586,13 +596,14 @@ textWrapping = true
|
||||
dismiss_web_banner: false,
|
||||
enable_ssao: None,
|
||||
stream_idle_mode: false,
|
||||
show_debug_panel: true,
|
||||
},
|
||||
modeling: ModelingSettings {
|
||||
base_unit: UnitLength::In,
|
||||
camera_projection: CameraProjectionType::Orthographic,
|
||||
mouse_controls: Default::default(),
|
||||
highlight_edges: Default::default(),
|
||||
show_debug_panel: true,
|
||||
show_debug_panel: Default::default(),
|
||||
enable_ssao: false.into(),
|
||||
show_scale_grid: false,
|
||||
},
|
||||
@ -647,13 +658,14 @@ includeSettings = false
|
||||
dismiss_web_banner: false,
|
||||
enable_ssao: None,
|
||||
stream_idle_mode: false,
|
||||
show_debug_panel: true,
|
||||
},
|
||||
modeling: ModelingSettings {
|
||||
base_unit: UnitLength::Yd,
|
||||
camera_projection: Default::default(),
|
||||
mouse_controls: Default::default(),
|
||||
highlight_edges: Default::default(),
|
||||
show_debug_panel: true,
|
||||
show_debug_panel: Default::default(),
|
||||
enable_ssao: true.into(),
|
||||
show_scale_grid: false,
|
||||
},
|
||||
@ -713,13 +725,14 @@ defaultProjectName = "projects-$nnn"
|
||||
dismiss_web_banner: false,
|
||||
enable_ssao: None,
|
||||
stream_idle_mode: false,
|
||||
show_debug_panel: true,
|
||||
},
|
||||
modeling: ModelingSettings {
|
||||
base_unit: UnitLength::Yd,
|
||||
camera_projection: Default::default(),
|
||||
mouse_controls: Default::default(),
|
||||
highlight_edges: Default::default(),
|
||||
show_debug_panel: true,
|
||||
show_debug_panel: false,
|
||||
enable_ssao: true.into(),
|
||||
show_scale_grid: false,
|
||||
},
|
||||
@ -744,6 +757,7 @@ defaultProjectName = "projects-$nnn"
|
||||
serialized,
|
||||
r#"[settings.app]
|
||||
onboarding_status = "dismissed"
|
||||
show_debug_panel = true
|
||||
|
||||
[settings.app.appearance]
|
||||
theme = "dark"
|
||||
@ -751,7 +765,6 @@ color = 138.0
|
||||
|
||||
[settings.modeling]
|
||||
base_unit = "yd"
|
||||
show_debug_panel = true
|
||||
|
||||
[settings.text_editor]
|
||||
text_wrapping = false
|
||||
@ -791,13 +804,14 @@ projectDirectory = "/Users/macinatormax/Documents/kittycad-modeling-projects""#;
|
||||
dismiss_web_banner: false,
|
||||
enable_ssao: None,
|
||||
stream_idle_mode: false,
|
||||
show_debug_panel: Default::default(),
|
||||
},
|
||||
modeling: ModelingSettings {
|
||||
base_unit: UnitLength::Mm,
|
||||
camera_projection: Default::default(),
|
||||
mouse_controls: Default::default(),
|
||||
highlight_edges: true.into(),
|
||||
show_debug_panel: false,
|
||||
show_debug_panel: Default::default(),
|
||||
enable_ssao: true.into(),
|
||||
show_scale_grid: false,
|
||||
},
|
||||
|
@ -5,8 +5,11 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
use crate::settings::types::{
|
||||
AppColor, AppSettings, AppTheme, CommandBarSettings, ModelingSettings, TextEditorSettings,
|
||||
use crate::{
|
||||
settings::types::{
|
||||
is_default, AppColor, CommandBarSettings, DefaultTrue, FloatOrInt, OnboardingStatus, TextEditorSettings,
|
||||
},
|
||||
UnitLength,
|
||||
};
|
||||
|
||||
/// High level project configuration.
|
||||
@ -24,14 +27,6 @@ impl ProjectConfiguration {
|
||||
// TODO: remove this when we remove backwards compatibility with the old settings file.
|
||||
pub fn backwards_compatible_toml_parse(toml_str: &str) -> Result<Self> {
|
||||
let mut settings = toml::from_str::<Self>(toml_str)?;
|
||||
settings.settings.app.project_directory = None;
|
||||
|
||||
if let Some(theme) = &settings.settings.app.theme {
|
||||
if settings.settings.app.appearance.theme == AppTheme::default() {
|
||||
settings.settings.app.appearance.theme = *theme;
|
||||
settings.settings.app.theme = None;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(theme_color) = &settings.settings.app.theme_color {
|
||||
if settings.settings.app.appearance.color == AppColor::default() {
|
||||
@ -47,6 +42,11 @@ impl ProjectConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
if settings.settings.modeling.show_debug_panel && !settings.settings.app.show_debug_panel {
|
||||
settings.settings.app.show_debug_panel = settings.settings.modeling.show_debug_panel;
|
||||
settings.settings.modeling.show_debug_panel = Default::default();
|
||||
}
|
||||
|
||||
settings.validate()?;
|
||||
|
||||
Ok(settings)
|
||||
@ -61,11 +61,11 @@ pub struct PerProjectSettings {
|
||||
/// The settings for the modeling app.
|
||||
#[serde(default)]
|
||||
#[validate(nested)]
|
||||
pub app: AppSettings,
|
||||
pub app: ProjectAppSettings,
|
||||
/// Settings that affect the behavior while modeling.
|
||||
#[serde(default)]
|
||||
#[validate(nested)]
|
||||
pub modeling: ModelingSettings,
|
||||
pub modeling: ProjectModelingSettings,
|
||||
/// Settings that affect the behavior of the KCL text editor.
|
||||
#[serde(default, alias = "textEditor")]
|
||||
#[validate(nested)]
|
||||
@ -76,15 +76,83 @@ pub struct PerProjectSettings {
|
||||
pub command_bar: CommandBarSettings,
|
||||
}
|
||||
|
||||
/// Project application settings.
|
||||
// TODO: When we remove backwards compatibility with the old settings file, we can remove the
|
||||
// aliases to camelCase (and projects plural) from everywhere.
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq, Validate)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct ProjectAppSettings {
|
||||
/// The settings for the appearance of the app.
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
#[validate(nested)]
|
||||
pub appearance: ProjectAppearanceSettings,
|
||||
/// The onboarding status of the app.
|
||||
#[serde(default, alias = "onboardingStatus", skip_serializing_if = "is_default")]
|
||||
pub onboarding_status: OnboardingStatus,
|
||||
/// The hue of the primary theme color for the app.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none", alias = "themeColor")]
|
||||
pub theme_color: Option<FloatOrInt>,
|
||||
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
|
||||
#[serde(default, alias = "enableSSAO", skip_serializing_if = "Option::is_none")]
|
||||
pub enable_ssao: Option<bool>,
|
||||
/// Permanently dismiss the banner warning to download the desktop app.
|
||||
/// This setting only applies to the web app. And is temporary until we have Linux support.
|
||||
#[serde(default, alias = "dismissWebBanner", skip_serializing_if = "is_default")]
|
||||
pub dismiss_web_banner: bool,
|
||||
/// When the user is idle, and this is true, the stream will be torn down.
|
||||
#[serde(default, alias = "streamIdleMode", skip_serializing_if = "is_default")]
|
||||
stream_idle_mode: bool,
|
||||
/// Whether to show the debug panel, which lets you see various states
|
||||
/// of the app to aid in development.
|
||||
#[serde(default, alias = "showDebugPanel", skip_serializing_if = "is_default")]
|
||||
pub show_debug_panel: bool,
|
||||
}
|
||||
|
||||
/// Per project appearance settings of the app.
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq, Validate)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct ProjectAppearanceSettings {
|
||||
/// The hue of the primary theme color for the app.
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
#[validate(nested)]
|
||||
pub color: AppColor,
|
||||
}
|
||||
|
||||
/// Per-project settings that affect the behavior while modeling.
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq, Eq, Validate)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export)]
|
||||
pub struct ProjectModelingSettings {
|
||||
/// The default unit to use in modeling dimensions.
|
||||
#[serde(default, alias = "defaultUnit", skip_serializing_if = "is_default")]
|
||||
pub base_unit: UnitLength,
|
||||
/// Highlight edges of 3D objects?
|
||||
#[serde(default, alias = "highlightEdges", skip_serializing_if = "is_default")]
|
||||
pub highlight_edges: DefaultTrue,
|
||||
/// Whether to show the debug panel, which lets you see various states
|
||||
/// of the app to aid in development.
|
||||
/// Remove this when we remove backwards compatibility with the old settings file.
|
||||
#[serde(default, alias = "showDebugPanel", skip_serializing_if = "is_default")]
|
||||
pub show_debug_panel: bool,
|
||||
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub enable_ssao: DefaultTrue,
|
||||
/// Whether or not to show a scale grid in the 3D modeling view
|
||||
#[serde(default, alias = "showScaleGrid", skip_serializing_if = "is_default")]
|
||||
pub show_scale_grid: bool,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::{
|
||||
AppSettings, AppTheme, CommandBarSettings, ModelingSettings, PerProjectSettings, ProjectConfiguration,
|
||||
TextEditorSettings,
|
||||
CommandBarSettings, PerProjectSettings, ProjectAppSettings, ProjectAppearanceSettings, ProjectConfiguration,
|
||||
ProjectModelingSettings, TextEditorSettings,
|
||||
};
|
||||
use crate::settings::types::{AppearanceSettings, UnitLength};
|
||||
use crate::settings::types::UnitLength;
|
||||
|
||||
#[test]
|
||||
// Test that we can deserialize a project file from the old format.
|
||||
@ -112,25 +180,19 @@ includeSettings = false
|
||||
parsed,
|
||||
ProjectConfiguration {
|
||||
settings: PerProjectSettings {
|
||||
app: AppSettings {
|
||||
appearance: AppearanceSettings {
|
||||
theme: AppTheme::Dark,
|
||||
color: 138.0.into()
|
||||
},
|
||||
app: ProjectAppSettings {
|
||||
appearance: ProjectAppearanceSettings { color: 138.0.into() },
|
||||
onboarding_status: Default::default(),
|
||||
project_directory: None,
|
||||
theme: None,
|
||||
theme_color: None,
|
||||
dismiss_web_banner: false,
|
||||
enable_ssao: None,
|
||||
stream_idle_mode: false,
|
||||
},
|
||||
modeling: ModelingSettings {
|
||||
base_unit: UnitLength::Yd,
|
||||
camera_projection: Default::default(),
|
||||
mouse_controls: Default::default(),
|
||||
highlight_edges: Default::default(),
|
||||
show_debug_panel: true,
|
||||
},
|
||||
modeling: ProjectModelingSettings {
|
||||
base_unit: UnitLength::Yd,
|
||||
highlight_edges: Default::default(),
|
||||
show_debug_panel: Default::default(),
|
||||
enable_ssao: true.into(),
|
||||
show_scale_grid: false,
|
||||
},
|
||||
@ -144,6 +206,28 @@ includeSettings = false
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Write the file back out.
|
||||
let serialized = toml::to_string(&parsed).unwrap();
|
||||
assert_eq!(
|
||||
serialized,
|
||||
r#"[settings.app]
|
||||
show_debug_panel = true
|
||||
|
||||
[settings.app.appearance]
|
||||
color = 138.0
|
||||
|
||||
[settings.modeling]
|
||||
base_unit = "yd"
|
||||
|
||||
[settings.text_editor]
|
||||
text_wrapping = false
|
||||
blinking_cursor = false
|
||||
|
||||
[settings.command_bar]
|
||||
include_settings = false
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -3,14 +3,13 @@
|
||||
use anyhow::Result;
|
||||
use derive_docs::stdlib;
|
||||
|
||||
use super::args::FromArgs;
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{ExecState, KclValue},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
use super::args::FromArgs;
|
||||
|
||||
/// Compute the remainder after dividing `num` by `div`.
|
||||
/// If `num` is negative, the result will be too.
|
||||
pub async fn rem(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
|
@ -2223,7 +2223,10 @@ mod tests {
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::{execution::TagIdentifier, std::sketch::PlaneData, std::utils::calculate_circle_center};
|
||||
use crate::{
|
||||
execution::TagIdentifier,
|
||||
std::{sketch::PlaneData, utils::calculate_circle_center},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_plane_data() {
|
||||
|
Reference in New Issue
Block a user