@flowdrop/flowdrop 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +252 -0
- package/dist/adapters/WorkflowAdapter.d.ts +167 -0
- package/dist/adapters/WorkflowAdapter.js +368 -0
- package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +96 -0
- package/dist/adapters/agentspec/AgentSpecAdapter.js +626 -0
- package/dist/adapters/agentspec/agentAdapter.d.ts +59 -0
- package/dist/adapters/agentspec/agentAdapter.js +91 -0
- package/dist/adapters/agentspec/autoLayout.d.ts +34 -0
- package/dist/adapters/agentspec/autoLayout.js +127 -0
- package/dist/adapters/agentspec/componentTypeDefaults.d.ts +73 -0
- package/dist/adapters/agentspec/componentTypeDefaults.js +238 -0
- package/dist/adapters/agentspec/defaultNodeTypes.d.ts +53 -0
- package/dist/adapters/agentspec/defaultNodeTypes.js +561 -0
- package/dist/adapters/agentspec/index.d.ts +37 -0
- package/dist/adapters/agentspec/index.js +39 -0
- package/dist/adapters/agentspec/validator.d.ts +34 -0
- package/dist/adapters/agentspec/validator.js +169 -0
- package/dist/api/enhanced-client.d.ts +183 -0
- package/dist/api/enhanced-client.js +430 -0
- package/dist/components/App.svelte +981 -0
- package/dist/components/App.svelte.d.ts +54 -0
- package/dist/components/CanvasBanner.stories.svelte +29 -0
- package/dist/components/CanvasBanner.stories.svelte.d.ts +27 -0
- package/dist/components/CanvasBanner.svelte +57 -0
- package/dist/components/CanvasBanner.svelte.d.ts +8 -0
- package/dist/components/ConfigForm.svelte +1138 -0
- package/dist/components/ConfigForm.svelte.d.ts +44 -0
- package/dist/components/ConfigModal.svelte +188 -0
- package/dist/components/ConfigModal.svelte.d.ts +13 -0
- package/dist/components/ConfigPanel.stories.svelte +47 -0
- package/dist/components/ConfigPanel.stories.svelte.d.ts +27 -0
- package/dist/components/ConfigPanel.svelte +182 -0
- package/dist/components/ConfigPanel.svelte.d.ts +32 -0
- package/dist/components/ConnectionLine.svelte +32 -0
- package/dist/components/ConnectionLine.svelte.d.ts +3 -0
- package/dist/components/EdgeRefresher.svelte +41 -0
- package/dist/components/EdgeRefresher.svelte.d.ts +9 -0
- package/dist/components/FlowDropZone.svelte +83 -0
- package/dist/components/FlowDropZone.svelte.d.ts +13 -0
- package/dist/components/LoadingSpinner.stories.svelte +30 -0
- package/dist/components/LoadingSpinner.stories.svelte.d.ts +27 -0
- package/dist/components/LoadingSpinner.svelte +36 -0
- package/dist/components/LoadingSpinner.svelte.d.ts +8 -0
- package/dist/components/Logo.stories.svelte +22 -0
- package/dist/components/Logo.stories.svelte.d.ts +27 -0
- package/dist/components/Logo.svelte +102 -0
- package/dist/components/Logo.svelte.d.ts +26 -0
- package/dist/components/LogsSidebar.svelte +563 -0
- package/dist/components/LogsSidebar.svelte.d.ts +17 -0
- package/dist/components/MarkdownDisplay.stories.svelte +36 -0
- package/dist/components/MarkdownDisplay.stories.svelte.d.ts +27 -0
- package/dist/components/MarkdownDisplay.svelte +29 -0
- package/dist/components/MarkdownDisplay.svelte.d.ts +7 -0
- package/dist/components/Navbar.stories.svelte +53 -0
- package/dist/components/Navbar.stories.svelte.d.ts +27 -0
- package/dist/components/Navbar.svelte +726 -0
- package/dist/components/Navbar.svelte.d.ts +29 -0
- package/dist/components/NodeSidebar.svelte +762 -0
- package/dist/components/NodeSidebar.svelte.d.ts +9 -0
- package/dist/components/NodeStatusOverlay.stories.svelte +85 -0
- package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +27 -0
- package/dist/components/NodeStatusOverlay.svelte +327 -0
- package/dist/components/NodeStatusOverlay.svelte.d.ts +11 -0
- package/dist/components/PipelineStatus.svelte +314 -0
- package/dist/components/PipelineStatus.svelte.d.ts +20 -0
- package/dist/components/PortCoordinateTracker.svelte +58 -0
- package/dist/components/PortCoordinateTracker.svelte.d.ts +12 -0
- package/dist/components/ReadOnlyDetails.svelte +170 -0
- package/dist/components/ReadOnlyDetails.svelte.d.ts +25 -0
- package/dist/components/SchemaForm.stories.svelte +116 -0
- package/dist/components/SchemaForm.stories.svelte.d.ts +27 -0
- package/dist/components/SchemaForm.svelte +536 -0
- package/dist/components/SchemaForm.svelte.d.ts +83 -0
- package/dist/components/SettingsModal.svelte +279 -0
- package/dist/components/SettingsModal.svelte.d.ts +23 -0
- package/dist/components/SettingsPanel.svelte +638 -0
- package/dist/components/SettingsPanel.svelte.d.ts +21 -0
- package/dist/components/StatusIcon.stories.svelte +60 -0
- package/dist/components/StatusIcon.stories.svelte.d.ts +27 -0
- package/dist/components/StatusIcon.svelte +119 -0
- package/dist/components/StatusIcon.svelte.d.ts +10 -0
- package/dist/components/StatusLabel.stories.svelte +17 -0
- package/dist/components/StatusLabel.stories.svelte.d.ts +27 -0
- package/dist/components/StatusLabel.svelte +33 -0
- package/dist/components/StatusLabel.svelte.d.ts +7 -0
- package/dist/components/ThemeToggle.stories.svelte +25 -0
- package/dist/components/ThemeToggle.stories.svelte.d.ts +27 -0
- package/dist/components/ThemeToggle.svelte +185 -0
- package/dist/components/ThemeToggle.svelte.d.ts +14 -0
- package/dist/components/UniversalNode.svelte +155 -0
- package/dist/components/UniversalNode.svelte.d.ts +15 -0
- package/dist/components/WorkflowEditor.svelte +1035 -0
- package/dist/components/WorkflowEditor.svelte.d.ts +23 -0
- package/dist/components/form/FormArray.svelte +1049 -0
- package/dist/components/form/FormArray.svelte.d.ts +22 -0
- package/dist/components/form/FormAutocomplete.svelte +1009 -0
- package/dist/components/form/FormAutocomplete.svelte.d.ts +25 -0
- package/dist/components/form/FormCheckboxGroup.stories.svelte +28 -0
- package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormCheckboxGroup.svelte +155 -0
- package/dist/components/form/FormCheckboxGroup.svelte.d.ts +17 -0
- package/dist/components/form/FormCodeEditor.svelte +458 -0
- package/dist/components/form/FormCodeEditor.svelte.d.ts +25 -0
- package/dist/components/form/FormField.svelte +417 -0
- package/dist/components/form/FormField.svelte.d.ts +29 -0
- package/dist/components/form/FormFieldLight.svelte +425 -0
- package/dist/components/form/FormFieldLight.svelte.d.ts +18 -0
- package/dist/components/form/FormFieldWrapper.stories.svelte +53 -0
- package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormFieldWrapper.svelte +125 -0
- package/dist/components/form/FormFieldWrapper.svelte.d.ts +18 -0
- package/dist/components/form/FormFieldset.svelte +142 -0
- package/dist/components/form/FormFieldset.svelte.d.ts +11 -0
- package/dist/components/form/FormMarkdownEditor.svelte +752 -0
- package/dist/components/form/FormMarkdownEditor.svelte.d.ts +33 -0
- package/dist/components/form/FormNumberField.stories.svelte +36 -0
- package/dist/components/form/FormNumberField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormNumberField.svelte +112 -0
- package/dist/components/form/FormNumberField.svelte.d.ts +25 -0
- package/dist/components/form/FormRangeField.stories.svelte +31 -0
- package/dist/components/form/FormRangeField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormRangeField.svelte +246 -0
- package/dist/components/form/FormRangeField.svelte.d.ts +23 -0
- package/dist/components/form/FormSelect.stories.svelte +50 -0
- package/dist/components/form/FormSelect.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormSelect.svelte +129 -0
- package/dist/components/form/FormSelect.svelte.d.ts +20 -0
- package/dist/components/form/FormTemplateEditor.svelte +825 -0
- package/dist/components/form/FormTemplateEditor.svelte.d.ts +41 -0
- package/dist/components/form/FormTextField.stories.svelte +30 -0
- package/dist/components/form/FormTextField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormTextField.svelte +91 -0
- package/dist/components/form/FormTextField.svelte.d.ts +19 -0
- package/dist/components/form/FormTextarea.stories.svelte +34 -0
- package/dist/components/form/FormTextarea.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormTextarea.svelte +97 -0
- package/dist/components/form/FormTextarea.svelte.d.ts +21 -0
- package/dist/components/form/FormToggle.stories.svelte +30 -0
- package/dist/components/form/FormToggle.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormToggle.svelte +126 -0
- package/dist/components/form/FormToggle.svelte.d.ts +19 -0
- package/dist/components/form/FormUISchemaRenderer.svelte +136 -0
- package/dist/components/form/FormUISchemaRenderer.svelte.d.ts +32 -0
- package/dist/components/form/index.d.ts +50 -0
- package/dist/components/form/index.js +54 -0
- package/dist/components/form/templateAutocomplete.d.ts +29 -0
- package/dist/components/form/templateAutocomplete.js +254 -0
- package/dist/components/form/types.d.ts +485 -0
- package/dist/components/form/types.js +73 -0
- package/dist/components/interrupt/ChoicePrompt.stories.svelte +52 -0
- package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ChoicePrompt.svelte +401 -0
- package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +23 -0
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +71 -0
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ConfirmationPrompt.svelte +292 -0
- package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +25 -0
- package/dist/components/interrupt/FormPrompt.svelte +236 -0
- package/dist/components/interrupt/FormPrompt.svelte.d.ts +23 -0
- package/dist/components/interrupt/InterruptBubble.svelte +601 -0
- package/dist/components/interrupt/InterruptBubble.svelte.d.ts +16 -0
- package/dist/components/interrupt/ReviewPrompt.stories.svelte +67 -0
- package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ReviewPrompt.svelte +861 -0
- package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +23 -0
- package/dist/components/interrupt/TextInputPrompt.stories.svelte +47 -0
- package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/TextInputPrompt.svelte +346 -0
- package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +23 -0
- package/dist/components/interrupt/index.d.ts +13 -0
- package/dist/components/interrupt/index.js +15 -0
- package/dist/components/layouts/MainLayout.svelte +718 -0
- package/dist/components/layouts/MainLayout.svelte.d.ts +62 -0
- package/dist/components/nodes/GatewayNode.stories.svelte +108 -0
- package/dist/components/nodes/GatewayNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/GatewayNode.svelte +591 -0
- package/dist/components/nodes/GatewayNode.svelte.d.ts +15 -0
- package/dist/components/nodes/IdeaNode.stories.svelte +52 -0
- package/dist/components/nodes/IdeaNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/IdeaNode.svelte +455 -0
- package/dist/components/nodes/IdeaNode.svelte.d.ts +24 -0
- package/dist/components/nodes/NotesNode.stories.svelte +76 -0
- package/dist/components/nodes/NotesNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/NotesNode.svelte +378 -0
- package/dist/components/nodes/NotesNode.svelte.d.ts +24 -0
- package/dist/components/nodes/SimpleNode.stories.svelte +159 -0
- package/dist/components/nodes/SimpleNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/SimpleNode.svelte +451 -0
- package/dist/components/nodes/SimpleNode.svelte.d.ts +25 -0
- package/dist/components/nodes/SquareNode.stories.svelte +82 -0
- package/dist/components/nodes/SquareNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/SquareNode.svelte +407 -0
- package/dist/components/nodes/SquareNode.svelte.d.ts +25 -0
- package/dist/components/nodes/TerminalNode.stories.svelte +25 -0
- package/dist/components/nodes/TerminalNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/TerminalNode.svelte +690 -0
- package/dist/components/nodes/TerminalNode.svelte.d.ts +25 -0
- package/dist/components/nodes/ToolNode.stories.svelte +189 -0
- package/dist/components/nodes/ToolNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/ToolNode.svelte +471 -0
- package/dist/components/nodes/ToolNode.svelte.d.ts +36 -0
- package/dist/components/nodes/WorkflowNode.stories.svelte +55 -0
- package/dist/components/nodes/WorkflowNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/WorkflowNode.svelte +571 -0
- package/dist/components/nodes/WorkflowNode.svelte.d.ts +15 -0
- package/dist/components/playground/ChatPanel.svelte +905 -0
- package/dist/components/playground/ChatPanel.svelte.d.ts +46 -0
- package/dist/components/playground/ExecutionLogs.svelte +488 -0
- package/dist/components/playground/ExecutionLogs.svelte.d.ts +14 -0
- package/dist/components/playground/InputCollector.svelte +444 -0
- package/dist/components/playground/InputCollector.svelte.d.ts +16 -0
- package/dist/components/playground/MessageBubble.stories.svelte +62 -0
- package/dist/components/playground/MessageBubble.stories.svelte.d.ts +27 -0
- package/dist/components/playground/MessageBubble.svelte +633 -0
- package/dist/components/playground/MessageBubble.svelte.d.ts +24 -0
- package/dist/components/playground/Playground.svelte +1075 -0
- package/dist/components/playground/Playground.svelte.d.ts +25 -0
- package/dist/components/playground/PlaygroundModal.svelte +220 -0
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +25 -0
- package/dist/components/playground/SessionManager.svelte +538 -0
- package/dist/components/playground/SessionManager.svelte.d.ts +20 -0
- package/dist/config/agentSpecEndpoints.d.ts +70 -0
- package/dist/config/agentSpecEndpoints.js +65 -0
- package/dist/config/constants.d.ts +43 -0
- package/dist/config/constants.js +31 -0
- package/dist/config/defaultCategories.d.ts +7 -0
- package/dist/config/defaultCategories.js +126 -0
- package/dist/config/defaultPortConfig.d.ts +6 -0
- package/dist/config/defaultPortConfig.js +201 -0
- package/dist/config/endpoints.d.ts +160 -0
- package/dist/config/endpoints.js +146 -0
- package/dist/config/runtimeConfig.d.ts +47 -0
- package/dist/config/runtimeConfig.js +80 -0
- package/dist/core/index.d.ts +75 -0
- package/dist/core/index.js +92 -0
- package/dist/display/index.d.ts +29 -0
- package/dist/display/index.js +36 -0
- package/dist/editor/index.d.ts +95 -0
- package/dist/editor/index.js +138 -0
- package/dist/form/code.d.ts +101 -0
- package/dist/form/code.js +168 -0
- package/dist/form/fieldRegistry.d.ts +169 -0
- package/dist/form/fieldRegistry.js +152 -0
- package/dist/form/full.d.ts +56 -0
- package/dist/form/full.js +80 -0
- package/dist/form/index.d.ts +77 -0
- package/dist/form/index.js +91 -0
- package/dist/form/markdown.d.ts +69 -0
- package/dist/form/markdown.js +103 -0
- package/dist/helpers/nodeLayoutHelper.d.ts +14 -0
- package/dist/helpers/nodeLayoutHelper.js +19 -0
- package/dist/helpers/proximityConnect.d.ts +94 -0
- package/dist/helpers/proximityConnect.js +314 -0
- package/dist/helpers/workflowEditorHelper.d.ts +183 -0
- package/dist/helpers/workflowEditorHelper.js +595 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +64 -0
- package/dist/mocks/app-environment.d.ts +8 -0
- package/dist/mocks/app-environment.js +16 -0
- package/dist/mocks/app-forms.d.ts +2 -0
- package/dist/mocks/app-forms.js +22 -0
- package/dist/mocks/app-navigation.d.ts +5 -0
- package/dist/mocks/app-navigation.js +36 -0
- package/dist/mocks/app-stores.d.ts +14 -0
- package/dist/mocks/app-stores.js +26 -0
- package/dist/playground/index.d.ts +131 -0
- package/dist/playground/index.js +172 -0
- package/dist/playground/mount.d.ts +203 -0
- package/dist/playground/mount.js +235 -0
- package/dist/registry/BaseRegistry.d.ts +92 -0
- package/dist/registry/BaseRegistry.js +124 -0
- package/dist/registry/builtinFormats.d.ts +23 -0
- package/dist/registry/builtinFormats.js +70 -0
- package/dist/registry/builtinNodes.d.ts +77 -0
- package/dist/registry/builtinNodes.js +211 -0
- package/dist/registry/index.d.ts +8 -0
- package/dist/registry/index.js +12 -0
- package/dist/registry/nodeComponentRegistry.d.ts +276 -0
- package/dist/registry/nodeComponentRegistry.js +262 -0
- package/dist/registry/plugin.d.ts +215 -0
- package/dist/registry/plugin.js +249 -0
- package/dist/registry/workflowFormatRegistry.d.ts +122 -0
- package/dist/registry/workflowFormatRegistry.js +96 -0
- package/dist/schema/index.d.ts +23 -0
- package/dist/schema/index.js +23 -0
- package/dist/schemas/v1/workflow.schema.json +1078 -0
- package/dist/services/agentSpecExecutionService.d.ts +106 -0
- package/dist/services/agentSpecExecutionService.js +334 -0
- package/dist/services/api.d.ts +115 -0
- package/dist/services/api.js +214 -0
- package/dist/services/apiVariableService.d.ts +114 -0
- package/dist/services/apiVariableService.js +338 -0
- package/dist/services/autoSaveService.d.ts +112 -0
- package/dist/services/autoSaveService.js +227 -0
- package/dist/services/categoriesApi.d.ts +14 -0
- package/dist/services/categoriesApi.js +49 -0
- package/dist/services/draftStorage.d.ts +171 -0
- package/dist/services/draftStorage.js +299 -0
- package/dist/services/dynamicSchemaService.d.ts +108 -0
- package/dist/services/dynamicSchemaService.js +444 -0
- package/dist/services/globalSave.d.ts +69 -0
- package/dist/services/globalSave.js +248 -0
- package/dist/services/historyService.d.ts +208 -0
- package/dist/services/historyService.js +321 -0
- package/dist/services/interruptService.d.ts +133 -0
- package/dist/services/interruptService.js +280 -0
- package/dist/services/nodeExecutionService.d.ts +63 -0
- package/dist/services/nodeExecutionService.js +266 -0
- package/dist/services/playgroundService.d.ts +130 -0
- package/dist/services/playgroundService.js +321 -0
- package/dist/services/portConfigApi.d.ts +14 -0
- package/dist/services/portConfigApi.js +54 -0
- package/dist/services/settingsService.d.ts +92 -0
- package/dist/services/settingsService.js +196 -0
- package/dist/services/toastService.d.ts +156 -0
- package/dist/services/toastService.js +265 -0
- package/dist/services/variableService.d.ts +141 -0
- package/dist/services/variableService.js +463 -0
- package/dist/services/workflowStorage.d.ts +37 -0
- package/dist/services/workflowStorage.js +116 -0
- package/dist/settings/index.d.ts +25 -0
- package/dist/settings/index.js +33 -0
- package/dist/stores/categoriesStore.svelte.d.ts +32 -0
- package/dist/stores/categoriesStore.svelte.js +77 -0
- package/dist/stores/editorStateMachine.svelte.d.ts +42 -0
- package/dist/stores/editorStateMachine.svelte.js +132 -0
- package/dist/stores/historyStore.svelte.d.ts +136 -0
- package/dist/stores/historyStore.svelte.js +207 -0
- package/dist/stores/interruptStore.svelte.d.ts +179 -0
- package/dist/stores/interruptStore.svelte.js +346 -0
- package/dist/stores/playgroundStore.svelte.d.ts +230 -0
- package/dist/stores/playgroundStore.svelte.js +515 -0
- package/dist/stores/portCoordinateStore.svelte.d.ts +66 -0
- package/dist/stores/portCoordinateStore.svelte.js +186 -0
- package/dist/stores/settingsStore.svelte.d.ts +158 -0
- package/dist/stores/settingsStore.svelte.js +544 -0
- package/dist/stores/workflowStore.svelte.d.ts +260 -0
- package/dist/stores/workflowStore.svelte.js +649 -0
- package/dist/stories/CanvasDecorator.svelte +49 -0
- package/dist/stories/CanvasDecorator.svelte.d.ts +8 -0
- package/dist/stories/NodeDecorator.svelte +73 -0
- package/dist/stories/NodeDecorator.svelte.d.ts +8 -0
- package/dist/stories/utils.d.ts +93 -0
- package/dist/stories/utils.js +122 -0
- package/dist/styles/base.css +1300 -0
- package/dist/styles/toast.css +35 -0
- package/dist/styles/tokens.css +475 -0
- package/dist/svelte-app.d.ts +150 -0
- package/dist/svelte-app.js +295 -0
- package/dist/types/agentspec.d.ts +318 -0
- package/dist/types/agentspec.js +48 -0
- package/dist/types/auth.d.ts +263 -0
- package/dist/types/auth.js +229 -0
- package/dist/types/config.d.ts +151 -0
- package/dist/types/config.js +7 -0
- package/dist/types/events.d.ts +190 -0
- package/dist/types/events.js +30 -0
- package/dist/types/index.d.ts +1234 -0
- package/dist/types/index.js +27 -0
- package/dist/types/interrupt.d.ts +390 -0
- package/dist/types/interrupt.js +145 -0
- package/dist/types/interruptState.d.ts +211 -0
- package/dist/types/interruptState.js +308 -0
- package/dist/types/playground.d.ts +351 -0
- package/dist/types/playground.js +95 -0
- package/dist/types/settings.d.ts +189 -0
- package/dist/types/settings.js +97 -0
- package/dist/types/uischema.d.ts +144 -0
- package/dist/types/uischema.js +51 -0
- package/dist/utils/colors.d.ts +288 -0
- package/dist/utils/colors.js +548 -0
- package/dist/utils/config.d.ts +37 -0
- package/dist/utils/config.js +226 -0
- package/dist/utils/connections.d.ts +125 -0
- package/dist/utils/connections.js +414 -0
- package/dist/utils/errors.d.ts +28 -0
- package/dist/utils/errors.js +44 -0
- package/dist/utils/fetchWithAuth.d.ts +25 -0
- package/dist/utils/fetchWithAuth.js +34 -0
- package/dist/utils/handleIds.d.ts +35 -0
- package/dist/utils/handleIds.js +58 -0
- package/dist/utils/handlePositioning.d.ts +31 -0
- package/dist/utils/handlePositioning.js +35 -0
- package/dist/utils/icons.d.ts +106 -0
- package/dist/utils/icons.js +157 -0
- package/dist/utils/logger.d.ts +47 -0
- package/dist/utils/logger.js +72 -0
- package/dist/utils/nodeStatus.d.ts +53 -0
- package/dist/utils/nodeStatus.js +183 -0
- package/dist/utils/nodeTypes.d.ts +117 -0
- package/dist/utils/nodeTypes.js +244 -0
- package/dist/utils/nodeWrapper.d.ts +39 -0
- package/dist/utils/nodeWrapper.js +62 -0
- package/dist/utils/performanceUtils.d.ts +30 -0
- package/dist/utils/performanceUtils.js +108 -0
- package/dist/utils/sanitize.d.ts +19 -0
- package/dist/utils/sanitize.js +31 -0
- package/dist/utils/uischema.d.ts +52 -0
- package/dist/utils/uischema.js +88 -0
- package/dist/utils/validation.d.ts +29 -0
- package/dist/utils/validation.js +39 -0
- package/package.json +292 -0
|
@@ -0,0 +1,1075 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Playground Component
|
|
3
|
+
|
|
4
|
+
Main component for the Playground feature.
|
|
5
|
+
Clean, conversational interface similar to Langflow.
|
|
6
|
+
Supports both embedded (panel) and standalone (page) modes.
|
|
7
|
+
Styled with BEM syntax.
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import { onMount, onDestroy } from 'svelte';
|
|
12
|
+
import Icon from '@iconify/svelte';
|
|
13
|
+
import ChatPanel from './ChatPanel.svelte';
|
|
14
|
+
import type { Workflow } from '../../types/index.js';
|
|
15
|
+
import type { EndpointConfig } from '../../config/endpoints.js';
|
|
16
|
+
import type { PlaygroundMode, PlaygroundConfig } from '../../types/playground.js';
|
|
17
|
+
import { playgroundService } from '../../services/playgroundService.js';
|
|
18
|
+
import { interruptService } from '../../services/interruptService.js';
|
|
19
|
+
import { setEndpointConfig } from '../../services/api.js';
|
|
20
|
+
import {
|
|
21
|
+
getCurrentSession,
|
|
22
|
+
getSessions,
|
|
23
|
+
getIsExecuting,
|
|
24
|
+
getIsLoading,
|
|
25
|
+
getError,
|
|
26
|
+
playgroundActions,
|
|
27
|
+
getInputFields,
|
|
28
|
+
createPollingCallback
|
|
29
|
+
} from '../../stores/playgroundStore.svelte.js';
|
|
30
|
+
import { interruptActions } from '../../stores/interruptStore.svelte.js';
|
|
31
|
+
import { logger } from '../../utils/logger.js';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Component props
|
|
35
|
+
*/
|
|
36
|
+
interface Props {
|
|
37
|
+
/** Target workflow ID */
|
|
38
|
+
workflowId: string;
|
|
39
|
+
/** Pre-loaded workflow (optional, will be fetched if not provided) */
|
|
40
|
+
workflow?: Workflow;
|
|
41
|
+
/** Display mode: embedded (panel) or standalone (page) */
|
|
42
|
+
mode?: PlaygroundMode;
|
|
43
|
+
/** Resume a specific session */
|
|
44
|
+
initialSessionId?: string;
|
|
45
|
+
/** API endpoint configuration */
|
|
46
|
+
endpointConfig?: EndpointConfig;
|
|
47
|
+
/** Playground configuration options */
|
|
48
|
+
config?: PlaygroundConfig;
|
|
49
|
+
/** Callback when playground is closed (for embedded mode) */
|
|
50
|
+
onClose?: () => void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let {
|
|
54
|
+
workflowId,
|
|
55
|
+
workflow,
|
|
56
|
+
mode = 'standalone',
|
|
57
|
+
initialSessionId,
|
|
58
|
+
endpointConfig,
|
|
59
|
+
config = {},
|
|
60
|
+
onClose
|
|
61
|
+
}: Props = $props();
|
|
62
|
+
|
|
63
|
+
/** Current input values from InputCollector */
|
|
64
|
+
let inputValues = $state<Record<string, unknown>>({});
|
|
65
|
+
|
|
66
|
+
/** Track session being edited for rename */
|
|
67
|
+
let editingSessionId = $state<string | null>(null);
|
|
68
|
+
|
|
69
|
+
/** Track which session's dropdown menu is open */
|
|
70
|
+
let openMenuId = $state<string | null>(null);
|
|
71
|
+
|
|
72
|
+
/** Track if initial session has been loaded to prevent duplicate loads */
|
|
73
|
+
let initialSessionLoaded = $state(false);
|
|
74
|
+
|
|
75
|
+
/** Track the session ID that was loaded to detect prop changes */
|
|
76
|
+
let loadedInitialSessionId = $state<string | undefined>(undefined);
|
|
77
|
+
|
|
78
|
+
/** Track if auto-run has already been triggered to prevent duplicate executions */
|
|
79
|
+
let autoRunTriggered = $state(false);
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Initialize the playground on mount
|
|
83
|
+
*/
|
|
84
|
+
onMount(() => {
|
|
85
|
+
// Set endpoint config if provided
|
|
86
|
+
if (endpointConfig) {
|
|
87
|
+
setEndpointConfig(endpointConfig);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Set workflow in store
|
|
91
|
+
if (workflow) {
|
|
92
|
+
playgroundActions.setWorkflow(workflow);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Async initialization
|
|
96
|
+
const initializePlayground = async (): Promise<void> => {
|
|
97
|
+
try {
|
|
98
|
+
// Load sessions
|
|
99
|
+
await loadSessions();
|
|
100
|
+
|
|
101
|
+
// Resume initial session if provided
|
|
102
|
+
if (initialSessionId) {
|
|
103
|
+
await loadInitialSession(initialSessionId);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Handle auto-run after initialization is complete
|
|
107
|
+
if (config.autoRun && !autoRunTriggered) {
|
|
108
|
+
autoRunTriggered = true;
|
|
109
|
+
const predefinedMessage = config.predefinedMessage ?? 'Run workflow';
|
|
110
|
+
logger.debug('[Playground] Auto-run triggered with message:', predefinedMessage);
|
|
111
|
+
await handleSendMessage(predefinedMessage);
|
|
112
|
+
}
|
|
113
|
+
} catch (err) {
|
|
114
|
+
logger.error('[Playground] Initialization error:', err);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Execute initialization
|
|
119
|
+
void initializePlayground();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Handle reactive changes to initialSessionId prop
|
|
124
|
+
* This allows the initial session to be set after mount
|
|
125
|
+
*/
|
|
126
|
+
$effect(() => {
|
|
127
|
+
// Skip if no initialSessionId provided
|
|
128
|
+
if (!initialSessionId) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Skip if this session was already loaded
|
|
133
|
+
if (initialSessionLoaded && loadedInitialSessionId === initialSessionId) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Skip if sessions haven't been loaded yet (will be handled by onMount)
|
|
138
|
+
const sessionList = getSessions();
|
|
139
|
+
if (sessionList.length === 0 && getIsLoading()) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Load the initial session if sessions are available
|
|
144
|
+
if (sessionList.length > 0 && !initialSessionLoaded) {
|
|
145
|
+
void loadInitialSession(initialSessionId);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Load the initial session with validation and error handling
|
|
151
|
+
*
|
|
152
|
+
* @param sessionId - The session ID to load
|
|
153
|
+
*/
|
|
154
|
+
async function loadInitialSession(sessionId: string): Promise<void> {
|
|
155
|
+
// Validate session exists in loaded sessions
|
|
156
|
+
const sessionList = getSessions();
|
|
157
|
+
const sessionExists = sessionList.some((s) => s.id === sessionId);
|
|
158
|
+
|
|
159
|
+
if (!sessionExists) {
|
|
160
|
+
logger.warn(
|
|
161
|
+
`[Playground] Initial session "${sessionId}" not found in available sessions. ` +
|
|
162
|
+
`Available sessions: ${sessionList.map((s) => s.id).join(', ') || 'none'}`
|
|
163
|
+
);
|
|
164
|
+
// Don't set error - just log warning and let user pick a session
|
|
165
|
+
initialSessionLoaded = true;
|
|
166
|
+
loadedInitialSessionId = sessionId;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
await loadSession(sessionId);
|
|
172
|
+
initialSessionLoaded = true;
|
|
173
|
+
loadedInitialSessionId = sessionId;
|
|
174
|
+
} catch (err) {
|
|
175
|
+
logger.error('[Playground] Failed to load initial session:', err);
|
|
176
|
+
// Mark as attempted to prevent retry loops
|
|
177
|
+
initialSessionLoaded = true;
|
|
178
|
+
loadedInitialSessionId = sessionId;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Cleanup on destroy
|
|
184
|
+
*/
|
|
185
|
+
onDestroy(() => {
|
|
186
|
+
playgroundService.stopPolling();
|
|
187
|
+
interruptService.stopPolling();
|
|
188
|
+
playgroundActions.reset();
|
|
189
|
+
interruptActions.reset();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Close dropdown menu when clicking outside
|
|
194
|
+
*/
|
|
195
|
+
$effect(() => {
|
|
196
|
+
if (!openMenuId) return;
|
|
197
|
+
|
|
198
|
+
function onDocumentClick() {
|
|
199
|
+
openMenuId = null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
document.addEventListener('click', onDocumentClick);
|
|
203
|
+
return () => document.removeEventListener('click', onDocumentClick);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Load sessions for the workflow
|
|
208
|
+
*/
|
|
209
|
+
async function loadSessions(): Promise<void> {
|
|
210
|
+
playgroundActions.setLoading(true);
|
|
211
|
+
playgroundActions.setError(null);
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
const sessionList = await playgroundService.listSessions(workflowId);
|
|
215
|
+
playgroundActions.setSessions(sessionList);
|
|
216
|
+
} catch (err) {
|
|
217
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to load sessions';
|
|
218
|
+
playgroundActions.setError(errorMessage);
|
|
219
|
+
logger.error('Failed to load sessions:', err);
|
|
220
|
+
} finally {
|
|
221
|
+
playgroundActions.setLoading(false);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Load a specific session and its messages
|
|
227
|
+
*/
|
|
228
|
+
async function loadSession(sessionId: string): Promise<void> {
|
|
229
|
+
playgroundActions.setLoading(true);
|
|
230
|
+
playgroundActions.setError(null);
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
// Get session details
|
|
234
|
+
const session = await playgroundService.getSession(sessionId);
|
|
235
|
+
playgroundActions.setCurrentSession(session);
|
|
236
|
+
|
|
237
|
+
// Get messages
|
|
238
|
+
const response = await playgroundService.getMessages(sessionId);
|
|
239
|
+
playgroundActions.setMessages(response.data ?? []);
|
|
240
|
+
|
|
241
|
+
// Start polling if session is running
|
|
242
|
+
if (session.status === 'running') {
|
|
243
|
+
startPolling(sessionId);
|
|
244
|
+
}
|
|
245
|
+
} catch (err) {
|
|
246
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to load session';
|
|
247
|
+
playgroundActions.setError(errorMessage);
|
|
248
|
+
logger.error('Failed to load session:', err);
|
|
249
|
+
} finally {
|
|
250
|
+
playgroundActions.setLoading(false);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Create a new session
|
|
256
|
+
*/
|
|
257
|
+
async function handleCreateSession(): Promise<void> {
|
|
258
|
+
playgroundActions.setLoading(true);
|
|
259
|
+
playgroundActions.setError(null);
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
const sessionName = `Session ${getSessions().length + 1}`;
|
|
263
|
+
const session = await playgroundService.createSession(workflowId, sessionName);
|
|
264
|
+
playgroundActions.addSession(session);
|
|
265
|
+
playgroundActions.setCurrentSession(session);
|
|
266
|
+
playgroundActions.clearMessages();
|
|
267
|
+
} catch (err) {
|
|
268
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to create session';
|
|
269
|
+
playgroundActions.setError(errorMessage);
|
|
270
|
+
logger.error('Failed to create session:', err);
|
|
271
|
+
} finally {
|
|
272
|
+
playgroundActions.setLoading(false);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Select a session
|
|
278
|
+
*/
|
|
279
|
+
async function handleSelectSession(sessionId: string): Promise<void> {
|
|
280
|
+
const currentSessionId = getCurrentSession()?.id;
|
|
281
|
+
if (currentSessionId === sessionId) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Stop polling for current session
|
|
286
|
+
playgroundService.stopPolling();
|
|
287
|
+
|
|
288
|
+
await loadSession(sessionId);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Delete a session
|
|
293
|
+
*/
|
|
294
|
+
async function handleDeleteSession(sessionId: string): Promise<void> {
|
|
295
|
+
try {
|
|
296
|
+
await playgroundService.deleteSession(sessionId);
|
|
297
|
+
playgroundActions.removeSession(sessionId);
|
|
298
|
+
|
|
299
|
+
// If we deleted the current session, clear it
|
|
300
|
+
if (getCurrentSession()?.id === sessionId) {
|
|
301
|
+
playgroundService.stopPolling();
|
|
302
|
+
}
|
|
303
|
+
} catch (err) {
|
|
304
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to delete session';
|
|
305
|
+
playgroundActions.setError(errorMessage);
|
|
306
|
+
logger.error('Failed to delete session:', err);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Toggle session dropdown menu
|
|
312
|
+
*/
|
|
313
|
+
function handleMenuToggle(event: Event, sessionId: string): void {
|
|
314
|
+
event.stopPropagation();
|
|
315
|
+
openMenuId = openMenuId === sessionId ? null : sessionId;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Handle delete from dropdown menu
|
|
320
|
+
*/
|
|
321
|
+
function handleMenuDelete(event: Event, sessionId: string): void {
|
|
322
|
+
event.stopPropagation();
|
|
323
|
+
openMenuId = null;
|
|
324
|
+
void handleDeleteSession(sessionId);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Close current session (go back to welcome)
|
|
329
|
+
*/
|
|
330
|
+
function handleCloseSession(): void {
|
|
331
|
+
playgroundService.stopPolling();
|
|
332
|
+
interruptService.stopPolling();
|
|
333
|
+
playgroundActions.setCurrentSession(null);
|
|
334
|
+
playgroundActions.clearMessages();
|
|
335
|
+
// Clear interrupts for this session
|
|
336
|
+
const sessionId = getCurrentSession()?.id;
|
|
337
|
+
if (sessionId) {
|
|
338
|
+
interruptActions.clearSessionInterrupts(sessionId);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Send a message
|
|
344
|
+
*/
|
|
345
|
+
async function handleSendMessage(content: string): Promise<void> {
|
|
346
|
+
const session = getCurrentSession();
|
|
347
|
+
if (!session) {
|
|
348
|
+
// Create a session first if none exists
|
|
349
|
+
await handleCreateSession();
|
|
350
|
+
const newSession = getCurrentSession();
|
|
351
|
+
if (!newSession) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const sessionId = getCurrentSession()?.id;
|
|
357
|
+
if (!sessionId) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
playgroundActions.setExecuting(true);
|
|
362
|
+
playgroundActions.setError(null);
|
|
363
|
+
|
|
364
|
+
try {
|
|
365
|
+
// Prepare inputs from the input collector
|
|
366
|
+
const inputs: Record<string, unknown> = {};
|
|
367
|
+
const fields = getInputFields();
|
|
368
|
+
|
|
369
|
+
fields.forEach((field) => {
|
|
370
|
+
const key = `${field.nodeId}:${field.fieldId}`;
|
|
371
|
+
if (inputValues[key] !== undefined) {
|
|
372
|
+
// Map to node ID and field ID for the backend
|
|
373
|
+
if (!inputs[field.nodeId]) {
|
|
374
|
+
inputs[field.nodeId] = {};
|
|
375
|
+
}
|
|
376
|
+
(inputs[field.nodeId] as Record<string, unknown>)[field.fieldId] = inputValues[key];
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
// Send message
|
|
381
|
+
const message = await playgroundService.sendMessage(sessionId, content, inputs);
|
|
382
|
+
playgroundActions.addMessage(message);
|
|
383
|
+
|
|
384
|
+
// Update session status
|
|
385
|
+
playgroundActions.updateSessionStatus('running');
|
|
386
|
+
|
|
387
|
+
// Start polling for responses
|
|
388
|
+
startPolling(sessionId);
|
|
389
|
+
} catch (err) {
|
|
390
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to send message';
|
|
391
|
+
playgroundActions.setError(errorMessage);
|
|
392
|
+
playgroundActions.setExecuting(false);
|
|
393
|
+
logger.error('Failed to send message:', err);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Stop execution
|
|
399
|
+
*/
|
|
400
|
+
async function handleStopExecution(): Promise<void> {
|
|
401
|
+
const sessionId = getCurrentSession()?.id;
|
|
402
|
+
if (!sessionId) {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
try {
|
|
407
|
+
await playgroundService.stopExecution(sessionId);
|
|
408
|
+
playgroundService.stopPolling();
|
|
409
|
+
playgroundActions.setExecuting(false);
|
|
410
|
+
playgroundActions.updateSessionStatus('idle');
|
|
411
|
+
} catch (err) {
|
|
412
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to stop execution';
|
|
413
|
+
playgroundActions.setError(errorMessage);
|
|
414
|
+
logger.error('Failed to stop execution:', err);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** Shared polling callback created from config lifecycle hooks */
|
|
419
|
+
// svelte-ignore state_referenced_locally — config is static
|
|
420
|
+
const pollingCallback = createPollingCallback(config.isTerminalStatus);
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Start polling for messages
|
|
424
|
+
*/
|
|
425
|
+
function startPolling(sessionId: string): void {
|
|
426
|
+
const pollingInterval = config.pollingInterval ?? 1500;
|
|
427
|
+
|
|
428
|
+
playgroundService.startPolling(
|
|
429
|
+
sessionId,
|
|
430
|
+
pollingCallback,
|
|
431
|
+
pollingInterval,
|
|
432
|
+
config.shouldStopPolling
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Refresh messages for the current session
|
|
438
|
+
* Called after interrupt resolution when polling has stopped
|
|
439
|
+
*/
|
|
440
|
+
async function handleInterruptResolved(): Promise<void> {
|
|
441
|
+
const sessionId = getCurrentSession()?.id;
|
|
442
|
+
if (!sessionId) return;
|
|
443
|
+
|
|
444
|
+
try {
|
|
445
|
+
const response = await playgroundService.getMessages(sessionId);
|
|
446
|
+
pollingCallback(response);
|
|
447
|
+
} catch (err) {
|
|
448
|
+
logger.error('[Playground] Failed to refresh messages after interrupt:', err);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Format date for display
|
|
454
|
+
*/
|
|
455
|
+
function formatDate(dateString: string): string {
|
|
456
|
+
const date = new Date(dateString);
|
|
457
|
+
const now = new Date();
|
|
458
|
+
const diffMs = now.getTime() - date.getTime();
|
|
459
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
460
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
461
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
462
|
+
|
|
463
|
+
if (diffMins < 1) {
|
|
464
|
+
return 'Just now';
|
|
465
|
+
}
|
|
466
|
+
if (diffMins < 60) {
|
|
467
|
+
return `${diffMins}m ago`;
|
|
468
|
+
}
|
|
469
|
+
if (diffHours < 24) {
|
|
470
|
+
return `${diffHours}h ago`;
|
|
471
|
+
}
|
|
472
|
+
if (diffDays < 7) {
|
|
473
|
+
return `${diffDays}d ago`;
|
|
474
|
+
}
|
|
475
|
+
return date.toLocaleDateString('en-US', {
|
|
476
|
+
month: 'short',
|
|
477
|
+
day: 'numeric'
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
</script>
|
|
481
|
+
|
|
482
|
+
<div
|
|
483
|
+
class="playground"
|
|
484
|
+
class:playground--embedded={mode === 'embedded'}
|
|
485
|
+
class:playground--standalone={mode === 'standalone'}
|
|
486
|
+
class:playground--modal={mode === 'modal'}
|
|
487
|
+
class:playground--no-sidebar={config.showSidebar === false}
|
|
488
|
+
>
|
|
489
|
+
<div class="playground__container">
|
|
490
|
+
<!-- Sidebar (conditionally rendered based on config.showSidebar) -->
|
|
491
|
+
{#if config.showSidebar !== false}
|
|
492
|
+
<aside
|
|
493
|
+
class="playground__sidebar"
|
|
494
|
+
style={config.sidebarWidth ? `--fd-playground-sidebar-width: ${config.sidebarWidth}` : ''}
|
|
495
|
+
>
|
|
496
|
+
<!-- Sidebar Header -->
|
|
497
|
+
<div class="playground__sidebar-header">
|
|
498
|
+
<div class="playground__sidebar-title">
|
|
499
|
+
<span>Playground</span>
|
|
500
|
+
</div>
|
|
501
|
+
{#if (mode === 'embedded' || mode === 'modal') && onClose}
|
|
502
|
+
<button
|
|
503
|
+
type="button"
|
|
504
|
+
class="playground__sidebar-close"
|
|
505
|
+
onclick={onClose}
|
|
506
|
+
title="Close playground"
|
|
507
|
+
>
|
|
508
|
+
{#if mode === 'modal'}
|
|
509
|
+
<Icon icon="mdi:close" />
|
|
510
|
+
{:else}
|
|
511
|
+
<Icon icon="mdi:dock-right" />
|
|
512
|
+
{/if}
|
|
513
|
+
</button>
|
|
514
|
+
{/if}
|
|
515
|
+
</div>
|
|
516
|
+
|
|
517
|
+
<!-- New Session Section -->
|
|
518
|
+
<div class="playground__section">
|
|
519
|
+
<button
|
|
520
|
+
type="button"
|
|
521
|
+
class="playground__new-session-btn"
|
|
522
|
+
onclick={handleCreateSession}
|
|
523
|
+
disabled={getIsLoading()}
|
|
524
|
+
title="Start a new session"
|
|
525
|
+
>
|
|
526
|
+
<Icon icon="mdi:plus" />
|
|
527
|
+
<span>New Session</span>
|
|
528
|
+
</button>
|
|
529
|
+
|
|
530
|
+
<!-- Sessions List - click a session to load it -->
|
|
531
|
+
<div class="playground__sessions-wrap">
|
|
532
|
+
{#if getSessions().length > 0}
|
|
533
|
+
<p class="playground__sessions-hint">Click a session to load it</p>
|
|
534
|
+
{/if}
|
|
535
|
+
<div class="playground__sessions">
|
|
536
|
+
{#if getSessions().length === 0 && !getIsLoading()}
|
|
537
|
+
<div class="playground__sessions-empty">
|
|
538
|
+
<span>No sessions yet</span>
|
|
539
|
+
</div>
|
|
540
|
+
{:else}
|
|
541
|
+
{#each getSessions() as session (session.id)}
|
|
542
|
+
<div
|
|
543
|
+
class="playground__session"
|
|
544
|
+
class:playground__session--active={getCurrentSession()?.id === session.id}
|
|
545
|
+
role="button"
|
|
546
|
+
tabindex="0"
|
|
547
|
+
title="Click to load this session"
|
|
548
|
+
aria-label="Load session: {session.name}"
|
|
549
|
+
onclick={() => handleSelectSession(session.id)}
|
|
550
|
+
onkeydown={(e) => e.key === 'Enter' && handleSelectSession(session.id)}
|
|
551
|
+
>
|
|
552
|
+
<span class="playground__session-name" title={session.name}>
|
|
553
|
+
{session.name}
|
|
554
|
+
</span>
|
|
555
|
+
<div class="playground__session-actions">
|
|
556
|
+
<button
|
|
557
|
+
type="button"
|
|
558
|
+
class="playground__session-menu"
|
|
559
|
+
class:playground__session-menu--open={openMenuId === session.id}
|
|
560
|
+
onclick={(e) => handleMenuToggle(e, session.id)}
|
|
561
|
+
title="Session options"
|
|
562
|
+
>
|
|
563
|
+
<Icon icon="mdi:dots-vertical" />
|
|
564
|
+
</button>
|
|
565
|
+
{#if openMenuId === session.id}
|
|
566
|
+
<div class="playground__session-dropdown">
|
|
567
|
+
<button
|
|
568
|
+
type="button"
|
|
569
|
+
class="playground__session-dropdown-item playground__session-dropdown-item--danger"
|
|
570
|
+
onclick={(e) => handleMenuDelete(e, session.id)}
|
|
571
|
+
>
|
|
572
|
+
<Icon icon="mdi:delete-outline" />
|
|
573
|
+
<span>Delete</span>
|
|
574
|
+
</button>
|
|
575
|
+
</div>
|
|
576
|
+
{/if}
|
|
577
|
+
</div>
|
|
578
|
+
</div>
|
|
579
|
+
{/each}
|
|
580
|
+
{/if}
|
|
581
|
+
</div>
|
|
582
|
+
</div>
|
|
583
|
+
</div>
|
|
584
|
+
</aside>
|
|
585
|
+
{/if}
|
|
586
|
+
|
|
587
|
+
<!-- Main Content -->
|
|
588
|
+
<main class="playground__main">
|
|
589
|
+
<!-- Session Header (conditionally rendered based on config.showSessionHeader) -->
|
|
590
|
+
{#if getCurrentSession() && config.showSessionHeader !== false}
|
|
591
|
+
<header class="playground__header">
|
|
592
|
+
<h2 class="playground__header-title">{getCurrentSession()?.name}</h2>
|
|
593
|
+
<button
|
|
594
|
+
type="button"
|
|
595
|
+
class="playground__header-close"
|
|
596
|
+
onclick={handleCloseSession}
|
|
597
|
+
title="Close session"
|
|
598
|
+
>
|
|
599
|
+
<Icon icon="mdi:close" />
|
|
600
|
+
</button>
|
|
601
|
+
</header>
|
|
602
|
+
{/if}
|
|
603
|
+
|
|
604
|
+
<!-- Error Banner -->
|
|
605
|
+
{#if getError()}
|
|
606
|
+
<div class="playground__error">
|
|
607
|
+
<Icon icon="mdi:alert-circle" />
|
|
608
|
+
<span>{getError()}</span>
|
|
609
|
+
<button
|
|
610
|
+
type="button"
|
|
611
|
+
class="playground__error-dismiss"
|
|
612
|
+
onclick={() => playgroundActions.setError(null)}
|
|
613
|
+
>
|
|
614
|
+
<Icon icon="mdi:close" />
|
|
615
|
+
</button>
|
|
616
|
+
</div>
|
|
617
|
+
{/if}
|
|
618
|
+
|
|
619
|
+
<!-- Chat Content -->
|
|
620
|
+
<div class="playground__content">
|
|
621
|
+
{#if getIsLoading() && !getCurrentSession()}
|
|
622
|
+
<div class="playground__loading">
|
|
623
|
+
<Icon icon="mdi:loading" class="playground__loading-icon" />
|
|
624
|
+
<span>Loading...</span>
|
|
625
|
+
</div>
|
|
626
|
+
{:else}
|
|
627
|
+
<ChatPanel
|
|
628
|
+
showTimestamps={config.showTimestamps ?? true}
|
|
629
|
+
autoScroll={config.autoScroll ?? true}
|
|
630
|
+
showLogsInline={config.logDisplayMode === 'inline'}
|
|
631
|
+
enableMarkdown={config.enableMarkdown ?? true}
|
|
632
|
+
showChatInput={config.showChatInput ?? true}
|
|
633
|
+
showRunButton={config.showRunButton ?? true}
|
|
634
|
+
predefinedMessage={config.predefinedMessage ?? 'Run workflow'}
|
|
635
|
+
onSendMessage={handleSendMessage}
|
|
636
|
+
onStopExecution={handleStopExecution}
|
|
637
|
+
onInterruptResolved={handleInterruptResolved}
|
|
638
|
+
/>
|
|
639
|
+
{/if}
|
|
640
|
+
</div>
|
|
641
|
+
</main>
|
|
642
|
+
</div>
|
|
643
|
+
</div>
|
|
644
|
+
|
|
645
|
+
<style>
|
|
646
|
+
.playground {
|
|
647
|
+
display: flex;
|
|
648
|
+
flex-direction: column;
|
|
649
|
+
height: 100%;
|
|
650
|
+
overflow: hidden; /* Prevent playground-level scrolling */
|
|
651
|
+
background-color: var(--fd-muted);
|
|
652
|
+
font-family:
|
|
653
|
+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
.playground--embedded {
|
|
657
|
+
border-left: 1px solid var(--fd-border);
|
|
658
|
+
box-shadow: -4px 0 20px rgba(0, 0, 0, 0.08);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.playground--standalone {
|
|
662
|
+
height: 100vh;
|
|
663
|
+
background: var(--fd-layout-background, var(--fd-muted));
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/* Dark mode override for standalone */
|
|
667
|
+
:global([data-theme='dark']) .playground--standalone {
|
|
668
|
+
background: linear-gradient(135deg, #141418 0%, #1a1a2e 50%, #16162a 100%);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.playground--modal {
|
|
672
|
+
height: 100%;
|
|
673
|
+
width: 100%;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/* No sidebar mode - minimal chat widget experience */
|
|
677
|
+
.playground--no-sidebar .playground__main {
|
|
678
|
+
border-left: none;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/* Container */
|
|
682
|
+
.playground__container {
|
|
683
|
+
display: flex;
|
|
684
|
+
flex: 1;
|
|
685
|
+
min-height: 0;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/* Sidebar */
|
|
689
|
+
.playground__sidebar {
|
|
690
|
+
width: var(--fd-playground-sidebar-width);
|
|
691
|
+
background-color: var(--fd-background);
|
|
692
|
+
border-right: 1px solid var(--fd-border);
|
|
693
|
+
display: flex;
|
|
694
|
+
flex-direction: column;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/* Fixed height so sidebar and main session header align on same horizontal line */
|
|
698
|
+
.playground__sidebar-header {
|
|
699
|
+
display: flex;
|
|
700
|
+
align-items: center;
|
|
701
|
+
justify-content: space-between;
|
|
702
|
+
height: var(--fd-playground-header-height);
|
|
703
|
+
padding: 0 var(--fd-space-xl);
|
|
704
|
+
border-bottom: 1px solid var(--fd-border);
|
|
705
|
+
box-sizing: border-box;
|
|
706
|
+
flex-shrink: 0;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
.playground__sidebar-title {
|
|
710
|
+
display: flex;
|
|
711
|
+
align-items: center;
|
|
712
|
+
gap: var(--fd-space-xs);
|
|
713
|
+
font-size: var(--fd-text-md);
|
|
714
|
+
font-weight: 600;
|
|
715
|
+
line-height: 1.25;
|
|
716
|
+
color: var(--fd-foreground);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
.playground__sidebar-close {
|
|
720
|
+
display: flex;
|
|
721
|
+
align-items: center;
|
|
722
|
+
justify-content: center;
|
|
723
|
+
width: var(--fd-playground-icon-btn-size);
|
|
724
|
+
height: var(--fd-playground-icon-btn-size);
|
|
725
|
+
border: none;
|
|
726
|
+
border-radius: var(--fd-radius-md);
|
|
727
|
+
background: transparent;
|
|
728
|
+
color: var(--fd-muted-foreground);
|
|
729
|
+
cursor: pointer;
|
|
730
|
+
transition: all var(--fd-transition-fast);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.playground__sidebar-close:hover {
|
|
734
|
+
background-color: var(--fd-muted);
|
|
735
|
+
color: var(--fd-foreground);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/* Section */
|
|
739
|
+
.playground__section {
|
|
740
|
+
flex: 1;
|
|
741
|
+
display: flex;
|
|
742
|
+
flex-direction: column;
|
|
743
|
+
min-height: 0;
|
|
744
|
+
padding: var(--fd-space-md) var(--fd-space-xs) 0;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/* New Session – neutral full-width button with icon */
|
|
748
|
+
.playground__new-session-btn {
|
|
749
|
+
display: flex;
|
|
750
|
+
align-items: center;
|
|
751
|
+
justify-content: center;
|
|
752
|
+
gap: var(--fd-space-xs);
|
|
753
|
+
width: 100%;
|
|
754
|
+
padding: var(--fd-space-sm) var(--fd-space-xl);
|
|
755
|
+
border: 1px solid var(--fd-border);
|
|
756
|
+
border-radius: var(--fd-radius-md);
|
|
757
|
+
background-color: var(--fd-background);
|
|
758
|
+
color: var(--fd-foreground);
|
|
759
|
+
font-size: var(--fd-text-sm);
|
|
760
|
+
font-weight: 500;
|
|
761
|
+
cursor: pointer;
|
|
762
|
+
transition:
|
|
763
|
+
background-color var(--fd-transition-fast),
|
|
764
|
+
border-color var(--fd-transition-fast),
|
|
765
|
+
transform 0.1s ease;
|
|
766
|
+
box-sizing: border-box;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.playground__new-session-btn:hover:not(:disabled) {
|
|
770
|
+
background-color: var(--fd-muted);
|
|
771
|
+
border-color: var(--fd-border);
|
|
772
|
+
transform: translateY(-1px);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
.playground__new-session-btn:focus {
|
|
776
|
+
outline: none;
|
|
777
|
+
box-shadow: 0 0 0 2px var(--fd-ring);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
.playground__new-session-btn:disabled {
|
|
781
|
+
opacity: 0.5;
|
|
782
|
+
cursor: not-allowed;
|
|
783
|
+
transform: none;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.playground__new-session-btn :global(svg) {
|
|
787
|
+
width: 1.125rem;
|
|
788
|
+
height: 1.125rem;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/* Sessions */
|
|
792
|
+
.playground__sessions-wrap {
|
|
793
|
+
flex: 1;
|
|
794
|
+
display: flex;
|
|
795
|
+
flex-direction: column;
|
|
796
|
+
min-height: 0;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
.playground__sessions-hint {
|
|
800
|
+
font-size: var(--fd-text-2xs);
|
|
801
|
+
color: var(--fd-muted-foreground);
|
|
802
|
+
margin: var(--fd-space-md) 0 var(--fd-space-2xs) var(--fd-space-md);
|
|
803
|
+
line-height: 1.3;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.playground__sessions {
|
|
807
|
+
flex: 1;
|
|
808
|
+
overflow-y: auto;
|
|
809
|
+
padding: 0 var(--fd-space-xs) var(--fd-space-xl);
|
|
810
|
+
min-height: 0;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
.playground__sessions-empty {
|
|
814
|
+
padding: var(--fd-space-xl);
|
|
815
|
+
text-align: center;
|
|
816
|
+
font-size: var(--fd-text-xsm);
|
|
817
|
+
color: var(--fd-muted-foreground);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/* Session row - clickable to load session; clear hover/active affordance */
|
|
821
|
+
.playground__session {
|
|
822
|
+
display: flex;
|
|
823
|
+
align-items: center;
|
|
824
|
+
justify-content: space-between;
|
|
825
|
+
padding: var(--fd-space-sm) var(--fd-space-md);
|
|
826
|
+
margin-bottom: var(--fd-space-3xs);
|
|
827
|
+
border-radius: var(--fd-radius-md);
|
|
828
|
+
border-left: 3px solid transparent;
|
|
829
|
+
cursor: pointer;
|
|
830
|
+
transition:
|
|
831
|
+
background-color var(--fd-transition-fast),
|
|
832
|
+
border-left-color var(--fd-transition-fast);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
.playground__session:hover {
|
|
836
|
+
background-color: var(--fd-muted);
|
|
837
|
+
border-left-color: var(--fd-border);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
.playground__session--active {
|
|
841
|
+
background-color: var(--fd-primary-muted);
|
|
842
|
+
border-left-color: var(--fd-primary);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
.playground__session--active:hover {
|
|
846
|
+
background-color: var(--fd-primary-muted);
|
|
847
|
+
border-left-color: var(--fd-primary);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
.playground__session-name {
|
|
851
|
+
flex: 1;
|
|
852
|
+
font-size: var(--fd-text-sm);
|
|
853
|
+
color: var(--fd-foreground);
|
|
854
|
+
white-space: nowrap;
|
|
855
|
+
overflow: hidden;
|
|
856
|
+
text-overflow: ellipsis;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
.playground__session--active .playground__session-name {
|
|
860
|
+
color: var(--fd-primary);
|
|
861
|
+
font-weight: 500;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
.playground__session-menu {
|
|
865
|
+
display: flex;
|
|
866
|
+
align-items: center;
|
|
867
|
+
justify-content: center;
|
|
868
|
+
width: var(--fd-space-3xl);
|
|
869
|
+
height: var(--fd-space-3xl);
|
|
870
|
+
border: none;
|
|
871
|
+
border-radius: var(--fd-radius-sm);
|
|
872
|
+
background: transparent;
|
|
873
|
+
color: var(--fd-muted-foreground);
|
|
874
|
+
cursor: pointer;
|
|
875
|
+
opacity: 0;
|
|
876
|
+
transition: all var(--fd-transition-fast);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
.playground__session:hover .playground__session-menu {
|
|
880
|
+
opacity: 1;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.playground__session-menu:hover {
|
|
884
|
+
background-color: var(--fd-muted);
|
|
885
|
+
color: var(--fd-foreground);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
.playground__session-menu--open {
|
|
889
|
+
opacity: 1;
|
|
890
|
+
background-color: var(--fd-muted);
|
|
891
|
+
color: var(--fd-foreground);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.playground__session-actions {
|
|
895
|
+
position: relative;
|
|
896
|
+
display: flex;
|
|
897
|
+
align-items: center;
|
|
898
|
+
flex-shrink: 0;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
.playground__session-dropdown {
|
|
902
|
+
position: absolute;
|
|
903
|
+
top: 100%;
|
|
904
|
+
right: 0;
|
|
905
|
+
z-index: 50;
|
|
906
|
+
min-width: 140px;
|
|
907
|
+
padding: var(--fd-space-xs);
|
|
908
|
+
background-color: var(--fd-background);
|
|
909
|
+
border: 1px solid var(--fd-border);
|
|
910
|
+
border-radius: var(--fd-radius-md);
|
|
911
|
+
box-shadow: var(--fd-shadow-lg);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
.playground__session-dropdown-item {
|
|
915
|
+
display: flex;
|
|
916
|
+
align-items: center;
|
|
917
|
+
gap: var(--fd-space-sm);
|
|
918
|
+
width: 100%;
|
|
919
|
+
padding: var(--fd-space-sm) var(--fd-space-md);
|
|
920
|
+
border: none;
|
|
921
|
+
border-radius: var(--fd-radius-sm);
|
|
922
|
+
background: transparent;
|
|
923
|
+
color: var(--fd-foreground);
|
|
924
|
+
font-size: var(--fd-text-sm);
|
|
925
|
+
cursor: pointer;
|
|
926
|
+
transition: all var(--fd-transition-fast);
|
|
927
|
+
white-space: nowrap;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
.playground__session-dropdown-item:hover {
|
|
931
|
+
background-color: var(--fd-muted);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
.playground__session-dropdown-item--danger {
|
|
935
|
+
color: var(--fd-error);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
.playground__session-dropdown-item--danger:hover {
|
|
939
|
+
background-color: var(--fd-error-muted);
|
|
940
|
+
color: var(--fd-error);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/* Main Content */
|
|
944
|
+
.playground__main {
|
|
945
|
+
flex: 1;
|
|
946
|
+
display: flex;
|
|
947
|
+
flex-direction: column;
|
|
948
|
+
min-width: 0;
|
|
949
|
+
min-height: 0; /* Allow proper flex shrinking */
|
|
950
|
+
overflow: hidden; /* Prevent scrolling - ChatPanel handles it */
|
|
951
|
+
background-color: var(--fd-background);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/* Header - exact same height as playground__sidebar-header for alignment */
|
|
955
|
+
.playground__header {
|
|
956
|
+
display: flex;
|
|
957
|
+
align-items: center;
|
|
958
|
+
justify-content: space-between;
|
|
959
|
+
height: var(--fd-playground-header-height);
|
|
960
|
+
padding: 0 var(--fd-space-2xl);
|
|
961
|
+
border-bottom: 1px solid var(--fd-border);
|
|
962
|
+
background-color: var(--fd-background);
|
|
963
|
+
box-sizing: border-box;
|
|
964
|
+
flex-shrink: 0;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
.playground__header-title {
|
|
968
|
+
font-size: var(--fd-text-md);
|
|
969
|
+
font-weight: 600;
|
|
970
|
+
line-height: 1.25;
|
|
971
|
+
color: var(--fd-foreground);
|
|
972
|
+
margin: 0;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
.playground__header-close {
|
|
976
|
+
display: flex;
|
|
977
|
+
align-items: center;
|
|
978
|
+
justify-content: center;
|
|
979
|
+
width: var(--fd-playground-icon-btn-size);
|
|
980
|
+
height: var(--fd-playground-icon-btn-size);
|
|
981
|
+
border: none;
|
|
982
|
+
border-radius: var(--fd-radius-md);
|
|
983
|
+
background: transparent;
|
|
984
|
+
color: var(--fd-muted-foreground);
|
|
985
|
+
cursor: pointer;
|
|
986
|
+
transition: all var(--fd-transition-fast);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
.playground__header-close:hover {
|
|
990
|
+
background-color: var(--fd-muted);
|
|
991
|
+
color: var(--fd-foreground);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
/* Error */
|
|
995
|
+
.playground__error {
|
|
996
|
+
display: flex;
|
|
997
|
+
align-items: center;
|
|
998
|
+
gap: var(--fd-space-xs);
|
|
999
|
+
padding: var(--fd-space-md) var(--fd-space-xl);
|
|
1000
|
+
background-color: var(--fd-error-muted);
|
|
1001
|
+
border-bottom: 1px solid var(--fd-error);
|
|
1002
|
+
color: var(--fd-error);
|
|
1003
|
+
font-size: var(--fd-text-sm);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
.playground__error-dismiss {
|
|
1007
|
+
margin-left: auto;
|
|
1008
|
+
display: flex;
|
|
1009
|
+
align-items: center;
|
|
1010
|
+
justify-content: center;
|
|
1011
|
+
width: var(--fd-space-3xl);
|
|
1012
|
+
height: var(--fd-space-3xl);
|
|
1013
|
+
border: none;
|
|
1014
|
+
border-radius: var(--fd-radius-sm);
|
|
1015
|
+
background: transparent;
|
|
1016
|
+
color: var(--fd-error);
|
|
1017
|
+
cursor: pointer;
|
|
1018
|
+
transition: background-color var(--fd-transition-fast);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
.playground__error-dismiss:hover {
|
|
1022
|
+
background-color: var(--fd-error-muted);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/* Content */
|
|
1026
|
+
.playground__content {
|
|
1027
|
+
flex: 1;
|
|
1028
|
+
min-height: 0;
|
|
1029
|
+
display: flex;
|
|
1030
|
+
flex-direction: column;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/* Loading */
|
|
1034
|
+
.playground__loading {
|
|
1035
|
+
display: flex;
|
|
1036
|
+
flex-direction: column;
|
|
1037
|
+
align-items: center;
|
|
1038
|
+
justify-content: center;
|
|
1039
|
+
flex: 1;
|
|
1040
|
+
gap: var(--fd-space-xl);
|
|
1041
|
+
color: var(--fd-muted-foreground);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
:global(.playground__loading-icon) {
|
|
1045
|
+
font-size: var(--fd-text-2xl);
|
|
1046
|
+
animation: spin 1s linear infinite;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
@keyframes spin {
|
|
1050
|
+
from {
|
|
1051
|
+
transform: rotate(0deg);
|
|
1052
|
+
}
|
|
1053
|
+
to {
|
|
1054
|
+
transform: rotate(360deg);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/* Responsive */
|
|
1059
|
+
@media (max-width: 768px) {
|
|
1060
|
+
.playground__sidebar {
|
|
1061
|
+
width: 180px;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
@media (max-width: 640px) {
|
|
1066
|
+
.playground__sidebar {
|
|
1067
|
+
position: absolute;
|
|
1068
|
+
left: 0;
|
|
1069
|
+
top: 0;
|
|
1070
|
+
bottom: 0;
|
|
1071
|
+
z-index: 20;
|
|
1072
|
+
box-shadow: 4px 0 20px rgba(0, 0, 0, 0.1);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
</style>
|