Compare commits

...

7 Commits

Author SHA1 Message Date
4107ab9b94 fix test 2024-09-05 14:29:45 +10:00
b473e23251 Merge remote-tracking branch 'origin' into kurt-modelstateindicator 2024-09-05 14:02:17 +10:00
81498fcafe fix test id 2024-09-05 14:02:06 +10:00
38d5fb8c41 more simple 2024-09-05 13:25:43 +10:00
a762d741a5 Generate download endpoint with linux links (#3778) 2024-09-04 20:03:55 -07:00
e62a5ccc47 ignore camera drags for model state indicator 2024-09-05 12:29:08 +10:00
4b8ca7f61f Double click multiple windows fixes (#3777)
* better way of doing on file open

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

* fixes

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

* updates

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

* cleanuer

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-05 02:18:33 +00:00
7 changed files with 94 additions and 94 deletions

View File

@ -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

View File

@ -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
View File

@ -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
} }

View File

@ -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)

View File

@ -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>
) )
} }

View File

@ -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)
} }
} }

View File

@ -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),