Merge branch 'main' into kurt-rust-sins
This commit is contained in:
33
.github/workflows/ci.yml
vendored
33
.github/workflows/ci.yml
vendored
@ -13,6 +13,7 @@ on:
|
|||||||
# Will checkout the last commit from the default branch (main as of 2023-10-04)
|
# Will checkout the last commit from the default branch (main as of 2023-10-04)
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
CUT_RELEASE_PR: ${{ github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }}
|
||||||
BUILD_RELEASE: ${{ github.event_name == 'release' || github.event_name == 'schedule' || github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }}
|
BUILD_RELEASE: ${{ github.event_name == 'release' || github.event_name == 'schedule' || github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }}
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
@ -110,8 +111,14 @@ jobs:
|
|||||||
echo "$(jq --arg name 'Zoo Modeling App (Nightly)' \
|
echo "$(jq --arg name 'Zoo Modeling App (Nightly)' \
|
||||||
'.productName=$name' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
|
'.productName=$name' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
|
||||||
|
|
||||||
|
- name: Set updater test version
|
||||||
|
if: ${{ env.CUT_RELEASE_PR == 'true' }}
|
||||||
|
run: |
|
||||||
|
echo "$(jq --arg url 'https://dl.zoo.dev/releases/modeling-app/test/last_update.json' \
|
||||||
|
'.plugins.updater.endpoints[]=$url' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
if: github.event_name == 'schedule'
|
if: ${{ github.event_name == 'schedule' || env.CUT_RELEASE_PR == 'true' }}
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
package.json
|
package.json
|
||||||
@ -377,6 +384,30 @@ jobs:
|
|||||||
E2E_TAURI_ENABLED: true
|
E2E_TAURI_ENABLED: true
|
||||||
TS_NODE_COMPILER_OPTIONS: '{"module": "commonjs"}'
|
TS_NODE_COMPILER_OPTIONS: '{"module": "commonjs"}'
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v3
|
||||||
|
if: ${{ env.CUT_RELEASE_PR == 'true' }}
|
||||||
|
|
||||||
|
- name: Copy updated .json file for updater test
|
||||||
|
if: ${{ env.CUT_RELEASE_PR == 'true' }}
|
||||||
|
run: |
|
||||||
|
ls -l artifact
|
||||||
|
cp artifact/src-tauri/tauri.release.conf.json src-tauri/tauri.release.conf.json
|
||||||
|
cat src-tauri/tauri.release.conf.json
|
||||||
|
|
||||||
|
- name: Build the app (release, updater test)
|
||||||
|
if: ${{ env.CUT_RELEASE_PR == 'true' && matrix.os != 'ubuntu-latest' }}
|
||||||
|
env:
|
||||||
|
TAURI_CONF_ARGS: "-c ${{ matrix.os == 'windows-latest' && 'src-tauri\\tauri.release.conf.json' || 'src-tauri/tauri.release.conf.json' }}"
|
||||||
|
TAURI_BUNDLE_ARGS: "-b ${{ matrix.os == 'windows-latest' && 'msi' || 'dmg' }}"
|
||||||
|
run: "yarn tauri build ${{ env.TAURI_CONF_ARGS }} ${{ env.TAURI_BUNDLE_ARGS }} ${{ env.TAURI_ARGS_MACOS }}"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: ${{ env.CUT_RELEASE_PR == 'true' && matrix.os != 'ubuntu-latest' }}
|
||||||
|
with:
|
||||||
|
path: "${{ matrix.os == 'macos-14' && 'src-tauri/target/universal-apple-darwin/release/bundle/dmg/*.dmg' || 'src-tauri/target/release/bundle/msi/*.msi' }}"
|
||||||
|
name: updater-test
|
||||||
|
|
||||||
|
|
||||||
publish-apps-release:
|
publish-apps-release:
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|||||||
151
.github/workflows/playwright.yml
vendored
151
.github/workflows/playwright.yml
vendored
@ -83,6 +83,20 @@ jobs:
|
|||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
workspaces: './src/wasm-lib'
|
workspaces: './src/wasm-lib'
|
||||||
|
- name: Install vector
|
||||||
|
run: |
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
|
||||||
|
chmod +x /tmp/vector.sh
|
||||||
|
/tmp/vector.sh -y -no-modify-path
|
||||||
|
mkdir -p /tmp/vector
|
||||||
|
cp .github/workflows/vector.toml /tmp/vector.toml
|
||||||
|
sed -i "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
|
||||||
|
sed -i "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
|
||||||
|
sed -i "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
|
||||||
|
sed -i "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
|
||||||
|
sed -i "s#GH_ACTIONS_AXIOM_TOKEN#${{secrets.GH_ACTIONS_AXIOM_TOKEN}}#g" /tmp/vector.toml
|
||||||
|
cat /tmp/vector.toml
|
||||||
|
${HOME}/.vector/bin/vector --config /tmp/vector.toml &
|
||||||
- name: Build Wasm (because rust diff)
|
- name: Build Wasm (because rust diff)
|
||||||
if: needs.check-rust-changes.outputs.rust-changed == 'true'
|
if: needs.check-rust-changes.outputs.rust-changed == 'true'
|
||||||
run: yarn build:wasm
|
run: yarn build:wasm
|
||||||
@ -139,27 +153,60 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: test-results-ubuntu-${{ github.sha }}
|
name: test-results-ubuntu-${{ github.sha }}
|
||||||
path: test-results/
|
path: test-results/
|
||||||
- name: Run ubuntu/chrome flow retry failures
|
- name: Run ubuntu/chrome flow (with retries)
|
||||||
id: retry
|
id: retry
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
if [[ -d "test-results" ]];
|
if [[ ! -f "test-results/.last-run.json" ]]; then
|
||||||
then if [[ $(ls -1 "test-results" | wc -l) != "0" ]];
|
# if no last run artifact, than run plawright normally
|
||||||
then echo "retried=true" >> $GITHUB_OUTPUT;
|
echo "run playwright normally"
|
||||||
else echo "retried=false" >> $GITHUB_OUTPUT; exit 0;
|
yarn playwright test --project="Google Chrome" e2e/playwright/flow-tests.spec.ts || true
|
||||||
fi;
|
# # send to axiom
|
||||||
else echo "retried=false" >> $GITHUB_OUTPUT; exit 0;
|
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
||||||
fi;
|
fi
|
||||||
yarn playwright test --project="Google Chrome" --last-failed e2e/playwright/flow-tests.spec.ts
|
|
||||||
env:
|
retry=1
|
||||||
CI: true
|
max_retrys=4
|
||||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
|
||||||
- name: Run ubuntu/chrome flow
|
# retry failed tests, doing our own retries because using inbuilt playwright retries causes connection issues
|
||||||
if: steps.retry.outputs.retried == 'false'
|
while [[ $retry -le $max_retrys ]]; do
|
||||||
run: yarn playwright test --project="Google Chrome" e2e/playwright/flow-tests.spec.ts
|
if [[ -f "test-results/.last-run.json" ]]; then
|
||||||
|
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
|
||||||
|
if [[ $failed_tests -gt 0 ]]; then
|
||||||
|
echo "retried=true" >>$GITHUB_OUTPUT
|
||||||
|
echo "run playwright with last failed tests and retry $retry"
|
||||||
|
yarn playwright test --project="Google Chrome" --last-failed e2e/playwright/flow-tests.spec.ts || true
|
||||||
|
# send to axiom
|
||||||
|
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
||||||
|
retry=$((retry + 1))
|
||||||
|
else
|
||||||
|
echo "retried=false" >>$GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "retried=false" >>$GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "retried=false" >>$GITHUB_OUTPUT
|
||||||
|
|
||||||
|
if [[ -f "test-results/.last-run.json" ]]; then
|
||||||
|
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
|
||||||
|
if [[ $failed_tests -gt 0 ]]; then
|
||||||
|
# if it still fails after 3 retrys, then fail the job
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||||
|
- name: send to axiom
|
||||||
|
if: always()
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
node playwrightProcess.mjs | tee /tmp/github-actions.log
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
@ -226,6 +273,20 @@ jobs:
|
|||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
workspaces: './src/wasm-lib'
|
workspaces: './src/wasm-lib'
|
||||||
|
- name: Install vector
|
||||||
|
run: |
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
|
||||||
|
chmod +x /tmp/vector.sh
|
||||||
|
/tmp/vector.sh -y -no-modify-path
|
||||||
|
mkdir -p /tmp/vector
|
||||||
|
cp .github/workflows/vector.toml /tmp/vector.toml
|
||||||
|
sed -i "" "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
|
||||||
|
sed -i "" "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
|
||||||
|
sed -i "" "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
|
||||||
|
sed -i "" "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
|
||||||
|
sed -i "" "s#GH_ACTIONS_AXIOM_TOKEN#${{secrets.GH_ACTIONS_AXIOM_TOKEN}}#g" /tmp/vector.toml
|
||||||
|
cat /tmp/vector.toml
|
||||||
|
${HOME}/.vector/bin/vector --config /tmp/vector.toml &
|
||||||
- name: Build Wasm (because rust diff)
|
- name: Build Wasm (because rust diff)
|
||||||
if: needs.check-rust-changes.outputs.rust-changed == 'true'
|
if: needs.check-rust-changes.outputs.rust-changed == 'true'
|
||||||
run: yarn build:wasm
|
run: yarn build:wasm
|
||||||
@ -241,26 +302,52 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: test-results-macos-${{ github.sha }}
|
name: test-results-macos-${{ github.sha }}
|
||||||
path: test-results/
|
path: test-results/
|
||||||
- name: Run macos/safari flow retry failures
|
- name: Run macos/safari flow (with retries)
|
||||||
id: retry
|
id: retry
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
if [[ -d "test-results" ]];
|
if [[ ! -f "test-results/.last-run.json" ]]; then
|
||||||
then if [[ $(ls -1 "test-results" | wc -l) != "0" ]];
|
# if no last run artifact, than run plawright normally
|
||||||
then echo "retried=true" >> $GITHUB_OUTPUT;
|
echo "run playwright normally"
|
||||||
else echo "retried=false" >> $GITHUB_OUTPUT; exit 0;
|
yarn playwright test --project="webkit" e2e/playwright/flow-tests.spec.ts || true
|
||||||
fi;
|
# # send to axiom
|
||||||
else echo "retried=false" >> $GITHUB_OUTPUT; exit 0;
|
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
||||||
fi;
|
fi
|
||||||
yarn playwright test --project="webkit" --last-failed e2e/playwright/flow-tests.spec.ts
|
|
||||||
env:
|
retry=1
|
||||||
CI: true
|
max_retrys=4
|
||||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
|
||||||
- name: Run macos/safari flow
|
# retry failed tests, doing our own retries because using inbuilt playwright retries causes connection issues
|
||||||
if: steps.retry.outputs.retried == 'false'
|
while [[ $retry -le $max_retrys ]]; do
|
||||||
# webkit doesn't work on Ubuntu because of the same reason tauri doesn't (webRTC issues)
|
if [[ -f "test-results/.last-run.json" ]]; then
|
||||||
# TODO remove this and the matrix and run all tests on ubuntu when this is fixed
|
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
|
||||||
run: yarn playwright test --project="webkit" e2e/playwright/flow-tests.spec.ts
|
if [[ $failed_tests -gt 0 ]]; then
|
||||||
|
echo "retried=true" >>$GITHUB_OUTPUT
|
||||||
|
echo "run playwright with last failed tests and retry $retry"
|
||||||
|
yarn playwright test --project="webkit" --last-failed e2e/playwright/flow-tests.spec.ts || true
|
||||||
|
# send to axiom
|
||||||
|
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
||||||
|
retry=$((retry + 1))
|
||||||
|
else
|
||||||
|
echo "retried=false" >>$GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "retried=false" >>$GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "retried=false" >>$GITHUB_OUTPUT
|
||||||
|
|
||||||
|
if [[ -f "test-results/.last-run.json" ]]; then
|
||||||
|
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
|
||||||
|
if [[ $failed_tests -gt 0 ]]; then
|
||||||
|
# if it still fails after 3 retrys, then fail the job
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||||
|
|||||||
@ -7726,6 +7726,31 @@ test('Basic default modeling and sketch hotkeys work', async ({ page }) => {
|
|||||||
await expect(page.locator('.cm-content')).toContainText('extrude(')
|
await expect(page.locator('.cm-content')).toContainText('extrude(')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('Delete key does not navigate back', async ({ page }) => {
|
||||||
|
await page.setViewportSize({ width: 1200, height: 500 })
|
||||||
|
await page.goto('/')
|
||||||
|
await page.waitForURL('**/file/**', { waitUntil: 'domcontentloaded' })
|
||||||
|
|
||||||
|
const settingsButton = page.getByRole('link', {
|
||||||
|
name: 'Settings',
|
||||||
|
exact: false,
|
||||||
|
})
|
||||||
|
const settingsCloseButton = page.getByTestId('settings-close-button')
|
||||||
|
|
||||||
|
await settingsButton.click()
|
||||||
|
await expect(page.url()).toContain('/settings')
|
||||||
|
|
||||||
|
// Make sure that delete doesn't go back from settings
|
||||||
|
await page.keyboard.press('Delete')
|
||||||
|
await expect(page.url()).toContain('/settings')
|
||||||
|
|
||||||
|
// Now close the settings and try delete again,
|
||||||
|
// make sure it doesn't go back to settings
|
||||||
|
await settingsCloseButton.click()
|
||||||
|
await page.keyboard.press('Delete')
|
||||||
|
await expect(page.url()).not.toContain('/settings')
|
||||||
|
})
|
||||||
|
|
||||||
test('Sketch on face', async ({ page }) => {
|
test('Sketch on face', async ({ page }) => {
|
||||||
test.setTimeout(90_000)
|
test.setTimeout(90_000)
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
|
|||||||
@ -20,7 +20,10 @@ export default defineConfig({
|
|||||||
/* Different amount of parallelism on CI and local. */
|
/* Different amount of parallelism on CI and local. */
|
||||||
workers: process.env.CI ? 4 : 4,
|
workers: process.env.CI ? 4 : 4,
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: 'html',
|
reporter: [
|
||||||
|
[process.env.CI ? 'dot' : 'list'],
|
||||||
|
['json', { outputFile: './test-results/report.json' }],
|
||||||
|
],
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
use: {
|
use: {
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
|||||||
65
playwrightProcess.mjs
Normal file
65
playwrightProcess.mjs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { readFileSync } from 'fs'
|
||||||
|
|
||||||
|
const data = readFileSync('./test-results/report.json', 'utf8')
|
||||||
|
|
||||||
|
// types, but was easier to store and run as normal js
|
||||||
|
// interface FailedTest {
|
||||||
|
// name: string;
|
||||||
|
// projectName: string;
|
||||||
|
// error: string;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// interface Spec {
|
||||||
|
// title: string;
|
||||||
|
// tests: Test[];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// interface Test {
|
||||||
|
// expectedStatus: 'passed' | 'failed' | 'pending';
|
||||||
|
// projectName: string;
|
||||||
|
// title: string;
|
||||||
|
// results: {
|
||||||
|
// status: 'passed' | 'failed' | 'pending';
|
||||||
|
// error: {stack: string}
|
||||||
|
// }[]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// interface Suite {
|
||||||
|
// title: string
|
||||||
|
// suites: Suite[];
|
||||||
|
// specs: Spec[];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const processReport = (suites: Suite[]): FailedTest[] => {
|
||||||
|
// const failedTests: FailedTest[] = []
|
||||||
|
// const loopSuites = (suites: Suite[], previousName = '') => {
|
||||||
|
const processReport = (suites) => {
|
||||||
|
const failedTests = []
|
||||||
|
const loopSuites = (suites, previousName = '') => {
|
||||||
|
if (!suites) return
|
||||||
|
for (const suite of suites) {
|
||||||
|
const name = (previousName ? `${previousName} -- ` : '') + suite.title
|
||||||
|
for (const spec of suite.specs) {
|
||||||
|
for (const test of spec.tests) {
|
||||||
|
for (const result of test.results) {
|
||||||
|
if ((result.status !== 'passed') && test.expectedStatus === 'passed') {
|
||||||
|
failedTests.push({
|
||||||
|
name: (name + ' -- ' + spec.title) + (test.title ? ` -- ${test.title}` : ''),
|
||||||
|
status: result.status,
|
||||||
|
projectName: test.projectName,
|
||||||
|
error: result.error?.stack,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loopSuites(suite.suites, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loopSuites(suites)
|
||||||
|
return failedTests.map(line => JSON.stringify(line)).join('\n')
|
||||||
|
}
|
||||||
|
const failedTests = processReport(JSON.parse(data).suites)
|
||||||
|
// log to stdout to be piped to axiom
|
||||||
|
console.log(failedTests)
|
||||||
|
|
||||||
@ -6,7 +6,7 @@ import { useModelingContext } from 'hooks/useModelingContext'
|
|||||||
import { useNetworkContext } from 'hooks/useNetworkContext'
|
import { useNetworkContext } from 'hooks/useNetworkContext'
|
||||||
import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
||||||
import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
|
import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
|
||||||
import { butName } from 'lib/cameraControls'
|
import { btnName } from 'lib/cameraControls'
|
||||||
import { sendSelectEventToEngine } from 'lib/selections'
|
import { sendSelectEventToEngine } from 'lib/selections'
|
||||||
import { kclManager, engineCommandManager, sceneInfra } from 'lib/singletons'
|
import { kclManager, engineCommandManager, sceneInfra } from 'lib/singletons'
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ export const Stream = () => {
|
|||||||
if (state.matches('Sketch')) return
|
if (state.matches('Sketch')) return
|
||||||
if (state.matches('Sketch no face')) return
|
if (state.matches('Sketch no face')) return
|
||||||
|
|
||||||
if (!context.store?.didDragInStream && butName(e).left) {
|
if (!context.store?.didDragInStream && btnName(e).left) {
|
||||||
sendSelectEventToEngine(
|
sendSelectEventToEngine(
|
||||||
e,
|
e,
|
||||||
videoRef.current,
|
videoRef.current,
|
||||||
|
|||||||
@ -64,7 +64,7 @@ export interface MouseGuard {
|
|||||||
rotate: MouseGuardHandler
|
rotate: MouseGuardHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
export const butName = (e: React.MouseEvent) => ({
|
export const btnName = (e: React.MouseEvent) => ({
|
||||||
middle: !!(e.buttons & 4) || e.button === 1,
|
middle: !!(e.buttons & 4) || e.button === 1,
|
||||||
right: !!(e.buttons & 2) || e.button === 2,
|
right: !!(e.buttons & 2) || e.button === 2,
|
||||||
left: !!(e.buttons & 1) || e.button === 0,
|
left: !!(e.buttons & 1) || e.button === 0,
|
||||||
@ -75,8 +75,8 @@ export const cameraMouseDragGuards: Record<CameraSystem, MouseGuard> = {
|
|||||||
pan: {
|
pan: {
|
||||||
description: 'Right click + Shift + drag or middle click + drag',
|
description: 'Right click + Shift + drag or middle click + drag',
|
||||||
callback: (e) =>
|
callback: (e) =>
|
||||||
(butName(e).middle && noModifiersPressed(e)) ||
|
(btnName(e).middle && noModifiersPressed(e)) ||
|
||||||
(butName(e).right && e.shiftKey),
|
(btnName(e).right && e.shiftKey),
|
||||||
},
|
},
|
||||||
zoom: {
|
zoom: {
|
||||||
description: 'Scroll wheel or Right click + Ctrl + drag',
|
description: 'Scroll wheel or Right click + Ctrl + drag',
|
||||||
@ -85,15 +85,15 @@ export const cameraMouseDragGuards: Record<CameraSystem, MouseGuard> = {
|
|||||||
},
|
},
|
||||||
rotate: {
|
rotate: {
|
||||||
description: 'Right click + drag',
|
description: 'Right click + drag',
|
||||||
callback: (e) => butName(e).right && noModifiersPressed(e),
|
callback: (e) => btnName(e).right && noModifiersPressed(e),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
OnShape: {
|
OnShape: {
|
||||||
pan: {
|
pan: {
|
||||||
description: 'Right click + Ctrl + drag or middle click + drag',
|
description: 'Right click + Ctrl + drag or middle click + drag',
|
||||||
callback: (e) =>
|
callback: (e) =>
|
||||||
(butName(e).right && e.ctrlKey) ||
|
(btnName(e).right && e.ctrlKey) ||
|
||||||
(butName(e).middle && noModifiersPressed(e)),
|
(btnName(e).middle && noModifiersPressed(e)),
|
||||||
},
|
},
|
||||||
zoom: {
|
zoom: {
|
||||||
description: 'Scroll wheel',
|
description: 'Scroll wheel',
|
||||||
@ -102,72 +102,72 @@ export const cameraMouseDragGuards: Record<CameraSystem, MouseGuard> = {
|
|||||||
},
|
},
|
||||||
rotate: {
|
rotate: {
|
||||||
description: 'Right click + drag',
|
description: 'Right click + drag',
|
||||||
callback: (e) => butName(e).right && noModifiersPressed(e),
|
callback: (e) => btnName(e).right && noModifiersPressed(e),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Trackpad Friendly': {
|
'Trackpad Friendly': {
|
||||||
pan: {
|
pan: {
|
||||||
description: 'Left click + Alt + Shift + drag or middle click + drag',
|
description: 'Left click + Alt + Shift + drag or middle click + drag',
|
||||||
callback: (e) =>
|
callback: (e) =>
|
||||||
(butName(e).left && e.altKey && e.shiftKey && !e.metaKey) ||
|
(btnName(e).left && e.altKey && e.shiftKey && !e.metaKey) ||
|
||||||
(butName(e).middle && noModifiersPressed(e)),
|
(btnName(e).middle && noModifiersPressed(e)),
|
||||||
},
|
},
|
||||||
zoom: {
|
zoom: {
|
||||||
description: 'Scroll wheel or Left click + Alt + OS + drag',
|
description: 'Scroll wheel or Left click + Alt + OS + drag',
|
||||||
dragCallback: (e) => butName(e).left && e.altKey && e.metaKey,
|
dragCallback: (e) => btnName(e).left && e.altKey && e.metaKey,
|
||||||
scrollCallback: () => true,
|
scrollCallback: () => true,
|
||||||
},
|
},
|
||||||
rotate: {
|
rotate: {
|
||||||
description: 'Left click + Alt + drag',
|
description: 'Left click + Alt + drag',
|
||||||
callback: (e) => butName(e).left && e.altKey && !e.shiftKey && !e.metaKey,
|
callback: (e) => btnName(e).left && e.altKey && !e.shiftKey && !e.metaKey,
|
||||||
lenientDragStartButton: 0,
|
lenientDragStartButton: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Solidworks: {
|
Solidworks: {
|
||||||
pan: {
|
pan: {
|
||||||
description: 'Right click + Ctrl + drag',
|
description: 'Right click + Ctrl + drag',
|
||||||
callback: (e) => butName(e).right && e.ctrlKey,
|
callback: (e) => btnName(e).right && e.ctrlKey,
|
||||||
lenientDragStartButton: 2,
|
lenientDragStartButton: 2,
|
||||||
},
|
},
|
||||||
zoom: {
|
zoom: {
|
||||||
description: 'Scroll wheel or Middle click + Shift + drag',
|
description: 'Scroll wheel or Middle click + Shift + drag',
|
||||||
dragCallback: (e) => butName(e).middle && e.shiftKey,
|
dragCallback: (e) => btnName(e).middle && e.shiftKey,
|
||||||
scrollCallback: () => true,
|
scrollCallback: () => true,
|
||||||
},
|
},
|
||||||
rotate: {
|
rotate: {
|
||||||
description: 'Middle click + drag',
|
description: 'Middle click + drag',
|
||||||
callback: (e) => butName(e).middle && noModifiersPressed(e),
|
callback: (e) => btnName(e).middle && noModifiersPressed(e),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NX: {
|
NX: {
|
||||||
pan: {
|
pan: {
|
||||||
description: 'Middle click + Shift + drag',
|
description: 'Middle click + Shift + drag',
|
||||||
callback: (e) => butName(e).middle && e.shiftKey,
|
callback: (e) => btnName(e).middle && e.shiftKey,
|
||||||
},
|
},
|
||||||
zoom: {
|
zoom: {
|
||||||
description: 'Scroll wheel or Middle click + Ctrl + drag',
|
description: 'Scroll wheel or Middle click + Ctrl + drag',
|
||||||
dragCallback: (e) => butName(e).middle && e.ctrlKey,
|
dragCallback: (e) => btnName(e).middle && e.ctrlKey,
|
||||||
scrollCallback: () => true,
|
scrollCallback: () => true,
|
||||||
},
|
},
|
||||||
rotate: {
|
rotate: {
|
||||||
description: 'Middle click + drag',
|
description: 'Middle click + drag',
|
||||||
callback: (e) => butName(e).middle && noModifiersPressed(e),
|
callback: (e) => btnName(e).middle && noModifiersPressed(e),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Creo: {
|
Creo: {
|
||||||
pan: {
|
pan: {
|
||||||
description: 'Left click + Ctrl + drag',
|
description: 'Left click + Ctrl + drag',
|
||||||
callback: (e) => butName(e).left && !butName(e).right && e.ctrlKey,
|
callback: (e) => btnName(e).left && !btnName(e).right && e.ctrlKey,
|
||||||
},
|
},
|
||||||
zoom: {
|
zoom: {
|
||||||
description: 'Scroll wheel or Right click + Ctrl + drag',
|
description: 'Scroll wheel or Right click + Ctrl + drag',
|
||||||
dragCallback: (e) => butName(e).right && !butName(e).left && e.ctrlKey,
|
dragCallback: (e) => btnName(e).right && !btnName(e).left && e.ctrlKey,
|
||||||
scrollCallback: () => true,
|
scrollCallback: () => true,
|
||||||
},
|
},
|
||||||
rotate: {
|
rotate: {
|
||||||
description: 'Middle (or Left + Right) click + Ctrl + drag',
|
description: 'Middle (or Left + Right) click + Ctrl + drag',
|
||||||
callback: (e) => {
|
callback: (e) => {
|
||||||
const b = butName(e)
|
const b = btnName(e)
|
||||||
return (b.middle || (b.left && b.right)) && e.ctrlKey
|
return (b.middle || (b.left && b.right)) && e.ctrlKey
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -175,7 +175,7 @@ export const cameraMouseDragGuards: Record<CameraSystem, MouseGuard> = {
|
|||||||
AutoCAD: {
|
AutoCAD: {
|
||||||
pan: {
|
pan: {
|
||||||
description: 'Middle click + drag',
|
description: 'Middle click + drag',
|
||||||
callback: (e) => butName(e).middle && noModifiersPressed(e),
|
callback: (e) => btnName(e).middle && noModifiersPressed(e),
|
||||||
},
|
},
|
||||||
zoom: {
|
zoom: {
|
||||||
description: 'Scroll wheel',
|
description: 'Scroll wheel',
|
||||||
@ -184,7 +184,7 @@ export const cameraMouseDragGuards: Record<CameraSystem, MouseGuard> = {
|
|||||||
},
|
},
|
||||||
rotate: {
|
rotate: {
|
||||||
description: 'Middle click + Shift + drag',
|
description: 'Middle click + Shift + drag',
|
||||||
callback: (e) => butName(e).middle && e.shiftKey,
|
callback: (e) => btnName(e).middle && e.shiftKey,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,6 +57,9 @@ const Home = () => {
|
|||||||
kclManager.cancelAllExecutions()
|
kclManager.cancelAllExecutions()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useHotkeys('backspace', (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
})
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
isTauri() ? 'mod+,' : 'shift+mod+,',
|
isTauri() ? 'mod+,' : 'shift+mod+,',
|
||||||
() => navigate(paths.HOME + paths.SETTINGS),
|
() => navigate(paths.HOME + paths.SETTINGS),
|
||||||
|
|||||||
Reference in New Issue
Block a user