Trying to fix tsc

This commit is contained in:
49lf
2024-08-01 12:18:32 -04:00
parent aa4e9cbc64
commit 7496f8a9db
23 changed files with 91 additions and 153 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@
/node_modules /node_modules
/.pnp /.pnp
.pnp.js .pnp.js
tsconfig.json
# testing # testing
/coverage /coverage

17
interface.d.ts vendored
View File

@ -12,21 +12,24 @@ export interface IElectronAPI {
arch: typeof process.env.arch arch: typeof process.env.arch
version: typeof process.env.version version: typeof process.env.version
readFile: (path: string) => ReturnType<fs.readFile> readFile: (path: string) => ReturnType<fs.readFile>
writeFile: (path: string, data: string | Uint8Array) => ReturnType<fs.writeFile> writeFile: (
path: string,
data: string | Uint8Array
) => ReturnType<fs.writeFile>
readdir: (path: string) => ReturnType<fs.readdir> readdir: (path: string) => ReturnType<fs.readdir>
getPath: (name: string) => Promise<string> getPath: (name: string) => Promise<string>
rm: typeof fs.rm rm: typeof fs.rm
stat: (path: string) => ReturnType<fs.stat> stat: (path: string) => ReturnType<fs.stat>
statIsDirectory: (path: string) => Promise<boolean> statIsDirectory: (path: string) => Promise<boolean>
path: typeof path, path: typeof path
mkdir: typeof fs.mkdir, mkdir: typeof fs.mkdir
rename: (prev: string, next: string) => typeof fs.rename, rename: (prev: string, next: string) => typeof fs.rename
packageJson: { packageJson: {
name: string, name: string
}, }
process: { process: {
env: { env: {
BASE_URL: (value?: string) => string, BASE_URL: (value?: string) => string
} }
} }
} }

View File

@ -145,11 +145,6 @@
"@typescript-eslint/parser": "^5.0.0", "@typescript-eslint/parser": "^5.0.0",
"@vitejs/plugin-react": "^4.3.0", "@vitejs/plugin-react": "^4.3.0",
"@vitest/web-worker": "^1.5.0", "@vitest/web-worker": "^1.5.0",
"@wdio/cli": "^8.24.3",
"@wdio/globals": "^8.36.0",
"@wdio/local-runner": "^8.36.0",
"@wdio/mocha-framework": "^8.36.0",
"@wdio/spec-reporter": "^8.36.0",
"@xstate/cli": "^0.5.17", "@xstate/cli": "^0.5.17",
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"electron": "^31.2.1", "electron": "^31.2.1",
@ -170,7 +165,7 @@
"setimmediate": "^1.0.5", "setimmediate": "^1.0.5",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"ts-node": "^10.0.0", "ts-node": "^10.0.0",
"typescript": "^4.5.4", "typescript": "^5.0.0",
"vite": "^5.0.12", "vite": "^5.0.12",
"vite-plugin-eslint": "^1.8.1", "vite-plugin-eslint": "^1.8.1",
"vite-plugin-package-version": "^1.1.0", "vite-plugin-package-version": "^1.1.0",

View File

