feat(frontend): Update split panes (#741)
This commit is contained in:
1656
frontend/package-lock.json
generated
1656
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -48,7 +48,7 @@
|
||||
"svelte-overlay": "^1.4.1",
|
||||
"svelte-popperjs": "^1.3.2",
|
||||
"svelte-preprocess": "^4.9.8",
|
||||
"svelte-split-pane": "^0.1.2",
|
||||
"svelte-splitpanes": "^0.7.3",
|
||||
"svelte2tsx": "^0.5.20",
|
||||
"tailwindcss": "^3.1.8",
|
||||
"tslib": "^2.3.1",
|
||||
|
||||
7
frontend/src/app.d.ts
vendored
7
frontend/src/app.d.ts
vendored
@@ -3,9 +3,9 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare namespace App {
|
||||
interface Stuff {
|
||||
title: string?
|
||||
}
|
||||
interface Stuff {
|
||||
title: string?
|
||||
}
|
||||
}
|
||||
|
||||
declare var __pkg__: { version: string }
|
||||
@@ -14,4 +14,3 @@ declare module 'svelte-highlight/languages/json'
|
||||
declare module 'svelte-highlight/languages/python'
|
||||
declare module 'svelte-highlight/languages/typescript'
|
||||
declare module 'svelte-highlight/styles/github'
|
||||
declare module 'svelte-split-pane'
|
||||
|
||||
@@ -219,7 +219,7 @@
|
||||
<div>
|
||||
<Button
|
||||
color="light"
|
||||
btnClasses="mr-1 !font-medium"
|
||||
btnClasses="mx-1 !font-medium"
|
||||
on:click={variablePicker.openModal}
|
||||
size="xs"
|
||||
spacingSize="md"
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
import type { Schema } from '$lib/common'
|
||||
import type { FlowModule, Job } from '$lib/gen'
|
||||
import { getScriptByPath, sendUserToast, truncateRev } from '$lib/utils'
|
||||
|
||||
import { HSplitPane, VSplitPane } from 'svelte-split-pane'
|
||||
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import RunForm from './RunForm.svelte'
|
||||
import TestJobLoader from './TestJobLoader.svelte'
|
||||
import LogViewer from './LogViewer.svelte'
|
||||
@@ -67,50 +65,47 @@
|
||||
bind:isLoading={testIsLoading}
|
||||
bind:job={testJob}
|
||||
/>
|
||||
<HSplitPane leftPaneSize="50%" rightPaneSize="50%" minLeftPaneSize="20%" minRightPaneSize="20%">
|
||||
<left slot="left" class="relative">
|
||||
<div class="overflow-auto h-full p-4">
|
||||
<RunForm
|
||||
runnable={{ summary: mod.summary ?? '', schema, description: '' }}
|
||||
runAction={(_, args) => runTest(args)}
|
||||
schedulable={false}
|
||||
buttonText="Test just this step (Ctrl+Enter)"
|
||||
detailed={false}
|
||||
bind:args={stepArgs}
|
||||
/>
|
||||
{#if testIsLoading}
|
||||
<Button
|
||||
on:click={testJobLoader?.cancelJob}
|
||||
btnClasses="w-full mt-4"
|
||||
color="red"
|
||||
size="sm"
|
||||
startIcon={{
|
||||
icon: faRotateRight,
|
||||
classes: 'animate-spin'
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</left>
|
||||
<right slot="right">
|
||||
<div class="overflow-auto h-full">
|
||||
<VSplitPane topPanelSize="50%" downPanelSize="50%">
|
||||
<top slot="top">
|
||||
<LogViewer content={testJob?.logs} isLoading={testIsLoading} />
|
||||
</top>
|
||||
<down slot="down">
|
||||
<pre class="overflow-x-auto break-all relative h-full p-2 text-sm"
|
||||
>{#if testJob != undefined && 'result' in testJob && testJob.result != undefined}<DisplayResult
|
||||
result={testJob.result}
|
||||
/>
|
||||
{:else if testIsLoading}Waiting for result...
|
||||
{:else}Test to see the result here
|
||||
{/if}
|
||||
</pre>
|
||||
</down>
|
||||
</VSplitPane>
|
||||
</div>
|
||||
</right>
|
||||
</HSplitPane>
|
||||
<Splitpanes>
|
||||
<Pane size={50} minSize={20} class="p-4">
|
||||
<RunForm
|
||||
runnable={{ summary: mod.summary ?? '', schema, description: '' }}
|
||||
runAction={(_, args) => runTest(args)}
|
||||
schedulable={false}
|
||||
buttonText="Test just this step (Ctrl+Enter)"
|
||||
detailed={false}
|
||||
bind:args={stepArgs}
|
||||
/>
|
||||
{#if testIsLoading}
|
||||
<Button
|
||||
on:click={testJobLoader?.cancelJob}
|
||||
btnClasses="w-full mt-4"
|
||||
color="red"
|
||||
size="sm"
|
||||
startIcon={{
|
||||
icon: faRotateRight,
|
||||
classes: 'animate-spin'
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
{/if}
|
||||
</Pane>
|
||||
<Pane size={50} minSize={20}>
|
||||
<Splitpanes horizontal>
|
||||
<Pane size={50} minSize={10}>
|
||||
<LogViewer content={testJob?.logs} isLoading={testIsLoading} />
|
||||
</Pane>
|
||||
<Pane size={50} minSize={10} class="text-sm text-gray-600">
|
||||
{#if testJob != undefined && 'result' in testJob && testJob.result != undefined}
|
||||
<pre class="overflow-x-auto break-all relative h-full px-2">
|
||||
<DisplayResult result={testJob.result} />
|
||||
</pre>
|
||||
{:else}
|
||||
<div class="p-2">
|
||||
{testIsLoading ? 'Waiting for result...' : 'Test to see the result here'}
|
||||
</div>
|
||||
{/if}
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
|
||||
@@ -5,19 +5,17 @@
|
||||
import { emptySchema, scriptLangToEditorLang } from '$lib/utils'
|
||||
import { faPlay, faRotateRight } from '@fortawesome/free-solid-svg-icons'
|
||||
import Editor from './Editor.svelte'
|
||||
|
||||
import { inferArgs } from '$lib/infer'
|
||||
|
||||
import type { Preview } from '$lib/gen/models/Preview'
|
||||
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
import LogPanel from './script_editor/LogPanel.svelte'
|
||||
import { HSplitPane, VSplitPane } from 'svelte-split-pane'
|
||||
import LogPanel from './scriptEditor/LogPanel.svelte'
|
||||
import { faGithub } from '@fortawesome/free-brands-svg-icons'
|
||||
import EditorBar from './EditorBar.svelte'
|
||||
import TestJobLoader from './TestJobLoader.svelte'
|
||||
import { onMount } from 'svelte'
|
||||
import { Button, Kbd } from './common'
|
||||
import SplitPanesWrapper from './splitPanes/SplitPanesWrapper.svelte'
|
||||
|
||||
// Exported
|
||||
export let schema: Schema = emptySchema()
|
||||
@@ -122,94 +120,84 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-auto">
|
||||
<HSplitPane leftPaneSize="60%" rightPaneSize="40%" minLeftPaneSize="50px" minRightPaneSize="50px">
|
||||
<left slot="left">
|
||||
<div class="h-full">
|
||||
<div
|
||||
class="p-2 h-full"
|
||||
on:mouseleave={() => {
|
||||
inferSchema()
|
||||
}}
|
||||
>
|
||||
<Editor
|
||||
bind:code
|
||||
bind:websocketAlive
|
||||
bind:this={editor}
|
||||
cmdEnterAction={async () => {
|
||||
await inferSchema()
|
||||
runTest()
|
||||
}}
|
||||
formatAction={async () => {
|
||||
await inferSchema()
|
||||
localStorage.setItem(path ?? 'last_save', code)
|
||||
lastSave = code
|
||||
}}
|
||||
class="flex flex-1 h-full"
|
||||
lang={scriptLangToEditorLang(lang)}
|
||||
automaticLayout={true}
|
||||
/>
|
||||
<SplitPanesWrapper>
|
||||
<Pane size={60} minSize={10}>
|
||||
<div
|
||||
class="p-2 h-full"
|
||||
on:mouseleave={() => {
|
||||
inferSchema()
|
||||
}}
|
||||
>
|
||||
<Editor
|
||||
bind:code
|
||||
bind:websocketAlive
|
||||
bind:this={editor}
|
||||
cmdEnterAction={async () => {
|
||||
await inferSchema()
|
||||
runTest()
|
||||
}}
|
||||
formatAction={async () => {
|
||||
await inferSchema()
|
||||
localStorage.setItem(path ?? 'last_save', code)
|
||||
lastSave = code
|
||||
}}
|
||||
class="flex flex-1 h-full"
|
||||
lang={scriptLangToEditorLang(lang)}
|
||||
automaticLayout={true}
|
||||
/>
|
||||
</div>
|
||||
</Pane>
|
||||
<Pane size={40} minSize={10}>
|
||||
<Splitpanes horizontal>
|
||||
<Pane size={30}>
|
||||
<div class="p-4">
|
||||
<div class="break-all relative font-sans">
|
||||
<p class="items-baseline break-normal text-sm text-gray-600 hidden md:block mb-3">
|
||||
To recompute the input schema press <Kbd>Ctrl/Cmd</Kbd> + <Kbd>S</Kbd> or move the focus
|
||||
outside of the text editor
|
||||
</p>
|
||||
<SchemaForm {schema} bind:args bind:isValid />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</left>
|
||||
<right slot="right">
|
||||
<div class="h-full">
|
||||
<VSplitPane topPanelSize="30%" downPanelSize="70%">
|
||||
<top slot="top">
|
||||
<div class="h-full overflow-auto">
|
||||
<div class="p-4">
|
||||
<div class="break-all relative font-sans">
|
||||
<p class="items-baseline break-normal text-sm text-gray-600 hidden md:block mb-3">
|
||||
To recompute the input schema press <Kbd>Ctrl/Cmd</Kbd> + <Kbd>S</Kbd> or move the
|
||||
focus outside of the text editor
|
||||
</p>
|
||||
<SchemaForm {schema} bind:args bind:isValid />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</top>
|
||||
<down slot="down">
|
||||
<div class="h-full overflow-hidden">
|
||||
<div class="px-2 py-1">
|
||||
{#if testIsLoading}
|
||||
<Button
|
||||
on:click={testJobLoader?.cancelJob}
|
||||
btnClasses="w-full"
|
||||
color="red"
|
||||
size="xs"
|
||||
startIcon={{
|
||||
icon: faRotateRight,
|
||||
classes: 'animate-spin'
|
||||
}}
|
||||
>
|
||||
'Cancel'
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
on:click={runTest}
|
||||
btnClasses="w-full"
|
||||
size="xs"
|
||||
startIcon={{
|
||||
icon: faPlay,
|
||||
classes: 'animate-none'
|
||||
}}
|
||||
>
|
||||
{testIsLoading ? 'Running' : 'Test (Ctrl+Enter)'}
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
<LogPanel
|
||||
{path}
|
||||
{lang}
|
||||
previewJob={testJob}
|
||||
{pastPreviews}
|
||||
previewIsLoading={testIsLoading}
|
||||
bind:lastSave
|
||||
/>
|
||||
</div>
|
||||
</down>
|
||||
</VSplitPane>
|
||||
</div>
|
||||
</right>
|
||||
</HSplitPane>
|
||||
</div>
|
||||
</Pane>
|
||||
<Pane size={70}>
|
||||
<div class="px-2 py-1">
|
||||
{#if testIsLoading}
|
||||
<Button
|
||||
on:click={testJobLoader?.cancelJob}
|
||||
btnClasses="w-full"
|
||||
color="red"
|
||||
size="xs"
|
||||
startIcon={{
|
||||
icon: faRotateRight,
|
||||
classes: 'animate-spin'
|
||||
}}
|
||||
>
|
||||
'Cancel'
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
on:click={runTest}
|
||||
btnClasses="w-full"
|
||||
size="xs"
|
||||
startIcon={{
|
||||
icon: faPlay,
|
||||
classes: 'animate-none'
|
||||
}}
|
||||
>
|
||||
{testIsLoading ? 'Running' : 'Test (Ctrl+Enter)'}
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
<LogPanel
|
||||
{path}
|
||||
{lang}
|
||||
previewJob={testJob}
|
||||
{pastPreviews}
|
||||
previewIsLoading={testIsLoading}
|
||||
bind:lastSave
|
||||
/>
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
</Pane>
|
||||
</SplitPanesWrapper>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
export let value: string
|
||||
export let alwaysMounted: boolean = false
|
||||
export let style = ''
|
||||
|
||||
let clazz: string = ''
|
||||
export { clazz as class }
|
||||
@@ -11,7 +12,7 @@
|
||||
</script>
|
||||
|
||||
{#if value === $selected || alwaysMounted}
|
||||
<div class={`${clazz} ${value === $selected ? 'visible' : 'hidden'}`}>
|
||||
<div class={`${clazz} ${value === $selected ? 'visible' : 'hidden'}`} {style}>
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -33,7 +33,9 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="border-b border-gray-200 flex flex-row">
|
||||
<div
|
||||
class="border-b border-gray-200 flex flex-row whitespace-nowrap overflow-y-auto {$$props.class}"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
<slot name="content" />
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<!-- Flow Editor: Top level component -->
|
||||
<script lang="ts">
|
||||
import { HSplitPane } from 'svelte-split-pane'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import FlowEditorPanel from './content/FlowEditorPanel.svelte'
|
||||
import FlowModuleSchemaMap from './map/FlowModuleSchemaMap.svelte'
|
||||
import { flowStore } from './flowStore'
|
||||
@@ -11,8 +10,8 @@
|
||||
</script>
|
||||
|
||||
<div class="h-full overflow-hidden border-t">
|
||||
<HSplitPane leftPaneSize="25%" rightPaneSize="75%" minLeftPaneSize="20%" minRightPaneSize="40%">
|
||||
<left slot="left" class="h-full flex flex-col ">
|
||||
<Splitpanes>
|
||||
<Pane size={25} minSize={20} class="h-full flex flex-col">
|
||||
<FlowPreviewButtons />
|
||||
<div class="grow overflow-auto p-4 bg-gray-50">
|
||||
{#if $flowStore.value.modules && $flowStateStore.modules}
|
||||
@@ -22,11 +21,9 @@
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</left>
|
||||
<right slot="right" class="h-full">
|
||||
<div class="h-full overflow-auto bg-white ">
|
||||
<FlowEditorPanel {initialPath} />
|
||||
</div>
|
||||
</right>
|
||||
</HSplitPane>
|
||||
</Pane>
|
||||
<Pane size={75} minSize={40}>
|
||||
<FlowEditorPanel {initialPath} />
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
</div>
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
import { getStepPropPicker } from '../flowStateUtils'
|
||||
import { flowStateStore } from '../flowState'
|
||||
import PropPickerWrapper from '../propPicker/PropPickerWrapper.svelte'
|
||||
import { VSplitPane } from 'svelte-split-pane'
|
||||
import FlowModuleEarlyStop from './FlowModuleEarlyStop.svelte'
|
||||
import FlowModuleSuspend from './FlowModuleSuspend.svelte'
|
||||
import FlowRetries from './FlowRetries.svelte'
|
||||
|
||||
import { Button, Tab, TabContent, Tabs } from '$lib/components/common'
|
||||
import type { FlowModule } from '$lib/gen/models/FlowModule'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import { faTrash, faPlus } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
const { previewArgs } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
@@ -40,85 +40,78 @@
|
||||
<div slot="header" class="grow">
|
||||
<input bind:value={mod.summary} placeholder={'Summary'} />
|
||||
</div>
|
||||
<div class="overflow-hidden flex-grow">
|
||||
<VSplitPane topPanelSize="60%" downPanelSize="40%" minTopPaneSize="20%" minDownPaneSize="20%">
|
||||
<top slot="top" class="h-full">
|
||||
<div class="p-6 flex flex-col h-full overflow-clip">
|
||||
{#if mod.value.type === 'forloopflow'}
|
||||
<span class="mb-2 text-sm font-bold"
|
||||
>Iterator expression
|
||||
<Tooltip>
|
||||
List to iterate over. For more information see the
|
||||
<a href="https://docs.windmill.dev/docs/getting_started/flows#for-loops">docs.</a>
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
||||
{#if mod.value.iterator.type == 'javascript'}
|
||||
<div class="border w-full">
|
||||
<PropPickerWrapper
|
||||
{pickableProperties}
|
||||
on:select={({ detail }) => {
|
||||
editor?.insertAtCursor(detail)
|
||||
}}
|
||||
>
|
||||
<SimpleEditor
|
||||
bind:this={editor}
|
||||
lang="javascript"
|
||||
bind:code={mod.value.iterator.expr}
|
||||
class="small-editor"
|
||||
shouldBindKey={false}
|
||||
/>
|
||||
</PropPickerWrapper>
|
||||
</div>
|
||||
{:else}
|
||||
<Button
|
||||
on:click={() => {
|
||||
if (mod.value.type === 'forloopflow') mod.value.iterator.type = 'javascript'
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<span class="my-2 text-sm font-bold">Skip failures</span>
|
||||
|
||||
<Toggle
|
||||
bind:checked={mod.value.skip_failures}
|
||||
options={{
|
||||
right: 'Skip failures'
|
||||
<Splitpanes horizontal class="!max-h-[calc(100%-48px)]">
|
||||
<Pane size={60} minSize={20} class="p-4">
|
||||
{#if mod.value.type === 'forloopflow'}
|
||||
<div class="mb-2 text-sm font-bold">
|
||||
Iterator expression
|
||||
<Tooltip>
|
||||
List to iterate over. For more information see the
|
||||
<a href="https://docs.windmill.dev/docs/getting_started/flows#for-loops">docs.</a>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{#if mod.value.iterator.type == 'javascript'}
|
||||
<div class="border w-full">
|
||||
<PropPickerWrapper
|
||||
{pickableProperties}
|
||||
on:select={({ detail }) => {
|
||||
editor?.insertAtCursor(detail)
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div></top
|
||||
>
|
||||
<down slot="down" class="flex flex-col flex-1 h-full">
|
||||
<Tabs bind:selected>
|
||||
<Tab value="retries">Retries</Tab>
|
||||
<Tab value="early-stop">Early Stop</Tab>
|
||||
<Tab value="suspend">Sleep/Suspend</Tab>
|
||||
>
|
||||
<SimpleEditor
|
||||
bind:this={editor}
|
||||
lang="javascript"
|
||||
bind:code={mod.value.iterator.expr}
|
||||
class="small-editor"
|
||||
shouldBindKey={false}
|
||||
/>
|
||||
</PropPickerWrapper>
|
||||
</div>
|
||||
{:else}
|
||||
<Button
|
||||
on:click={() => {
|
||||
if (mod.value.type === 'forloopflow') mod.value.iterator.type = 'javascript'
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<div class="mt-6 mb-2 text-sm font-bold">Skip failures</div>
|
||||
<Toggle
|
||||
bind:checked={mod.value.skip_failures}
|
||||
options={{
|
||||
right: 'Skip failures'
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</Pane>
|
||||
<Pane size={40} minSize={20} class="flex flex-col flex-1">
|
||||
<Tabs bind:selected>
|
||||
<Tab value="retries">Retries</Tab>
|
||||
<Tab value="early-stop">Early Stop</Tab>
|
||||
<Tab value="suspend">Sleep/Suspend</Tab>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<div class="overflow-hidden bg-white" style="height:calc(100% - 32px);">
|
||||
<TabContent value="retries" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowRetries bind:flowModule={mod} />
|
||||
</div>
|
||||
</TabContent>
|
||||
<svelte:fragment slot="content">
|
||||
<div class="overflow-hidden bg-white" style="height:calc(100% - 32px);">
|
||||
<TabContent value="retries" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowRetries bind:flowModule={mod} />
|
||||
</div>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="early-stop" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleEarlyStop bind:flowModule={mod} />
|
||||
</div>
|
||||
</TabContent>
|
||||
<TabContent value="early-stop" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleEarlyStop bind:flowModule={mod} />
|
||||
</div>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="suspend" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleSuspend bind:flowModule={mod} />
|
||||
</div>
|
||||
</TabContent>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Tabs>
|
||||
</down>
|
||||
</VSplitPane>
|
||||
</div></FlowCard
|
||||
>
|
||||
<TabContent value="suspend" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleSuspend bind:flowModule={mod} />
|
||||
</div>
|
||||
</TabContent>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Tabs>
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
</FlowCard>
|
||||
</div>
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { VSplitPane } from 'svelte-split-pane'
|
||||
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import Tab from '$lib/components/common/tabs/Tab.svelte'
|
||||
import TabContent from '$lib/components/common/tabs/TabContent.svelte'
|
||||
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
|
||||
import Editor from '$lib/components/Editor.svelte'
|
||||
import EditorBar from '$lib/components/EditorBar.svelte'
|
||||
@@ -26,14 +24,13 @@
|
||||
} from '$lib/components/flows/flowStateUtils'
|
||||
import { flowStore } from '$lib/components/flows/flowStore'
|
||||
import SchemaForm from '$lib/components/SchemaForm.svelte'
|
||||
|
||||
import { RawScript, type FlowModule } from '$lib/gen'
|
||||
import FlowCard from '../common/FlowCard.svelte'
|
||||
import FlowModuleHeader from './FlowModuleHeader.svelte'
|
||||
import { flowStateStore, type FlowModuleState } from '../flowState'
|
||||
import { scriptLangToEditorLang } from '$lib/utils'
|
||||
import PropPickerWrapper from '../propPicker/PropPickerWrapper.svelte'
|
||||
import { getContext, setContext } from 'svelte'
|
||||
import { afterUpdate, getContext, setContext } from 'svelte'
|
||||
import type { FlowEditorContext } from '../types'
|
||||
import { loadSchemaFromModule, selectedIdToIndexes } from '../utils'
|
||||
import { writable, type Writable } from 'svelte/store'
|
||||
@@ -54,6 +51,9 @@
|
||||
let modulePreview: ModulePreview
|
||||
let websocketAlive = { pyright: false, black: false, deno: false, go: false }
|
||||
let selected = 'inputs'
|
||||
let wrapper: HTMLDivElement
|
||||
let panes: HTMLElement
|
||||
let totalTopGap = 0
|
||||
|
||||
$: shouldPick = isEmptyFlowModule(flowModule)
|
||||
$: stepPropPicker = failureModule
|
||||
@@ -99,11 +99,20 @@
|
||||
width,
|
||||
threshold: FLOW_MODULE_WIDTH_THRESHOLD
|
||||
})
|
||||
|
||||
afterUpdate(() => {
|
||||
totalTopGap = 0
|
||||
if (!(wrapper && panes)) return
|
||||
|
||||
const wrapperTop = wrapper.getBoundingClientRect().top
|
||||
const panesTop = panes.getBoundingClientRect().top
|
||||
totalTopGap = panesTop - wrapperTop
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
|
||||
<div class="flex flex-col h-full" bind:clientWidth={$width}>
|
||||
<div class="h-full" bind:this={wrapper} bind:clientWidth={$width}>
|
||||
<FlowCard bind:flowModule>
|
||||
<svelte:fragment slot="header">
|
||||
<FlowModuleHeader
|
||||
@@ -143,7 +152,7 @@
|
||||
/>
|
||||
{:else}
|
||||
{#if flowModule.value.type === 'rawscript'}
|
||||
<div class="flex-shrink-0 border-b-2 shadow-sm p-1 mb-1">
|
||||
<div class="border-b-2 shadow-sm p-1 mb-1">
|
||||
<EditorBar
|
||||
{editor}
|
||||
lang={flowModule.value['language'] ?? 'deno'}
|
||||
@@ -153,16 +162,15 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="overflow-hidden flex-grow">
|
||||
<VSplitPane
|
||||
topPanelSize={flowModule.value.type === 'rawscript' ? '50%' : '0%'}
|
||||
downPanelSize={flowModule.value.type === 'rawscript' ? '50%' : '100%'}
|
||||
minTopPaneSize="20%"
|
||||
minDownPaneSize="20%"
|
||||
>
|
||||
<top slot="top">
|
||||
<div
|
||||
bind:this={panes}
|
||||
class="h-full"
|
||||
style="max-height: calc(100% - {totalTopGap}px) !important;"
|
||||
>
|
||||
<Splitpanes horizontal>
|
||||
<Pane size={50} minSize={20}>
|
||||
{#if flowModule.value.type === 'rawscript'}
|
||||
<div on:mouseleave={() => reload(flowModule)} class="h-full overflow-auto">
|
||||
<div on:mouseleave={() => reload(flowModule)} class="h-full">
|
||||
<Editor
|
||||
bind:websocketAlive
|
||||
bind:this={editor}
|
||||
@@ -182,9 +190,8 @@
|
||||
{:else if flowModule.value.type === 'script'}
|
||||
<FlowModuleScript {flowModule} />
|
||||
{/if}
|
||||
</top>
|
||||
|
||||
<down slot="down" class="flex flex-col flex-1 h-full">
|
||||
</Pane>
|
||||
<Pane size={50} minSize={20}>
|
||||
<Tabs bind:selected>
|
||||
<Tab value="inputs">Inputs</Tab>
|
||||
<Tab value="test">Test</Tab>
|
||||
@@ -193,56 +200,43 @@
|
||||
<Tab value="early-stop">Early Stop</Tab>
|
||||
<Tab value="suspend">Sleep/Suspend</Tab>
|
||||
{/if}
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<div class="overflow-hidden bg-white" style="height:calc(100% - 32px);">
|
||||
<TabContent value="inputs" class="flex flex-col flex-1 h-full">
|
||||
<PropPickerWrapper pickableProperties={stepPropPicker.pickableProperties}>
|
||||
<!-- <pre class="text-xs">{JSON.stringify($flowStateStore, null, 4)}</pre> -->
|
||||
<p class="items-baseline text-xs text-gray-700 italic hidden md:block mb-2">
|
||||
Move the focus outside of the text editor to recompute the inputs or press
|
||||
Ctrl/Cmd+S
|
||||
</p>
|
||||
<SchemaForm
|
||||
schema={flowModuleState.schema}
|
||||
inputTransform={true}
|
||||
importPath={$selectedId}
|
||||
bind:args={flowModule.input_transforms}
|
||||
bind:extraLib={stepPropPicker.extraLib}
|
||||
/>
|
||||
</PropPickerWrapper>
|
||||
</TabContent>
|
||||
<TabContent value="test" class="flex flex-col flex-1 h-full" alwaysMounted={true}>
|
||||
<ModulePreview
|
||||
bind:this={modulePreview}
|
||||
mod={flowModule}
|
||||
schema={flowModuleState.schema}
|
||||
indices={[parentIndex, childIndex]}
|
||||
/>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="retries" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowRetries bind:flowModule />
|
||||
</div>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="early-stop" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleEarlyStop bind:flowModule />
|
||||
</div>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="suspend" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleSuspend bind:flowModule />
|
||||
</div>
|
||||
</TabContent>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Tabs>
|
||||
</down>
|
||||
</VSplitPane>
|
||||
<div class="h-[calc(100%-32px)]">
|
||||
{#if selected === 'inputs'}
|
||||
<div class="h-full overflow-auto">
|
||||
<PropPickerWrapper pickableProperties={stepPropPicker.pickableProperties}>
|
||||
<p class="items-baseline text-xs text-gray-700 italic hidden md:block mb-2">
|
||||
Move the focus outside of the text editor to recompute the inputs or press
|
||||
Ctrl/Cmd+S
|
||||
</p>
|
||||
<SchemaForm
|
||||
schema={flowModuleState.schema}
|
||||
inputTransform={true}
|
||||
importPath={$selectedId}
|
||||
bind:args={flowModule.input_transforms}
|
||||
bind:extraLib={stepPropPicker.extraLib}
|
||||
/>
|
||||
</PropPickerWrapper>
|
||||
</div>
|
||||
{:else if selected === 'test'}
|
||||
<ModulePreview
|
||||
bind:this={modulePreview}
|
||||
mod={flowModule}
|
||||
schema={flowModuleState.schema}
|
||||
indices={[parentIndex, childIndex]}
|
||||
/>
|
||||
{:else if selected === 'retries'}
|
||||
<FlowRetries bind:flowModule class="px-4 pb-4 h-full overflow-auto" />
|
||||
{:else if selected === 'early-stop'}
|
||||
<FlowModuleEarlyStop bind:flowModule class="px-4 pb-4 h-full overflow-auto" />
|
||||
{:else if selected === 'suspend'}
|
||||
<div class="px-4 pb-4 h-full overflow-auto">
|
||||
<FlowModuleSuspend bind:flowModule />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
</div>
|
||||
{/if}
|
||||
</FlowCard>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col items-start space-y-2">
|
||||
<div class="flex flex-col items-start space-y-2 {$$props.class}">
|
||||
<Toggle
|
||||
checked={isStopAfterIfEnabled}
|
||||
on:change={() => {
|
||||
@@ -86,6 +86,6 @@
|
||||
<span class="text-xs font-bold">Should skip if stopped</span>
|
||||
<input type="checkbox" disabled />
|
||||
<span class="text-xs font-bold">Stop condition expression</span>
|
||||
<textarea disabled rows="3" />
|
||||
<textarea disabled rows="3" class="min-h-[80px]" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
$: flowModule && loadCode(flowModule)
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col flex-1 h-full overflow-auto">
|
||||
<div class="flex flex-col flex-1 h-full overflow-auto p-2">
|
||||
<HighlightCode {language} {code} />
|
||||
</div>
|
||||
|
||||
@@ -85,15 +85,17 @@
|
||||
<span class="text-xs font-bold">Sleep for duration (seconds)</span>
|
||||
|
||||
{#if flowModule.sleep && schema.properties['sleep']}
|
||||
<PropPickerWrapper
|
||||
displayContext={false}
|
||||
{pickableProperties}
|
||||
on:select={({ detail }) => {
|
||||
editor?.insertAtCursor(detail)
|
||||
}}
|
||||
>
|
||||
<InputTransformForm bind:arg={flowModule.sleep} argName="sleep" {schema} />
|
||||
</PropPickerWrapper>
|
||||
<div class="border">
|
||||
<PropPickerWrapper
|
||||
displayContext={false}
|
||||
{pickableProperties}
|
||||
on:select={({ detail }) => {
|
||||
editor?.insertAtCursor(detail)
|
||||
}}
|
||||
>
|
||||
<InputTransformForm bind:arg={flowModule.sleep} argName="sleep" {schema} />
|
||||
</PropPickerWrapper>
|
||||
</div>
|
||||
{:else}
|
||||
<input type="number" disabled />
|
||||
{/if}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
$: isExponentialRetryEnabled = Boolean(flowModule.retry?.exponential)
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col items-start space-y-1">
|
||||
<div class="flex flex-col items-start space-y-1 {$$props.class}">
|
||||
<Toggle
|
||||
checked={isConstantRetryEnabled}
|
||||
on:change={() => {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</script>
|
||||
|
||||
<span
|
||||
class="flex flex-row-reverse justify-between flex-wrap gap-2 w-full py-2 px-4 bg-white border-b border-t"
|
||||
class="flex flex-row-reverse justify-between items-center flex-wrap gap-2 w-full min-h-[48px] py-1 px-4 bg-white border-b"
|
||||
>
|
||||
<Button
|
||||
btnClasses="grow"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<script lang="ts">
|
||||
import PropPicker from '$lib/components/propertyPicker/PropPicker.svelte'
|
||||
import { createEventDispatcher, setContext } from 'svelte'
|
||||
import { HSplitPane } from 'svelte-split-pane'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import { writable, type Writable } from 'svelte/store'
|
||||
|
||||
export let pickableProperties: Object = {}
|
||||
@@ -43,23 +43,19 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<HSplitPane leftPaneSize="50%" rightPaneSize="50%" minLeftPaneSize="20%" minRightPaneSize="20%">
|
||||
<left slot="left" class="relative">
|
||||
<div class="overflow-auto h-full p-4">
|
||||
<slot />
|
||||
</div>
|
||||
</left>
|
||||
<right slot="right">
|
||||
<div class="overflow-auto h-full">
|
||||
<PropPicker
|
||||
{displayContext}
|
||||
{pickableProperties}
|
||||
on:select={({ detail }) => {
|
||||
dispatch('select', detail)
|
||||
$propPickerConfig?.onSelect(detail)
|
||||
propPickerConfig.set(undefined)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</right>
|
||||
</HSplitPane>
|
||||
<Splitpanes>
|
||||
<Pane minSize={20} class="relative p-4 !duration-[0ms]">
|
||||
<slot />
|
||||
</Pane>
|
||||
<Pane minSize={20} class="px-2 py-2 h-full !duration-[0ms]">
|
||||
<PropPicker
|
||||
{displayContext}
|
||||
{pickableProperties}
|
||||
on:select={({ detail }) => {
|
||||
dispatch('select', detail)
|
||||
$propPickerConfig?.onSelect(detail)
|
||||
propPickerConfig.set(undefined)
|
||||
}}
|
||||
/>
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
|
||||
@@ -49,92 +49,90 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="px-2 pt-2">
|
||||
<input
|
||||
type="text"
|
||||
bind:value={search}
|
||||
class="bg-gray-50 mt-1 border border-gray-300 text-gray-900 text-sm rounded-lg block px-2 mb-2 w-full"
|
||||
placeholder="Search prop..."
|
||||
/>
|
||||
<div class="flex justify-between items-center space-x-1">
|
||||
<span class="font-bold text-sm">Step Context</span>
|
||||
<div class="flex space-x-2 items-center">
|
||||
{#if $propPickerConfig}
|
||||
<span
|
||||
class="flex items-center bg-blue-100 text-blue-800 text-xs font-semibold px-2 py-1 rounded dark:bg-green-200 dark:text-green-900"
|
||||
>
|
||||
{`Selected: ${$propPickerConfig?.propName}`}
|
||||
</span>
|
||||
<span
|
||||
class="flex items-center bg-blue-100 text-blue-800 text-xs font-semibold px-2 py-1 rounded dark:bg-green-200 dark:text-green-900"
|
||||
>
|
||||
{`Mode: ${$propPickerConfig?.insertionMode}`}
|
||||
</span>
|
||||
<button
|
||||
class="border px-2 py-1 text-xs rounded-md flex items-center hover:bg-gray-50 hover:text-gray-900"
|
||||
on:click={() => clearFocus()}
|
||||
>
|
||||
<Icon data={faClose} class="mr-2" scale={0.8} />
|
||||
Deselect
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={search}
|
||||
class="bg-gray-50 mt-1 border border-gray-300 text-gray-900 text-sm rounded-lg block px-2 mb-2 w-full"
|
||||
placeholder="Search prop..."
|
||||
/>
|
||||
<div class="flex justify-between items-center space-x-1">
|
||||
<span class="font-bold text-sm">Step Context</span>
|
||||
<div class="flex space-x-2 items-center">
|
||||
{#if $propPickerConfig}
|
||||
<span
|
||||
class="flex items-center bg-blue-100 text-blue-800 text-xs font-semibold px-2 py-1 rounded dark:bg-green-200 dark:text-green-900"
|
||||
>
|
||||
{`Selected: ${$propPickerConfig?.propName}`}
|
||||
</span>
|
||||
<span
|
||||
class="flex items-center bg-blue-100 text-blue-800 text-xs font-semibold px-2 py-1 rounded dark:bg-green-200 dark:text-green-900"
|
||||
>
|
||||
{`Mode: ${$propPickerConfig?.insertionMode}`}
|
||||
</span>
|
||||
<button
|
||||
class="border px-2 py-1 text-xs rounded-md flex items-center hover:bg-gray-50 hover:text-gray-900"
|
||||
on:click={() => clearFocus()}
|
||||
>
|
||||
<Icon data={faClose} class="mr-2" scale={0.8} />
|
||||
Deselect
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="overflow-y-auto mb-2">
|
||||
<ObjectViewer json={propsFiltered} on:select />
|
||||
</div>
|
||||
{#if displayContext}
|
||||
<span class="font-bold text-sm">Variables </span>
|
||||
<div class="overflow-y-auto mb-2">
|
||||
{#if displayVariable}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
on:click={() => {
|
||||
displayVariable = false
|
||||
}}>(-)</Button
|
||||
>
|
||||
<ObjectViewer
|
||||
rawKey={true}
|
||||
json={variables}
|
||||
on:select={(e) => dispatch('select', `variable('${e.detail}')`)}
|
||||
/>
|
||||
{:else}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
on:click={async () => {
|
||||
await loadVariables()
|
||||
displayVariable = true
|
||||
}}>{'{...}'}</Button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<span class="font-bold text-sm">Resources</span>
|
||||
<div class="overflow-y-auto mb-2">
|
||||
{#if displayResources}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
on:click={() => {
|
||||
displayResources = false
|
||||
}}>(-)</Button
|
||||
>
|
||||
<ObjectViewer
|
||||
rawKey={true}
|
||||
json={resources}
|
||||
on:select={(e) => dispatch('select', `resource('${e.detail}')`)}
|
||||
/>
|
||||
{:else}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
on:click={async () => {
|
||||
await loadResources()
|
||||
displayResources = true
|
||||
}}>{'{...}'}</Button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="overflow-y-auto mb-2">
|
||||
<ObjectViewer json={propsFiltered} on:select />
|
||||
</div>
|
||||
{#if displayContext}
|
||||
<span class="font-bold text-sm">Variables </span>
|
||||
<div class="overflow-y-auto mb-2">
|
||||
{#if displayVariable}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
on:click={() => {
|
||||
displayVariable = false
|
||||
}}>(-)</Button
|
||||
>
|
||||
<ObjectViewer
|
||||
rawKey={true}
|
||||
json={variables}
|
||||
on:select={(e) => dispatch('select', `variable('${e.detail}')`)}
|
||||
/>
|
||||
{:else}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
on:click={async () => {
|
||||
await loadVariables()
|
||||
displayVariable = true
|
||||
}}>{'{...}'}</Button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<span class="font-bold text-sm">Resources</span>
|
||||
<div class="overflow-y-auto mb-2">
|
||||
{#if displayResources}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
on:click={() => {
|
||||
displayResources = false
|
||||
}}>(-)</Button
|
||||
>
|
||||
<ObjectViewer
|
||||
rawKey={true}
|
||||
json={resources}
|
||||
on:select={(e) => dispatch('select', `resource('${e.detail}')`)}
|
||||
/>
|
||||
{:else}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
on:click={async () => {
|
||||
await loadResources()
|
||||
displayResources = true
|
||||
}}>{'{...}'}</Button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
import { faTimes } from '@fortawesome/free-solid-svg-icons'
|
||||
import Icon from 'svelte-awesome'
|
||||
import { check } from 'svelte-awesome/icons'
|
||||
|
||||
import Tabs from '../common/tabs/Tabs.svelte'
|
||||
import Tab from '../common/tabs/Tab.svelte'
|
||||
import TabContent from '../common/tabs/TabContent.svelte'
|
||||
@@ -16,8 +15,9 @@
|
||||
import { json } from 'svelte-highlight/languages'
|
||||
import DrawerContent from '../common/drawer/DrawerContent.svelte'
|
||||
import HighlightCode from '../HighlightCode.svelte'
|
||||
import { VSplitPane } from 'svelte-split-pane'
|
||||
import LogViewer from '../LogViewer.svelte'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import SplitPanesWrapper from '../splitPanes/SplitPanesWrapper.svelte'
|
||||
|
||||
export let path: string | undefined
|
||||
export let lang: Preview.language
|
||||
@@ -70,23 +70,28 @@
|
||||
<Tab value="last_save"><span class="text-xs">Last save</span></Tab>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<TabContent value="logs" class="h-full w-full relative">
|
||||
<VSplitPane topPanelSize="50%" downPanelSize="50%">
|
||||
<top slot="top">
|
||||
<!--
|
||||
TabContent would wrap it in an extra div which is undesirable in this situation
|
||||
because SplitPanesWrapper uses the parent element as a reference point.
|
||||
-->
|
||||
{#if selectedTab === 'logs'}
|
||||
<SplitPanesWrapper horizontal>
|
||||
<Pane class="!duration-[0ms]">
|
||||
<LogViewer content={previewJob?.logs} isLoading={previewIsLoading} />
|
||||
</top>
|
||||
<down slot="down">
|
||||
<pre class="overflow-x-auto break-all relative h-full p-2 text-sm"
|
||||
>{#if previewJob != undefined && 'result' in previewJob && previewJob.result != undefined}<DisplayResult
|
||||
result={previewJob.result}
|
||||
/>
|
||||
{:else if previewIsLoading}Waiting for result...
|
||||
{:else}Test to see the result here
|
||||
{/if}
|
||||
</pre>
|
||||
</down>
|
||||
</VSplitPane>
|
||||
</TabContent>
|
||||
</Pane>
|
||||
<Pane class="!duration-[0ms]">
|
||||
{#if previewJob != undefined && 'result' in previewJob && previewJob.result != undefined}
|
||||
<pre class="overflow-x-auto break-all relative h-full px-2">
|
||||
<DisplayResult result={previewJob.result} />
|
||||
</pre>
|
||||
{:else}
|
||||
<div class="text-sm text-gray-600 p-2">
|
||||
{previewIsLoading ? 'Waiting for result...' : 'Test to see the result here'}
|
||||
</div>
|
||||
{/if}
|
||||
</Pane>
|
||||
</SplitPanesWrapper>
|
||||
{/if}
|
||||
<TabContent value="history" class="p-2">
|
||||
<TableCustom>
|
||||
<tr slot="header-row">
|
||||
@@ -0,0 +1,39 @@
|
||||
<script lang="ts">
|
||||
import { afterUpdate } from 'svelte'
|
||||
import { Splitpanes } from 'svelte-splitpanes'
|
||||
|
||||
/**
|
||||
* This component should be used instead of `Splitpanes` if the wrapper `Splitpanes`
|
||||
* has elements that are **NOT** `Pane` above the place of this component.
|
||||
*/
|
||||
|
||||
/** This element will act as the reference point to the `Splitpanes`
|
||||
* and the top difference will be calculated from it. */
|
||||
export let refElement: HTMLElement | undefined = undefined
|
||||
export let panesClass = ''
|
||||
let wrapper: HTMLDivElement
|
||||
let gap = 0
|
||||
|
||||
function getTopDifference(): number {
|
||||
const parent = refElement || wrapper.parentElement
|
||||
if (!(wrapper && parent)) return 0
|
||||
|
||||
const wrapperTop = wrapper.getBoundingClientRect().top
|
||||
const parentTop = parent.getBoundingClientRect().top
|
||||
return wrapperTop - parentTop
|
||||
}
|
||||
|
||||
afterUpdate(() => {
|
||||
gap = getTopDifference()
|
||||
})
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={wrapper}
|
||||
class="h-full {$$props.class || ''}"
|
||||
style="max-height: calc(100% - {gap}px) !important;"
|
||||
>
|
||||
<Splitpanes class={panesClass} {...$$restProps}>
|
||||
<slot />
|
||||
</Splitpanes>
|
||||
</div>
|
||||
@@ -7,7 +7,9 @@ const config = {
|
||||
"./node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}",
|
||||
],
|
||||
safelist: [
|
||||
'hljs'
|
||||
'hljs',
|
||||
'splitpanes__pane',
|
||||
'splitpanes__splitter'
|
||||
],
|
||||
theme: {
|
||||
colors: {
|
||||
@@ -293,6 +295,59 @@ const config = {
|
||||
color: 'transparent',
|
||||
backgroundClip: 'text',
|
||||
backgroundImage: `linear-gradient(to right, ${theme('colors.blue.600')}, ${theme('colors.blue.500')})`
|
||||
},
|
||||
'.splitpanes__pane': {
|
||||
backgroundColor: theme('colors.white') + ' !important',
|
||||
overflow: 'auto !important',
|
||||
},
|
||||
'.splitpanes__splitter': {
|
||||
backgroundColor: theme('colors.gray.300') + ' !important',
|
||||
margin: '0 !important',
|
||||
border: 'none !important',
|
||||
'&::before': {
|
||||
backgroundColor: '#00000060 !important',
|
||||
},
|
||||
'&::after': {
|
||||
backgroundColor: '#3f83f850 !important',
|
||||
margin: '0 !important',
|
||||
transform: 'none !important',
|
||||
zIndex: '1001 !important',
|
||||
transition: 'opacity 200ms !important',
|
||||
opacity: '0',
|
||||
'--splitter-hover-size': '7px',
|
||||
'--splitter-hover-adjustment': '-2px'
|
||||
},
|
||||
'&:hover::after': {
|
||||
opacity: '1',
|
||||
}
|
||||
},
|
||||
'.splitpanes--vertical>.splitpanes__splitter': {
|
||||
width: '3px !important',
|
||||
'&::before': {
|
||||
left: '1px !important',
|
||||
width: '1px !important',
|
||||
marginLeft: '0 !important',
|
||||
},
|
||||
'&::after': {
|
||||
top: '0 !important',
|
||||
height: '100% !important',
|
||||
left: 'var(--splitter-hover-adjustment) !important',
|
||||
width: 'var(--splitter-hover-size) !important',
|
||||
}
|
||||
},
|
||||
'.splitpanes--horizontal>.splitpanes__splitter': {
|
||||
height: '3px !important',
|
||||
'&::before': {
|
||||
top: '1px !important',
|
||||
height: '1px !important',
|
||||
marginTop: '0 !important',
|
||||
},
|
||||
'&::after': {
|
||||
top: 'var(--splitter-hover-adjustment) !important',
|
||||
height: 'var(--splitter-hover-size) !important',
|
||||
left: '0 !important',
|
||||
width: '100% !important',
|
||||
}
|
||||
}
|
||||
});
|
||||
addUtilities({
|
||||
|
||||
Reference in New Issue
Block a user