Set a default initial directory, handle an existing settings file with no project directory (#3734)

* Fix the project directory setting assignment from file

* Fix default project directory value initialization

* Add a couple tests for loading the app without project directory settings

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* trigger CI

* Object merging logic was bad, blew away other app settings if they existed

* Update silly little export file size expectation numbers

* Make rename timeout in test way shorter

* Fix silly little test issues

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
This commit is contained in:
Frank Noirot
2024-09-04 11:30:09 -04:00
committed by GitHub
parent cbddb3553d
commit 35f9b82a65
8 changed files with 121 additions and 53 deletions

View File

@ -271,10 +271,7 @@ test(
await page.getByText('bracket').click() await page.getByText('bracket').click()
await expect(page.getByTestId('loading')).toBeAttached() await u.waitForPageLoad()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
}) })
// If they're open by default, we're not actually testing anything. // If they're open by default, we're not actually testing anything.
@ -302,16 +299,7 @@ test(
await page.getByText('router-template-slate').click() await page.getByText('router-template-slate').click()
await expect(page.getByTestId('loading')).toBeAttached() await u.waitForPageLoad()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
}) })
await test.step('All panes opened before should be visible', async () => { await test.step('All panes opened before should be visible', async () => {

View File

@ -938,16 +938,7 @@ test(
await page.getByText('bracket').click() await page.getByText('bracket').click()
await expect(page.getByTestId('loading')).toBeAttached() await u.waitForPageLoad()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
// gray at this pixel means the stream has loaded in the most // gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color) // user way we can verify it (pixel color)
@ -972,16 +963,7 @@ test(
await page.getByText('router-template-slate').click() await page.getByText('router-template-slate').click()
await expect(page.getByTestId('loading')).toBeAttached() await u.waitForPageLoad()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
// gray at this pixel means the stream has loaded in the most // gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color) // user way we can verify it (pixel color)
@ -1740,7 +1722,7 @@ test.describe('Renaming in the file tree', () => {
}) })
await test.step('Rename the folder', async () => { await test.step('Rename the folder', async () => {
await page.waitForTimeout(60000) await page.waitForTimeout(2000)
await folderToRename.click({ button: 'right' }) await folderToRename.click({ button: 'right' })
await expect(renameMenuItem).toBeVisible() await expect(renameMenuItem).toBeVisible()
await renameMenuItem.click() await renameMenuItem.click()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -852,10 +852,12 @@ export async function setupElectron({
testInfo, testInfo,
folderSetupFn, folderSetupFn,
cleanProjectDir = true, cleanProjectDir = true,
appSettings,
}: { }: {
testInfo: TestInfo testInfo: TestInfo
folderSetupFn?: (projectDirName: string) => Promise<void> folderSetupFn?: (projectDirName: string) => Promise<void>
cleanProjectDir?: boolean cleanProjectDir?: boolean
appSettings?: Partial<SaveSettingsPayload>
}) { }) {
// create or otherwise clear the folder // create or otherwise clear the folder
const projectDirName = testInfo.outputPath('electron-test-projects-dir') const projectDirName = testInfo.outputPath('electron-test-projects-dir')
@ -889,7 +891,10 @@ export async function setupElectron({
if (cleanProjectDir) { if (cleanProjectDir) {
const tempSettingsFilePath = join(projectDirName, SETTINGS_FILE_NAME) const tempSettingsFilePath = join(projectDirName, SETTINGS_FILE_NAME)
const settingsOverrides = TOML.stringify({ const settingsOverrides = TOML.stringify(
appSettings
? { settings: appSettings }
: {
...TEST_SETTINGS, ...TEST_SETTINGS,
settings: { settings: {
app: { app: {
@ -897,7 +902,8 @@ export async function setupElectron({
projectDirectory: projectDirName, projectDirectory: projectDirName,
}, },
}, },
}) }
)
await fsp.writeFile(tempSettingsFilePath, settingsOverrides) await fsp.writeFile(tempSettingsFilePath, settingsOverrides)
} }

View File

@ -303,6 +303,61 @@ test.describe('Testing settings', () => {
} }
) )
test(
`Load desktop app with no settings file`,
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page } = await setupElectron({
// This is what makes no settings file get created
cleanProjectDir: false,
testInfo,
})
await page.setViewportSize({ width: 1200, height: 500 })
// Selectors and constants
const errorHeading = page.getByRole('heading', {
name: 'An unextected error occurred',
})
const projectDirLink = page.getByText('Loaded from')
// If the app loads without exploding we're in the clear
await expect(errorHeading).not.toBeVisible()
await expect(projectDirLink).toBeVisible()
await electronApp.close()
}
)
test(
`Load desktop app with a settings file, but no project directory setting`,
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
appSettings: {
app: {
themeColor: '259',
},
},
})
await page.setViewportSize({ width: 1200, height: 500 })
// Selectors and constants
const errorHeading = page.getByRole('heading', {
name: 'An unextected error occurred',
})
const projectDirLink = page.getByText('Loaded from')
// If the app loads without exploding we're in the clear
await expect(errorHeading).not.toBeVisible()
await expect(projectDirLink).toBeVisible()
await electronApp.close()
}
)
test( test(
`Closing settings modal should go back to the original file being viewed`, `Closing settings modal should go back to the original file being viewed`,
{ tag: '@electron' }, { tag: '@electron' },

View File

@ -462,29 +462,60 @@ export const readProjectSettingsFile = async (
*/ */
export const readAppSettingsFile = async () => { export const readAppSettingsFile = async () => {
let settingsPath = await getAppSettingsFilePath() let settingsPath = await getAppSettingsFilePath()
const initialProjectDirConfig: DeepPartial<
Configuration['settings']['project']
> = { directory: await getInitialDefaultDir() }
// The file exists, read it and parse it. // The file exists, read it and parse it.
if (window.electron.exists(settingsPath)) { if (window.electron.exists(settingsPath)) {
const configToml = await window.electron.readFile(settingsPath) const configToml = await window.electron.readFile(settingsPath)
const configObj = parseAppSettings(configToml) const parsedAppConfig = parseAppSettings(configToml)
if (err(configObj)) { if (err(parsedAppConfig)) {
return Promise.reject(configObj) return Promise.reject(parsedAppConfig)
} }
return configObj const hasProjectDirectorySetting =
parsedAppConfig.settings?.project?.directory ||
parsedAppConfig.settings?.app?.project_directory
if (hasProjectDirectorySetting) {
return parsedAppConfig
} else {
// inject the default project directory setting
const mergedConfig: DeepPartial<Configuration> = {
...parsedAppConfig,
settings: {
...parsedAppConfig.settings,
project: Object.assign(
{},
parsedAppConfig.settings?.project,
initialProjectDirConfig
),
},
}
return mergedConfig
}
} }
// The file doesn't exist, create a new one. // The file doesn't exist, create a new one.
// This defaultAppConfig is truly an empty object every time.
const defaultAppConfig = defaultAppSettings() const defaultAppConfig = defaultAppSettings()
if (err(defaultAppConfig)) { if (err(defaultAppConfig)) {
return Promise.reject(defaultAppConfig) return Promise.reject(defaultAppConfig)
} }
const initialDirConfig: DeepPartial<Configuration> = {
settings: { project: { directory: await getInitialDefaultDir() } }, // inject the default project directory setting
const mergedDefaultConfig: DeepPartial<Configuration> = {
...defaultAppConfig,
settings: {
...defaultAppConfig.settings,
project: Object.assign(
{},
defaultAppConfig.settings?.project,
initialProjectDirConfig
),
},
} }
const config = Object.assign(defaultAppConfig, initialDirConfig) return mergedDefaultConfig
return config
} }
export const writeAppSettingsFile = async (tomlStr: string) => { export const writeAppSettingsFile = async (tomlStr: string) => {

View File

@ -14,6 +14,7 @@ import { Configuration } from 'wasm-lib/kcl/bindings/Configuration'
import { mouseControlsToCameraSystem } from 'lib/cameraControls' import { mouseControlsToCameraSystem } from 'lib/cameraControls'
import { appThemeToTheme } from 'lib/theme' import { appThemeToTheme } from 'lib/theme'
import { import {
getInitialDefaultDir,
readAppSettingsFile, readAppSettingsFile,
readProjectSettingsFile, readProjectSettingsFile,
writeAppSettingsFile, writeAppSettingsFile,
@ -176,6 +177,11 @@ export async function loadAndValidateSettings(
if (err(appSettingsPayload)) return Promise.reject(appSettingsPayload) if (err(appSettingsPayload)) return Promise.reject(appSettingsPayload)
const settings = createSettings() const settings = createSettings()
// Because getting the default directory is async, we need to set it after
if (onDesktop) {
settings.app.projectDirectory.default = await getInitialDefaultDir()
}
setSettingsAtLevel( setSettingsAtLevel(
settings, settings,
'user', 'user',