save as bw compatible (#6088)

* save as bw compatible

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* js side only for bw compatibility changes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* failure for doing wrong thing

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* remove from ts side

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2025-04-01 20:39:55 -07:00
committed by GitHub
parent 4e36e398ee
commit af482c30bd
11 changed files with 66 additions and 29 deletions

View File

@ -69,6 +69,14 @@
{
"selector": "CallExpression[callee.object.name='Array'][callee.property.name='isArray']",
"message": "Use isArray() in lib/utils.ts instead of Array.isArray()."
},
{
"selector": "CallExpression[callee.object.name='TOML'][callee.property.name='stringify']",
"message": "Do not use TOML.stringify directly. Use the wrappers in test-utils instead like settingsToToml."
},
{
"selector": "CallExpression[callee.object.name='TOML'][callee.property.name='parse']",
"message": "Do not use TOML.parse directly. Use the wrappers in test-utils instead like tomlToSettings."
}
],
"semi": [

View File

@ -1,5 +1,4 @@
/* eslint-disable react-hooks/rules-of-hooks */
import type {
BrowserContext,
ElectronApplication,
@ -9,10 +8,9 @@ import type {
import { _electron as electron } from '@playwright/test'
import * as TOML from '@iarna/toml'
import { TEST_SETTINGS } from '../storageStates'
import { SETTINGS_FILE_NAME } from 'lib/constants'
import { getUtils, setup } from '../test-utils'
import { getUtils, setup, settingsToToml } from '../test-utils'
import fsp from 'fs/promises'
import fs from 'node:fs'
import path from 'path'
@ -287,26 +285,30 @@ export class ElectronZoo {
let settingsOverridesToml = ''
if (appSettings) {
settingsOverridesToml = TOML.stringify({
// @ts-expect-error
settingsOverridesToml = settingsToToml({
settings: {
...TEST_SETTINGS,
...appSettings,
app: {
...TEST_SETTINGS.app,
project_directory: this.projectDirName,
...appSettings.app,
},
project: {
...TEST_SETTINGS.project,
directory: this.projectDirName,
},
},
})
} else {
settingsOverridesToml = TOML.stringify({
// @ts-expect-error
settingsOverridesToml = settingsToToml({
settings: {
...TEST_SETTINGS,
app: {
...TEST_SETTINGS.app,
project_directory: this.projectDirName,
},
project: {
...TEST_SETTINGS.project,
directory: this.projectDirName,
},
},
})

View File

@ -345,7 +345,9 @@ const extrudeDefaultPlane = async (
app: {
onboarding_status: 'dismissed',
show_debug_panel: true,
theme: 'dark',
appearance: {
theme: 'dark',
},
},
project: {
default_project_name: 'project-$nnn',

View File

@ -9,9 +9,10 @@ export const IS_PLAYWRIGHT_KEY = 'playwright'
export const TEST_SETTINGS_KEY = '/settings.toml'
export const TEST_SETTINGS: DeepPartial<Settings> = {
app: {
theme: Themes.Dark,
appearance: {
theme: Themes.Dark,
},
onboarding_status: 'dismissed',
project_directory: '',
show_debug_panel: true,
},
modeling: {
@ -22,6 +23,7 @@ export const TEST_SETTINGS: DeepPartial<Settings> = {
},
project: {
default_project_name: 'project-$nnn',
directory: '',
},
text_editor: {
text_wrapping: true,
@ -54,7 +56,7 @@ export const TEST_SETTINGS_ONBOARDING_START: DeepPartial<Settings> = {
export const TEST_SETTINGS_DEFAULT_THEME: DeepPartial<Settings> = {
...TEST_SETTINGS,
app: { ...TEST_SETTINGS.app, theme: Themes.System },
app: { ...TEST_SETTINGS.app, appearance: { theme: Themes.System } },
}
export const TEST_SETTINGS_CORRUPTED = {

View File

@ -903,15 +903,21 @@ export async function setup(
settings: {
...TEST_SETTINGS,
app: {
appearance: {
...TEST_SETTINGS.app?.appearance,
theme: 'dark',
},
...TEST_SETTINGS.project,
project_directory: TEST_SETTINGS.app?.project_directory,
onboarding_status: 'dismissed',
theme: 'dark',
},
project: {
...TEST_SETTINGS.project,
directory: TEST_SETTINGS.project?.directory,
},
},
}),
IS_PLAYWRIGHT_KEY,
PLAYWRIGHT_TEST_DIR: TEST_SETTINGS.app?.project_directory || '',
PLAYWRIGHT_TEST_DIR: TEST_SETTINGS.project?.directory || '',
PERSIST_MODELING_CONTEXT,
}
)
@ -1112,21 +1118,25 @@ export async function pollEditorLinesSelectedLength(page: Page, lines: number) {
}
export function settingsToToml(settings: DeepPartial<Configuration>) {
// eslint-disable-next-line no-restricted-syntax
return TOML.stringify(settings as any)
}
export function tomlToSettings(toml: string): DeepPartial<Configuration> {
// eslint-disable-next-line no-restricted-syntax
return TOML.parse(toml)
}
export function tomlToPerProjectSettings(
toml: string
): DeepPartial<ProjectConfiguration> {
// eslint-disable-next-line no-restricted-syntax
return TOML.parse(toml)
}
export function perProjectsettingsToToml(
settings: DeepPartial<ProjectConfiguration>
) {
// eslint-disable-next-line no-restricted-syntax
return TOML.stringify(settings as any)
}

View File

@ -45,12 +45,12 @@ test.describe('Testing settings', () => {
)
)
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?.base_unit).toBe('in')
expect(storedSettings.settings?.modeling?.mouse_controls).toBe('zoo')
expect(storedSettings.settings?.app?.project_directory).toBe('')
expect(storedSettings.settings?.project?.directory).toBe('')
expect(storedSettings.settings?.project?.default_project_name).toBe(
'project-$nnn'
)
@ -381,7 +381,9 @@ test.describe('Testing settings', () => {
}
await tronApp.cleanProjectDir({
app: {
theme_color: '259',
appearance: {
color: 259,
},
},
})
@ -413,9 +415,12 @@ test.describe('Testing settings', () => {
await tronApp.cleanProjectDir({
app: {
// Doesn't matter what you set it to. It will
// default to 264.5
theme_color: '0',
appearance: {
// Doesn't matter what you set it to. It will
// default to 264.5
color: 0,
},
},
})

View File

@ -113,15 +113,19 @@ pub struct AppSettings {
pub onboarding_status: OnboardingStatus,
/// Backwards compatible project directory setting.
#[serde(default, alias = "projectDirectory", skip_serializing_if = "Option::is_none")]
#[ts(skip)]
pub project_directory: Option<std::path::PathBuf>,
/// Backwards compatible theme setting.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(skip)]
pub theme: Option<AppTheme>,
/// The hue of the primary theme color for the app.
#[serde(default, skip_serializing_if = "Option::is_none", alias = "themeColor")]
#[ts(skip)]
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")]
#[ts(skip)]
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.
@ -285,6 +289,7 @@ pub struct ModelingSettings {
/// 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")]
#[ts(skip)]
pub show_debug_panel: bool,
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
#[serde(default, skip_serializing_if = "is_default")]

View File

@ -94,9 +94,11 @@ pub struct ProjectAppSettings {
pub onboarding_status: OnboardingStatus,
/// The hue of the primary theme color for the app.
#[serde(default, skip_serializing_if = "Option::is_none", alias = "themeColor")]
#[ts(skip)]
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")]
#[ts(skip)]
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.
@ -143,6 +145,7 @@ pub struct ProjectModelingSettings {
/// 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")]
#[ts(skip)]
pub show_debug_panel: bool,
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
#[serde(default, skip_serializing_if = "is_default")]

View File

@ -176,6 +176,8 @@ pub fn serialize_configuration(val: JsValue) -> Result<JsValue, String> {
let config: kcl_lib::Configuration = val.into_serde().map_err(|e| e.to_string())?;
let toml_str = toml::to_string_pretty(&config).map_err(|e| e.to_string())?;
let settings = kcl_lib::Configuration::backwards_compatible_toml_parse(&toml_str).map_err(|e| e.to_string())?;
let toml_str = toml::to_string_pretty(&settings).map_err(|e| e.to_string())?;
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
// gloo-serialize crate instead.
@ -190,6 +192,9 @@ pub fn serialize_project_configuration(val: JsValue) -> Result<JsValue, String>
let config: kcl_lib::ProjectConfiguration = val.into_serde().map_err(|e| e.to_string())?;
let toml_str = toml::to_string_pretty(&config).map_err(|e| e.to_string())?;
let settings =
kcl_lib::ProjectConfiguration::backwards_compatible_toml_parse(&toml_str).map_err(|e| e.to_string())?;
let toml_str = toml::to_string_pretty(&settings).map_err(|e| e.to_string())?;
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
// gloo-serialize crate instead.

View File

@ -39,7 +39,6 @@ export function mouseControlsToCameraSystem(
// TODO: understand why the values come back without underscores and fix the root cause
// @ts-ignore: TS2678
case 'onshape':
case 'on_shape':
return 'OnShape'
case 'trackpad_friendly':
return 'Trackpad Friendly'
@ -52,7 +51,6 @@ export function mouseControlsToCameraSystem(
// TODO: understand why the values come back without underscores and fix the root cause
// @ts-ignore: TS2678
case 'autocad':
case 'auto_cad':
return 'AutoCAD'
default:
return undefined

View File

@ -67,9 +67,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'))
@ -588,8 +586,7 @@ export const readAppSettingsFile = async () => {
}
const hasProjectDirectorySetting =
parsedAppConfig.settings?.project?.directory ||
parsedAppConfig.settings?.app?.project_directory
parsedAppConfig.settings?.project?.directory
if (hasProjectDirectorySetting) {
return parsedAppConfig