Show "experimental" badges around ML functionality (#6648)
* Make "experimental" a valid status for toolbar and commands
* Wire up status through createMachineCommand
* Add beaker icon
* Show UI elements if status is experimental
* Make ML operations experimental, powered by a flag
* Update command descriptions
* Add tooltip to home page Text-to-CAD button
* Splelnig erorrs
* 🧹lints
* Oopsie daisy Add KCL file isn't experimental
* Add warning message element to text area arg input
* Update message to common named constant
This commit is contained in:
@ -147,7 +147,7 @@ export class CmdBarFixture {
|
|||||||
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.page.getByText(
|
||||||
'Use Zoo AI to edit your kcl'
|
'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()
|
||||||
|
@ -95,7 +95,7 @@ export function Toolbar({
|
|||||||
|
|
||||||
const tooltipContentClassName = !showRichContent
|
const tooltipContentClassName = !showRichContent
|
||||||
? ''
|
? ''
|
||||||
: '!text-left text-wrap !text-xs !p-0 !pb-2 flex gap-2 !max-w-none !w-72 flex-col items-stretch'
|
: '!text-left text-wrap !text-xs !p-0 !pb-2 flex !max-w-none !w-72 flex-col items-stretch'
|
||||||
const richContentTimeout = useRef<number | null>(null)
|
const richContentTimeout = useRef<number | null>(null)
|
||||||
const richContentClearTimeout = useRef<number | null>(null)
|
const richContentClearTimeout = useRef<number | null>(null)
|
||||||
// On mouse enter, show rich content after a 1s delay
|
// On mouse enter, show rich content after a 1s delay
|
||||||
@ -155,9 +155,12 @@ export function Toolbar({
|
|||||||
maybeIconConfig: ToolbarItem,
|
maybeIconConfig: ToolbarItem,
|
||||||
dropdownId?: string
|
dropdownId?: string
|
||||||
): ToolbarItemResolved {
|
): ToolbarItemResolved {
|
||||||
|
const isConfiguredAvailable = ['available', 'experimental'].includes(
|
||||||
|
maybeIconConfig.status
|
||||||
|
)
|
||||||
const isDisabled =
|
const isDisabled =
|
||||||
disableAllButtons ||
|
disableAllButtons ||
|
||||||
maybeIconConfig.status !== 'available' ||
|
!isConfiguredAvailable ||
|
||||||
maybeIconConfig.disabled?.(state) === true
|
maybeIconConfig.disabled?.(state) === true
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -248,7 +251,9 @@ export function Toolbar({
|
|||||||
onClick: () => itemConfig.onClick(configCallbackProps),
|
onClick: () => itemConfig.onClick(configCallbackProps),
|
||||||
disabled:
|
disabled:
|
||||||
disableAllButtons ||
|
disableAllButtons ||
|
||||||
itemConfig.status !== 'available' ||
|
!['available', 'experimental'].includes(
|
||||||
|
itemConfig.status
|
||||||
|
) ||
|
||||||
itemConfig.disabled === true,
|
itemConfig.disabled === true,
|
||||||
status: itemConfig.status,
|
status: itemConfig.status,
|
||||||
}))}
|
}))}
|
||||||
@ -276,7 +281,9 @@ export function Toolbar({
|
|||||||
aria-pressed={selectedIcon.isActive}
|
aria-pressed={selectedIcon.isActive}
|
||||||
disabled={
|
disabled={
|
||||||
disableAllButtons ||
|
disableAllButtons ||
|
||||||
selectedIcon.status !== 'available' ||
|
!['available', 'experimental'].includes(
|
||||||
|
selectedIcon.status
|
||||||
|
) ||
|
||||||
selectedIcon.disabled
|
selectedIcon.disabled
|
||||||
}
|
}
|
||||||
name={selectedIcon.title}
|
name={selectedIcon.title}
|
||||||
@ -347,7 +354,7 @@ export function Toolbar({
|
|||||||
aria-pressed={itemConfig.isActive}
|
aria-pressed={itemConfig.isActive}
|
||||||
disabled={
|
disabled={
|
||||||
disableAllButtons ||
|
disableAllButtons ||
|
||||||
itemConfig.status !== 'available' ||
|
!['available', 'experimental'].includes(itemConfig.status) ||
|
||||||
itemConfig.disabled
|
itemConfig.disabled
|
||||||
}
|
}
|
||||||
onClick={() => itemConfig.onClick(configCallbackProps)}
|
onClick={() => itemConfig.onClick(configCallbackProps)}
|
||||||
@ -409,7 +416,7 @@ const ToolbarItemTooltip = memo(function ToolbarItemContents({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled:
|
enabled:
|
||||||
itemConfig.status === 'available' &&
|
['available', 'experimental'].includes(itemConfig.status) &&
|
||||||
!!itemConfig.hotkey &&
|
!!itemConfig.hotkey &&
|
||||||
!itemConfig.disabled &&
|
!itemConfig.disabled &&
|
||||||
!itemConfig.disableHotkey,
|
!itemConfig.disableHotkey,
|
||||||
@ -444,18 +451,28 @@ const ToolbarItemTooltipShortContent = ({
|
|||||||
title: string
|
title: string
|
||||||
hotkey?: string | string[]
|
hotkey?: string | string[]
|
||||||
}) => (
|
}) => (
|
||||||
<span
|
<div
|
||||||
className={`text-sm ${
|
className={`text-sm flex flex-col ${
|
||||||
status !== 'available' ? 'text-chalkboard-70 dark:text-chalkboard-40' : ''
|
!['available', 'experimental'].includes(status)
|
||||||
|
? 'text-chalkboard-70 dark:text-chalkboard-40'
|
||||||
|
: ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{title}
|
{status === 'experimental' && (
|
||||||
{hotkey && (
|
<div className="text-xs flex justify-center item-center gap-1 pb-1 border-b border-chalkboard-50">
|
||||||
<kbd className="inline-block ml-2 flex-none hotkey">
|
<CustomIcon name="beaker" className="w-4 h-4" />
|
||||||
{displayHotkeys(hotkey)}
|
<span>Experimental</span>
|
||||||
</kbd>
|
</div>
|
||||||
)}
|
)}
|
||||||
</span>
|
<div className={`flex gap-4 ${status === 'experimental' ? 'pt-1' : 'p-0'}`}>
|
||||||
|
{title}
|
||||||
|
{hotkey && (
|
||||||
|
<kbd className="inline-block ml-2 flex-none hotkey">
|
||||||
|
{displayHotkeys(hotkey)}
|
||||||
|
</kbd>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const ToolbarItemTooltipRichContent = ({
|
const ToolbarItemTooltipRichContent = ({
|
||||||
@ -463,9 +480,18 @@ const ToolbarItemTooltipRichContent = ({
|
|||||||
}: {
|
}: {
|
||||||
itemConfig: ToolbarItemResolved
|
itemConfig: ToolbarItemResolved
|
||||||
}) => {
|
}) => {
|
||||||
|
const shouldBeEnabled = ['available', 'experimental'].includes(
|
||||||
|
itemConfig.status
|
||||||
|
)
|
||||||
const { state } = useModelingContext()
|
const { state } = useModelingContext()
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{itemConfig.status === 'experimental' && (
|
||||||
|
<div className="text-xs flex items-center justify-center self-stretch gap-1 p-1 border-b">
|
||||||
|
<CustomIcon name="beaker" className="w-4 h-4" />
|
||||||
|
<span className="block">Experimental</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="rounded-top flex items-center gap-2 pt-3 pb-2 px-2 bg-chalkboard-20/50 dark:bg-chalkboard-80/50">
|
<div className="rounded-top flex items-center gap-2 pt-3 pb-2 px-2 bg-chalkboard-20/50 dark:bg-chalkboard-80/50">
|
||||||
{itemConfig.icon && (
|
{itemConfig.icon && (
|
||||||
<CustomIcon
|
<CustomIcon
|
||||||
@ -474,16 +500,14 @@ const ToolbarItemTooltipRichContent = ({
|
|||||||
name={itemConfig.icon}
|
name={itemConfig.icon}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<span
|
<div
|
||||||
className={`text-sm flex-1 ${
|
className={`text-sm flex-1 flex flex-col gap-1 ${
|
||||||
itemConfig.status !== 'available'
|
!shouldBeEnabled ? 'text-chalkboard-70 dark:text-chalkboard-40' : ''
|
||||||
? 'text-chalkboard-70 dark:text-chalkboard-40'
|
|
||||||
: ''
|
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{itemConfig.title}
|
{itemConfig.title}
|
||||||
</span>
|
</div>
|
||||||
{itemConfig.status === 'available' && itemConfig.hotkey ? (
|
{shouldBeEnabled && itemConfig.hotkey ? (
|
||||||
<kbd className="flex-none hotkey">
|
<kbd className="flex-none hotkey">
|
||||||
{displayHotkeys(itemConfig.hotkey)}
|
{displayHotkeys(itemConfig.hotkey)}
|
||||||
</kbd>
|
</kbd>
|
||||||
@ -511,12 +535,12 @@ const ToolbarItemTooltipRichContent = ({
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="px-2 text-ch font-sans">{itemConfig.description}</p>
|
<p className="px-2 my-2 text-ch font-sans">{itemConfig.description}</p>
|
||||||
{/* Add disabled reason if item is disabled */}
|
{/* Add disabled reason if item is disabled */}
|
||||||
{itemConfig.disabled && itemConfig.disabledReason && (
|
{itemConfig.disabled && itemConfig.disabledReason && (
|
||||||
<>
|
<>
|
||||||
<hr className="border-chalkboard-20 dark:border-chalkboard-80" />
|
<hr className="border-chalkboard-20 dark:border-chalkboard-80" />
|
||||||
<p className="px-2 text-ch font-sans text-chalkboard-70 dark:text-chalkboard-40">
|
<p className="px-2 my-2 text-ch font-sans text-chalkboard-70 dark:text-chalkboard-40">
|
||||||
{typeof itemConfig.disabledReason === 'function'
|
{typeof itemConfig.disabledReason === 'function'
|
||||||
? itemConfig.disabledReason(state)
|
? itemConfig.disabledReason(state)
|
||||||
: itemConfig.disabledReason}
|
: itemConfig.disabledReason}
|
||||||
|
@ -13,7 +13,7 @@ type ActionButtonSplitProps = ActionButtonProps & { Element: 'button' } & {
|
|||||||
shortcut?: string
|
shortcut?: string
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
status?: 'available' | 'unavailable' | 'kcl-only'
|
status?: 'available' | 'unavailable' | 'kcl-only' | 'experimental'
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +101,9 @@ export function ActionButtonDropdown({
|
|||||||
{item.shortcut}
|
{item.shortcut}
|
||||||
</kbd>
|
</kbd>
|
||||||
) : null}
|
) : null}
|
||||||
|
{item.status === 'experimental' ? (
|
||||||
|
<CustomIcon name="beaker" className="w-4 h-4" />
|
||||||
|
) : null}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
@ -36,8 +36,13 @@ function CommandBarTextareaInput({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id="arg-form" onSubmit={handleSubmit} ref={formRef}>
|
<form
|
||||||
<label className="flex items-start rounded mx-4 my-4 border border-chalkboard-100 dark:border-chalkboard-80">
|
id="arg-form"
|
||||||
|
className="flex flex-col items-stretch gap-2 mx-4 my-4 "
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
ref={formRef}
|
||||||
|
>
|
||||||
|
<label className="flex items-start rounded border border-chalkboard-100 dark:border-chalkboard-80">
|
||||||
<span
|
<span
|
||||||
data-testid="cmd-bar-arg-name"
|
data-testid="cmd-bar-arg-name"
|
||||||
className="capitalize px-2 py-1 rounded-br bg-chalkboard-100 dark:bg-chalkboard-80 text-chalkboard-10 border-b border-b-chalkboard-100 dark:border-b-chalkboard-80"
|
className="capitalize px-2 py-1 rounded-br bg-chalkboard-100 dark:bg-chalkboard-80 text-chalkboard-10 border-b border-b-chalkboard-100 dark:border-b-chalkboard-80"
|
||||||
@ -86,6 +91,11 @@ function CommandBarTextareaInput({
|
|||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
{arg.warningMessage && (
|
||||||
|
<p className="text-warn-80 bg-warn-10 px-2 py-1 rounded-sm mt-3 mr-2 -mb-2 w-full text-sm cursor-default">
|
||||||
|
{arg.warningMessage}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</form>
|
</form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,12 @@ function CommandComboBox({
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{option.status === 'experimental' && (
|
||||||
|
<div className="text-xs flex items-center justify-center gap-1 text-primary">
|
||||||
|
<CustomIcon name="beaker" className="w-4 h-4" />
|
||||||
|
<span>Experimental</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Combobox.Option>
|
</Combobox.Option>
|
||||||
))}
|
))}
|
||||||
</Combobox.Options>
|
</Combobox.Options>
|
||||||
|
@ -106,6 +106,14 @@ const CustomIconMap = {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
|
beaker: (
|
||||||
|
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M13.4747 4.1582L12.5353 6.97363L15.8322 14.3906L15.9015 14.5781C16.1808 15.5181 15.4786 16.5 14.4611 16.5H5.61828C4.50321 16.5 3.77781 15.3265 4.27649 14.3291L7.96008 6.96191L7.02551 4.1582L7.50012 3.5H13.0001L13.4747 4.1582ZM13.6183 11.873C13.2276 11.7045 12.8282 11.6908 12.38 11.7686C11.8504 11.8605 11.3185 12.0648 10.6671 12.2764C9.48553 12.6601 8.08344 12.9938 6.49133 12.1348L5.17102 14.7764C5.00479 15.1088 5.24659 15.5 5.61828 15.5H14.4611C14.8002 15.5 15.0346 15.1727 14.9415 14.8594L14.9181 14.7969L13.6183 11.873ZM8.97473 6.8418L9.04016 7.03809L6.9386 11.2402C8.17525 11.9192 9.24713 11.6862 10.3585 11.3252C10.9385 11.1368 11.5865 10.8913 12.2091 10.7832C12.5041 10.732 12.8059 10.7103 13.1124 10.7344L11.5431 7.20312L11.464 7.02539L11.5255 6.8418L12.3058 4.5H8.19445L8.97473 6.8418Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
booleanExclude: (
|
booleanExclude: (
|
||||||
<svg
|
<svg
|
||||||
viewBox="0 0 20 20"
|
viewBox="0 0 20 20"
|
||||||
|
@ -5,7 +5,11 @@ import { SystemIOMachineEvents } from '@src/machines/systemIO/utils'
|
|||||||
import { isDesktop } from '@src/lib/isDesktop'
|
import { isDesktop } from '@src/lib/isDesktop'
|
||||||
import { kclSamplesManifestWithNoMultipleFiles } from '@src/lib/kclSamples'
|
import { kclSamplesManifestWithNoMultipleFiles } from '@src/lib/kclSamples'
|
||||||
import { getUniqueProjectName } from '@src/lib/desktopFS'
|
import { getUniqueProjectName } from '@src/lib/desktopFS'
|
||||||
import { FILE_EXT } from '@src/lib/constants'
|
import {
|
||||||
|
FILE_EXT,
|
||||||
|
IS_ML_EXPERIMENTAL,
|
||||||
|
ML_EXPERIMENTAL_MESSAGE,
|
||||||
|
} from '@src/lib/constants'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import { reportRejection } from '@src/lib/trap'
|
import { reportRejection } from '@src/lib/trap'
|
||||||
import { relevantFileExtensions } from '@src/lang/wasmUtils'
|
import { relevantFileExtensions } from '@src/lang/wasmUtils'
|
||||||
@ -17,10 +21,11 @@ export function createApplicationCommands({
|
|||||||
}) {
|
}) {
|
||||||
const textToCADCommand: Command = {
|
const textToCADCommand: Command = {
|
||||||
name: 'Text-to-CAD',
|
name: 'Text-to-CAD',
|
||||||
description: 'Use the Zoo Text-to-CAD API to generate part starters.',
|
description: 'Generate parts from text prompts.',
|
||||||
displayName: `Text to CAD`,
|
displayName: 'Text to CAD',
|
||||||
groupId: 'application',
|
groupId: 'application',
|
||||||
needsReview: false,
|
needsReview: false,
|
||||||
|
status: IS_ML_EXPERIMENTAL ? 'experimental' : 'active',
|
||||||
icon: 'sparkles',
|
icon: 'sparkles',
|
||||||
onSubmit: (record) => {
|
onSubmit: (record) => {
|
||||||
if (record) {
|
if (record) {
|
||||||
@ -81,6 +86,7 @@ export function createApplicationCommands({
|
|||||||
prompt: {
|
prompt: {
|
||||||
inputType: 'text',
|
inputType: 'text',
|
||||||
required: true,
|
required: true,
|
||||||
|
warningMessage: ML_EXPERIMENTAL_MESSAGE,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,12 @@ import type {
|
|||||||
StateMachineCommandSetConfig,
|
StateMachineCommandSetConfig,
|
||||||
} from '@src/lib/commandTypes'
|
} from '@src/lib/commandTypes'
|
||||||
import {
|
import {
|
||||||
|
IS_ML_EXPERIMENTAL,
|
||||||
KCL_DEFAULT_CONSTANT_PREFIXES,
|
KCL_DEFAULT_CONSTANT_PREFIXES,
|
||||||
KCL_DEFAULT_DEGREE,
|
KCL_DEFAULT_DEGREE,
|
||||||
KCL_DEFAULT_LENGTH,
|
KCL_DEFAULT_LENGTH,
|
||||||
KCL_DEFAULT_TRANSFORM,
|
KCL_DEFAULT_TRANSFORM,
|
||||||
|
ML_EXPERIMENTAL_MESSAGE,
|
||||||
} from '@src/lib/constants'
|
} from '@src/lib/constants'
|
||||||
import type { components } from '@src/lib/machine-api'
|
import type { components } from '@src/lib/machine-api'
|
||||||
import type { Selections } from '@src/lib/selections'
|
import type { Selections } from '@src/lib/selections'
|
||||||
@ -964,8 +966,9 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Prompt-to-edit': {
|
'Prompt-to-edit': {
|
||||||
description: 'Use Zoo AI to edit your kcl',
|
description: 'Use Zoo AI to edit your parts and code.',
|
||||||
icon: 'chat',
|
icon: 'chat',
|
||||||
|
status: IS_ML_EXPERIMENTAL ? 'experimental' : 'active',
|
||||||
args: {
|
args: {
|
||||||
selection: {
|
selection: {
|
||||||
inputType: 'selectionMixed',
|
inputType: 'selectionMixed',
|
||||||
@ -989,6 +992,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
prompt: {
|
prompt: {
|
||||||
inputType: 'text',
|
inputType: 'text',
|
||||||
required: true,
|
required: true,
|
||||||
|
warningMessage: ML_EXPERIMENTAL_MESSAGE,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -40,7 +40,7 @@ export interface KclExpressionWithVariable extends KclExpression {
|
|||||||
}
|
}
|
||||||
export type KclCommandValue = KclExpression | KclExpressionWithVariable
|
export type KclCommandValue = KclExpression | KclExpressionWithVariable
|
||||||
export type CommandInputType = INPUT_TYPE[number]
|
export type CommandInputType = INPUT_TYPE[number]
|
||||||
|
type CommandStatus = 'active' | 'development' | 'inactive' | 'experimental'
|
||||||
export type FileFilter = {
|
export type FileFilter = {
|
||||||
name: string
|
name: string
|
||||||
extensions: string[]
|
extensions: string[]
|
||||||
@ -103,6 +103,7 @@ export type Command<
|
|||||||
icon?: Icon
|
icon?: Icon
|
||||||
hide?: PLATFORM[number]
|
hide?: PLATFORM[number]
|
||||||
hideFromSearch?: boolean
|
hideFromSearch?: boolean
|
||||||
|
status?: CommandStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CommandConfig<
|
export type CommandConfig<
|
||||||
@ -115,7 +116,7 @@ export type CommandConfig<
|
|||||||
'name' | 'groupId' | 'onSubmit' | 'onCancel' | 'args' | 'needsReview'
|
'name' | 'groupId' | 'onSubmit' | 'onCancel' | 'args' | 'needsReview'
|
||||||
> & {
|
> & {
|
||||||
needsReview?: boolean
|
needsReview?: boolean
|
||||||
status?: 'active' | 'development' | 'inactive'
|
status?: CommandStatus
|
||||||
args?: {
|
args?: {
|
||||||
[ArgName in keyof CommandSchema]: CommandArgumentConfig<
|
[ArgName in keyof CommandSchema]: CommandArgumentConfig<
|
||||||
CommandSchema[ArgName],
|
CommandSchema[ArgName],
|
||||||
|
@ -190,3 +190,8 @@ export type ExecutionType =
|
|||||||
|
|
||||||
/** Key for setting window.localStorage.setItem and .getItem to determine if the runtime is playwright for browsers */
|
/** Key for setting window.localStorage.setItem and .getItem to determine if the runtime is playwright for browsers */
|
||||||
export const IS_PLAYWRIGHT_KEY = 'playwright'
|
export const IS_PLAYWRIGHT_KEY = 'playwright'
|
||||||
|
|
||||||
|
/** Should we mark all the ML features as "beta"? */
|
||||||
|
export const IS_ML_EXPERIMENTAL = true
|
||||||
|
export const ML_EXPERIMENTAL_MESSAGE =
|
||||||
|
'This feature is experimental and undergoing constant improvement, stay tuned for updates.'
|
||||||
|
@ -123,6 +123,9 @@ export function createMachineCommand<
|
|||||||
if ('reviewMessage' in commandConfig) {
|
if ('reviewMessage' in commandConfig) {
|
||||||
command.reviewMessage = commandConfig.reviewMessage
|
command.reviewMessage = commandConfig.reviewMessage
|
||||||
}
|
}
|
||||||
|
if ('status' in commandConfig) {
|
||||||
|
command.status = commandConfig.status
|
||||||
|
}
|
||||||
|
|
||||||
return command
|
return command
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
isEditingExistingSketch,
|
isEditingExistingSketch,
|
||||||
pipeHasCircle,
|
pipeHasCircle,
|
||||||
} from '@src/machines/modelingMachine'
|
} from '@src/machines/modelingMachine'
|
||||||
|
import { IS_ML_EXPERIMENTAL } from '@src/lib/constants'
|
||||||
|
|
||||||
export type ToolbarModeName = 'modeling' | 'sketching'
|
export type ToolbarModeName = 'modeling' | 'sketching'
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ export type ToolbarItem = {
|
|||||||
icon?: CustomIconName
|
icon?: CustomIconName
|
||||||
iconColor?: string
|
iconColor?: string
|
||||||
alwaysDark?: true
|
alwaysDark?: true
|
||||||
status: 'available' | 'unavailable' | 'kcl-only'
|
status: 'available' | 'unavailable' | 'kcl-only' | 'experimental'
|
||||||
disabled?: (state: StateFrom<typeof modelingMachine>) => boolean
|
disabled?: (state: StateFrom<typeof modelingMachine>) => boolean
|
||||||
disableHotkey?: (state: StateFrom<typeof modelingMachine>) => boolean
|
disableHotkey?: (state: StateFrom<typeof modelingMachine>) => boolean
|
||||||
title: string | ((props: ToolbarItemCallbackProps) => string)
|
title: string | ((props: ToolbarItemCallbackProps) => string)
|
||||||
@ -440,7 +441,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
icon: 'sparkles',
|
icon: 'sparkles',
|
||||||
iconColor: '#29FFA4',
|
iconColor: '#29FFA4',
|
||||||
alwaysDark: true,
|
alwaysDark: true,
|
||||||
status: 'available',
|
status: IS_ML_EXPERIMENTAL ? 'experimental' : 'available',
|
||||||
title: 'Create with Zoo Text-to-CAD',
|
title: 'Create with Zoo Text-to-CAD',
|
||||||
description: 'Create geometry with AI / ML.',
|
description: 'Create geometry with AI / ML.',
|
||||||
links: [
|
links: [
|
||||||
@ -460,7 +461,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
icon: 'sparkles',
|
icon: 'sparkles',
|
||||||
iconColor: '#29FFA4',
|
iconColor: '#29FFA4',
|
||||||
alwaysDark: true,
|
alwaysDark: true,
|
||||||
status: 'available',
|
status: IS_ML_EXPERIMENTAL ? 'experimental' : 'available',
|
||||||
title: 'Modify with Zoo Text-to-CAD',
|
title: 'Modify with Zoo Text-to-CAD',
|
||||||
description: 'Edit geometry with AI / ML.',
|
description: 'Edit geometry with AI / ML.',
|
||||||
links: [],
|
links: [],
|
||||||
|
@ -49,7 +49,9 @@ import {
|
|||||||
needsToOnboard,
|
needsToOnboard,
|
||||||
onDismissOnboardingInvite,
|
onDismissOnboardingInvite,
|
||||||
} from '@src/routes/Onboarding/utils'
|
} from '@src/routes/Onboarding/utils'
|
||||||
|
import { CustomIcon } from '@src/components/CustomIcon'
|
||||||
import Tooltip from '@src/components/Tooltip'
|
import Tooltip from '@src/components/Tooltip'
|
||||||
|
import { ML_EXPERIMENTAL_MESSAGE } from '@src/lib/constants'
|
||||||
|
|
||||||
type ReadWriteProjectState = {
|
type ReadWriteProjectState = {
|
||||||
value: boolean
|
value: boolean
|
||||||
@ -299,6 +301,15 @@ const Home = () => {
|
|||||||
data-testid="home-text-to-cad"
|
data-testid="home-text-to-cad"
|
||||||
>
|
>
|
||||||
Generate with Text-to-CAD
|
Generate with Text-to-CAD
|
||||||
|
<Tooltip position="bottom-left">
|
||||||
|
<div className="text-sm flex flex-col max-w-xs">
|
||||||
|
<div className="text-xs flex justify-center item-center gap-1 pb-1 border-b border-chalkboard-50">
|
||||||
|
<CustomIcon name="beaker" className="w-4 h-4" />
|
||||||
|
<span>Experimental</span>
|
||||||
|
</div>
|
||||||
|
<p className="pt-2 text-left">{ML_EXPERIMENTAL_MESSAGE}</p>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</li>
|
</li>
|
||||||
<li className="contents">
|
<li className="contents">
|
||||||
|
Reference in New Issue
Block a user