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:
@ -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 () => {
|
||||||
|
@ -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 |
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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' },
|
||||||
|
@ -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) => {
|
||||||
|
@ -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',
|
||||||
|
Reference in New Issue
Block a user