Compare commits
24 Commits
multi-sket
...
jtran/fix-
Author | SHA1 | Date | |
---|---|---|---|
32068983a0 | |||
263a4f324d | |||
3160c58d8a | |||
73e26cbb4d | |||
21e2a92f54 | |||
d7f2bfdabe | |||
a76eabbb80 | |||
a82564989e | |||
e69837a411 | |||
7e31f870bf | |||
2f51763df9 | |||
7c4bf8d793 | |||
4747cdcab6 | |||
de73f335fe | |||
a62004da82 | |||
92e0da1f8d | |||
a111473658 | |||
7cfed9bff4 | |||
a30bd185d8 | |||
e8cae630a1 | |||
74ec749560 | |||
ebdaf59d1c | |||
cd68414d54 | |||
e63134e9fb |
@ -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 () => {
|
||||
|
@ -857,6 +857,11 @@ export class SceneEntities {
|
||||
let addingNewSegmentStatus: 'nothing' | 'pending' | 'added' = 'nothing'
|
||||
sceneInfra.setCallbacks({
|
||||
onDragEnd: async () => {
|
||||
// After the user drags, code has been updated, and source ranges are
|
||||
// potentially stale.
|
||||
const astResult = kclManager.updateSourceRanges()
|
||||
if (trap(astResult)) return
|
||||
|
||||
if (addingNewSegmentStatus !== 'nothing') {
|
||||
await this.tearDownSketch({ removeAxis: false })
|
||||
this.setupSketch({
|
||||
|
@ -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
|
||||
|
@ -154,6 +154,16 @@ export class KclManager {
|
||||
this._executeCallback = callback
|
||||
}
|
||||
|
||||
updateSourceRanges(): Error | null {
|
||||
const newAst = parse(recast(this.ast))
|
||||
if (err(newAst)) {
|
||||
return newAst
|
||||
}
|
||||
|
||||
this.ast = newAst
|
||||
return null
|
||||
}
|
||||
|
||||
clearAst() {
|
||||
this._ast = {
|
||||
body: [],
|
||||
|
@ -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