Remove Create with Text-to-CAD from toolbar, make commands in command palette more distinct (#7048)
* Remove Create with Text-to-CAD from the toolbar * Remove "prompt-to-edit" wording, call commands "create" and "edit" * Use sparkles for the ML feature, not chat * lints * Start fixing up tests, there are probably more though * Fix up a few more tests * Fix up prompt-to-edit tests (yay using fixtures!) * Fix native file menu tests * Update snapshots * Fix menu test * Fix snaps --------- Co-authored-by: Pierre Jacquier <pierre@zoo.dev> Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
@ -146,9 +146,7 @@ export class CmdBarFixture {
|
|||||||
await this.cmdBarOpenBtn.click()
|
await this.cmdBarOpenBtn.click()
|
||||||
await expect(this.page.getByPlaceholder('Search commands')).toBeVisible()
|
await expect(this.page.getByPlaceholder('Search commands')).toBeVisible()
|
||||||
if (selectCmd === 'promptToEdit') {
|
if (selectCmd === 'promptToEdit') {
|
||||||
const promptEditCommand = this.page.getByText(
|
const promptEditCommand = this.selectOption({ name: 'Text-to-CAD Edit' })
|
||||||
'Use Zoo AI to edit your parts and code.'
|
|
||||||
)
|
|
||||||
await expect(promptEditCommand.first()).toBeVisible()
|
await expect(promptEditCommand.first()).toBeVisible()
|
||||||
await promptEditCommand.first().scrollIntoViewIfNeeded()
|
await promptEditCommand.first().scrollIntoViewIfNeeded()
|
||||||
await promptEditCommand.first().click()
|
await promptEditCommand.first().click()
|
||||||
|
@ -121,11 +121,13 @@ export class HomePageFixture {
|
|||||||
await projectCard.click()
|
await projectCard.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
goToModelingScene = async (name: string = 'testDefault') => {
|
/** Returns the project name in case caller has used the default and needs it */
|
||||||
|
goToModelingScene = async (name = 'testDefault') => {
|
||||||
// On web this is a no-op. There is no project view.
|
// On web this is a no-op. There is no project view.
|
||||||
if (process.env.PLATFORM === 'web') return
|
if (process.env.PLATFORM === 'web') return ''
|
||||||
|
|
||||||
await this.createAndGoToProject(name)
|
await this.createAndGoToProject(name)
|
||||||
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
isNativeFileMenuCreated = async () => {
|
isNativeFileMenuCreated = async () => {
|
||||||
|
@ -252,7 +252,7 @@ test.describe(
|
|||||||
tronApp,
|
tronApp,
|
||||||
'Edit.Modify with Zoo Text-To-CAD'
|
'Edit.Modify with Zoo Text-To-CAD'
|
||||||
)
|
)
|
||||||
await cmdBar.expectCommandName('Prompt-to-edit')
|
await cmdBar.expectCommandName('Text-to-CAD Edit')
|
||||||
})
|
})
|
||||||
await test.step('Modeling.Edit.Edit parameter', async () => {
|
await test.step('Modeling.Edit.Edit parameter', async () => {
|
||||||
await page.waitForTimeout(250)
|
await page.waitForTimeout(250)
|
||||||
@ -518,7 +518,7 @@ test.describe(
|
|||||||
'Design.Create with Zoo Text-To-CAD'
|
'Design.Create with Zoo Text-To-CAD'
|
||||||
)
|
)
|
||||||
await cmdBar.toBeOpened()
|
await cmdBar.toBeOpened()
|
||||||
await cmdBar.expectCommandName('Text to CAD')
|
await cmdBar.expectCommandName('Text-to-CAD Create')
|
||||||
})
|
})
|
||||||
|
|
||||||
await test.step('Modeling.Design.Modify with Zoo Text-To-CAD', async () => {
|
await test.step('Modeling.Design.Modify with Zoo Text-To-CAD', async () => {
|
||||||
@ -528,7 +528,7 @@ test.describe(
|
|||||||
'Design.Modify with Zoo Text-To-CAD'
|
'Design.Modify with Zoo Text-To-CAD'
|
||||||
)
|
)
|
||||||
await cmdBar.toBeOpened()
|
await cmdBar.toBeOpened()
|
||||||
await cmdBar.expectCommandName('Prompt-to-edit')
|
await cmdBar.expectCommandName('Text-to-CAD Edit')
|
||||||
})
|
})
|
||||||
|
|
||||||
await test.step('Modeling.Help.KCL code samples', async () => {
|
await test.step('Modeling.Help.KCL code samples', async () => {
|
||||||
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 135 KiB |
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 65 KiB |
@ -4,9 +4,10 @@ import type { Page } from '@playwright/test'
|
|||||||
|
|
||||||
import { createProject, getUtils } from '@e2e/playwright/test-utils'
|
import { createProject, getUtils } from '@e2e/playwright/test-utils'
|
||||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||||
|
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
|
||||||
|
|
||||||
test.describe('Text-to-CAD tests', () => {
|
test.describe('Text-to-CAD tests', () => {
|
||||||
test('basic lego happy case', async ({ page, homePage }) => {
|
test('basic lego happy case', async ({ page, homePage, cmdBar }) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
|
|
||||||
await test.step('Set up', async () => {
|
await test.step('Set up', async () => {
|
||||||
@ -15,7 +16,11 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
await u.waitForPageLoad()
|
await u.waitForPageLoad()
|
||||||
})
|
})
|
||||||
|
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, 'a 2x4 lego')
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
page,
|
||||||
|
'a 2x4 lego',
|
||||||
|
cmdBar
|
||||||
|
)
|
||||||
|
|
||||||
// Find the toast.
|
// Find the toast.
|
||||||
// Look out for the toast message
|
// Look out for the toast message
|
||||||
@ -56,6 +61,7 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
test('success model, then ignore success toast, user can create new prompt from command bar', async ({
|
test('success model, then ignore success toast, user can create new prompt from command bar', async ({
|
||||||
page,
|
page,
|
||||||
homePage,
|
homePage,
|
||||||
|
cmdBar,
|
||||||
}) => {
|
}) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
|
|
||||||
@ -64,7 +70,11 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
await homePage.goToModelingScene()
|
await homePage.goToModelingScene()
|
||||||
await u.waitForPageLoad()
|
await u.waitForPageLoad()
|
||||||
|
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, 'a 2x6 lego')
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
page,
|
||||||
|
'a 2x6 lego',
|
||||||
|
cmdBar
|
||||||
|
)
|
||||||
|
|
||||||
// Find the toast.
|
// Find the toast.
|
||||||
// Look out for the toast message
|
// Look out for the toast message
|
||||||
@ -82,7 +92,11 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
await expect(successToastMessage).toBeVisible({ timeout: 15000 })
|
await expect(successToastMessage).toBeVisible({ timeout: 15000 })
|
||||||
|
|
||||||
// Can send a new prompt from the command bar.
|
// Can send a new prompt from the command bar.
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, 'a 2x4 lego')
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
page,
|
||||||
|
'a 2x4 lego',
|
||||||
|
cmdBar
|
||||||
|
)
|
||||||
|
|
||||||
// Find the toast.
|
// Find the toast.
|
||||||
// Look out for the toast message
|
// Look out for the toast message
|
||||||
@ -100,6 +114,7 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
test('you can reject text-to-cad output and it does nothing', async ({
|
test('you can reject text-to-cad output and it does nothing', async ({
|
||||||
page,
|
page,
|
||||||
homePage,
|
homePage,
|
||||||
|
cmdBar,
|
||||||
}) => {
|
}) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
|
|
||||||
@ -108,7 +123,11 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
await homePage.goToModelingScene()
|
await homePage.goToModelingScene()
|
||||||
await u.waitForPageLoad()
|
await u.waitForPageLoad()
|
||||||
|
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, 'a 2x4 lego')
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
page,
|
||||||
|
'a 2x4 lego',
|
||||||
|
cmdBar
|
||||||
|
)
|
||||||
|
|
||||||
// Find the toast.
|
// Find the toast.
|
||||||
// Look out for the toast message
|
// Look out for the toast message
|
||||||
@ -141,6 +160,7 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
test('sending a bad prompt fails, can dismiss', async ({
|
test('sending a bad prompt fails, can dismiss', async ({
|
||||||
page,
|
page,
|
||||||
homePage,
|
homePage,
|
||||||
|
cmdBar,
|
||||||
}) => {
|
}) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
|
|
||||||
@ -150,7 +170,11 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
await u.waitForPageLoad()
|
await u.waitForPageLoad()
|
||||||
|
|
||||||
const randomPrompt = `aslkdfja;` + Date.now() + `FFFFEIWJF`
|
const randomPrompt = `aslkdfja;` + Date.now() + `FFFFEIWJF`
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, randomPrompt)
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
page,
|
||||||
|
randomPrompt,
|
||||||
|
cmdBar
|
||||||
|
)
|
||||||
|
|
||||||
// Find the toast.
|
// Find the toast.
|
||||||
// Look out for the toast message
|
// Look out for the toast message
|
||||||
@ -188,6 +212,7 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
test('sending a bad prompt fails, can start over from toast', async ({
|
test('sending a bad prompt fails, can start over from toast', async ({
|
||||||
page,
|
page,
|
||||||
homePage,
|
homePage,
|
||||||
|
cmdBar,
|
||||||
}) => {
|
}) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
|
|
||||||
@ -197,7 +222,7 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
await u.waitForPageLoad()
|
await u.waitForPageLoad()
|
||||||
|
|
||||||
const badPrompt = 'akjsndladf lajbhflauweyfaaaljhr472iouafyvsssssss'
|
const badPrompt = 'akjsndladf lajbhflauweyfaaaljhr472iouafyvsssssss'
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, badPrompt)
|
await sendPromptFromCommandBarAndSetExistingProject(page, badPrompt, cmdBar)
|
||||||
|
|
||||||
// Find the toast.
|
// Find the toast.
|
||||||
// Look out for the toast message
|
// Look out for the toast message
|
||||||
@ -256,6 +281,7 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
test('sending a bad prompt fails, can ignore toast, can start over from command bar', async ({
|
test('sending a bad prompt fails, can ignore toast, can start over from command bar', async ({
|
||||||
page,
|
page,
|
||||||
homePage,
|
homePage,
|
||||||
|
cmdBar,
|
||||||
}) => {
|
}) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
|
|
||||||
@ -265,7 +291,7 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
await u.waitForPageLoad()
|
await u.waitForPageLoad()
|
||||||
|
|
||||||
const badPrompt = 'akjsndladflajbhflauweyf15;'
|
const badPrompt = 'akjsndladflajbhflauweyf15;'
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, badPrompt)
|
await sendPromptFromCommandBarAndSetExistingProject(page, badPrompt, cmdBar)
|
||||||
|
|
||||||
// Find the toast.
|
// Find the toast.
|
||||||
// Look out for the toast message
|
// Look out for the toast message
|
||||||
@ -292,7 +318,11 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
await expect(page.getByText(`Text-to-CAD failed`)).toBeVisible()
|
await expect(page.getByText(`Text-to-CAD failed`)).toBeVisible()
|
||||||
|
|
||||||
// They should be able to try again from the command bar.
|
// They should be able to try again from the command bar.
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, 'a 2x4 lego')
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
page,
|
||||||
|
'a 2x4 lego',
|
||||||
|
cmdBar
|
||||||
|
)
|
||||||
|
|
||||||
// Find the toast.
|
// Find the toast.
|
||||||
// Look out for the toast message
|
// Look out for the toast message
|
||||||
@ -310,17 +340,40 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
test('ensure you can shift+enter in the prompt box', async ({
|
test('ensure you can shift+enter in the prompt box', async ({
|
||||||
page,
|
page,
|
||||||
homePage,
|
homePage,
|
||||||
|
cmdBar,
|
||||||
}) => {
|
}) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
|
|
||||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||||
|
|
||||||
await homePage.goToModelingScene()
|
const projectName = await homePage.goToModelingScene()
|
||||||
await u.waitForPageLoad()
|
await u.waitForPageLoad()
|
||||||
|
|
||||||
const promptWithNewline = `a 2x4\nlego`
|
const promptWithNewline = `a 2x4\nlego`
|
||||||
|
|
||||||
await page.getByTestId('text-to-cad').click()
|
await test.step('Get to the prompt step to test', async () => {
|
||||||
|
await cmdBar.openCmdBar()
|
||||||
|
await cmdBar.selectOption({ name: 'Text-to-CAD Create' }).click()
|
||||||
|
|
||||||
|
await cmdBar.currentArgumentInput.fill('existing')
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
|
||||||
|
await cmdBar.currentArgumentInput.fill(projectName)
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
|
||||||
|
await cmdBar.expectState({
|
||||||
|
commandName: 'Text-to-CAD Create',
|
||||||
|
stage: 'arguments',
|
||||||
|
currentArgKey: 'prompt',
|
||||||
|
currentArgValue: '',
|
||||||
|
highlightedHeaderArg: 'prompt',
|
||||||
|
headerArguments: {
|
||||||
|
Method: 'Existing project',
|
||||||
|
ProjectName: projectName,
|
||||||
|
Prompt: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
// Type the prompt.
|
// Type the prompt.
|
||||||
await page.keyboard.type('a 2x4')
|
await page.keyboard.type('a 2x4')
|
||||||
@ -354,6 +407,7 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
test('can do many at once and get many prompts back, and interact with many', async ({
|
test('can do many at once and get many prompts back, and interact with many', async ({
|
||||||
page,
|
page,
|
||||||
homePage,
|
homePage,
|
||||||
|
cmdBar,
|
||||||
}) => {
|
}) => {
|
||||||
// Let this test run longer since we've seen it timeout.
|
// Let this test run longer since we've seen it timeout.
|
||||||
test.setTimeout(180_000)
|
test.setTimeout(180_000)
|
||||||
@ -365,11 +419,23 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
await homePage.goToModelingScene()
|
await homePage.goToModelingScene()
|
||||||
await u.waitForPageLoad()
|
await u.waitForPageLoad()
|
||||||
|
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, 'a 2x4 lego')
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
page,
|
||||||
|
'a 2x4 lego',
|
||||||
|
cmdBar
|
||||||
|
)
|
||||||
|
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, 'a 2x8 lego')
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
page,
|
||||||
|
'a 2x8 lego',
|
||||||
|
cmdBar
|
||||||
|
)
|
||||||
|
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, 'a 2x10 lego')
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
page,
|
||||||
|
'a 2x10 lego',
|
||||||
|
cmdBar
|
||||||
|
)
|
||||||
|
|
||||||
// Find the toast.
|
// Find the toast.
|
||||||
// Look out for the toast message
|
// Look out for the toast message
|
||||||
@ -440,6 +506,7 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
test('can do many at once with errors, clicking dismiss error does not dismiss all', async ({
|
test('can do many at once with errors, clicking dismiss error does not dismiss all', async ({
|
||||||
page,
|
page,
|
||||||
homePage,
|
homePage,
|
||||||
|
cmdBar,
|
||||||
}) => {
|
}) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
|
|
||||||
@ -448,11 +515,16 @@ test.describe('Text-to-CAD tests', () => {
|
|||||||
await homePage.goToModelingScene()
|
await homePage.goToModelingScene()
|
||||||
await u.waitForPageLoad()
|
await u.waitForPageLoad()
|
||||||
|
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, 'a 2x4 lego')
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
|
||||||
await sendPromptFromCommandBarTriggeredByButton(
|
|
||||||
page,
|
page,
|
||||||
'alkjsdnlajshdbfjlhsbdf a;askjdnf'
|
'a 2x4 lego',
|
||||||
|
cmdBar
|
||||||
|
)
|
||||||
|
|
||||||
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
page,
|
||||||
|
'alkjsdnlajshdbfjlhsbdf a;askjdnf',
|
||||||
|
cmdBar
|
||||||
)
|
)
|
||||||
|
|
||||||
// Find the toast.
|
// Find the toast.
|
||||||
@ -526,7 +598,9 @@ async function _sendPromptFromCommandBar(page: Page, promptStr: string) {
|
|||||||
const cmdSearchBar = page.getByPlaceholder('Search commands')
|
const cmdSearchBar = page.getByPlaceholder('Search commands')
|
||||||
await expect(cmdSearchBar).toBeVisible()
|
await expect(cmdSearchBar).toBeVisible()
|
||||||
|
|
||||||
const textToCadCommand = page.getByText('Use the Zoo Text-to-CAD API')
|
const textToCadCommand = page.getByRole('option', {
|
||||||
|
name: 'Text-to-CAD Create',
|
||||||
|
})
|
||||||
await expect(textToCadCommand.first()).toBeVisible()
|
await expect(textToCadCommand.first()).toBeVisible()
|
||||||
// Click the Text-to-CAD command
|
// Click the Text-to-CAD command
|
||||||
await textToCadCommand.first().scrollIntoViewIfNeeded()
|
await textToCadCommand.first().scrollIntoViewIfNeeded()
|
||||||
@ -544,29 +618,67 @@ async function _sendPromptFromCommandBar(page: Page, promptStr: string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendPromptFromCommandBarTriggeredByButton(
|
async function sendPromptFromCommandBarAndSetExistingProject(
|
||||||
page: Page,
|
page: Page,
|
||||||
promptStr: string
|
promptStr: string,
|
||||||
|
cmdBar: CmdBarFixture,
|
||||||
|
projectName = 'testDefault'
|
||||||
) {
|
) {
|
||||||
await page.waitForTimeout(1000)
|
await page.waitForTimeout(1000)
|
||||||
await test.step(`Send prompt from command bar: ${promptStr}`, async () => {
|
await test.step(`Send prompt from command bar: ${promptStr}`, async () => {
|
||||||
await page.getByTestId('text-to-cad').click()
|
await cmdBar.openCmdBar()
|
||||||
|
await cmdBar.selectOption({ name: 'Text-to-CAD Create' }).click()
|
||||||
|
|
||||||
// Enter the prompt.
|
await cmdBar.expectState({
|
||||||
const prompt = page.getByRole('textbox', { name: 'Prompt' })
|
commandName: 'Text-to-CAD Create',
|
||||||
await expect(prompt.first()).toBeVisible()
|
stage: 'arguments',
|
||||||
|
currentArgKey: 'method',
|
||||||
|
currentArgValue: '',
|
||||||
|
highlightedHeaderArg: 'method',
|
||||||
|
headerArguments: {
|
||||||
|
Method: '',
|
||||||
|
Prompt: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await cmdBar.currentArgumentInput.fill('existing')
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
|
||||||
// Type the prompt.
|
await cmdBar.expectState({
|
||||||
await page.keyboard.type(promptStr)
|
commandName: 'Text-to-CAD Create',
|
||||||
await page.waitForTimeout(200)
|
stage: 'arguments',
|
||||||
await page.keyboard.press('Enter')
|
currentArgKey: 'projectName',
|
||||||
|
currentArgValue: '',
|
||||||
|
highlightedHeaderArg: 'projectName',
|
||||||
|
headerArguments: {
|
||||||
|
Method: 'Existing project',
|
||||||
|
ProjectName: '',
|
||||||
|
Prompt: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await cmdBar.currentArgumentInput.fill(projectName)
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
|
||||||
|
await cmdBar.expectState({
|
||||||
|
commandName: 'Text-to-CAD Create',
|
||||||
|
stage: 'arguments',
|
||||||
|
currentArgKey: 'prompt',
|
||||||
|
currentArgValue: '',
|
||||||
|
highlightedHeaderArg: 'prompt',
|
||||||
|
headerArguments: {
|
||||||
|
Method: 'Existing project',
|
||||||
|
ProjectName: projectName,
|
||||||
|
Prompt: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await cmdBar.currentArgumentInput.fill(promptStr)
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'Text-to-CAD functionality',
|
'Text-to-CAD functionality',
|
||||||
{ tag: '@electron' },
|
{ tag: '@electron' },
|
||||||
async ({ context, page }, testInfo) => {
|
async ({ context, page, cmdBar }, testInfo) => {
|
||||||
const projectName = 'project-000'
|
const projectName = 'project-000'
|
||||||
const prompt = 'lego 2x4'
|
const prompt = 'lego 2x4'
|
||||||
const textToCadFileName = 'lego-2x4.kcl'
|
const textToCadFileName = 'lego-2x4.kcl'
|
||||||
@ -603,7 +715,12 @@ test(
|
|||||||
await openKclCodePanel()
|
await openKclCodePanel()
|
||||||
|
|
||||||
await test.step(`Test file creation`, async () => {
|
await test.step(`Test file creation`, async () => {
|
||||||
await sendPromptFromCommandBarTriggeredByButton(page, prompt)
|
await sendPromptFromCommandBarAndSetExistingProject(
|
||||||
|
page,
|
||||||
|
prompt,
|
||||||
|
cmdBar,
|
||||||
|
projectName
|
||||||
|
)
|
||||||
// File is considered created if it shows up in the Project Files pane
|
// File is considered created if it shows up in the Project Files pane
|
||||||
await expect(textToCadFileButton).toBeVisible({ timeout: 20_000 })
|
await expect(textToCadFileButton).toBeVisible({ timeout: 20_000 })
|
||||||
expect(fileExists()).toBeTruthy()
|
expect(fileExists()).toBeTruthy()
|
||||||
|
@ -325,7 +325,7 @@ export function Toolbar({
|
|||||||
// A single button
|
// A single button
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="relative"
|
className={`relative ${itemConfig.alwaysDark ? ' dark bg-chalkboard-90 ' : ''}`}
|
||||||
key={itemConfig.id}
|
key={itemConfig.id}
|
||||||
// Mouse events do not fire on disabled buttons
|
// Mouse events do not fire on disabled buttons
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
|
@ -110,7 +110,7 @@ export function createApplicationCommands({
|
|||||||
const textToCADCommand: Command = {
|
const textToCADCommand: Command = {
|
||||||
name: 'Text-to-CAD',
|
name: 'Text-to-CAD',
|
||||||
description: 'Generate parts from text prompts.',
|
description: 'Generate parts from text prompts.',
|
||||||
displayName: 'Text to CAD',
|
displayName: 'Text-to-CAD Create',
|
||||||
groupId: 'application',
|
groupId: 'application',
|
||||||
needsReview: false,
|
needsReview: false,
|
||||||
status: IS_ML_EXPERIMENTAL ? 'experimental' : 'active',
|
status: IS_ML_EXPERIMENTAL ? 'experimental' : 'active',
|
||||||
|
@ -939,8 +939,10 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Prompt-to-edit': {
|
'Prompt-to-edit': {
|
||||||
description: 'Use Zoo AI to edit your parts and code.',
|
displayName: 'Text-to-CAD Edit',
|
||||||
icon: 'chat',
|
description:
|
||||||
|
'Use machine learning to edit your parts and code from a text prompt.',
|
||||||
|
icon: 'sparkles',
|
||||||
status: IS_ML_EXPERIMENTAL ? 'experimental' : 'active',
|
status: IS_ML_EXPERIMENTAL ? 'experimental' : 'active',
|
||||||
args: {
|
args: {
|
||||||
selection: {
|
selection: {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import type { EventFrom, StateFrom } from 'xstate'
|
import type { EventFrom, StateFrom } from 'xstate'
|
||||||
import { settingsActor } from '@src/lib/singletons'
|
|
||||||
|
|
||||||
import type { CustomIconName } from '@src/components/CustomIcon'
|
import type { CustomIconName } from '@src/components/CustomIcon'
|
||||||
import { createLiteral } from '@src/lang/create'
|
import { createLiteral } from '@src/lang/create'
|
||||||
@ -35,6 +34,7 @@ export type ToolbarItem = {
|
|||||||
id: string
|
id: string
|
||||||
onClick: (props: ToolbarItemCallbackProps) => void
|
onClick: (props: ToolbarItemCallbackProps) => void
|
||||||
icon?: CustomIconName
|
icon?: CustomIconName
|
||||||
|
className?: string
|
||||||
iconColor?: string
|
iconColor?: string
|
||||||
alwaysDark?: true
|
alwaysDark?: true
|
||||||
status: 'available' | 'unavailable' | 'kcl-only' | 'experimental'
|
status: 'available' | 'unavailable' | 'kcl-only' | 'experimental'
|
||||||
@ -424,39 +424,6 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
'break',
|
'break',
|
||||||
{
|
|
||||||
id: 'ai',
|
|
||||||
array: [
|
|
||||||
{
|
|
||||||
id: 'text-to-cad',
|
|
||||||
onClick: () => {
|
|
||||||
const currentProject =
|
|
||||||
settingsActor.getSnapshot().context.currentProject
|
|
||||||
commandBarActor.send({
|
|
||||||
type: 'Find and select command',
|
|
||||||
data: {
|
|
||||||
name: 'Text-to-CAD',
|
|
||||||
groupId: 'application',
|
|
||||||
argDefaultValues: {
|
|
||||||
method: 'existingProject',
|
|
||||||
projectName: currentProject?.name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
icon: 'sparkles',
|
|
||||||
iconColor: '#29FFA4',
|
|
||||||
alwaysDark: true,
|
|
||||||
status: IS_ML_EXPERIMENTAL ? 'experimental' : 'available',
|
|
||||||
title: 'Create with Zoo Text-to-CAD',
|
|
||||||
description: 'Create geometry with AI / ML.',
|
|
||||||
links: [
|
|
||||||
{
|
|
||||||
label: 'API docs',
|
|
||||||
url: 'https://zoo.dev/docs/api/ml/generate-a-cad-model-from-text',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'prompt-to-edit',
|
id: 'prompt-to-edit',
|
||||||
onClick: () =>
|
onClick: () =>
|
||||||
@ -468,14 +435,13 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
iconColor: '#29FFA4',
|
iconColor: '#29FFA4',
|
||||||
alwaysDark: true,
|
alwaysDark: true,
|
||||||
status: IS_ML_EXPERIMENTAL ? 'experimental' : 'available',
|
status: IS_ML_EXPERIMENTAL ? 'experimental' : 'available',
|
||||||
title: 'Modify with Zoo Text-to-CAD',
|
title: 'Text-to-CAD',
|
||||||
description: 'Edit geometry with AI / ML.',
|
description:
|
||||||
|
'Edit or create geometry from a text prompt and selection.',
|
||||||
links: [],
|
links: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
sketching: {
|
sketching: {
|
||||||
check: (state) =>
|
check: (state) =>
|
||||||
state.matches('Sketch') ||
|
state.matches('Sketch') ||
|
||||||
|