Compare commits
7 Commits
v0.25.0
...
kurt-model
Author | SHA1 | Date | |
---|---|---|---|
4107ab9b94 | |||
b473e23251 | |||
81498fcafe | |||
38d5fb8c41 | |||
a762d741a5 | |||
e62a5ccc47 | |||
4b8ca7f61f |
@ -224,6 +224,8 @@ jobs:
|
|||||||
--arg mac_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-mac.dmg" \
|
--arg mac_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-mac.dmg" \
|
||||||
--arg windows_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-win.msi" \
|
--arg windows_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-win.msi" \
|
||||||
--arg windows_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-win.msi" \
|
--arg windows_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-win.msi" \
|
||||||
|
--arg linux_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-linux.AppImage" \
|
||||||
|
--arg linux_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x86_64-linux.AppImage" \
|
||||||
'{
|
'{
|
||||||
"version": $version,
|
"version": $version,
|
||||||
"pub_date": $pub_date,
|
"pub_date": $pub_date,
|
||||||
@ -240,6 +242,12 @@ jobs:
|
|||||||
},
|
},
|
||||||
"msi-x64": {
|
"msi-x64": {
|
||||||
"url": $windows_x64_url
|
"url": $windows_x64_url
|
||||||
|
},
|
||||||
|
"appimage-arm64": {
|
||||||
|
"url": $linux_arm64_url
|
||||||
|
},
|
||||||
|
"appimage-x64": {
|
||||||
|
"url": $linux_x64_url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}' > last_download.json
|
}' > last_download.json
|
||||||
|
@ -54,6 +54,11 @@ test(
|
|||||||
const modelStateIndicator = page.getByTestId(
|
const modelStateIndicator = page.getByTestId(
|
||||||
'model-state-indicator-execution-done'
|
'model-state-indicator-execution-done'
|
||||||
)
|
)
|
||||||
|
const modelStateIndicatorLoading = page.getByTestId(
|
||||||
|
'model-state-indicator-loading'
|
||||||
|
)
|
||||||
|
|
||||||
|
await expect(modelStateIndicatorLoading).toBeVisible()
|
||||||
await expect(modelStateIndicator).toBeVisible({ timeout: 60000 })
|
await expect(modelStateIndicator).toBeVisible({ timeout: 60000 })
|
||||||
|
|
||||||
const gltfOption = page.getByText('glTF')
|
const gltfOption = page.getByText('glTF')
|
||||||
|
1
interface.d.ts
vendored
1
interface.d.ts
vendored
@ -31,7 +31,6 @@ export interface IElectronAPI {
|
|||||||
sep: typeof path.sep
|
sep: typeof path.sep
|
||||||
rename: (prev: string, next: string) => typeof fs.rename
|
rename: (prev: string, next: string) => typeof fs.rename
|
||||||
setBaseUrl: (value: string) => void
|
setBaseUrl: (value: string) => void
|
||||||
loadProjectAtStartup: () => Promise<ProjectState | null>
|
|
||||||
packageJson: {
|
packageJson: {
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
@ -69,19 +69,6 @@ const router = createRouter([
|
|||||||
path: PATHS.INDEX,
|
path: PATHS.INDEX,
|
||||||
loader: async () => {
|
loader: async () => {
|
||||||
const onDesktop = isDesktop()
|
const onDesktop = isDesktop()
|
||||||
if (onDesktop) {
|
|
||||||
const projectStartupFile =
|
|
||||||
await window.electron.loadProjectAtStartup()
|
|
||||||
if (projectStartupFile !== null) {
|
|
||||||
// Redirect to the file if we have a file path.
|
|
||||||
if (projectStartupFile.length > 0) {
|
|
||||||
return redirect(
|
|
||||||
PATHS.FILE + '/' + encodeURIComponent(projectStartupFile)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return onDesktop
|
return onDesktop
|
||||||
? redirect(PATHS.HOME)
|
? redirect(PATHS.HOME)
|
||||||
: redirect(PATHS.FILE + '/%2F' + BROWSER_PROJECT_NAME)
|
: redirect(PATHS.FILE + '/%2F' + BROWSER_PROJECT_NAME)
|
||||||
|
@ -1,45 +1,27 @@
|
|||||||
import { useEngineCommands } from './EngineCommands'
|
|
||||||
import { Spinner } from './Spinner'
|
import { Spinner } from './Spinner'
|
||||||
import { CustomIcon } from './CustomIcon'
|
import { CustomIcon } from './CustomIcon'
|
||||||
|
import { useKclContext } from 'lang/KclProvider'
|
||||||
|
|
||||||
export const ModelStateIndicator = () => {
|
export const ModelStateIndicator = () => {
|
||||||
const [commands] = useEngineCommands()
|
const { isExecuting } = useKclContext()
|
||||||
|
|
||||||
const lastCommandType = commands[commands.length - 1]?.type
|
if (isExecuting)
|
||||||
|
return (
|
||||||
let className = 'w-6 h-6 '
|
<div className="w-6 h-6" data-testid="model-state-indicator-loading">
|
||||||
let icon = <Spinner className={className} />
|
<Spinner className="w-6 h-6" />
|
||||||
let dataTestId = 'model-state-indicator'
|
</div>
|
||||||
|
|
||||||
if (lastCommandType === 'receive-reliable') {
|
|
||||||
className +=
|
|
||||||
'bg-chalkboard-20 dark:bg-chalkboard-80 !group-disabled:bg-chalkboard-30 !dark:group-disabled:bg-chalkboard-80 rounded-sm bg-succeed-10/30 dark:bg-succeed'
|
|
||||||
icon = (
|
|
||||||
<CustomIcon
|
|
||||||
data-testid={dataTestId + '-receive-reliable'}
|
|
||||||
name="checkmark"
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
} else if (lastCommandType === 'execution-done') {
|
|
||||||
className +=
|
|
||||||
'border-6 border border-solid border-chalkboard-60 dark:border-chalkboard-80 bg-chalkboard-20 dark:bg-chalkboard-80 !group-disabled:bg-chalkboard-30 !dark:group-disabled:bg-chalkboard-80 rounded-sm bg-succeed-10/30 dark:bg-succeed'
|
|
||||||
icon = (
|
|
||||||
<CustomIcon
|
|
||||||
data-testid={dataTestId + '-execution-done'}
|
|
||||||
name="checkmark"
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
} else if (lastCommandType === 'export-done') {
|
|
||||||
className +=
|
|
||||||
'border-6 border border-solid border-chalkboard-60 dark:border-chalkboard-80 bg-chalkboard-20 dark:bg-chalkboard-80 !group-disabled:bg-chalkboard-30 !dark:group-disabled:bg-chalkboard-80 rounded-sm bg-succeed-10/30 dark:bg-succeed'
|
|
||||||
icon = (
|
|
||||||
<CustomIcon data-testid={dataTestId + '-export-done'} name="checkmark" />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className} data-testid="model-state-indicator">
|
<div
|
||||||
{icon}
|
className="border-6 border border-solid border-chalkboard-60 dark:border-chalkboard-80 bg-chalkboard-20 dark:bg-chalkboard-80 !group-disabled:bg-chalkboard-30 !dark:group-disabled:bg-chalkboard-80 rounded-sm bg-succeed-10/30 dark:bg-succeed"
|
||||||
|
data-testid="model-state-indicator"
|
||||||
|
>
|
||||||
|
<CustomIcon
|
||||||
|
data-testid="model-state-indicator-execution-done"
|
||||||
|
name="checkmark"
|
||||||
|
className="w-6 h-6"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
53
src/main.ts
53
src/main.ts
@ -60,7 +60,7 @@ if (process.defaultApp) {
|
|||||||
// Must be done before ready event.
|
// Must be done before ready event.
|
||||||
registerStartupListeners()
|
registerStartupListeners()
|
||||||
|
|
||||||
const createWindow = (): BrowserWindow => {
|
const createWindow = (filePath?: string): BrowserWindow => {
|
||||||
const newWindow = new BrowserWindow({
|
const newWindow = new BrowserWindow({
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
show: false,
|
show: false,
|
||||||
@ -81,9 +81,26 @@ const createWindow = (): BrowserWindow => {
|
|||||||
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
|
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
|
||||||
newWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL)
|
newWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL)
|
||||||
} else {
|
} else {
|
||||||
newWindow.loadFile(
|
getProjectPathAtStartup(filePath).then((projectPath) => {
|
||||||
path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`)
|
const startIndex = path.join(
|
||||||
|
__dirname,
|
||||||
|
`../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (projectPath === null) {
|
||||||
|
newWindow.loadFile(startIndex)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Loading file', projectPath)
|
||||||
|
|
||||||
|
const fullUrl = `/file/${encodeURIComponent(projectPath)}`
|
||||||
|
console.log('Full URL', fullUrl)
|
||||||
|
|
||||||
|
newWindow.loadFile(startIndex, {
|
||||||
|
hash: fullUrl,
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the DevTools.
|
// Open the DevTools.
|
||||||
@ -233,7 +250,9 @@ app.on('ready', async () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('loadProjectAtStartup', async () => {
|
const getProjectPathAtStartup = async (
|
||||||
|
filePath?: string
|
||||||
|
): Promise<string | null> => {
|
||||||
// If we are in development mode, we don't want to load a project at
|
// If we are in development mode, we don't want to load a project at
|
||||||
// startup.
|
// startup.
|
||||||
// Since the args passed are always '.'
|
// Since the args passed are always '.'
|
||||||
@ -241,7 +260,8 @@ ipcMain.handle('loadProjectAtStartup', async () => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
let projectPath: string | null = null
|
let projectPath: string | null = filePath || null
|
||||||
|
if (projectPath === null) {
|
||||||
// macOS: open-file events that were received before the app is ready
|
// macOS: open-file events that were received before the app is ready
|
||||||
const macOpenFiles: string[] = (global as any).macOpenFiles
|
const macOpenFiles: string[] = (global as any).macOpenFiles
|
||||||
if (macOpenFiles && macOpenFiles && macOpenFiles.length > 0) {
|
if (macOpenFiles && macOpenFiles && macOpenFiles.length > 0) {
|
||||||
@ -270,24 +290,25 @@ ipcMain.handle('loadProjectAtStartup', async () => {
|
|||||||
args._[1] = ''
|
args._[1] = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (projectPath) {
|
if (projectPath) {
|
||||||
// We have a project path, load the project information.
|
// We have a project path, load the project information.
|
||||||
console.log(`Loading project at startup: ${projectPath}`)
|
console.log(`Loading project at startup: ${projectPath}`)
|
||||||
try {
|
|
||||||
const currentFile = await getCurrentProjectFile(projectPath)
|
const currentFile = await getCurrentProjectFile(projectPath)
|
||||||
|
|
||||||
|
if (currentFile instanceof Error) {
|
||||||
|
console.error(currentFile)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`Project loaded: ${currentFile}`)
|
console.log(`Project loaded: ${currentFile}`)
|
||||||
return currentFile
|
return currentFile
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
|
||||||
})
|
|
||||||
|
|
||||||
function parseCLIArgs(): minimist.ParsedArgs {
|
function parseCLIArgs(): minimist.ParsedArgs {
|
||||||
return minimist(process.argv, {})
|
return minimist(process.argv, {})
|
||||||
}
|
}
|
||||||
@ -303,10 +324,11 @@ function registerStartupListeners() {
|
|||||||
app.on('open-file', function (event, path) {
|
app.on('open-file', function (event, path) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
macOpenFiles.push(path)
|
|
||||||
// If we have a mainWindow, lets open another window.
|
// If we have a mainWindow, lets open another window.
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
createWindow()
|
createWindow(path)
|
||||||
|
} else {
|
||||||
|
macOpenFiles.push(path)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -322,10 +344,11 @@ function registerStartupListeners() {
|
|||||||
) {
|
) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
openUrls.push(url)
|
|
||||||
// If we have a mainWindow, lets open another window.
|
// If we have a mainWindow, lets open another window.
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
createWindow()
|
createWindow(url)
|
||||||
|
} else {
|
||||||
|
openUrls.push(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,9 +60,6 @@ const listMachines = async (): Promise<MachinesListing> => {
|
|||||||
const getMachineApiIp = async (): Promise<String | null> =>
|
const getMachineApiIp = async (): Promise<String | null> =>
|
||||||
ipcRenderer.invoke('find_machine_api')
|
ipcRenderer.invoke('find_machine_api')
|
||||||
|
|
||||||
const loadProjectAtStartup = async (): Promise<string | null> =>
|
|
||||||
ipcRenderer.invoke('loadProjectAtStartup')
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electron', {
|
contextBridge.exposeInMainWorld('electron', {
|
||||||
login,
|
login,
|
||||||
// Passing fs directly is not recommended since it gives a lot of power
|
// Passing fs directly is not recommended since it gives a lot of power
|
||||||
@ -96,7 +93,6 @@ contextBridge.exposeInMainWorld('electron', {
|
|||||||
isWindows,
|
isWindows,
|
||||||
isLinux,
|
isLinux,
|
||||||
},
|
},
|
||||||
loadProjectAtStartup,
|
|
||||||
// IMPORTANT NOTE: kittycad.ts reads process.env.BASE_URL. But there is
|
// IMPORTANT NOTE: kittycad.ts reads process.env.BASE_URL. But there is
|
||||||
// no way to set it across the bridge boundary. We need to make it a command.
|
// no way to set it across the bridge boundary. We need to make it a command.
|
||||||
setBaseUrl: (value: string) => (process.env.BASE_URL = value),
|
setBaseUrl: (value: string) => (process.env.BASE_URL = value),
|
||||||
|
Reference in New Issue
Block a user