apps improvements

This commit is contained in:
Ruben Fiszel
2023-01-03 07:54:34 +01:00
parent eddb71354d
commit cc938166ca
34 changed files with 268 additions and 219 deletions
@@ -224,7 +224,7 @@
<div class="max-w-xs" />
<div
class="relative pb-6 {$propPickerConfig?.propName == argName
class="relative mb-6 {$propPickerConfig?.propName == argName
? 'outline outline-offset-0 outline-2 outline-blue-500 rounded-md'
: ''}"
>
@@ -88,7 +88,7 @@
{#if !loading}
<span class="w-5" />
{:else}
<Loader2 class="animate-spin" />
<Loader2 class="animate-spin ml-1" size={14} />
{/if}
</Button>
</AlignWrapper>
@@ -1,6 +1,6 @@
<script lang="ts">
import { isCodeInjection } from '$lib/components/flows/utils'
import { getContext, onMount } from 'svelte'
import { createEventDispatcher, getContext, onMount } from 'svelte'
import type { AppInput } from '../../inputType'
import type { AppEditorContext } from '../../types'
import { accessPropertyByPath } from '../../utils'
@@ -14,26 +14,19 @@
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
$: input && setDefault()
$: state = $worldStore?.state
$: input && $worldStore && row && handleConnection()
$: input && $state && input.type == 'template' && (value = getValue(input))
function setDefault() {
if (!value && input.defaultValue) {
value = input.defaultValue
}
}
function handleConnection() {
if (input.type === 'connected') {
$worldStore?.connect<any>(input, onValueChange)
} else if (input.type === 'row') {
value = row[input.column]
setTimeout(() => (value = row[input['column']]), 0)
} else if (input.type === 'static' || input.type == 'template') {
value = getValue(input)
setTimeout(() => (value = getValue(input)), 0)
} else {
value = undefined
setTimeout(() => (value = undefined), 0)
}
}
@@ -21,13 +21,11 @@
outputs.loading.set(false, true)
}
function setOutput() {
if (outputs) {
outputs.result?.set(result)
}
function setOutput(v: any) {
outputs.result?.set(v, true)
}
$: result !== undefined && outputs && setOutput()
$: result && outputs && setOutput(result)
</script>
{#if componentInput.type !== 'runnable'}
@@ -22,7 +22,7 @@
export let result: any = undefined
export let forceSchemaDisplay: boolean = false
const { worldStore, runnableComponents, workspace, appPath, mode } =
const { worldStore, runnableComponents, workspace, appPath, isEditor } =
getContext<AppEditorContext>('AppEditorContext')
onMount(() => {
@@ -47,7 +47,30 @@
}, 200)
}
$: fields && runnableInputValues && args && autoRefresh && testJobLoader && setDebouncedExecute()
function computeStaticValues() {
return Object.entries(fields ?? {})
.filter(([k, v]) => v.type == 'static')
.map(([name, field]) => {
return [name, field['value']]
})
}
let lazyStaticValues = computeStaticValues()
let currentStaticValues = lazyStaticValues
$: fields && (currentStaticValues = computeStaticValues())
$: if (JSON.stringify(currentStaticValues) != JSON.stringify(lazyStaticValues)) {
lazyStaticValues = currentStaticValues
setDebouncedExecute()
}
$: fields && (lazyStaticValues = computeStaticValues())
$: runnableInputValues &&
extraQueryParams &&
args &&
autoRefresh &&
testJobLoader &&
setDebouncedExecute()
// Test job internal state
let testJob: CompletedJob | undefined = undefined
@@ -164,17 +187,18 @@
await testJobLoader?.abstractRun(() => {
const nonStaticRunnableInputs = {}
const staticRunnableInputs = {}
Object.keys(fields ?? {}).forEach(([k, v]) => {
Object.keys(fields ?? {}).forEach((k) => {
let field = fields[k]
if (field.type == 'static') {
if (field?.type == 'static' && fields[k]) {
staticRunnableInputs[k] = field.value
} else {
nonStaticRunnableInputs[k] = runnableInputValues[k]
}
}, {})
})
const requestBody = {
args: { ...nonStaticRunnableInputs, ...args },
force_viewer_static_fields: $mode == 'preview' ? undefined : staticRunnableInputs
force_viewer_static_fields: !isEditor ? undefined : staticRunnableInputs
}
if (runnable?.type === 'runnableByName') {
@@ -11,7 +11,6 @@
import { classNames, isObject } from '$lib/utils'
import DebouncedInput from '../helpers/DebouncedInput.svelte'
import AppTableFooter from './AppTableFooter.svelte'
import RefreshButton from '../helpers/RefreshButton.svelte'
import { tableOptions } from './tableOptions'
import Alert from '$lib/components/common/alert/Alert.svelte'
@@ -20,17 +19,22 @@
export let configuration: Record<string, AppInput>
export let actionButtons: (BaseAppComponent & ButtonComponent)[]
export const staticOutputs: string[] = ['selectedRow', 'loading', 'result']
export const staticOutputs: string[] = ['selectedRow', 'loading', 'result', 'search']
type T = Record<string, any>
$: result = [] as Array<Record<string, any>>
let search: 'Runnable' | 'Component' | 'Disabled' | undefined = undefined
let search: 'By Runnable' | 'By Component' | 'Disabled' | undefined = undefined
let searchValue = ''
let pagination: boolean | undefined = undefined
let page = 1
$: setSearch(searchValue)
function setSearch(srch) {
outputs?.search?.set(srch)
}
const options = writable<TableOptions<T>>({
data: [],
@@ -79,7 +83,7 @@
return result
}
return result.filter((row) =>
Object.values(row).some((value) => value.toString().includes(searchValue))
Object.values(row).some((value) => value?.toString()?.includes(searchValue))
)
}
@@ -94,11 +98,11 @@
let filteredResult: Array<Record<string, any>> = []
$: filteredResult && setOptions(filteredResult)
$: extraQueryParams = search === 'Runnable' ? { search: searchValue, page } : { page, search: '' }
$: search === 'Runnable' && (filteredResult = searchInResult(result, searchValue))
$: (search === 'Runnable' || search === 'Disabled') && (filteredResult = result)
$: search === 'By Component' && (filteredResult = searchInResult(result, searchValue))
$: (search === 'By Runnable' || search === 'Disabled') && (filteredResult = result)
$: outputs = $worldStore?.outputsById[id] as {
selectedRow: Output<any>
search: Output<string>
}
function rerender() {
@@ -111,7 +115,7 @@
<InputValue {id} input={configuration.search} bind:value={search} />
<InputValue {id} input={configuration.pagination} bind:value={pagination} />
<RunnableWrapper bind:componentInput {id} bind:result {extraQueryParams}>
<RunnableWrapper bind:componentInput {id} bind:result>
{#if Array.isArray(result) && result.every(isObject)}
<div class="border border-gray-300 shadow-sm divide-y divide-gray-300 flex flex-col h-full">
{#if search !== 'Disabled'}
@@ -48,7 +48,8 @@
const summaryStore = writable(summary)
const connectingInput = writable<ConnectingInput>({
opened: false,
input: undefined
input: undefined,
hoveredComponent: undefined
})
const runnableComponents = writable<Record<string, () => Promise<void>>>({})
@@ -66,7 +67,8 @@
runnableComponents,
appPath: path,
workspace: $workspaceStore ?? '',
onchange: () => saveDraft()
onchange: () => saveDraft(),
isEditor: true
})
let timeout: NodeJS.Timeout | undefined = undefined
@@ -96,6 +98,11 @@
}
</script>
{#if $connectingInput.opened}
<div
class="absolute w-full h-screen bg-black border-2 bg-opacity-25 z-20 flex justify-center items-center"
/>
{/if}
{#if !$userStore?.operator}
<UnsavedConfirmationModal />
{#if initialMode !== 'preview'}
@@ -110,15 +117,16 @@
appPath={path}
{breakpoint}
{policy}
isEditor
/>
{:else}
<SplitPanesWrapper class="max-w-full overflow-hidden">
<Pane size={15} minSize={5} maxSize={33}>
<Pane size={$connectingInput?.opened ? 40 : 15} minSize={5} maxSize={33}>
<ContextPanel />
</Pane>
<Pane size={64}>
<SplitPanesWrapper horizontal>
<Pane size={70}>
<Pane size={$connectingInput?.opened ? 100 : 70}>
<div
class="bg-gray-100 relative w-full h-full overflow-auto {app.fullscreen
? ''
@@ -129,22 +137,12 @@
<GridEditor {policy} />
</div>
{/if}
{#if $connectingInput.opened}
<div
class="absolute top-0 left-0 w-full h-full bg-black border-2 bg-opacity-25 z-1 flex justify-center items-center"
/>
{/if}
</div>
</Pane>
<Pane size={30}>
<Pane size={$connectingInput?.opened ? 0 : 30}>
<div class="relative h-full w-full">
<InlineScriptsPanel />
{#if $connectingInput.opened}
<div
class="absolute top-0 left-0 w-full h-full bg-black border-2 bg-opacity-25 z-1 flex justify-center items-center"
/>
{/if}</div
>
</div>
</Pane>
</SplitPanesWrapper>
</Pane>
@@ -178,10 +176,7 @@
</Tabs>
{#if $connectingInput.opened}
<div
class="absolute top-0 left-0 w-full h-full bg-black border-2 bg-opacity-25 z-1 flex justify-center items-center"
/>
<div
class="fixed top-32 p-2 z-10 flex justify-center items-center"
class="fixed top-32 p-2 z-50 flex justify-center items-center"
transition:fly={{ duration: 100, y: -100 }}
>
<Alert title="Connecting" type="info">
@@ -12,7 +12,14 @@
import { AppService, Policy } from '$lib/gen'
import { userStore, workspaceStore } from '$lib/stores'
import { faClipboard, faExternalLink, faSave } from '@fortawesome/free-solid-svg-icons'
import { Eye, Laptop2, Pencil, Smartphone } from 'lucide-svelte'
import {
AlignHorizontalSpaceAround,
Expand,
Eye,
Laptop2,
Pencil,
Smartphone
} from 'lucide-svelte'
import { getContext } from 'svelte'
import { Icon } from 'svelte-awesome'
import { copyToClipboard, sendUserToast } from '../../../utils'
@@ -211,11 +218,11 @@
</DrawerContent>
</Drawer>
<div class="border-b flex flex-row justify-between py-1 gap-1 flex-wrap gap-y-2 px-4 items-center">
<div class="border-b flex flex-row justify-between py-1 gap-4 flex-wrap gap-y-2 px-4 items-center">
<div class="w-64">
<input type="text" placeholder="App summary" class="text-sm w-full" bind:value={$summary} />
</div>
<div class="flex gap-8 items-center">
<div class="flex gap-8 items-center grow justify-center">
<div>
<ToggleButtonGroup bind:selected={$mode}>
<ToggleButton position="left" value="dnd" size="xs">
@@ -240,12 +247,12 @@
<ToggleButtonGroup bind:selected={$app.fullscreen}>
<ToggleButton position="left" value={false} size="xs"
>Centered &nbsp; <Tooltip
><AlignHorizontalSpaceAround size={14} /> &nbsp; <Tooltip
>The max width is 1168px and the content stay centered instead of taking the full page
width</Tooltip
></ToggleButton
>
<ToggleButton position="right" value={true} size="xs">Full</ToggleButton>
<ToggleButton position="right" value={true} size="xs"><Expand size={14} /></ToggleButton>
</ToggleButtonGroup>
</div>
<div class="flex flex-row grow gap-4 justify-end ">
@@ -16,13 +16,7 @@
export let app: App
</script>
<Button
btnClasses="pr-4"
size="sm"
variant="border"
color="light"
on:click={() => jsonViewerDrawer.toggleDrawer()}
>
<Button size="sm" variant="border" color="light" on:click={() => jsonViewerDrawer.toggleDrawer()}>
<Icon data={faFileExport} scale={0.6} class="inline mr-2" />
JSON
</Button>
@@ -21,6 +21,7 @@
export let policy: Policy
export let summary: string
export let workspace: string
export let isEditor: boolean
const appStore = writable<App>(app)
const worldStore = writable<World | undefined>(undefined)
@@ -30,7 +31,8 @@
const connectingInput = writable<ConnectingInput>({
opened: false,
input: undefined
input: undefined,
hoveredComponent: undefined
})
const runnableComponents = writable<Record<string, () => Promise<void>>>({})
@@ -48,7 +50,8 @@
runnableComponents,
appPath,
workspace,
onchange: undefined
onchange: undefined,
isEditor
})
let mounted = false
@@ -61,7 +64,7 @@
$: width = $breakpoint === 'sm' ? 'max-w-[640px]' : 'w-full '
</script>
<div class="h-full w-full {app.fullscreen ? '' : 'max-w-6xl'} px-4 mx-auto">
<div class="h-full w-full {app.fullscreen ? '' : 'max-w-6xl'} mx-auto">
{#if $appStore.grid}
<div class={classNames('mx-auto pb-4', width)}>
<GridEditor {policy} />
@@ -101,15 +101,26 @@
}
</script>
<div class="bg-white px-2 pb-2 relative">
<div class="w-full flex justify-between border-b px-4 py-2 mb-4 items-center gap-4">
<div class="pb-2 relative z-20">
<div
class="w-full flex justify-between border-b {$connectingInput?.opened
? ''
: 'bg-gray-50 '}px-4 py-2 items-center gap-4"
>
<h2 class="truncate">{$summary}</h2>
<RecomputeAllComponents />
{#if !$connectingInput.opened}
<RecomputeAllComponents />
{/if}
<div class="text-2xs text-gray-600"
>{policy.on_behalf_of ? `on behalf of ${policy.on_behalf_of}` : ''}</div
>
</div>
<div on:pointerdown={onpointerdown} on:pointerleave={onpointerup} on:pointerup={onpointerup}>
<div
class="px-4 pt-4 {$connectingInput?.opened ? '' : 'bg-gray-50/70'}"
on:pointerdown={onpointerdown}
on:pointerleave={onpointerup}
on:pointerup={onpointerup}
>
<Grid
bind:items={$app.grid}
let:dataItem
@@ -122,9 +133,23 @@
{#each $lazyGrid as gridComponent (gridComponent.id)}
{#if gridComponent.data.id === dataItem.data.id}
<!-- svelte-ignore a11y-click-events-have-key-events -->
{#if $connectingInput.opened}
{#if $connectingInput.opened}
<div
on:pointerenter={() => ($connectingInput.hoveredComponent = gridComponent.data.id)}
on:pointerleave={() => ($connectingInput.hoveredComponent = undefined)}
class="absolute w-full h-full bg-black border-2 bg-opacity-25 z-20 flex justify-center items-center"
/>
{/if}
<div
style="transform: translate(-50%, -50%);"
class="absolute w-fit justify-center bg-indigo-500/90 left-[50%] top-[50%] z-50 px-6 rounded border text-white py-2 text-5xl center-center"
>{dataItem.data.id}</div
>
{/if}
<div
class={classNames(
'h-full w-full flex justify-center align-center',
'h-full w-full flex justify-center align-center items-center',
gridComponent.data.card ? 'border border-gray-100' : ''
)}
on:click|preventDefault|capture|once
@@ -75,14 +75,7 @@
}
let newData: AppComponent = JSON.parse(JSON.stringify(appComponent))
Object.values(newData.configuration).forEach((x) => {
if (x.type == 'static' && !x.value) {
x.value = x.defaultValue
}
})
if (newData?.componentInput?.type == 'static') {
newData.componentInput.value = newData.componentInput.defaultValue
}
const newItem: GridItem = {
data: newData,
id: id
@@ -5,7 +5,7 @@ const buttonColorOptions = [...BUTTON_COLORS]
export const staticValues = {
buttonColorOptions,
buttonSizeOptions: ['xs', 'sm', 'md', 'lg', 'xl'],
tableSearchOptions: ['Component', 'Runnable', 'Disabled'],
tableSearchOptions: ['By Component', 'By Runnable', 'Disabled'],
chartThemeOptions: ['theme1', 'theme2', 'theme3'],
textStyleOptions: ['Title', 'Subtitle', 'Body', 'Label', 'Caption']
} as const
@@ -14,7 +14,6 @@ const inputs: ComponentSet = {
type: 'static',
value: 'Type...',
fieldType: 'text',
defaultValue: 'Type...'
},
},
card: false
@@ -45,13 +44,11 @@ const inputs: ComponentSet = {
type: 'static',
value: '',
fieldType: 'date',
defaultValue: ''
},
maxDate: {
type: 'static',
value: '',
fieldType: 'date',
defaultValue: ''
}
},
card: false,
@@ -67,7 +64,6 @@ const inputs: ComponentSet = {
type: 'static',
value: 'Label',
fieldType: 'text',
defaultValue: 'Label'
}
},
card: false
@@ -82,10 +78,6 @@ const inputs: ComponentSet = {
type: 'static',
fieldType: 'array',
subFieldType: 'object',
defaultValue: [
{ value: 'foo', label: 'Foo' },
{ value: 'bar', label: 'Bar' }
],
value: [
{ value: 'foo', label: 'Foo' },
{ value: 'bar', label: 'Bar' }
@@ -94,7 +86,6 @@ const inputs: ComponentSet = {
itemKey: {
type: 'static',
fieldType: 'text',
defaultValue: 'value',
value: 'value'
}
},
@@ -116,29 +107,29 @@ const buttons: ComponentSet = {
fieldType: 'any',
fields: {},
runnable: undefined,
defaultValue: undefined
},
recomputeIds: undefined,
configuration: {
label: {
type: 'static',
value: undefined,
fieldType: 'text',
defaultValue: 'Lorem ipsum'
value: 'Lorem ipsum'
},
color: {
fieldType: 'select',
type: 'static',
value: undefined,
optionValuesKey: 'buttonColorOptions',
defaultValue: 'blue'
value: 'blue'
},
size: {
fieldType: 'select',
type: 'static',
value: undefined,
optionValuesKey: 'buttonSizeOptions',
defaultValue: 'xs'
value: 'xs'
}
},
@@ -153,7 +144,7 @@ const buttons: ComponentSet = {
fieldType: 'any',
fields: {},
runnable: undefined,
defaultValue: undefined
},
recomputeIds: undefined,
configuration: {
@@ -161,21 +152,18 @@ const buttons: ComponentSet = {
type: 'static',
value: 'Submit',
fieldType: 'text',
defaultValue: 'formcomponent'
},
color: {
fieldType: 'select',
type: 'static',
value: 'dark',
optionValuesKey: 'buttonColorOptions',
defaultValue: 'dark'
},
size: {
fieldType: 'select',
type: 'static',
value: 'xs',
optionValuesKey: 'buttonSizeOptions',
defaultValue: 'xs'
}
},
@@ -194,23 +182,23 @@ const display: ComponentSet = {
componentInput: {
type: 'static',
fieldType: 'textarea',
defaultValue: 'Lorem ipsum',
value: undefined
value: 'Lorem ipsum',
},
configuration: {
style: {
fieldType: 'select',
type: 'static',
value: undefined,
optionValuesKey: 'textStyleOptions',
defaultValue: 'Body'
value: 'Body'
},
extraStyle:
{
type: 'static',
fieldType: 'text',
defaultValue: '',
value: undefined
value: '',
},
},
@@ -223,22 +211,22 @@ const display: ComponentSet = {
search: {
fieldType: 'select',
type: 'static',
value: undefined,
optionValuesKey: 'tableSearchOptions',
defaultValue: 'Disabled'
value: 'Disabled'
},
pagination: {
type: 'static',
value: undefined,
fieldType: 'boolean',
defaultValue: false
value: false
}
},
componentInput: {
type: 'static',
fieldType: 'array',
subFieldType: 'object',
defaultValue: [
value: [
{
id: 1,
name: 'Lorem ipsum',
@@ -250,7 +238,7 @@ const display: ComponentSet = {
age: 42
}
],
value: undefined
},
card: true,
actionButtons: []
@@ -261,26 +249,24 @@ const display: ComponentSet = {
configuration: {
theme: {
type: 'static',
value: undefined,
fieldType: 'select',
optionValuesKey: 'chartThemeOptions',
defaultValue: 'theme1'
value: 'theme1'
},
labels: {
type: 'static',
value: ['First', 'Second', 'Third'],
fieldType: 'array',
subFieldType: 'text',
defaultValue: ['First', 'Second', 'Third']
}
},
componentInput: {
type: 'static',
fieldType: 'array',
subFieldType: 'number',
defaultValue: [25, 50, 25],
value: undefined
value: [25, 50, 25],
},
card: true
},
@@ -290,25 +276,25 @@ const display: ComponentSet = {
configuration: {
theme: {
type: 'static',
value: undefined,
fieldType: 'select',
optionValuesKey: 'chartThemeOptions',
defaultValue: 'theme1'
value: 'theme1'
},
labels: {
type: 'static',
value: undefined,
fieldType: 'array',
subFieldType: 'text',
defaultValue: ['Lorem ipsum', 'Lorem ipsum', 'Lorem ipsum']
value: ['Lorem ipsum', 'Lorem ipsum', 'Lorem ipsum']
}
},
componentInput: {
type: 'static',
fieldType: 'array',
subFieldType: 'number',
defaultValue: [25, 50, 25],
value: undefined
value: [25, 50, 25],
},
card: true
},
@@ -318,8 +304,8 @@ const display: ComponentSet = {
componentInput: {
type: 'static',
fieldType: 'object',
defaultValue: { "foo": 42 },
value: undefined
value: { "foo": 42 },
},
configuration: {},
card: false
@@ -19,7 +19,8 @@
path
},
type: 'connected'
}
},
hoveredComponent: undefined
}
}
}
@@ -36,10 +37,14 @@
</script>
<PanelSection noPadding titlePadding="px-4 pt-2" title="Outputs">
<div class="overflow-auto min-w-[150px] border-t w-full relative flex flex-col gap-2 px-4">
<div class="overflow-auto min-w-[150px] border-t w-full relative flex flex-col gap-2 px-4 pb-2">
{#each Object.entries($staticOutputs) as [componentId, outputs] (componentId)}
{#if outputs.length > 0 && $worldStore?.outputsById[componentId]}
<div class="flex flex-row justify-between w-full -mb-2">
<div
class="flex {$connectingInput?.opened
? 'bg-white z-50'
: ''} flex-row justify-between w-full -mb-2"
>
<button
on:click|stopPropagation|preventDefault={$connectingInput.opened
? undefined
@@ -66,13 +71,15 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class={classNames(
'w-full py-2 border relative overflow-auto',
$selectedComponent === componentId ? 'border border-blue-500 ' : ''
$connectingInput?.opened ? 'bg-white z-50' : '',
`w-full py-2 border relative overflow-auto`,
$selectedComponent === componentId ? 'border border-blue-500 ' : '',
$connectingInput.hoveredComponent === componentId ? 'outline outline-blue-500' : ''
)}
>
{#if $selectedComponent === componentId && $connectingInput?.opened}
<!-- {#if $selectedComponent === componentId && $connectingInput?.opened}
<div class="absolute top-0 left-0 w-full h-full bg-gray-500 bg-opacity-50 z-10" />
{/if}
{/if} -->
<ComponentOutputViewer
{outputs}
{componentId}
@@ -2,8 +2,8 @@
import Button from '$lib/components/common/button/Button.svelte'
import type { Preview } from '$lib/gen'
import { faTrash } from '@fortawesome/free-solid-svg-icons'
import { createEventDispatcher, onMount } from 'svelte'
import type { InlineScript } from '../../types'
import { createEventDispatcher, getContext, onMount } from 'svelte'
import type { AppEditorContext, InlineScript } from '../../types'
import { CheckCircle, Code2, X } from 'lucide-svelte'
import InlineScriptEditorDrawer from './InlineScriptEditorDrawer.svelte'
import { inferArgs } from '$lib/infer'
@@ -18,6 +18,8 @@
export let inlineScript: InlineScript
export let name: string | undefined = undefined
const { app } = getContext<AppEditorContext>('AppEditorContext')
let editor: Editor
let validCode = false
@@ -68,14 +70,17 @@
</Badge>
{/if}
<Button
size="xs"
color="light"
variant="border"
iconOnly
startIcon={{ icon: faTrash }}
on:click={() => dispatch('delete')}
/>
{#if $app.unusedInlineScripts.map((x) => x.name).includes(name ?? '')}
<Button
size="xs"
color="light"
variant="border"
iconOnly
startIcon={{ icon: faTrash }}
on:click={() => dispatch('delete')}
/>
{/if}
<Button
size="xs"
color="blue"
@@ -32,8 +32,6 @@
let drawerFlowViewer: Drawer
let flowPath: string = ''
// $: inlineScript && (componentInput = componentInput)
</script>
<Drawer bind:this={drawerFlowViewer} size="1200px">
@@ -30,19 +30,18 @@
{/each}
{/if}
{/each}
{#if Array.isArray($app.unusedInlineScripts)}
{#each $app.unusedInlineScripts as unusedInlineScript, index (index)}
{#if unusedInlineScript.name === selectedScriptComponentId}
<InlineScriptEditor
bind:inlineScript={unusedInlineScript.inlineScript}
on:delete={() => {
// remove the script from the array at the index
$app.unusedInlineScripts.splice(index, 1)
$app.unusedInlineScripts = [...$app.unusedInlineScripts]
}}
/>
{/if}
{/each}
{/if}
{#each $app.unusedInlineScripts as unusedInlineScript, index (index)}
{#if `unused-${index}` === selectedScriptComponentId}
<InlineScriptEditor
bind:name={unusedInlineScript.name}
bind:inlineScript={unusedInlineScript.inlineScript}
on:delete={() => {
// remove the script from the array at the index
$app.unusedInlineScripts.splice(index, 1)
$app.unusedInlineScripts = [...$app.unusedInlineScripts]
}}
/>
{/if}
{/each}
</Pane>
</SplitPanesWrapper>
@@ -11,7 +11,9 @@
function selectInlineScript(id: string) {
selectedScriptComponentId = id
$selectedComponent = selectedScriptComponentId
if (!id.startsWith('unused-')) {
$selectedComponent = selectedScriptComponentId
}
}
$: runnablesByName = $lazyGrid.reduce((acc, gridComponent) => {
@@ -110,11 +112,9 @@
<div
class="{classNames(
'border flex gap-1 truncate justify-between flex-row w-full items-center p-2 rounded-md cursor-pointer hover:bg-blue-50 hover:text-blue-400',
selectedScriptComponentId === unusedInlineScript.name
? 'bg-blue-100 text-blue-600'
: ''
selectedScriptComponentId === `unused-${index}` ? 'bg-blue-100 text-blue-600' : ''
)},"
on:click={() => selectInlineScript(unusedInlineScript.name)}
on:click={() => selectInlineScript(`unused-${index}`)}
>
<span class="text-xs truncate">{unusedInlineScript.name}</span>
<Badge color="red">Detached</Badge>
@@ -43,25 +43,25 @@
{/if}
<ToggleButton
title="Connected"
title="Connect"
value="connected"
position="center"
startIcon={{ icon: faArrowRight }}
size="xs"
>
{#if clientWidth > 250}
<span class="hidden lg:block"> Connected </span>
<span class="hidden lg:block"> Connect </span>
{/if}
</ToggleButton>
<ToggleButton
title="Computed"
title="Compute"
position="right"
value="runnable"
startIcon={{ icon: faCode }}
size="xs"
>
{#if clientWidth > 250}
<span class="hidden lg:block"> Computed </span>
<span class="hidden lg:block"> Compute </span>
{/if}
</ToggleButton>
</ToggleButtonGroup>
@@ -23,10 +23,11 @@
export let onDelete: (() => void) | undefined = undefined
export let rowColumns = false
const { app, staticOutputs, runnableComponents, worldStore } =
const { app, staticOutputs, runnableComponents, selectedComponent, worldStore } =
getContext<AppEditorContext>('AppEditorContext')
function removeGridElement() {
$selectedComponent = undefined
if (onDelete && component) {
delete $staticOutputs[component.id]
$staticOutputs = $staticOutputs
@@ -92,7 +93,7 @@ declare const ${k} = ${JSON.stringify(v)};
{#if component}
<div class="flex flex-col min-w-[150px] w-full divide-y">
{#if component.componentInput}
<PanelSection title={component.componentInput.fieldType === 'any' ? 'Runnable' : 'Input'}>
<PanelSection title={component.componentInput.fieldType === 'any' ? 'By Runnable' : 'Input'}>
<svelte:fragment slot="action">
<span
class={classNames(
@@ -25,22 +25,19 @@
label: {
type: 'static',
value: 'Action',
fieldType: 'text',
defaultValue: 'Action'
fieldType: 'text'
},
color: {
fieldType: 'select',
type: 'static',
value: 'dark',
optionValuesKey: 'buttonColorOptions',
defaultValue: 'dark'
optionValuesKey: 'buttonColorOptions'
},
size: {
fieldType: 'select',
type: 'static',
value: 'xs',
optionValuesKey: 'buttonSizeOptions',
defaultValue: 'xs'
optionValuesKey: 'buttonSizeOptions'
}
},
componentInput: {
@@ -48,7 +45,7 @@
fieldType: 'any',
fields: {},
runnable: undefined,
defaultValue: undefined
value: undefined
},
recomputeIds: undefined,
card: false
@@ -9,6 +9,7 @@
<div
class={classNames(
$$props.class,
'flex flex-col h-full gap-2 items-start',
noPadding ? '' : smallPadding ? 'p-2' : 'p-4'
)}
@@ -19,7 +19,8 @@
componentInput.connection = $connectingInput.input.connection
$connectingInput = {
opened: false,
input: undefined
input: undefined,
hoveredComponent: undefined
}
}
}
@@ -67,7 +68,8 @@
if (componentInput.type === 'connected') {
$connectingInput = {
opened: true,
input: undefined
input: undefined,
hoveredComponent: undefined
}
}
}}
@@ -186,6 +186,7 @@
color="light"
variant="border"
startIcon={{ icon: faPlus }}
btnClasses="truncate"
>
Create an inline script
</Button>
@@ -194,6 +195,7 @@
size="sm"
color="blue"
startIcon={{ icon: faMousePointer }}
btnClasses="truncate"
>
Select a script or flow
</Button>
@@ -84,7 +84,6 @@ type AppInputSpec<T extends InputType, U, V extends InputType = never> = (
type InputConfiguration<T extends InputType, U, V extends InputType> = {
fieldType: T
defaultValue: U
subFieldType?: V
format?: string | undefined
}
+3 -1
View File
@@ -122,6 +122,7 @@ export type ConnectingInput = {
opened: boolean
input?: ConnectedInput
sourceName?: string
hoveredComponent: string | undefined
}
export type AppEditorContext = {
@@ -137,7 +138,8 @@ export type AppEditorContext = {
runnableComponents: Writable<Record<string, () => Promise<void>>>
appPath: string,
workspace: string,
onchange: (() => void) | undefined
onchange: (() => void) | undefined,
isEditor: boolean
}
export type EditorMode = 'dnd' | 'preview'
+1 -2
View File
@@ -58,8 +58,7 @@ export function schemaToInputsSpec(schema: Schema): Record<string, StaticAppInpu
accu[key] = {
type: 'static',
defaultValue: property.default,
value: undefined,
value: property.default,
visible: property.format ? false : true,
fieldType: property.type,
format: property.format
@@ -66,7 +66,7 @@
>
{/if}
<h3 class="pb-2 pt-4">
Inline new <span class="text-blue-500">{kind == 'script' ? 'common' : kind}</span> script
Inline new <span class="text-blue-500">{kind == 'script' ? 'action' : kind}</span> script
<Tooltip>
Embed a script directly inside a flow instead of saving the script into your workspace for
reuse. You can always save an inline script to your workspace later.
@@ -19,6 +19,7 @@
<script lang="ts">
import PropPicker from '$lib/components/propertyPicker/PropPicker.svelte'
import PropPickerResult from '$lib/components/propertyPicker/PropPickerResult.svelte'
import { clickOutside } from '$lib/utils'
import { createEventDispatcher, setContext } from 'svelte'
import { Pane, Splitpanes } from 'svelte-splitpanes'
import { writable, type Writable } from 'svelte/store'
@@ -48,34 +49,44 @@
})
</script>
<Splitpanes>
<Pane minSize={20} size={60} class="relative p-4 !transition-none">
<slot />
</Pane>
<Pane minSize={20} size={40} class="py-2 relative !transition-none">
{#if result}
<PropPickerResult
{result}
on:select={({ detail }) => {
dispatch('select', detail)
if ($propPickerConfig?.onSelect(detail)) {
propPickerConfig.set(undefined)
}
}}
/>
{:else if pickableProperties}
<PropPicker
{displayContext}
{error}
{pickableProperties}
{notSelectable}
on:select={({ detail }) => {
dispatch('select', detail)
if ($propPickerConfig?.onSelect(detail)) {
propPickerConfig.set(undefined)
}
}}
/>
{/if}
</Pane>
</Splitpanes>
<div
class="h-full w-full"
use:clickOutside
on:click_outside={() => propPickerConfig.set(undefined)}
>
<Splitpanes>
<Pane minSize={20} size={60} class="relative p-4 !transition-none">
<slot />
</Pane>
<Pane
minSize={20}
size={40}
class="pt-2 relative !transition-none {$propPickerConfig ? 'border-2 border-blue-500' : ''}"
>
{#if result}
<PropPickerResult
{result}
on:select={({ detail }) => {
dispatch('select', detail)
if ($propPickerConfig?.onSelect(detail)) {
propPickerConfig.set(undefined)
}
}}
/>
{:else if pickableProperties}
<PropPicker
{displayContext}
{error}
{pickableProperties}
{notSelectable}
on:select={({ detail }) => {
dispatch('select', detail)
if ($propPickerConfig?.onSelect(detail)) {
propPickerConfig.set(undefined)
}
}}
/>
{/if}
</Pane>
</Splitpanes>
</div>
@@ -117,8 +117,10 @@
{#if !isLast && collapsed}
<span class="text-black">,</span>
{/if}
{:else}
{:else if topBrackets}
<span class="text-black">{openBracket}{closeBracket}</span>
{:else}
<span class="text-gray-600 text-xs">No items</span>
{/if}
<style>
@@ -59,7 +59,7 @@
}
</script>
<div class="flex flex-col h-full">
<div class="flex flex-col h-full ">
<div class="px-2">
{#if !notSelectable}
<div class="flex flex-row space-x-1">
@@ -30,6 +30,7 @@
appPath={app.path}
{breakpoint}
policy={app.policy}
isEditor={false}
/>
</div>
{:else}
@@ -73,6 +73,7 @@
appPath={app.path}
{breakpoint}
policy={app.policy}
isEditor={false}
/>
</div>
{:else}