diff --git a/frontend/package.json b/frontend/package.json index 446ba8e5ee..ed207322d5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -244,6 +244,16 @@ "svelte": "./package/components/SchemaForm.svelte", "default": "./package/components/SchemaForm.svelte" }, + "./components/EditableSchemaWrapper.svelte": { + "types": "./package/components/schema/EditableSchemaWrapper.svelte.d.ts", + "svelte": "./package/components/schema/EditableSchemaWrapper.svelte", + "default": "./package/components/schema/EditableSchemaWrapper.svelte" + }, + "./components/ResourceEditor.svelte": { + "types": "./package/components/ResourceEditor.svelte.d.ts", + "svelte": "./package/components/ResourceEditor.svelte", + "default": "./package/components/ResourceEditor.svelte" + }, "./components/SchemaEditor.svelte": { "types": "./package/components/EditableSchemaForm.svelte.d.ts", "svelte": "./package/components/EditableSchemaForm.svelte", @@ -384,6 +394,9 @@ "components/SchemaEditor.svelte": [ "./package/components/SchemaEditor.svelte.d.ts" ], + "components/EditableSchemaWrapper.svelte": [ + "./package/components/schema/EditableSchemaWrapper.svelte.d.ts" + ], "utils": [ "./package/utils.d.ts" ], diff --git a/frontend/src/lib/assets/app.css b/frontend/src/lib/assets/app.css index ee706b19e6..01f2d37d56 100644 --- a/frontend/src/lib/assets/app.css +++ b/frontend/src/lib/assets/app.css @@ -28,33 +28,7 @@ list-style-type: '- '; padding-left: 3rem; } - .splitpanes--vertical > .splitpanes__pane { - transition: none !important; - } - .splitpanes--horizontal > .splitpanes__pane { - transition: none !important; - } - - .monaco-workbench > .notifications-toasts.visible { - display: none !important; - } - - .monaco-editor .suggest-widget { - z-index: 10001 !important; - } - - .nowrap pre code.hljs { - whitespace: normal !important; - } - - .z5000 { - z-index: 5000 !important; - } - - .foo { - color: red !important; - } .autocomplete-list-item-create { @apply !text-primary-inverse !bg-surface-inverse; } @@ -74,34 +48,8 @@ .autocomplete-list { @apply !bg-surface; } - pre code.hljs { - overflow: visible !important; - } - - svelte-virtual-list-row { - overflow: visible !important; - } - - svelte-virtual-list-contents > * + * { - border-top-width: 1px !important; - border-bottom-width: 0px !important; - } - - .monaco-editor textarea:focus { - box-shadow: none !important; - } - - .Template-editor span.mtk20 { - color: black !important; - } } -@layer components { - /* Flow graph viewer -> Svelvet library internal class overwrite */ - .Node { - display: flex !important; - } -} @layer utilities { @variants responsive { /* Hide scrollbar for Chrome, Safari and Opera */ @@ -117,28 +65,35 @@ } } -.grid-cell-centered { - display: flex; - align-items: center; - justify-content: center; -} -.grid-cell-centered .svelte-select { - height: 32px !important; +.splitpanes--vertical > .splitpanes__pane { + transition: none !important; } -.grid-cell-centered .selected-item { - margin-top: -4px; +.splitpanes--horizontal > .splitpanes__pane { + transition: none !important; } -.ol-overlaycontainer-stopevent { - @apply flex flex-col justify-start items-end; -} -.ol-control button { - @apply w-7 h-7 center-center bg-surface border text-secondary - rounded mt-1 mr-1 shadow duration-200 hover:bg-surface-hover focus:bg-surface-hover; +.monaco-workbench > .notifications-toasts.visible { + display: none !important; +} + +.monaco-editor .suggest-widget { + z-index: 10001 !important; +} + +svelte-virtual-list-row { + overflow: visible !important; +} + +svelte-virtual-list-contents > * + * { + border-top-width: 1px !important; + border-bottom-width: 0px !important; +} + +.monaco-editor textarea:focus { + box-shadow: none !important; } -/* Components */ .component-wrapper { @apply rounded-component border overflow-hidden border-gray-300 dark:border-gray-600; } diff --git a/frontend/src/lib/components/ChartHighlightTheme.svelte b/frontend/src/lib/components/ChartHighlightTheme.svelte deleted file mode 100644 index ee842b0084..0000000000 --- a/frontend/src/lib/components/ChartHighlightTheme.svelte +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - {#if darkMode} - {@html nord} - {:else} - {@html github} - {/if} - diff --git a/frontend/src/lib/components/DisplayResult.svelte b/frontend/src/lib/components/DisplayResult.svelte index 1d766431d4..33b26453c0 100644 --- a/frontend/src/lib/components/DisplayResult.svelte +++ b/frontend/src/lib/components/DisplayResult.svelte @@ -31,6 +31,7 @@ import DownloadCsv from './table/DownloadCsv.svelte' import { convertJsonToCsv } from './table/tableUtils' import Tooltip from './Tooltip.svelte' + import HighlightTheme from './HighlightTheme.svelte' export let result: any export let requireHtmlApproval = false @@ -341,6 +342,7 @@ let seeS3PreviewFileFromList = '' + {#if is_render_all}
{#if !noControls} diff --git a/frontend/src/lib/components/EditorBar.svelte b/frontend/src/lib/components/EditorBar.svelte index fc91a3eae7..fa0488187e 100644 --- a/frontend/src/lib/components/EditorBar.svelte +++ b/frontend/src/lib/components/EditorBar.svelte @@ -8,7 +8,6 @@ import { workspaceStore } from '$lib/stores' import type Editor from './Editor.svelte' import ItemPicker from './ItemPicker.svelte' - import ResourceEditor from './ResourceEditor.svelte' import VariableEditor from './VariableEditor.svelte' import Button from './common/button/Button.svelte' import HighlightCode from './HighlightCode.svelte' @@ -44,6 +43,7 @@ import { getResetCode } from '$lib/script_helpers' import CodeCompletionStatus from './copilot/CodeCompletionStatus.svelte' import Popover from './Popover.svelte' + import ResourceEditorDrawer from './ResourceEditorDrawer.svelte' export let lang: SupportedLanguage | undefined export let editor: Editor | undefined @@ -72,7 +72,7 @@ let resourcePicker: ItemPicker let resourceTypePicker: ItemPicker let variableEditor: VariableEditor - let resourceEditor: ResourceEditor + let resourceEditor: ResourceEditorDrawer let showContextVarPicker = false let showVarPicker = false let showResourcePicker = false @@ -498,7 +498,7 @@ $res = json_decode(curl_exec($ch));`) await ResourceService.listResourceType({ workspace: $workspaceStore ?? 'NO_W' })} /> {/if} - +
diff --git a/frontend/src/lib/components/FlowGraphViewerStep.svelte b/frontend/src/lib/components/FlowGraphViewerStep.svelte index 6e25b174cb..90746650ec 100644 --- a/frontend/src/lib/components/FlowGraphViewerStep.svelte +++ b/frontend/src/lib/components/FlowGraphViewerStep.svelte @@ -16,6 +16,7 @@ import { twMerge } from 'tailwind-merge' import FlowModuleScript from './flows/content/FlowModuleScript.svelte' import { Copy } from 'lucide-svelte' + import HighlightTheme from './HighlightTheme.svelte' export let schema: any | undefined = undefined @@ -23,6 +24,8 @@ let codeViewer: Drawer + + {#if stepDetail && typeof stepDetail != 'string'} diff --git a/frontend/src/lib/components/FlowViewer.svelte b/frontend/src/lib/components/FlowViewer.svelte index a0caf31edc..b067f445fa 100644 --- a/frontend/src/lib/components/FlowViewer.svelte +++ b/frontend/src/lib/components/FlowViewer.svelte @@ -11,6 +11,7 @@ import { Clipboard } from 'lucide-svelte' import YAML from 'yaml' import { yaml } from 'svelte-highlight/languages' + import HighlightTheme from './HighlightTheme.svelte' export let flow: { summary: string @@ -45,6 +46,8 @@ } + + {#if !noGraph} Graph diff --git a/frontend/src/lib/components/HighlightCode.svelte b/frontend/src/lib/components/HighlightCode.svelte index 88079450a2..9669ef34e0 100644 --- a/frontend/src/lib/components/HighlightCode.svelte +++ b/frontend/src/lib/components/HighlightCode.svelte @@ -13,6 +13,7 @@ import { Button } from './common' import { copyToClipboard } from '$lib/utils' import { ClipboardCopy } from 'lucide-svelte' + import HighlightTheme from './HighlightTheme.svelte' export let code: string = '' export let language: Script['language'] | 'frontend' | undefined @@ -57,6 +58,8 @@ $: lang = getLang(language) + +
+ + diff --git a/frontend/src/lib/components/ResourceEditor.svelte b/frontend/src/lib/components/ResourceEditor.svelte index 63082d66c8..6d5529f56e 100644 --- a/frontend/src/lib/components/ResourceEditor.svelte +++ b/frontend/src/lib/components/ResourceEditor.svelte @@ -3,66 +3,80 @@ import { ResourceService, type Resource, type ResourceType } from '$lib/gen' import { canWrite, emptyString, isOwner, urlize } from '$lib/utils' import { createEventDispatcher } from 'svelte' - import { Alert, Button, Drawer, Skeleton } from './common' + import { Alert, Skeleton } from './common' import Path from './Path.svelte' import Required from './Required.svelte' import { userStore, workspaceStore } from '$lib/stores' - import DrawerContent from './common/drawer/DrawerContent.svelte' import SchemaForm from './SchemaForm.svelte' import SimpleEditor from './SimpleEditor.svelte' import Toggle from './Toggle.svelte' import { sendUserToast } from '$lib/toast' import TestConnection from './TestConnection.svelte' - import { Pen, Save } from 'lucide-svelte' + import { Pen } from 'lucide-svelte' import Markdown from 'svelte-exmarkdown' import autosize from '$lib/autosize' import GfmMarkdown from './GfmMarkdown.svelte' - let path = '' - let initialPath = '' + export let canSave = true + export let resource_type: string | undefined = undefined + export let path: string = '' + export let newResource: boolean = false + export let hidePath: boolean = false + export let watchChanges: boolean = false - let resourceToEdit: Resource | undefined + let isValid = true + let jsonError = '' + let can_write = true + + $: canSave = can_write && isValid && jsonError == '' + + let initialPath = path + + let resourceToEdit: Resource | undefined = undefined let description: string = '' let DESCRIPTION_PLACEHOLDER = `Describe what this resource is for` - let selectedResourceType: string | undefined - let resourceSchema: Schema | undefined + let resourceSchema: Schema | undefined = undefined let args: Record = {} - let can_write = true - let loadingSchema = false + let loadingSchema = true let linkedVars: string[] = [] - let drawer: Drawer let resourceTypeInfo: ResourceType | undefined = undefined - let renderDescription = true - - let rawCode: string | undefined = undefined + let editDescription = false + let viewJsonSchema = false const dispatch = createEventDispatcher() - export async function initEdit(p: string): Promise { - initialPath = p - path = p - resourceToEdit = undefined - resourceSchema = undefined - viewJsonSchema = false - loadingSchema = true - drawer.openDrawer?.() - resourceToEdit = await ResourceService.getResource({ workspace: $workspaceStore!, path: p }) + $: watchChanges && dispatch('change', { path, args, description }) + + let rawCode: string | undefined = undefined + + async function initEdit() { + resourceToEdit = await ResourceService.getResource({ workspace: $workspaceStore!, path }) description = resourceToEdit!.description ?? '' - selectedResourceType = resourceToEdit!.resource_type + resource_type = resourceToEdit!.resource_type + args = resourceToEdit?.value ?? ({} as any) loadResourceType() - args = resourceToEdit!.value as any can_write = resourceToEdit.workspace_id == $workspaceStore && - canWrite(p, resourceToEdit.extra_perms ?? {}, $userStore) + canWrite(path, resourceToEdit.extra_perms ?? {}, $userStore) linkedVars = Object.entries(args) .filter(([_, v]) => typeof v == 'string' && v == `$var:${initialPath}`) .map(([k, _]) => k) - renderDescription = false } - async function editResource(): Promise { + if (!newResource) { + initEdit() + } else if (resource_type) { + loadResourceType() + } else { + sendUserToast('Resource type cannot be undefined for new resource creation', true) + } + + $: rawCode && parseJson() + $: linkedVars.length > 0 && path && updateArgsFromLinkedVars() + + export async function editResource(): Promise { if (resourceToEdit) { await ResourceService.updateResource({ workspace: $workspaceStore!, @@ -71,18 +85,26 @@ }) sendUserToast(`Updated resource at ${path}`) dispatch('refresh', path) - drawer.closeDrawer?.() } else { throw Error('Cannot edit undefined resourceToEdit') } } + export async function createResource(): Promise { + await ResourceService.createResource({ + workspace: $workspaceStore!, + requestBody: { path, value: args, description, resource_type: resource_type! } + }) + sendUserToast(`Updated resource at ${path}`) + dispatch('refresh', path) + } + async function loadResourceType(): Promise { - if (selectedResourceType) { + if (resource_type) { try { const resourceType = await ResourceService.getResourceType({ workspace: $workspaceStore!, - path: selectedResourceType + path: resource_type }) resourceTypeInfo = resourceType @@ -100,11 +122,6 @@ loadingSchema = false } - let isValid = true - let jsonError = '' - - $: rawCode && parseJson() - function parseJson() { try { args = JSON.parse(rawCode ?? '') @@ -114,14 +131,11 @@ } } - $: linkedVars.length > 0 && path && updateArgsFromLinkedVars() - function updateArgsFromLinkedVars() { linkedVars.forEach((k) => { args[k] = `$var:${path}` }) } - let viewJsonSchema = false function switchTab(asJson: boolean) { viewJsonSchema = asJson @@ -133,118 +147,106 @@ } - - -
-
-
- {#if !can_write} -
- - You only have read access to this resource and cannot edit it - -
- {/if} - -
- {#if !emptyString(resourceTypeInfo?.description)} -

{resourceTypeInfo?.name} description

-
- +
+
+ {#if !hidePath} +
+ {#if !can_write} +
+ + You only have read access to this resource and cannot edit it +
{/if} -

Resource description - {#if can_write} -
- - -
- {/if}

- - {#if can_write && renderDescription} -
-
GH Markdown
-