43
.github/workflows/ci.yml
vendored
43
.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)
|
||||
|
||||
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')) }}
|
||||
|
||||
# concurrency:
|
||||
@ -110,8 +111,14 @@ jobs:
|
||||
echo "$(jq --arg name 'Zoo Modeling App (Nightly)' \
|
||||
'.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
|
||||
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
|
||||
if: github.event_name == 'schedule'
|
||||
if: ${{ github.event_name == 'schedule' || env.CUT_RELEASE_PR }}
|
||||
with:
|
||||
path: |
|
||||
package.json
|
||||
@ -283,6 +290,23 @@ jobs:
|
||||
with:
|
||||
path: "src-tauri/target/universal-apple-darwin/${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }}/bundle/*/*"
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
if: env.CUT_RELEASE_PR
|
||||
|
||||
- name: Copy updated .json file for updater test
|
||||
if: env.CUT_RELEASE_PR
|
||||
run: "cp artifact/src-tauri/tauri.release.conf.json src-tauri/tauri.release.conf.json"
|
||||
|
||||
- name: Build the app (release, updater test)
|
||||
if: env.CUT_RELEASE_PR
|
||||
run: "yarn tauri build -c src-tauri/tauri.release.conf.json -b dmg --target universal-apple-darwin"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: env.CUT_RELEASE_PR
|
||||
with:
|
||||
path: "src-tauri/target/universal-apple-darwin/release/bundle/dmg/*.dmg"
|
||||
name: updater-test
|
||||
|
||||
|
||||
build-test-app-windows:
|
||||
needs: [prepare-json-files]
|
||||
@ -413,6 +437,23 @@ jobs:
|
||||
E2E_TAURI_ENABLED: true
|
||||
TS_NODE_COMPILER_OPTIONS: '{"module": "commonjs"}'
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
if: env.CUT_RELEASE_PR
|
||||
|
||||
- name: Copy updated .json file for updater test
|
||||
if: env.CUT_RELEASE_PR
|
||||
run: "cp artifact/src-tauri/tauri.release.conf.json src-tauri/tauri.release.conf.json"
|
||||
|
||||
- name: Build the app (release, updater test)
|
||||
if: env.CUT_RELEASE_PR
|
||||
run: "yarn tauri build -c src-tauri\\tauri.release.conf.json -b msi"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: env.CUT_RELEASE_PR
|
||||
with:
|
||||
path: "src-tauri/target/release/bundle/msi/*.msi"
|
||||
name: updater-test
|
||||
|
||||
|
||||
build-test-app-ubuntu:
|
||||
needs: [prepare-json-files]
|
||||
|
||||
151
.github/workflows/playwright.yml
vendored
151
.github/workflows/playwright.yml
vendored
@ -83,6 +83,20 @@ jobs:
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
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)
|
||||
if: needs.check-rust-changes.outputs.rust-changed == 'true'
|
||||
run: yarn build:wasm
|
||||
@ -139,27 +153,60 @@ jobs:
|
||||
with:
|
||||
name: test-results-ubuntu-${{ github.sha }}
|
||||
path: test-results/
|
||||
- name: Run ubuntu/chrome flow retry failures
|
||||
- name: Run ubuntu/chrome flow (with retries)
|
||||
id: retry
|
||||
if: always()
|
||||
run: |
|
||||
if [[ -d "test-results" ]];
|
||||
then if [[ $(ls -1 "test-results" | wc -l) != "0" ]];
|
||||
then echo "retried=true" >> $GITHUB_OUTPUT;
|
||||
else echo "retried=false" >> $GITHUB_OUTPUT; exit 0;
|
||||
fi;
|
||||
else echo "retried=false" >> $GITHUB_OUTPUT; exit 0;
|
||||
fi;
|
||||
yarn playwright test --project="Google Chrome" --last-failed e2e/playwright/flow-tests.spec.ts
|
||||
env:
|
||||
CI: true
|
||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
- name: Run ubuntu/chrome flow
|
||||
if: steps.retry.outputs.retried == 'false'
|
||||
run: yarn playwright test --project="Google Chrome" e2e/playwright/flow-tests.spec.ts
|
||||
if [[ ! -f "test-results/.last-run.json" ]]; then
|
||||
# if no last run artifact, than run plawright normally
|
||||
echo "run playwright normally"
|
||||
yarn playwright test --project="Google Chrome" e2e/playwright/flow-tests.spec.ts || true
|
||||
# # send to axiom
|
||||
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
retry=1
|
||||
max_retrys=4
|
||||
|
||||
# retry failed tests, doing our own retries because using inbuilt playwright retries causes connection issues
|
||||
while [[ $retry -le $max_retrys ]]; do
|
||||
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:
|
||||
CI: true
|
||||
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
|
||||
if: always()
|
||||
with:
|
||||
@ -226,6 +273,20 @@ jobs:
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
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)
|
||||
if: needs.check-rust-changes.outputs.rust-changed == 'true'
|
||||
run: yarn build:wasm
|
||||
@ -241,26 +302,52 @@ jobs:
|
||||
with:
|
||||
name: test-results-macos-${{ github.sha }}
|
||||
path: test-results/
|
||||
- name: Run macos/safari flow retry failures
|
||||
- name: Run macos/safari flow (with retries)
|
||||
id: retry
|
||||
if: always()
|
||||
run: |
|
||||
if [[ -d "test-results" ]];
|
||||
then if [[ $(ls -1 "test-results" | wc -l) != "0" ]];
|
||||
then echo "retried=true" >> $GITHUB_OUTPUT;
|
||||
else echo "retried=false" >> $GITHUB_OUTPUT; exit 0;
|
||||
fi;
|
||||
else echo "retried=false" >> $GITHUB_OUTPUT; exit 0;
|
||||
fi;
|
||||
yarn playwright test --project="webkit" --last-failed e2e/playwright/flow-tests.spec.ts
|
||||
env:
|
||||
CI: true
|
||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
- name: Run macos/safari flow
|
||||
if: steps.retry.outputs.retried == 'false'
|
||||
# webkit doesn't work on Ubuntu because of the same reason tauri doesn't (webRTC issues)
|
||||
# TODO remove this and the matrix and run all tests on ubuntu when this is fixed
|
||||
run: yarn playwright test --project="webkit" e2e/playwright/flow-tests.spec.ts
|
||||
if [[ ! -f "test-results/.last-run.json" ]]; then
|
||||
# if no last run artifact, than run plawright normally
|
||||
echo "run playwright normally"
|
||||
yarn playwright test --project="webkit" e2e/playwright/flow-tests.spec.ts || true
|
||||
# # send to axiom
|
||||
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
retry=1
|
||||
max_retrys=4
|
||||
|
||||
# retry failed tests, doing our own retries because using inbuilt playwright retries causes connection issues
|
||||
while [[ $retry -le $max_retrys ]]; do
|
||||
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="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:
|
||||
CI: true
|
||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
|
||||
@ -2458,6 +2458,44 @@ test.describe('Onboarding tests', () => {
|
||||
await expect(onboardingOverlayLocator).toBeVisible()
|
||||
await expect(onboardingOverlayLocator).toContainText('the menu button')
|
||||
})
|
||||
|
||||
test("Avatar text doesn't mention avatar when no avatar", async ({
|
||||
page,
|
||||
}) => {
|
||||
// Override beforeEach test setup
|
||||
await page.addInitScript(
|
||||
async ({ settingsKey, settings }) => {
|
||||
localStorage.setItem(settingsKey, settings)
|
||||
localStorage.setItem('FORCE_NO_IMAGE', 'FORCE_NO_IMAGE')
|
||||
},
|
||||
{
|
||||
settingsKey: TEST_SETTINGS_KEY,
|
||||
settings: TOML.stringify({
|
||||
settings: TEST_SETTINGS_ONBOARDING_USER_MENU,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
const u = await getUtils(page)
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await page.waitForURL('**/file/**', { waitUntil: 'domcontentloaded' })
|
||||
|
||||
// Test that the text in this step is correct
|
||||
const avatarLocator = await page
|
||||
.getByTestId('user-sidebar-toggle')
|
||||
.locator('img')
|
||||
const onboardingOverlayLocator = await page
|
||||
.getByTestId('onboarding-content')
|
||||
.locator('div')
|
||||
.nth(1)
|
||||
|
||||
// Expect the avatar to be visible and for the text to reference it
|
||||
await expect(avatarLocator).not.toBeVisible()
|
||||
await expect(onboardingOverlayLocator).toBeVisible()
|
||||
await expect(onboardingOverlayLocator).toContainText('the menu button')
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Testing selections', () => {
|
||||
@ -4563,6 +4601,53 @@ test.describe('Sketch tests', () => {
|
||||
await doSnapAtDifferentScales(page, [0, 10000, 10000])
|
||||
})
|
||||
})
|
||||
test('exiting a close extrude, has the extrude button enabled ready to go', async ({
|
||||
page,
|
||||
}) => {
|
||||
// this was a regression https://github.com/KittyCAD/modeling-app/issues/2832
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`const sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt([-0.45, 0.87], %)
|
||||
|> line([1.32, 0.38], %)
|
||||
|> line([1.02, -1.32], %, $seg01)
|
||||
|> line([-1.01, -0.77], %)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
`
|
||||
)
|
||||
})
|
||||
|
||||
const u = await getUtils(page)
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
// click "line([1.32, 0.38], %)"
|
||||
await page.getByText(`line([1.32, 0.38], %)`).click()
|
||||
await page.waitForTimeout(100)
|
||||
// click edit sketch
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
await page.waitForTimeout(600) // wait for animation
|
||||
|
||||
// exit sketch
|
||||
await page.getByRole('button', { name: 'Exit Sketch' }).click()
|
||||
|
||||
// expect extrude button to be enabled
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Extrude' })
|
||||
).not.toBeDisabled()
|
||||
|
||||
// click extrude
|
||||
await page.getByRole('button', { name: 'Extrude' }).click()
|
||||
|
||||
// sketch selection should already have been made. "Selection 1 face" only show up when the selection has been made already
|
||||
// otherwise the cmdbar would be waiting for a selection.
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Selection 1 face' })
|
||||
).toBeVisible()
|
||||
})
|
||||
test("Existing sketch with bad code delete user's code", async ({ page }) => {
|
||||
// this was a regression https://github.com/KittyCAD/modeling-app/issues/2832
|
||||
await page.addInitScript(async () => {
|
||||
|
||||
@ -20,7 +20,10 @@ export default defineConfig({
|
||||
/* Different amount of parallelism on CI and local. */
|
||||
workers: process.env.CI ? 4 : 4,
|
||||
/* 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. */
|
||||
use: {
|
||||
/* 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)
|
||||
|
||||
@ -518,9 +518,9 @@ export class CameraControls {
|
||||
direction.normalize()
|
||||
this.camera.position.copy(this.target).addScaledVector(direction, distance)
|
||||
}
|
||||
usePerspectiveCamera = async () => {
|
||||
usePerspectiveCamera = async (forceSend = false) => {
|
||||
this._usePerspectiveCamera()
|
||||
if (this.syncDirection === 'clientToEngine') {
|
||||
if (forceSend || this.syncDirection === 'clientToEngine') {
|
||||
await this.engineCommandManager.sendSceneCommand({
|
||||
type: 'modeling_cmd_req',
|
||||
cmd_id: uuidv4(),
|
||||
|
||||
@ -717,7 +717,7 @@ export const CamDebugSettings = () => {
|
||||
if (camSettings.type === 'perspective') {
|
||||
sceneInfra.camControls.useOrthographicCamera()
|
||||
} else {
|
||||
sceneInfra.camControls.usePerspectiveCamera()
|
||||
sceneInfra.camControls.usePerspectiveCamera(true)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -35,6 +35,7 @@ import {
|
||||
canExtrudeSelection,
|
||||
handleSelectionBatch,
|
||||
isSelectionLastLine,
|
||||
isRangeInbetweenCharacters,
|
||||
isSketchPipe,
|
||||
updateSelections,
|
||||
} from 'lib/selections'
|
||||
@ -425,6 +426,7 @@ export const ModelingMachineProvider = ({
|
||||
|
||||
if (
|
||||
selectionRanges.codeBasedSelections.length === 0 ||
|
||||
isRangeInbetweenCharacters(selectionRanges) ||
|
||||
isSelectionLastLine(selectionRanges, codeManager.code)
|
||||
) {
|
||||
// they have no selection, we should enable the button
|
||||
|
||||
@ -360,6 +360,14 @@ export function isSelectionLastLine(
|
||||
return selectionRanges.codeBasedSelections[i].range[1] === code.length
|
||||
}
|
||||
|
||||
export function isRangeInbetweenCharacters(selectionRanges: Selections) {
|
||||
return (
|
||||
selectionRanges.codeBasedSelections.length === 1 &&
|
||||
selectionRanges.codeBasedSelections[0].range[0] === 0 &&
|
||||
selectionRanges.codeBasedSelections[0].range[1] === 0
|
||||
)
|
||||
}
|
||||
|
||||
export type CommonASTNode = {
|
||||
selection: Selection
|
||||
ast: Program
|
||||
|
||||
@ -126,11 +126,17 @@ async function getUser(context: UserContext) {
|
||||
if (!token && isTauri()) return Promise.reject(new Error('No token found'))
|
||||
if (token) headers['Authorization'] = `Bearer ${context.token}`
|
||||
|
||||
if (SKIP_AUTH)
|
||||
if (SKIP_AUTH) {
|
||||
// For local tests
|
||||
if (localStorage.getItem('FORCE_NO_IMAGE')) {
|
||||
LOCAL_USER.image = ''
|
||||
}
|
||||
|
||||
return {
|
||||
user: LOCAL_USER,
|
||||
token,
|
||||
}
|
||||
}
|
||||
|
||||
const userPromise = !isTauri()
|
||||
? fetch(url, {
|
||||
@ -144,6 +150,11 @@ async function getUser(context: UserContext) {
|
||||
|
||||
const user = await userPromise
|
||||
|
||||
// Necessary here because we use Kurt's API key in CI
|
||||
if (localStorage.getItem('FORCE_NO_IMAGE')) {
|
||||
user.image = ''
|
||||
}
|
||||
|
||||
if ('error_code' in user) return Promise.reject(new Error(user.message))
|
||||
|
||||
return {
|
||||
|
||||
@ -2,13 +2,18 @@ import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useModelingContext } from 'hooks/useModelingContext'
|
||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||
|
||||
export default function UserMenu() {
|
||||
const { context } = useModelingContext()
|
||||
const { auth } = useSettingsAuthContext()
|
||||
const dismiss = useDismiss()
|
||||
const next = useNextClick(onboardingPaths.PROJECT_MENU)
|
||||
const [avatarErrored, setAvatarErrored] = useState(false)
|
||||
const buttonDescription = !avatarErrored ? 'your avatar' : 'the menu button'
|
||||
|
||||
const user = auth?.context?.user
|
||||
const errorOrNoImage = !user?.image || avatarErrored
|
||||
const buttonDescription = errorOrNoImage ? 'the menu button' : 'your avatar'
|
||||
|
||||
// Set up error handling for the user's avatar image,
|
||||
// so the onboarding text can be updated if it fails to load.
|
||||
|
||||
Reference in New Issue
Block a user