Compare commits
17 Commits
franknoiro
...
iterion/en
Author | SHA1 | Date | |
---|---|---|---|
37f1518d59 | |||
cbddb3553d | |||
a24789d944 | |||
dd754c78ab | |||
150f56b47a | |||
f417727a7f | |||
3efdba9cae | |||
0eef6ab7d3 | |||
91d3ba3fce | |||
7165aa1b41 | |||
1a73a640f4 | |||
691a98d345 | |||
18995802f2 | |||
5bb6607452 | |||
e446b71ab6 | |||
05c5a782c2 | |||
cf480bb679 |
@ -297,7 +297,7 @@ jobs:
|
||||
project_id: ${{ env.GOOGLE_CLOUD_PROJECT_ID }}
|
||||
|
||||
- name: Upload release files to public bucket
|
||||
uses: google-github-actions/upload-cloud-storage@v2.1.3
|
||||
uses: google-github-actions/upload-cloud-storage@v2.2.0
|
||||
with:
|
||||
path: out
|
||||
glob: 'Zoo*'
|
||||
@ -305,7 +305,7 @@ jobs:
|
||||
destination: ${{ env.BUCKET_DIR }}
|
||||
|
||||
- name: Upload update endpoint to public bucket
|
||||
uses: google-github-actions/upload-cloud-storage@v2.1.3
|
||||
uses: google-github-actions/upload-cloud-storage@v2.2.0
|
||||
with:
|
||||
path: out
|
||||
glob: 'latest*'
|
||||
@ -313,7 +313,7 @@ jobs:
|
||||
destination: ${{ env.BUCKET_DIR }}
|
||||
|
||||
- name: Upload download endpoint to public bucket
|
||||
uses: google-github-actions/upload-cloud-storage@v2.1.3
|
||||
uses: google-github-actions/upload-cloud-storage@v2.2.0
|
||||
with:
|
||||
path: last_download.json
|
||||
destination: ${{ env.BUCKET_DIR }}
|
||||
|
4
.github/workflows/playwright.yml
vendored
4
.github/workflows/playwright.yml
vendored
@ -262,7 +262,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-14]
|
||||
timeout-minutes: 30
|
||||
timeout-minutes: 40
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: check-rust-changes
|
||||
steps:
|
||||
@ -381,7 +381,7 @@ jobs:
|
||||
echo "retried=true" >>$GITHUB_OUTPUT
|
||||
echo "run playwright with last failed tests and retry $retry"
|
||||
if [[ "$IS_UBUNTU" == "true" ]]; then
|
||||
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn playwright test --config=playwright.electron.config.ts --grep=@electron || true
|
||||
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn playwright test --config=playwright.electron.config.ts --last-failed --grep=@electron || true
|
||||
else
|
||||
yarn playwright test --config=playwright.electron.config.ts --grep=@electron || true
|
||||
fi
|
||||
|
8
Makefile
8
Makefile
@ -7,6 +7,14 @@ XSTATE_TYPEGENS := $(wildcard src/machines/*.typegen.ts)
|
||||
dev: node_modules public/wasm_lib_bg.wasm $(XSTATE_TYPEGENS)
|
||||
yarn start
|
||||
|
||||
# I'm sorry this is so specific to my setup you may as well ignore this.
|
||||
# This is so you don't have to deal with electron windows popping up constantly.
|
||||
# It should work for you other Linux users.
|
||||
lee-electron-test:
|
||||
Xephyr -br -ac -noreset -screen 1200x500 :2 &
|
||||
DISPLAY=:2 NODE_ENV=development PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ yarn tron:test -g "when using the file tree"
|
||||
killall Xephyr
|
||||
|
||||
$(XSTATE_TYPEGENS): $(TS_SRC)
|
||||
yarn xstate typegen 'src/**/*.ts?(x)'
|
||||
|
||||
|
@ -27,9 +27,19 @@ test.describe('Code pane and errors', () => {
|
||||
const u = await getUtils(page)
|
||||
|
||||
// Load the app with the working starter code
|
||||
await page.addInitScript((code) => {
|
||||
localStorage.setItem('persistCode', code)
|
||||
}, bracket)
|
||||
await page.addInitScript(() => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`// Extruded Triangle
|
||||
const sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([10, 0], %)
|
||||
|> line([-5, 10], %)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
const extrude001 = extrude(5, sketch001)`
|
||||
)
|
||||
})
|
||||
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
@ -43,12 +43,6 @@ test(
|
||||
// open the project
|
||||
await page.getByText(`bracket`).click()
|
||||
|
||||
// wait for the project to load
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
||||
// expect zero errors in guter
|
||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||
|
||||
@ -56,6 +50,12 @@ test(
|
||||
const exportButton = page.getByTestId('export-pane-button')
|
||||
await expect(exportButton).toBeVisible()
|
||||
|
||||
// Wait for the model to finish loading
|
||||
const modelStateIndicator = page.getByTestId(
|
||||
'model-state-indicator-execution-done'
|
||||
)
|
||||
await expect(modelStateIndicator).toBeVisible({ timeout: 60000 })
|
||||
|
||||
const gltfOption = page.getByText('glTF')
|
||||
const submitButton = page.getByText('Confirm Export')
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
@ -104,7 +104,7 @@ test(
|
||||
},
|
||||
{ timeout: 15_000 }
|
||||
)
|
||||
.toBe(477327)
|
||||
.toBe(477481)
|
||||
|
||||
// clean up output.gltf
|
||||
await fsp.rm('output.gltf')
|
||||
|
@ -173,10 +173,10 @@ test.describe('Can export from electron app', () => {
|
||||
// gray at this pixel means the stream has loaded in the most
|
||||
// user way we can verify it (pixel color)
|
||||
await expect
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [75, 75, 75]), {
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBeLessThan(10)
|
||||
.toBeLessThan(15)
|
||||
})
|
||||
|
||||
const exportLocations: Array<Paths> = []
|
||||
@ -207,7 +207,7 @@ test.describe('Can export from electron app', () => {
|
||||
},
|
||||
{ timeout: 15_000 }
|
||||
)
|
||||
.toBe(477327)
|
||||
.toBe(477481)
|
||||
|
||||
// clean up output.gltf
|
||||
await fsp.rm('output.gltf')
|
||||
@ -495,10 +495,6 @@ test(
|
||||
|
||||
await file.click()
|
||||
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
await expect(u.codeLocator).toContainText(
|
||||
'A mounting bracket for the Focusrite Scarlett Solo audio interface'
|
||||
)
|
||||
@ -856,10 +852,10 @@ const extrude001 = extrude(200, sketch001)`)
|
||||
// gray at this pixel means the stream has loaded in the most
|
||||
// user way we can verify it (pixel color)
|
||||
await expect
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [132, 132, 132]), {
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [143, 143, 143]), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBeLessThan(10)
|
||||
.toBeLessThan(15)
|
||||
|
||||
await expect(async () => {
|
||||
await page.mouse.move(0, 0, { steps: 5 })
|
||||
@ -867,8 +863,8 @@ const extrude001 = extrude(200, sketch001)`)
|
||||
await page.mouse.click(pointOnModel.x, pointOnModel.y)
|
||||
// check user can interact with model by checking it turns yellow
|
||||
await expect
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [176, 180, 132]))
|
||||
.toBeLessThan(10)
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [180, 180, 137]))
|
||||
.toBeLessThan(15)
|
||||
}).toPass({ timeout: 40_000, intervals: [1_000] })
|
||||
|
||||
await page.getByTestId('app-logo').click()
|
||||
@ -956,10 +952,10 @@ test(
|
||||
// gray at this pixel means the stream has loaded in the most
|
||||
// user way we can verify it (pixel color)
|
||||
await expect
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [75, 75, 75]), {
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBeLessThan(10)
|
||||
.toBeLessThan(15)
|
||||
})
|
||||
|
||||
await test.step('Clicking the logo takes us back to the projects page / home', async () => {
|
||||
@ -990,10 +986,10 @@ test(
|
||||
// gray at this pixel means the stream has loaded in the most
|
||||
// user way we can verify it (pixel color)
|
||||
await expect
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [132, 132, 132]), {
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [143, 143, 143]), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBeLessThan(10)
|
||||
.toBeLessThan(15)
|
||||
})
|
||||
|
||||
await test.step('Opening the router-template project should load the stream', async () => {
|
||||
|
@ -358,6 +358,7 @@ const sketch001 = startSketchAt([-0, -0])
|
||||
await page.addInitScript(
|
||||
async ({ code }) => {
|
||||
localStorage.setItem('persistCode', code)
|
||||
;(window as any).playwrightSkipFilePicker = true
|
||||
},
|
||||
{
|
||||
code: bracket,
|
||||
@ -393,20 +394,22 @@ const sketch001 = startSketchAt([-0, -0])
|
||||
await test.step('The second export is blocked', async () => {
|
||||
// Find the toast.
|
||||
// Look out for the toast message
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
await expect(alreadyExportingToastMessage).toBeVisible()
|
||||
|
||||
await page.waitForTimeout(1000)
|
||||
await Promise.all([
|
||||
expect(exportingToastMessage.first()).toBeVisible(),
|
||||
expect(alreadyExportingToastMessage).toBeVisible(),
|
||||
])
|
||||
})
|
||||
|
||||
await test.step('The first export still succeeds', async () => {
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
await expect(errorToastMessage).not.toBeVisible()
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
|
||||
await expect(successToastMessage).toBeVisible()
|
||||
|
||||
await expect(alreadyExportingToastMessage).not.toBeVisible()
|
||||
await Promise.all([
|
||||
expect(exportingToastMessage).not.toBeVisible({ timeout: 15_000 }),
|
||||
expect(errorToastMessage).not.toBeVisible(),
|
||||
expect(engineErrorToastMessage).not.toBeVisible(),
|
||||
expect(successToastMessage).toBeVisible({ timeout: 15_000 }),
|
||||
expect(alreadyExportingToastMessage).not.toBeVisible({
|
||||
timeout: 15_000,
|
||||
}),
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@ -419,10 +422,12 @@ const sketch001 = startSketchAt([-0, -0])
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
|
||||
// Expect it to succeed.
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
await expect(errorToastMessage).not.toBeVisible()
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
await expect(alreadyExportingToastMessage).not.toBeVisible()
|
||||
await Promise.all([
|
||||
expect(exportingToastMessage).not.toBeVisible(),
|
||||
expect(errorToastMessage).not.toBeVisible(),
|
||||
expect(engineErrorToastMessage).not.toBeVisible(),
|
||||
expect(alreadyExportingToastMessage).not.toBeVisible(),
|
||||
])
|
||||
|
||||
await expect(successToastMessage).toBeVisible()
|
||||
})
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Binary file not shown.
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 31 KiB |
@ -773,9 +773,9 @@ const extrude001 = extrude(50, sketch001)
|
||||
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
let noHoverColor: [number, number, number] = [82, 82, 82]
|
||||
let hoverColor: [number, number, number] = [116, 116, 116]
|
||||
let selectColor: [number, number, number] = [144, 148, 97]
|
||||
let noHoverColor: [number, number, number] = [92, 92, 92]
|
||||
let hoverColor: [number, number, number] = [127, 127, 127]
|
||||
let selectColor: [number, number, number] = [155, 155, 105]
|
||||
|
||||
const extrudeWall = { x: 670, y: 275 }
|
||||
const extrudeText = `line([170.36, -121.61], %, $seg01)`
|
||||
@ -787,7 +787,7 @@ const extrude001 = extrude(50, sketch001)
|
||||
|
||||
await expect
|
||||
.poll(() => u.getGreatestPixDiff(extrudeWall, noHoverColor))
|
||||
.toBeLessThan(5)
|
||||
.toBeLessThan(15)
|
||||
await page.mouse.move(nothing.x, nothing.y)
|
||||
await page.waitForTimeout(100)
|
||||
await page.mouse.move(extrudeWall.x, extrudeWall.y)
|
||||
@ -798,43 +798,43 @@ const extrude001 = extrude(50, sketch001)
|
||||
await page.waitForTimeout(200)
|
||||
await expect(
|
||||
await u.getGreatestPixDiff(extrudeWall, hoverColor)
|
||||
).toBeLessThan(6)
|
||||
).toBeLessThan(15)
|
||||
await page.mouse.click(extrudeWall.x, extrudeWall.y)
|
||||
await expect(page.locator('.cm-activeLine')).toHaveText(`|> ${extrudeText}`)
|
||||
await page.waitForTimeout(200)
|
||||
await expect(
|
||||
await u.getGreatestPixDiff(extrudeWall, selectColor)
|
||||
).toBeLessThan(6)
|
||||
).toBeLessThan(15)
|
||||
await page.waitForTimeout(1000)
|
||||
// check color stays there, i.e. not overridden (this was a bug previously)
|
||||
await expect(
|
||||
await u.getGreatestPixDiff(extrudeWall, selectColor)
|
||||
).toBeLessThan(6)
|
||||
).toBeLessThan(15)
|
||||
|
||||
await page.mouse.move(nothing.x, nothing.y)
|
||||
await page.waitForTimeout(300)
|
||||
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
|
||||
|
||||
// because of shading, color is not exact everywhere on the face
|
||||
noHoverColor = [104, 104, 104]
|
||||
hoverColor = [134, 134, 134]
|
||||
selectColor = [158, 162, 110]
|
||||
noHoverColor = [115, 115, 115]
|
||||
hoverColor = [145, 145, 145]
|
||||
selectColor = [168, 168, 120]
|
||||
|
||||
await expect(await u.getGreatestPixDiff(cap, noHoverColor)).toBeLessThan(6)
|
||||
await expect(await u.getGreatestPixDiff(cap, noHoverColor)).toBeLessThan(15)
|
||||
await page.mouse.move(cap.x, cap.y)
|
||||
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
|
||||
await expect(page.getByTestId('hover-highlight').first()).toContainText(
|
||||
removeAfterFirstParenthesis(capText)
|
||||
)
|
||||
await page.waitForTimeout(200)
|
||||
await expect(await u.getGreatestPixDiff(cap, hoverColor)).toBeLessThan(6)
|
||||
await expect(await u.getGreatestPixDiff(cap, hoverColor)).toBeLessThan(15)
|
||||
await page.mouse.click(cap.x, cap.y)
|
||||
await expect(page.locator('.cm-activeLine')).toHaveText(`|> ${capText}`)
|
||||
await page.waitForTimeout(200)
|
||||
await expect(await u.getGreatestPixDiff(cap, selectColor)).toBeLessThan(6)
|
||||
await expect(await u.getGreatestPixDiff(cap, selectColor)).toBeLessThan(15)
|
||||
await page.waitForTimeout(1000)
|
||||
// check color stays there, i.e. not overridden (this was a bug previously)
|
||||
await expect(await u.getGreatestPixDiff(cap, selectColor)).toBeLessThan(6)
|
||||
await expect(await u.getGreatestPixDiff(cap, selectColor)).toBeLessThan(15)
|
||||
})
|
||||
test("Various pipe expressions should and shouldn't allow edit and or extrude", async ({
|
||||
page,
|
||||
|
@ -233,10 +233,6 @@ test.describe('Testing settings', () => {
|
||||
`Project settings override user settings on desktop`,
|
||||
{ tag: '@electron' },
|
||||
async ({ browser: _ }, testInfo) => {
|
||||
test.skip(
|
||||
process.platform === 'win32',
|
||||
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
|
||||
)
|
||||
const { electronApp, page } = await setupElectron({
|
||||
testInfo,
|
||||
folderSetupFn: async (dir) => {
|
||||
@ -276,11 +272,26 @@ test.describe('Testing settings', () => {
|
||||
await expect(logoLink).toHaveCSS('--primary-hue', userThemeColor)
|
||||
await settingsCloseButton.click()
|
||||
})
|
||||
let screenshot = await page.screenshot()
|
||||
await testInfo.attach('screenshot1', {
|
||||
body: screenshot,
|
||||
contentType: 'image/png',
|
||||
})
|
||||
|
||||
await test.step('Set project theme color', async () => {
|
||||
// Open the project
|
||||
await projectLink.click()
|
||||
screenshot = await page.screenshot()
|
||||
await testInfo.attach('screenshot2', {
|
||||
body: screenshot,
|
||||
contentType: 'image/png',
|
||||
})
|
||||
await settingsOpenButton.click()
|
||||
screenshot = await page.screenshot()
|
||||
await testInfo.attach('screenshot3', {
|
||||
body: screenshot,
|
||||
contentType: 'image/png',
|
||||
})
|
||||
// The project tab should be selected by default within a project
|
||||
await expect(projectSettingsTab).toBeChecked()
|
||||
await themeColorSetting.fill(projectThemeColor)
|
||||
|
@ -47,7 +47,6 @@ nsis:
|
||||
oneClick: false
|
||||
perMachine: true
|
||||
allowElevation: true
|
||||
license: "LICENSE"
|
||||
installerIcon: "assets/icon.ico"
|
||||
include: "./installer.nsh"
|
||||
|
||||
|
@ -39,7 +39,7 @@
|
||||
"codemirror": "^6.0.1",
|
||||
"decamelize": "^6.0.0",
|
||||
"electron-squirrel-startup": "^1.0.1",
|
||||
"electron-updater": "^6.2.1",
|
||||
"electron-updater": "^6.3.0",
|
||||
"fuse.js": "^7.0.0",
|
||||
"html2canvas-pro": "^1.5.8",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
|
@ -2,7 +2,7 @@ import { CommandLog } from 'lang/std/engineConnection'
|
||||
import { engineCommandManager } from 'lib/singletons'
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
function useEngineCommands(): [CommandLog[], () => void] {
|
||||
export function useEngineCommands(): [CommandLog[], () => void] {
|
||||
const [engineCommands, setEngineCommands] = useState<CommandLog[]>(
|
||||
engineCommandManager.commandLogs
|
||||
)
|
||||
|
@ -179,10 +179,7 @@ const FileTreeItem = ({
|
||||
codeManager.writeToFile()
|
||||
|
||||
// Prevent seeing the model built one piece at a time when changing files
|
||||
kclManager.isFirstRender = true
|
||||
kclManager.executeCode(true).then(() => {
|
||||
kclManager.isFirstRender = false
|
||||
})
|
||||
kclManager.executeCode(true)
|
||||
} else {
|
||||
// Let the lsp servers know we closed a file.
|
||||
onFileClose(currentFile?.path || null, project?.path || null)
|
||||
|
@ -11,6 +11,8 @@ import {
|
||||
|
||||
import { engineCommandManager } from '../lib/singletons'
|
||||
|
||||
import { Spinner } from './Spinner'
|
||||
|
||||
const Loading = ({ children }: React.PropsWithChildren) => {
|
||||
const [error, setError] = useState<ConnectionError>(ConnectionError.Unset)
|
||||
|
||||
@ -65,17 +67,7 @@ const Loading = ({ children }: React.PropsWithChildren) => {
|
||||
className="body-bg flex flex-col items-center justify-center h-screen"
|
||||
data-testid="loading"
|
||||
>
|
||||
<svg viewBox="0 0 10 10" className="w-8 h-8">
|
||||
<circle
|
||||
cx="5"
|
||||
cy="5"
|
||||
r="4"
|
||||
stroke="var(--primary)"
|
||||
fill="none"
|
||||
strokeDasharray="4, 4"
|
||||
className="animate-spin origin-center"
|
||||
/>
|
||||
</svg>
|
||||
<Spinner />
|
||||
<p className="text-base mt-4 text-primary">{children || 'Loading'}</p>
|
||||
<p
|
||||
className={
|
||||
|
@ -11,6 +11,7 @@ import toast from 'react-hot-toast'
|
||||
import { CoreDumpManager } from 'lib/coredump'
|
||||
import openWindow, { openExternalBrowserIfDesktop } from 'lib/openWindow'
|
||||
import { NetworkMachineIndicator } from './NetworkMachineIndicator'
|
||||
import { ModelStateIndicator } from './ModelStateIndicator'
|
||||
|
||||
export function LowerRightControls({
|
||||
children,
|
||||
@ -65,6 +66,7 @@ export function LowerRightControls({
|
||||
<section className="fixed bottom-2 right-2 flex flex-col items-end gap-3 pointer-events-none">
|
||||
{children}
|
||||
<menu className="flex items-center justify-end gap-3 pointer-events-auto">
|
||||
{!location.pathname.startsWith(PATHS.HOME) && <ModelStateIndicator />}
|
||||
<a
|
||||
onClick={openExternalBrowserIfDesktop(
|
||||
`https://github.com/KittyCAD/modeling-app/releases/tag/v${APP_VERSION}`
|
||||
|
39
src/components/ModelStateIndicator.tsx
Normal file
39
src/components/ModelStateIndicator.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { useEngineCommands } from './EngineCommands'
|
||||
import { Spinner } from './Spinner'
|
||||
import { CustomIcon } from './CustomIcon'
|
||||
|
||||
export const ModelStateIndicator = () => {
|
||||
const [commands] = useEngineCommands()
|
||||
|
||||
const lastCommandType = commands[commands.length - 1]?.type
|
||||
|
||||
let className = 'w-6 h-6 '
|
||||
let icon = <Spinner className={className} />
|
||||
let dataTestId = 'model-state-indicator'
|
||||
|
||||
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"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className} data-testid="model-state-indicator">
|
||||
{icon}
|
||||
</div>
|
||||
)
|
||||
}
|
@ -66,7 +66,6 @@ import {
|
||||
hasExtrudableGeometry,
|
||||
isSingleCursorInPipe,
|
||||
} from 'lang/queryAst'
|
||||
import { TEST } from 'env'
|
||||
import { exportFromEngine } from 'lib/exportFromEngine'
|
||||
import { Models } from '@kittycad/lib/dist/types/src'
|
||||
import toast from 'react-hot-toast'
|
||||
@ -161,9 +160,7 @@ export const ModelingMachineProvider = ({
|
||||
|
||||
store.videoElement?.pause()
|
||||
|
||||
kclManager.isFirstRender = true
|
||||
kclManager.executeCode().then(() => {
|
||||
kclManager.isFirstRender = false
|
||||
if (engineCommandManager.engineConnection?.idleMode) return
|
||||
|
||||
store.videoElement?.play().catch((e) => {
|
||||
@ -363,7 +360,7 @@ export const ModelingMachineProvider = ({
|
||||
return {}
|
||||
}),
|
||||
Make: async (_, event) => {
|
||||
if (event.type !== 'Make' || TEST) return
|
||||
if (event.type !== 'Make') return
|
||||
// Check if we already have an export intent.
|
||||
if (engineCommandManager.exportIntent) {
|
||||
toast.error('Already exporting')
|
||||
@ -407,7 +404,7 @@ export const ModelingMachineProvider = ({
|
||||
)
|
||||
},
|
||||
'Engine export': async (_, event) => {
|
||||
if (event.type !== 'Export' || TEST) return
|
||||
if (event.type !== 'Export') return
|
||||
if (engineCommandManager.exportIntent) {
|
||||
toast.error('Already exporting')
|
||||
return
|
||||
|
@ -193,10 +193,7 @@ export const SettingsAuthProviderBase = ({
|
||||
resetSettingsIncludesUnitChange
|
||||
) {
|
||||
// Unit changes requires a re-exec of code
|
||||
kclManager.isFirstRender = true
|
||||
kclManager.executeCode(true).then(() => {
|
||||
kclManager.isFirstRender = false
|
||||
})
|
||||
kclManager.executeCode(true)
|
||||
} else {
|
||||
// For any future logging we'd like to do
|
||||
// console.log(
|
||||
|
17
src/components/Spinner.tsx
Normal file
17
src/components/Spinner.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { SVGProps } from 'react'
|
||||
|
||||
export const Spinner = (props: SVGProps<SVGSVGElement>) => {
|
||||
return (
|
||||
<svg viewBox="0 0 10 10" className={'w-8 h-8'} {...props}>
|
||||
<circle
|
||||
cx="5"
|
||||
cy="5"
|
||||
r="4"
|
||||
stroke="var(--primary)"
|
||||
fill="none"
|
||||
strokeDasharray="4, 4"
|
||||
className="animate-spin origin-center"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
@ -54,12 +54,10 @@ export const Stream = () => {
|
||||
* central place, we can move this code there.
|
||||
*/
|
||||
async function executeCodeAndPlayStream() {
|
||||
kclManager.isFirstRender = true
|
||||
kclManager.executeCode(true).then(() => {
|
||||
videoRef.current?.play().catch((e) => {
|
||||
console.warn('Video playing was prevented', e, videoRef.current)
|
||||
})
|
||||
kclManager.isFirstRender = false
|
||||
setStreamState(StreamState.Playing)
|
||||
})
|
||||
}
|
||||
@ -219,7 +217,7 @@ export const Stream = () => {
|
||||
* Play the vid
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!kclManager.isFirstRender) {
|
||||
if (!kclManager.isExecuting) {
|
||||
setTimeout(() =>
|
||||
// execute in the next event loop
|
||||
videoRef.current?.play().catch((e) => {
|
||||
@ -227,7 +225,7 @@ export const Stream = () => {
|
||||
})
|
||||
)
|
||||
}
|
||||
}, [kclManager.isFirstRender])
|
||||
}, [kclManager.isExecuting])
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
@ -382,15 +380,15 @@ export const Stream = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{(!isNetworkOkay || isLoading || kclManager.isFirstRender) && (
|
||||
{(!isNetworkOkay || isLoading) && (
|
||||
<div className="text-center absolute inset-0">
|
||||
<Loading>
|
||||
{!isNetworkOkay && !isLoading && !kclManager.isFirstRender ? (
|
||||
{!isNetworkOkay && !isLoading ? (
|
||||
<span data-testid="loading-stream">Stream disconnected...</span>
|
||||
) : !isLoading && kclManager.isFirstRender ? (
|
||||
<span data-testid="loading-stream">Building scene...</span>
|
||||
) : (
|
||||
<span data-testid="loading-stream">Loading stream...</span>
|
||||
!isLoading && (
|
||||
<span data-testid="loading-stream">Loading stream...</span>
|
||||
)
|
||||
)}
|
||||
</Loading>
|
||||
</div>
|
||||
|
@ -60,8 +60,6 @@ export class KclManager {
|
||||
private _wasmInitFailedCallback: (arg: boolean) => void = () => {}
|
||||
private _executeCallback: () => void = () => {}
|
||||
|
||||
isFirstRender = true
|
||||
|
||||
get ast() {
|
||||
return this._ast
|
||||
}
|
||||
|
@ -95,8 +95,6 @@ export const wasmUrl = () => {
|
||||
document.location.pathname.split('/').slice(0, -1).join('/') +
|
||||
'/wasm_lib_bg.wasm'
|
||||
|
||||
console.log(`Full URL for WASM: ${fullUrl}`)
|
||||
|
||||
return fullUrl
|
||||
}
|
||||
|
||||
|
@ -31,11 +31,11 @@ const bracket = startSketchOn('XY')
|
||||
|> extrude(width, %)
|
||||
|> fillet({
|
||||
radius: filletR,
|
||||
tags: [getPreviousAdjacentEdge(innerEdge)]
|
||||
tags: [getNextAdjacentEdge(innerEdge)]
|
||||
}, %)
|
||||
|> fillet({
|
||||
radius: filletR + thickness,
|
||||
tags: [getPreviousAdjacentEdge(outerEdge)]
|
||||
tags: [getNextAdjacentEdge(outerEdge)]
|
||||
}, %)`
|
||||
|
||||
/**
|
||||
|
@ -81,7 +81,6 @@ export class MachineManager {
|
||||
}
|
||||
|
||||
this._machines = await window.electron.listMachines()
|
||||
console.log('Machines:', this._machines)
|
||||
}
|
||||
|
||||
private async updateMachineApiIp(): Promise<void> {
|
||||
|
@ -16,7 +16,6 @@ window.tearDown = engineCommandManager.tearDown
|
||||
|
||||
// This needs to be after codeManager is created.
|
||||
export const kclManager = new KclManager(engineCommandManager)
|
||||
kclManager.isFirstRender = true
|
||||
engineCommandManager.kclManager = kclManager
|
||||
|
||||
engineCommandManager.getAstCb = () => kclManager.ast
|
||||
|
@ -107,10 +107,7 @@ function OnboardingWarningWeb(props: OnboardingResetWarningProps) {
|
||||
codeManager.updateCodeStateEditor(bracket)
|
||||
await codeManager.writeToFile()
|
||||
|
||||
kclManager.isFirstRender = true
|
||||
await kclManager.executeCode(true).then(() => {
|
||||
kclManager.isFirstRender = false
|
||||
})
|
||||
await kclManager.executeCode(true)
|
||||
props.setShouldShowWarning(false)
|
||||
}}
|
||||
nextText="Overwrite code and continue"
|
||||
|
@ -13,10 +13,7 @@ export default function Sketching() {
|
||||
async function clearEditor() {
|
||||
// We do want to update both the state and editor here.
|
||||
codeManager.updateCodeStateEditor('')
|
||||
kclManager.isFirstRender = true
|
||||
await kclManager.executeCode(true).then(() => {
|
||||
kclManager.isFirstRender = false
|
||||
})
|
||||
await kclManager.executeCode(true)
|
||||
}
|
||||
|
||||
clearEditor()
|
||||
|
@ -82,10 +82,7 @@ export function useDemoCode() {
|
||||
if (!editorManager.editorView || codeManager.code === bracket) return
|
||||
setTimeout(async () => {
|
||||
codeManager.updateCodeStateEditor(bracket)
|
||||
kclManager.isFirstRender = true
|
||||
await kclManager.executeCode(true).then(() => {
|
||||
kclManager.isFirstRender = false
|
||||
})
|
||||
await kclManager.executeCode(true)
|
||||
await codeManager.writeToFile()
|
||||
})
|
||||
}, [editorManager.editorView])
|
||||
|
6
src/wasm-lib/Cargo.lock
generated
6
src/wasm-lib/Cargo.lock
generated
@ -672,7 +672,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "derive-docs"
|
||||
version = "0.1.25"
|
||||
version = "0.1.26"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
@ -1345,7 +1345,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx",
|
||||
@ -1417,7 +1417,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-test-server"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hyper",
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "derive-docs"
|
||||
description = "A tool for generating documentation from Rust derive macros"
|
||||
version = "0.1.25"
|
||||
version = "0.1.26"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-test-server"
|
||||
description = "A test server for KCL"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-lib"
|
||||
description = "KittyCAD Language implementation and tools"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
@ -20,7 +20,7 @@ clap = { version = "4.5.16", default-features = false, optional = true, features
|
||||
convert_case = "0.6.0"
|
||||
dashmap = "6.0.1"
|
||||
databake = { version = "0.1.8", features = ["derive"] }
|
||||
derive-docs = { version = "0.1.24", path = "../derive-docs" }
|
||||
derive-docs = { version = "0.1.26", path = "../derive-docs" }
|
||||
form_urlencoded = "1.2.1"
|
||||
futures = { version = "0.3.30" }
|
||||
git_rev = "0.1.0"
|
||||
|
@ -55,10 +55,10 @@ const bracketBody = bs
|
||||
|> fillet({
|
||||
radius: radius,
|
||||
tags: [
|
||||
getNextAdjacentEdge(bs.tags.edge7),
|
||||
getNextAdjacentEdge(bs.tags.edge2),
|
||||
getNextAdjacentEdge(bs.tags.edge3),
|
||||
getNextAdjacentEdge(bs.tags.edge6)
|
||||
getPreviousAdjacentEdge(bs.tags.edge7),
|
||||
getPreviousAdjacentEdge(bs.tags.edge2),
|
||||
getPreviousAdjacentEdge(bs.tags.edge3),
|
||||
getPreviousAdjacentEdge(bs.tags.edge6)
|
||||
]
|
||||
}, %)
|
||||
|
||||
|
18
yarn.lock
18
yarn.lock
@ -3668,6 +3668,14 @@ builder-util-runtime@9.2.4:
|
||||
debug "^4.3.4"
|
||||
sax "^1.2.4"
|
||||
|
||||
builder-util-runtime@9.2.5:
|
||||
version "9.2.5"
|
||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.2.5.tgz#0afdffa0adb5c84c14926c7dd2cf3c6e96e9be83"
|
||||
integrity sha512-HjIDfhvqx/8B3TDN4GbABQcgpewTU4LMRTQPkVpKYV3lsuxEJoIfvg09GyWTNmfVNSUAYf+fbTN//JX4TH20pg==
|
||||
dependencies:
|
||||
debug "^4.3.4"
|
||||
sax "^1.2.4"
|
||||
|
||||
builder-util@24.13.1:
|
||||
version "24.13.1"
|
||||
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-24.13.1.tgz#4a4c4f9466b016b85c6990a0ea15aa14edec6816"
|
||||
@ -4613,12 +4621,12 @@ electron-to-chromium@^1.5.4:
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz#1abf0410c5344b2b829b7247e031f02810d442e6"
|
||||
integrity sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==
|
||||
|
||||
electron-updater@^6.2.1:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.2.1.tgz#1c9adb9ba2a21a5dc50a8c434c45360d5e9fe6c9"
|
||||
integrity sha512-83eKIPW14qwZqUUM6wdsIRwVKZyjmHxQ4/8G+1C6iS5PdDt7b1umYQyj1/qPpH510GmHEQe4q0kCPe3qmb3a0Q==
|
||||
electron-updater@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.3.0.tgz#13a5c3c3f0b2b114fe33181e24a8270096734b3e"
|
||||
integrity sha512-3Xlezhk+dKaSQrOnkQNqCGiuGSSUPO9BV9TQZ4Iig6AyTJ4FzJONE5gFFc382sY53Sh9dwJfzKsA3DxRHt2btw==
|
||||
dependencies:
|
||||
builder-util-runtime "9.2.4"
|
||||
builder-util-runtime "9.2.5"
|
||||
fs-extra "^10.1.0"
|
||||
js-yaml "^4.1.0"
|
||||
lazy-val "^1.0.5"
|
||||
|
Reference in New Issue
Block a user