Add offset plane point-and-click user flow (#4552)
* Add a code mod for offset plane * Add support for default plane selections to our `otherSelections` object * Make availableVars work without a selection range (because default planes don't have one) * Make default planes selectable in cmdbar even if AST is empty * Add offset plane command and activate in toolbar * Avoid unnecessary error when sketching on offset plane by returning early * Add supporting test features for offset plane E2E test * Add WIP E2E test for offset plane Struggling to get local electron test suite running properly * Typos * Lints * Fix test by making it a web-based one: I couldn't use the cmdBar fixture with an electron test for some reason. * Update src/lib/commandBarConfigs/modelingCommandConfig.ts * Update src/machines/modelingMachine.ts * Revert changes to `homePageFixture`, as they were unused * @Irev-Dev feedback: convert action to actor, fix machine layout * Update plane icon to be not dashed, follow conventions closer
This commit is contained in:
		| @ -1,21 +1,26 @@ | ||||
| import { useSelector } from '@xstate/react' | ||||
| import { useCommandsContext } from 'hooks/useCommandsContext' | ||||
| import { useKclContext } from 'lang/KclProvider' | ||||
| import { Artifact } from 'lang/std/artifactGraph' | ||||
| import { CommandArgument } from 'lib/commandTypes' | ||||
| import { | ||||
|   canSubmitSelectionArg, | ||||
|   getSelectionType, | ||||
|   getSelectionCountByType, | ||||
|   getSelectionTypeDisplayText, | ||||
| } from 'lib/selections' | ||||
| import { kclManager } from 'lib/singletons' | ||||
| import { reportRejection } from 'lib/trap' | ||||
| import { toSync } from 'lib/utils' | ||||
| import { modelingMachine } from 'machines/modelingMachine' | ||||
| import { useEffect, useMemo, useRef, useState } from 'react' | ||||
| import { StateFrom } from 'xstate' | ||||
|  | ||||
| const semanticEntityNames: { [key: string]: Array<Artifact['type']> } = { | ||||
| const semanticEntityNames: { | ||||
|   [key: string]: Array<Artifact['type'] | 'defaultPlane'> | ||||
| } = { | ||||
|   face: ['wall', 'cap', 'solid2D'], | ||||
|   edge: ['segment', 'sweepEdge', 'edgeCutEdge'], | ||||
|   point: [], | ||||
|   plane: ['defaultPlane'], | ||||
| } | ||||
|  | ||||
| function getSemanticSelectionType(selectionType: Array<Artifact['type']>) { | ||||
| @ -43,21 +48,13 @@ function CommandBarSelectionInput({ | ||||
|   stepBack: () => void | ||||
|   onSubmit: (data: unknown) => void | ||||
| }) { | ||||
|   const { code } = useKclContext() | ||||
|   const inputRef = useRef<HTMLInputElement>(null) | ||||
|   const { commandBarState, commandBarSend } = useCommandsContext() | ||||
|   const [hasSubmitted, setHasSubmitted] = useState(false) | ||||
|   const selection = useSelector(arg.machineActor, selectionSelector) | ||||
|   const selectionsByType = useMemo(() => { | ||||
|     const selectionRangeEnd = !selection | ||||
|       ? null | ||||
|       : selection?.graphSelections[0]?.codeRef?.range[1] | ||||
|     return !selectionRangeEnd || selectionRangeEnd === code.length || !selection | ||||
|       ? 'none' | ||||
|       : !selection | ||||
|       ? 'none' | ||||
|       : getSelectionType(selection) | ||||
|   }, [selection, code]) | ||||
|     return getSelectionCountByType(selection) | ||||
|   }, [selection]) | ||||
|   const canSubmitSelection = useMemo<boolean>( | ||||
|     () => canSubmitSelectionArg(selectionsByType, arg), | ||||
|     [selectionsByType] | ||||
| @ -67,6 +64,30 @@ function CommandBarSelectionInput({ | ||||
|     inputRef.current?.focus() | ||||
|   }, [selection, inputRef]) | ||||
|  | ||||
|   // Show the default planes if the selection type is 'plane' | ||||
|   useEffect(() => { | ||||
|     if (arg.selectionTypes.includes('plane') && !canSubmitSelection) { | ||||
|       toSync(() => { | ||||
|         return Promise.all([ | ||||
|           kclManager.showPlanes(), | ||||
|           kclManager.setSelectionFilter(['plane', 'object']), | ||||
|         ]) | ||||
|       }, reportRejection)() | ||||
|     } | ||||
|  | ||||
|     return () => { | ||||
|       toSync(() => { | ||||
|         const promises = [ | ||||
|           new Promise(() => kclManager.defaultSelectionFilter()), | ||||
|         ] | ||||
|         if (!kclManager._isAstEmpty(kclManager.ast)) { | ||||
|           promises.push(kclManager.hidePlanes()) | ||||
|         } | ||||
|         return Promise.all(promises) | ||||
|       }, reportRejection)() | ||||
|     } | ||||
|   }, []) | ||||
|  | ||||
|   // Fast-forward through this arg if it's marked as skippable | ||||
|   // and we have a valid selection already | ||||
|   useEffect(() => { | ||||
| @ -109,11 +130,15 @@ function CommandBarSelectionInput({ | ||||
|             {arg.warningMessage} | ||||
|           </p> | ||||
|         )} | ||||
|         <span data-testid="cmd-bar-arg-name" className="sr-only"> | ||||
|           {arg.name} | ||||
|         </span> | ||||
|         <input | ||||
|           id="selection" | ||||
|           name="selection" | ||||
|           ref={inputRef} | ||||
|           required | ||||
|           data-testid="cmd-bar-arg-value" | ||||
|           placeholder="Select an entity with your mouse" | ||||
|           className="absolute inset-0 w-full h-full opacity-0 cursor-default" | ||||
|           onKeyDown={(event) => { | ||||
|  | ||||
		Reference in New Issue
	
	Block a user