@ -108,7 +108,7 @@ export const ActionButton = forwardRef((props: ActionButtonProps, ref) => {
ref={ref as ForwardedRef<HTMLAnchorElement>} ref={ref as ForwardedRef<HTMLAnchorElement>}
to={to || paths.INDEX} to={to || paths.INDEX}
className={classNames} className={classNames}
onClick={openExternalBrowserIfDesktop(to)} onClick={openExternalBrowserIfDesktop(to as string)}
{...rest} {...rest}
target="_blank" target="_blank"
> >

View File

@ -135,7 +135,9 @@ export const FileMachineProvider = ({
const newPath = const newPath =
newDirPath + (name.endsWith(FILE_EXT) || isDir ? '' : FILE_EXT) newDirPath + (name.endsWith(FILE_EXT) || isDir ? '' : FILE_EXT)
await window.electron.rename(oldPath, newPath, {}) await window.electron.rename(oldPath, newPath)
if (!file) { return Promise.reject(new Error('file is not defined')) }
const currentFilePath = window.electron.path.join(file.path, file.name) const currentFilePath = window.electron.path.join(file.path, file.name)
if (oldPath === currentFilePath && project?.path) { if (oldPath === currentFilePath && project?.path) {

View File

@ -142,7 +142,7 @@ function HelpMenuItem({
{as === 'a' ? ( {as === 'a' ? (
<a <a
{...(props as React.ComponentProps<'a'>)} {...(props as React.ComponentProps<'a'>)}
onClick={openExternalBrowserIfDesktop(props.href)} onClick={openExternalBrowserIfDesktop((props as React.ComponentProps<'a'>).href)}
className={`no-underline text-inherit ${baseClassName} ${className}`} className={`no-underline text-inherit ${baseClassName} ${className}`}
> >
{children} {children}

View File

@ -26,7 +26,7 @@ export function LowerRightControls({
const isPlayWright = window?.localStorage.getItem('playwright') === 'true' const isPlayWright = window?.localStorage.getItem('playwright') === 'true'
async function reportbug(event: { preventDefault: () => void }) { async function reportbug(event: { preventDefault: () => void, stopPropagation: () => void }) {
event?.preventDefault() event?.preventDefault()
event?.stopPropagation() event?.stopPropagation()

View File

@ -113,8 +113,8 @@ function ProjectCard({
</span> </span>
<span className="px-2 text-chalkboard-60 text-xs"> <span className="px-2 text-chalkboard-60 text-xs">
Edited{' '} Edited{' '}
{project.metadata && project.metadata.mtimeMs {project.metadata && project.metadata.modified
? getDisplayedTime(project.metadata.mtimeMs) ? getDisplayedTime(project.metadata.modified.toString())
: 'never'} : 'never'}
</span> </span>
</div> </div>

View File

@ -195,7 +195,9 @@ export const AllSettingsFields = forwardRef(
const paths = await getSettingsFolderPaths( const paths = await getSettingsFolderPaths(
projectPath ? decodeURIComponent(projectPath) : undefined projectPath ? decodeURIComponent(projectPath) : undefined
) )
window.electron.showInFolder(paths[searchParamTab]) const finalPath = paths[searchParamTab]
if (!finalPath) { return new Error('finalPath undefined') }
window.electron.showInFolder(finalPath)
}} }}
iconStart={{ iconStart={{
icon: 'folder', icon: 'folder',

View File

@ -209,7 +209,7 @@ export const SettingsAuthProviderBase = ({
}, },
services: { services: {
'Persist settings': (context) => 'Persist settings': (context) =>
saveSettings(context, loadedProject?.project.path), saveSettings(context, loadedProject?.project?.path),
}, },
} }
) )

View File

@ -7,8 +7,6 @@ import { HotkeysProvider } from 'react-hotkeys-hook'
import ModalContainer from 'react-modal-promise' import ModalContainer from 'react-modal-promise'
import { UpdaterModal, createUpdaterModal } from 'components/UpdaterModal' import { UpdaterModal, createUpdaterModal } from 'components/UpdaterModal'
import { isDesktop } from 'lib/isDesktop' import { isDesktop } from 'lib/isDesktop'
import { relaunch } from '@tauri-apps/plugin-process'
import { check } from '@tauri-apps/plugin-updater'
import { import {
UpdaterRestartModal, UpdaterRestartModal,
createUpdaterRestartModal, createUpdaterRestartModal,
@ -59,32 +57,4 @@ root.render(
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals() reportWebVitals()
const runTauriUpdater = async () => { isDesktop()
console.log('STUB: @pierre')
return
try {
const update = await check()
if (update && update.available) {
const { date, version, body } = update
const modal = createUpdaterModal(UpdaterModal)
const { wantUpdate } = await modal({ date, version, body })
if (wantUpdate) {
await update.downloadAndInstall()
// On macOS and Linux, the restart needs to be manually triggered
const isNotWindows = navigator.userAgent.indexOf('Win') === -1
if (isNotWindows) {
const relaunchModal = createUpdaterRestartModal(UpdaterRestartModal)
const { wantRestart } = await relaunchModal({ version })
if (wantRestart) {
await relaunch()
}
}
}
}
} catch (error) {
console.error(error)
}
}
isDesktop() && runTauriUpdater()

View File

@ -28,13 +28,9 @@ class FileSystemManager {
) )
} }
return this.join(this.dir, path) return this.join(this.dir, path).then((filePath) => {
.catch((error) => { return window.electron.readFile(filePath)
return Promise.reject(new Error(`Error reading file: ${error}`)) })
})
.then((filePath) => {
return window.electron.readFile(filePath)
})
} }
async exists(path: string): Promise<boolean | void> { async exists(path: string): Promise<boolean | void> {
@ -47,20 +43,16 @@ class FileSystemManager {
) )
} }
return this.join(this.dir, path) return this.join(this.dir, path).then(async (file) => {
.catch((error) => { try {
return Promise.reject(new Error(`Error checking file exists: ${error}`)) await window.electron.stat(file)
}) } catch (e) {
.then(async (file) => { if (e === 'ENOENT') {
try { return false
await window.electron.stat(file)
} catch (e) {
if (e === 'ENOENT') {
return false
}
} }
return true }
}) return true
})
} }
async getAllFiles(path: string): Promise<string[] | void> { async getAllFiles(path: string): Promise<string[] | void> {
@ -73,20 +65,16 @@ class FileSystemManager {
) )
} }
return this.join(this.dir, path) return this.join(this.dir, path).then((filepath) => {
.catch((error) => { return window.electron
return Promise.reject(new Error(`Error joining dir: ${error}`)) .readdir(filepath)
}) .catch((error: Error) => {
.then((filepath) => { return Promise.reject(new Error(`Error reading dir: ${error}`))
return window.electron })
.readdir(filepath) .then((files: string[]) => {
.catch((error) => { return files.map((filePath) => filePath)
return Promise.reject(new Error(`Error reading dir: ${error}`)) })
}) })
.then((files) => {
return files.map((file) => file.path)
})
})
} }
} }

View File

@ -22,8 +22,10 @@ import init, {
import { import {
configurationToSettingsPayload, configurationToSettingsPayload,
projectConfigurationToSettingsPayload, projectConfigurationToSettingsPayload,
SaveSettingsPayload,
} from 'lib/settings/settingsUtils' } from 'lib/settings/settingsUtils'
import {
SaveSettingsPayload,
} from 'lib/settings/settingsTypes'
import { KCLError } from './errors' import { KCLError } from './errors'
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError' import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
import { EngineCommandManager } from './std/engineConnection' import { EngineCommandManager } from './std/engineConnection'

View File

@ -1,3 +1,4 @@
import { err } from 'lib/trap'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import { ProjectConfiguration } from 'wasm-lib/kcl/bindings/ProjectConfiguration' import { ProjectConfiguration } from 'wasm-lib/kcl/bindings/ProjectConfiguration'
import { Project } from 'wasm-lib/kcl/bindings/Project' import { Project } from 'wasm-lib/kcl/bindings/Project'
@ -77,7 +78,8 @@ export async function renameProjectDirectory(
export async function ensureProjectDirectoryExists( export async function ensureProjectDirectoryExists(
config: Partial<SaveSettingsPayload> config: Partial<SaveSettingsPayload>
): Promise<string | undefined> { ): Promise<string | undefined> {
const projectDir = config.app.projectDirectory const projectDir = config.app?.projectDirectory
if (!projectDir) { return Promise.reject(new Error('projectDir is falsey')) }
try { try {
await window.electron.stat(projectDir) await window.electron.stat(projectDir)
} catch (e) { } catch (e) {
@ -104,6 +106,7 @@ export async function createNewProjectDirectory(
return Promise.reject('Project name cannot be empty.') return Promise.reject('Project name cannot be empty.')
} }
if (!mainDir) { return Promise.reject(new Error('mainDir is falsey')) }
const projectDir = window.electron.path.join(mainDir, projectName) const projectDir = window.electron.path.join(mainDir, projectName)
try { try {
@ -142,6 +145,8 @@ export async function listProjects(
} }
const projectDir = await ensureProjectDirectoryExists(configuration) const projectDir = await ensureProjectDirectoryExists(configuration)
const projects = [] const projects = []
if (!projectDir) return Promise.reject(new Error('projectDir was falsey'))
const entries = await window.electron.readdir(projectDir) const entries = await window.electron.readdir(projectDir)
for (let entry of entries) { for (let entry of entries) {
const projectPath = window.electron.path.join(projectDir, entry) const projectPath = window.electron.path.join(projectDir, entry)
@ -231,7 +236,7 @@ const collectAllFilesRecursiveFrom = async (path: string) => {
return entry return entry
} }
const getDefaultKclFileForDir = async (projectDir, file) => { const getDefaultKclFileForDir = async (projectDir: string, file: FileEntry) => {
// Make sure the dir is a directory. // Make sure the dir is a directory.
const isFileEntryDir = await window.electron.statIsDirectory(projectDir) const isFileEntryDir = await window.electron.statIsDirectory(projectDir)
if (!isFileEntryDir) { if (!isFileEntryDir) {
@ -305,7 +310,7 @@ export async function getProjectInfo(projectPath: string): Promise<Project> {
} catch (e) { } catch (e) {
if (e === 'ENOENT') { if (e === 'ENOENT') {
return Promise.reject( return Promise.reject(
new Error(`Project directory does not exist: ${project_path}`) new Error(`Project directory does not exist: ${projectPath}`)
) )
} }
} }
@ -314,7 +319,7 @@ export async function getProjectInfo(projectPath: string): Promise<Project> {
const projectPathIsDir = await window.electron.statIsDirectory(projectPath) const projectPathIsDir = await window.electron.statIsDirectory(projectPath)
if (!projectPathIsDir) { if (!projectPathIsDir) {
return Promise.reject( return Promise.reject(
new Error(`Project path is not a directory: ${project_path}`) new Error(`Project path is not a directory: ${projectPath}`)
) )
} }
@ -322,9 +327,10 @@ export async function getProjectInfo(projectPath: string): Promise<Project> {
let default_file = await getDefaultKclFileForDir(projectPath, walked) let default_file = await getDefaultKclFileForDir(projectPath, walked)
const metadata = await window.electron.stat(projectPath) const metadata = await window.electron.stat(projectPath)
let project = /* FileEntry */ { let project = {
...walked, ...walked,
metadata, // We need to map from node fs.Stats to FileMetadata
metadata: metadata.map((data: { mtimeMs: number }) => ({ modified: data.mtimeMs })),
kcl_file_count: 0, kcl_file_count: 0,
directory_count: 0, directory_count: 0,
default_file, default_file,
@ -349,6 +355,7 @@ export async function writeProjectSettingsFile({
}): Promise<void> { }): Promise<void> {
const projectSettingsFilePath = await getProjectSettingsFilePath(projectPath) const projectSettingsFilePath = await getProjectSettingsFilePath(projectPath)
const tomlStr = tomlStringify(configuration) const tomlStr = tomlStringify(configuration)
if (err(tomlStr)) return Promise.reject(tomlStr)
return window.electron.writeFile(projectSettingsFilePath, tomlStr) return window.electron.writeFile(projectSettingsFilePath, tomlStr)
} }
@ -387,7 +394,7 @@ export const getInitialDefaultDir = async () => {
export const readProjectSettingsFile = async ( export const readProjectSettingsFile = async (
projectPath: string projectPath: string
): Promise<ProjectConfiguration> => { ): Promise<Partial<SaveSettingsPayload>> => {
let settingsPath = await getProjectSettingsFilePath(projectPath) let settingsPath = await getProjectSettingsFilePath(projectPath)
// Check if this file exists. // Check if this file exists.
@ -426,6 +433,7 @@ export const writeAppSettingsFile = async (
) => { ) => {
const appSettingsFilePath = await getAppSettingsFilePath() const appSettingsFilePath = await getAppSettingsFilePath()
const tomlStr = tomlStringify(config) const tomlStr = tomlStringify(config)
if (err(tomlStr)) return Promise.reject(tomlStr)
return window.electron.writeFile(appSettingsFilePath, tomlStr) return window.electron.writeFile(appSettingsFilePath, tomlStr)
} }

View File

@ -8,7 +8,8 @@ const save = (args: any) => ipcRenderer.invoke('dialog.showSaveDialog', args)
const openExternal = (url: any) => ipcRenderer.invoke('shell.openExternal', url) const openExternal = (url: any) => ipcRenderer.invoke('shell.openExternal', url)
const showInFolder = (path: string) => const showInFolder = (path: string) =>
ipcRenderer.invoke('shell.showItemInFolder', path) ipcRenderer.invoke('shell.showItemInFolder', path)
const login = (host: string): Promise<string> => ipcRenderer.invoke('login', host) const login = (host: string): Promise<string> =>
ipcRenderer.invoke('login', host)
const readFile = (path: string) => fs.readFile(path, 'utf-8') const readFile = (path: string) => fs.readFile(path, 'utf-8')
const rename = (prev: string, next: string) => fs.rename(prev, next) const rename = (prev: string, next: string) => fs.rename(prev, next)

View File

@ -1,7 +1,8 @@
import { MouseEventHandler } from 'react'
import { isDesktop } from 'lib/isDesktop' import { isDesktop } from 'lib/isDesktop'
export const openExternalBrowserIfDesktop = (to?: string) => export const openExternalBrowserIfDesktop = (to?: string) =>
function (e: Event) { function (e) {
if (isDesktop()) { if (isDesktop()) {
// Ignoring because currentTarget could be a few different things // Ignoring because currentTarget could be a few different things
// @ts-ignore // @ts-ignore
@ -10,7 +11,7 @@ export const openExternalBrowserIfDesktop = (to?: string) =>
e.stopPropagation() e.stopPropagation()
return false return false
} }
} } as MouseEventHandler<HTMLAnchorElement>
// Open a new browser window desktop style or browser style. // Open a new browser window desktop style or browser style.
export default async function openWindow(url: string) { export default async function openWindow(url: string) {

View File

@ -117,19 +117,21 @@ export const fileLoader: LoaderFunction = async (
// So that WASM gets an updated path for operations // So that WASM gets an updated path for operations
fileSystemManager.dir = project_path fileSystemManager.dir = project_path
const projectData: IndexLoaderData = { const defaultProjectData = {
code, name: project_name || 'unnamed',
project: isDesktop()
? await getProjectInfo(project_path)
: {
name: project_name,
path: project_path, path: project_path,
children: [], children: [],
kcl_file_count: 0, kcl_file_count: 0,
directory_count: 0, directory_count: 0,
metadata: null, metadata: null,
default_file: project_path, default_file: project_path,
}, }
const projectData: IndexLoaderData = {
code,
project: isDesktop()
? (await getProjectInfo(project_path)) ?? defaultProjectData
: defaultProjectData,
file: { file: {
name: current_file_name || '', name: current_file_name || '',
path: current_file_path?.split('/').slice(0, -1).join('/') ?? '', path: current_file_path?.split('/').slice(0, -1).join('/') ?? '',

View File

@ -63,7 +63,9 @@ export class Setting<T = unknown> {
return this._user return this._user
} }
set user(v: T | undefined) { set user(v: T | undefined) {
this._user = this.validate(v) ? v : this._user this._user = v !== undefined
? this.validate(v) ? v : this._user
: v
this.current = this.resolve() this.current = this.resolve()
} }
/** /**
@ -72,8 +74,10 @@ export class Setting<T = unknown> {
get project(): T | undefined { get project(): T | undefined {
return this._project return this._project
} }
set project(v: T) { set project(v: T | undefined) {
this._project = this.validate(v) ? v : this._project this._project = v !== undefined
? this.validate(v) ? v : this._project
: v
this.current = this.resolve() this.current = this.resolve()
} }
/** /**

View File

@ -129,7 +129,7 @@ export function readLocalStorageAppSettingsFile(): Configuration | Error {
} }
} }
function readLocalStorageProjectSettingsFile(): ProjectConfiguration | Error { function readLocalStorageProjectSettingsFile(): Partial<SaveSettingsPayload> | Error {
// TODO: Remove backwards compatibility after a few releases. // TODO: Remove backwards compatibility after a few releases.
let stored = localStorage.getItem(localStorageProjectSettingsPath()) ?? '' let stored = localStorage.getItem(localStorageProjectSettingsPath()) ?? ''

View File

@ -36,9 +36,9 @@ export function getSortFunction(sortBy: string) {
} }
const sortByModified = (a: Project, b: Project) => { const sortByModified = (a: Project, b: Project) => {
if (a.metadata?.mtimeMs && b.metadata?.mtimeMs) { if (a.metadata?.modified && b.metadata?.modified) {
const aDate = new Date(a.metadata.mtimeMs) const aDate = new Date(a.metadata.modified)
const bDate = new Date(b.metadata.mtimeMs) const bDate = new Date(b.metadata.modified)
return !sortBy || sortBy.includes('desc') return !sortBy || sortBy.includes('desc')
? bDate.getTime() - aDate.getTime() ? bDate.getTime() - aDate.getTime()
: aDate.getTime() - bDate.getTime() : aDate.getTime() - bDate.getTime()

View File

@ -7,6 +7,7 @@ import { getUser as getUserDesktop } from 'lib/desktop'
const SKIP_AUTH = const SKIP_AUTH =
import.meta.env.VITE_KC_SKIP_AUTH === 'true' && import.meta.env.DEV import.meta.env.VITE_KC_SKIP_AUTH === 'true' && import.meta.env.DEV
const LOCAL_USER: Models['User_type'] = { const LOCAL_USER: Models['User_type'] = {
id: '8675309', id: '8675309',
name: 'Test User', name: 'Test User',

View File

@ -1,42 +0,0 @@
import os from 'os'
import path from 'path'
import { spawn, ChildProcess } from 'child_process'
let tauriDriver: ChildProcess
const application =
process.env.E2E_APPLICATION || `./src-tauri/target/release/zoo-modeling-app`
export const config = {
hostname: '127.0.0.1',
port: 4444,
specs: ['./e2e/tauri/specs/**/*.ts'],
maxInstances: 1,
capabilities: [
{
maxInstances: 1,
'tauri:options': {
application,
webviewOptions: {}, // Windows only
},
},
],
reporters: ['spec'],
framework: 'mocha',
mochaOpts: {
bail: true,
ui: 'bdd',
timeout: 600000,
},
// ensure we are running `tauri-driver` before the session starts so that we can proxy the webdriver requests
beforeSession: () =>
(tauriDriver = spawn(
path.resolve(os.homedir(), '.cargo', 'bin', 'tauri-driver'),
[],
{ stdio: [null, process.stdout, process.stderr] }
)),
// clean up the `tauri-driver` process we spawned at the start of the session
afterSession: () => tauriDriver.kill(),
}