From 2e7d71d459d5c6be9b95d5dc866de46a33597b9f Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Wed, 3 Jan 2024 14:37:52 +0100 Subject: [PATCH] Refactor widgets to handle dynamic config in input (#8624) * Merged ArgumentAst and ArgumentPlaceholder into single class. * Created `AnyWidget` input being a "general use" widget input. Most wigets try to match with it; the `Argument` input is now solely for WidgetArgument(Name) or those handling arguments in a specific way (like selector which want to show on arg name click). * dynamic config is now part of widget input, and is properly propagated through vector editor/function widgets. # Important Notes The widgets still does not work perfectly: * The chosen options often don't have argument placeholders - that's because we don't display them for constructors. Needs to be added on our side, or engine should send us methodCall info for constructors. * There are issues with engine's messages sent to us. This makes widgets does not set up (so there is no drop-down, or vector adds `_` instead of default). I'm investigating them and going to fill issues. --- .../shared/languageServerTypes/suggestions.ts | 2 +- app/gui2/src/App.vue | 2 +- app/gui2/src/components/GraphEditor.vue | 29 +-- .../src/components/GraphEditor/NodeWidget.vue | 4 - .../components/GraphEditor/NodeWidgetTree.vue | 6 +- .../GraphEditor/widgets/WidgetApplication.vue | 12 +- .../GraphEditor/widgets/WidgetArgument.vue | 2 +- .../widgets/WidgetArgumentName.vue | 17 +- .../GraphEditor/widgets/WidgetBlank.vue | 13 +- .../GraphEditor/widgets/WidgetCheckbox.vue | 26 +-- .../GraphEditor/widgets/WidgetFunction.vue | 75 +++--- .../GraphEditor/widgets/WidgetHierarchy.vue | 32 +-- .../GraphEditor/widgets/WidgetNumber.vue | 32 ++- .../GraphEditor/widgets/WidgetPort.vue | 72 +++--- .../GraphEditor/widgets/WidgetSelection.vue | 96 ++++---- .../widgets/WidgetTopLevelArgument.vue | 2 +- .../GraphEditor/widgets/WidgetVector.vue | 44 ++-- .../__tests__/widgetRegistry.test.ts | 36 +-- app/gui2/src/providers/portInfo.ts | 4 +- app/gui2/src/providers/widgetRegistry.ts | 69 +++++- .../providers/widgetRegistry/configuration.ts | 104 +++++---- app/gui2/src/stores/graph/graphDatabase.ts | 3 +- .../__tests__/lsUpdate.test.ts | 10 +- .../src/stores/suggestionDatabase/entry.ts | 9 + .../src/stores/suggestionDatabase/lsUpdate.ts | 2 +- .../src/util/ast/__tests__/callTree.test.ts | 202 +++++++++------- app/gui2/src/util/ast/abstract.ts | 2 - app/gui2/src/util/ast/extended.ts | 7 - app/gui2/src/util/callTree.ts | 215 ++++++++++++------ .../protocol-language-server.md | 2 +- 30 files changed, 684 insertions(+), 447 deletions(-) diff --git a/app/gui2/shared/languageServerTypes/suggestions.ts b/app/gui2/shared/languageServerTypes/suggestions.ts index af54950c09c6..a00f28a42dbc 100644 --- a/app/gui2/shared/languageServerTypes/suggestions.ts +++ b/app/gui2/shared/languageServerTypes/suggestions.ts @@ -7,7 +7,7 @@ export interface SuggestionEntryArgument { /** The argument name. */ name: string /** The argument type. String 'Any' is used to specify generic types. */ - type: string + reprType: string /** Indicates whether the argument is lazy. */ isSuspended: boolean /** Indicates whether the argument has default value. */ diff --git a/app/gui2/src/App.vue b/app/gui2/src/App.vue index c1d9e98d1c45..eae2397ad97d 100644 --- a/app/gui2/src/App.vue +++ b/app/gui2/src/App.vue @@ -9,7 +9,7 @@ import { computed, onMounted } from 'vue' const props = defineProps<{ config: ApplicationConfig - accessToken: string + accessToken: string | null metadata: object unrecognizedOptions: string[] }>() diff --git a/app/gui2/src/components/GraphEditor.vue b/app/gui2/src/components/GraphEditor.vue index 132f3983f88e..51e577012cf1 100644 --- a/app/gui2/src/components/GraphEditor.vue +++ b/app/gui2/src/components/GraphEditor.vue @@ -30,10 +30,11 @@ import { Rect } from '@/util/data/rect' import { Vec2 } from '@/util/data/vec2' import * as set from 'lib0/set' import type { ExprId, NodeMetadata } from 'shared/yjsModel' -import { computed, onMounted, onUnmounted, ref, watch } from 'vue' -import { toast } from 'vue3-toastify' +import { computed, onMounted, onScopeDispose, ref, watch } from 'vue' +import { toast, type Id as ToastId } from 'vue3-toastify' import { type Usage } from './ComponentBrowser/input' +const STARTUP_TOAST_DELAY_MS = 100 const EXECUTION_MODES = ['design', 'live'] // Assumed size of a newly created node. This is used to place the component browser. const DEFAULT_NODE_SIZE = new Vec2(0, 24) @@ -52,19 +53,13 @@ const suggestionDb = useSuggestionDbStore() const interaction = provideInteractionHandler() function initStartupToast() { - const startupToast = toast.info('Initializing the project. This can take up to one minute.', { + let startupToast = toast.info('Initializing the project. This can take up to one minute.', { autoClose: false, }) - projectStore.firstExecution.then(() => { - if (startupToast != null) { - toast.remove(startupToast) - } - }) - onUnmounted(() => { - if (startupToast != null) { - toast.remove(startupToast) - } - }) + + const removeToast = () => toast.remove(startupToast) + projectStore.firstExecution.then(removeToast) + onScopeDispose(removeToast) } onMounted(() => { @@ -548,14 +543,6 @@ function handleEdgeDrop(source: ExprId, position: Vec2) { @dragover.prevent @drop.prevent="handleFileDrop($event)" > -
import type { PortId } from '@/providers/portInfo' import { injectWidgetRegistry, type WidgetInput } from '@/providers/widgetRegistry' -import type { WidgetConfiguration } from '@/providers/widgetRegistry/configuration' import { injectWidgetTree } from '@/providers/widgetTree' import { injectWidgetUsageInfo, @@ -14,7 +13,6 @@ import { computed, proxyRefs } from 'vue' const props = defineProps<{ input: WidgetInput nest?: boolean - dynamicConfig?: WidgetConfiguration | undefined /** * A function that intercepts and handles a value update emitted by this widget. When it returns * `false`, the update continues to be propagated to the parent widget. When it returns `true`, @@ -43,7 +41,6 @@ const selectedWidget = computed(() => { return registry.select( { input: props.input, - config: props.dynamicConfig ?? undefined, nesting: nesting.value, }, sameInputParentWidgets.value, @@ -95,7 +92,6 @@ const spanStart = computed(() => { v-if="selectedWidget" ref="rootNode" :input="props.input" - :config="dynamicConfig" :nesting="nesting" :data-span-start="spanStart" @update="updateHandler" diff --git a/app/gui2/src/components/GraphEditor/NodeWidgetTree.vue b/app/gui2/src/components/GraphEditor/NodeWidgetTree.vue index 064406b2db67..3dd354f4471e 100644 --- a/app/gui2/src/components/GraphEditor/NodeWidgetTree.vue +++ b/app/gui2/src/components/GraphEditor/NodeWidgetTree.vue @@ -2,6 +2,7 @@ import NodeWidget from '@/components/GraphEditor/NodeWidget.vue' import { useTransitioning } from '@/composables/animation' import { ForcePort, type PortId } from '@/providers/portInfo' +import { AnyWidget } from '@/providers/widgetRegistry' import { provideWidgetTree } from '@/providers/widgetTree' import { useGraphStore } from '@/stores/graph' import { Ast } from '@/util/ast' @@ -11,9 +12,10 @@ import { computed, toRef } from 'vue' const props = defineProps<{ ast: Ast.Ast }>() const graph = useGraphStore() const rootPort = computed(() => { + const input = AnyWidget.Ast(props.ast) return props.ast instanceof Ast.Ident && !graph.db.isKnownFunctionCall(props.ast.exprId) - ? new ForcePort(props.ast) - : props.ast + ? new ForcePort(input) + : input }) const observedLayoutTransitions = new Set([ diff --git a/app/gui2/src/components/GraphEditor/widgets/WidgetApplication.vue b/app/gui2/src/components/GraphEditor/widgets/WidgetApplication.vue index 177f690bbc6b..b88600dfc50a 100644 --- a/app/gui2/src/components/GraphEditor/widgets/WidgetApplication.vue +++ b/app/gui2/src/components/GraphEditor/widgets/WidgetApplication.vue @@ -1,14 +1,18 @@ diff --git a/app/gui2/src/components/GraphEditor/widgets/WidgetArgumentName.vue b/app/gui2/src/components/GraphEditor/widgets/WidgetArgumentName.vue index 37b0014c7528..7dc6a4ac7260 100644 --- a/app/gui2/src/components/GraphEditor/widgets/WidgetArgumentName.vue +++ b/app/gui2/src/components/GraphEditor/widgets/WidgetArgumentName.vue @@ -22,24 +22,23 @@ const primary = computed(() => props.nesting < 2) diff --git a/app/gui2/src/components/GraphEditor/widgets/WidgetBlank.vue b/app/gui2/src/components/GraphEditor/widgets/WidgetBlank.vue index 6fa4e10e0c00..45ea03513e65 100644 --- a/app/gui2/src/components/GraphEditor/widgets/WidgetBlank.vue +++ b/app/gui2/src/components/GraphEditor/widgets/WidgetBlank.vue @@ -1,14 +1,17 @@