This commit is contained in:
Ruben Fiszel
2025-06-14 09:55:51 +02:00
parent 355a92a3df
commit a9ef31f314
42 changed files with 780 additions and 575 deletions
@@ -3,10 +3,15 @@
import type { Writable } from 'svelte/store'
import type { GroupContext } from '../types'
export let context: Writable<Record<string, any>>
export let id: string
interface Props {
context: Writable<Record<string, any>>
id: string
children?: import('svelte').Snippet
}
let { context, id, children }: Props = $props()
setContext<GroupContext>('GroupContext', { id, context })
</script>
<slot />
{@render children?.()}
@@ -70,7 +70,7 @@
let errors: Record<string, string> = {}
let css = $state(initCss($app?.css?.formbuttoncomponent, customCss))
let css = $state(initCss(app?.css?.formbuttoncomponent, customCss))
let runnableWrapper: RunnableWrapper | undefined = $state()
let loading = $state(false)
let modal: AlwaysMountedModal | undefined = $state()
@@ -93,7 +93,7 @@
{customCss}
{key}
bind:css={css[key]}
componentStyle={$app.css?.formbuttoncomponent}
componentStyle={app.css?.formbuttoncomponent}
/>
{/each}
@@ -102,7 +102,7 @@
}
}
let css = $state(initCss($app.css?.schemaformcomponent, customCss))
let css = $state(initCss(app.css?.schemaformcomponent, customCss))
const resolvedConfig = $state(
initConfig(components['schemaformcomponent'].initialData.configuration, configuration)
@@ -125,7 +125,15 @@
return policy
}
$effect(() => {
args && untrack(() => handleArgsChange())
if (!args) return
{
if (args && typeof args === 'object') {
for (const key in args) {
args[key]
}
}
}
untrack(() => handleArgsChange())
})
$effect(() => {
outputs.valid.set(valid)
@@ -152,7 +160,7 @@
{customCss}
{key}
bind:css={css[key]}
componentStyle={$app.css?.schemaformcomponent}
componentStyle={app.css?.schemaformcomponent}
/>
{/each}
@@ -164,8 +172,7 @@
>
<div
onpointerdown={stopPropagation(
(e) =>
!$connectingInput.opened && selectId(e as PointerEvent, id, selectedComponent, $app)
(e) => !$connectingInput.opened && selectId(e as PointerEvent, id, selectedComponent, app)
)}
>
<SchemaForm
@@ -18,18 +18,27 @@
import DisplayResult from '$lib/components/DisplayResult.svelte'
import { userStore } from '$lib/stores'
export let id: string
export let initializing: boolean | undefined = false
export let customCss: ComponentCustomCSS<'jobiddisplaycomponent'> | undefined = undefined
export let configuration: RichConfigurations
export let render: boolean
interface Props {
id: string
initializing?: boolean | undefined
customCss?: ComponentCustomCSS<'jobiddisplaycomponent'> | undefined
configuration: RichConfigurations
render: boolean
}
let {
id,
initializing = $bindable(false),
customCss = undefined,
configuration,
render
}: Props = $props()
const { app, worldStore, workspace, appPath } = getContext<AppViewerContext>('AppViewerContext')
const requireHtmlApproval = getContext<boolean | undefined>(IS_APP_PUBLIC_CONTEXT_KEY)
let resolvedConfig = initConfig(
components['jobiddisplaycomponent'].initialData.configuration,
configuration
let resolvedConfig = $state(
initConfig(components['jobiddisplaycomponent'].initialData.configuration, configuration)
)
const outputs = initOutput($worldStore, id, {
@@ -40,18 +49,20 @@
initializing = false
let css = initCss($app.css?.jobiddisplaycomponent, customCss)
let css = $state(initCss(app.css?.jobiddisplaycomponent, customCss))
let testJobLoader: TestJobLoader | undefined = undefined
let testIsLoading: boolean = false
let testJob: Job | undefined = undefined
let testJobLoader: TestJobLoader | undefined = $state(undefined)
let testIsLoading: boolean = $state(false)
let testJob: Job | undefined = $state(undefined)
$: if (resolvedConfig.jobId) {
outputs.loading.set(true)
testJobLoader?.watchJob(resolvedConfig?.['jobId'])
}
$effect(() => {
if (resolvedConfig.jobId) {
outputs.loading.set(true)
testJobLoader?.watchJob(resolvedConfig?.['jobId'])
}
})
let result: any = undefined
let result: any = $state(undefined)
</script>
{#each Object.keys(components['jobiddisplaycomponent'].initialData.configuration) as key (key)}
@@ -69,7 +80,7 @@
{customCss}
{key}
bind:css={css[key]}
componentStyle={$app.css?.jobiddisplaycomponent}
componentStyle={app.css?.jobiddisplaycomponent}
/>
{/each}
@@ -101,13 +112,13 @@
</div>
<div
style={twMerge(
$app.css?.['displaycomponent']?.['container']?.style,
app.css?.['displaycomponent']?.['container']?.style,
customCss?.container?.style,
'wm-rich-result-container'
)}
class={twMerge(
'p-2 grow overflow-auto',
$app.css?.['displaycomponent']?.['container']?.class,
app.css?.['displaycomponent']?.['container']?.class,
customCss?.container?.class
)}
>
@@ -35,7 +35,7 @@
initializing = false
let css = initCss($app.css?.recomputeallcomponent, customCss)
let css = initCss(app.css?.recomputeallcomponent, customCss)
$: resolvedConfig.defaultRefreshInterval && handleRefreshInterval()
@@ -68,7 +68,7 @@
{customCss}
{key}
bind:css={css[key]}
componentStyle={$app.css?.recomputeallcomponent}
componentStyle={app.css?.recomputeallcomponent}
/>
{/each}
@@ -1,4 +1,7 @@
<script lang="ts">
import { run, createBubbler, stopPropagation } from 'svelte/legacy'
const bubble = createBubbler()
import Tooltip from '$lib/components/Tooltip.svelte'
import { Clipboard } from 'lucide-svelte'
import { getContext } from 'svelte'
@@ -15,23 +18,34 @@
import { initCss } from '../../utils'
import ResolveStyle from '../helpers/ResolveStyle.svelte'
export let id: string
export let componentInput: AppInput | undefined
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = 'left'
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let configuration: RichConfigurations
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'textcomponent'> | undefined = undefined
export let render: boolean
export let editorMode: boolean = false
interface Props {
id: string
componentInput: AppInput | undefined
horizontalAlignment?: 'left' | 'center' | 'right' | undefined
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
configuration: RichConfigurations
initializing?: boolean | undefined
customCss?: ComponentCustomCSS<'textcomponent'> | undefined
render: boolean
editorMode?: boolean
}
let resolvedConfig = initConfig(
components['textcomponent'].initialData.configuration,
configuration
let {
id,
componentInput,
horizontalAlignment = 'left',
verticalAlignment = undefined,
configuration,
initializing = $bindable(undefined),
customCss = undefined,
render,
editorMode = $bindable(false)
}: Props = $props()
let resolvedConfig = $state(
initConfig(components['textcomponent'].initialData.configuration, configuration)
)
$: editorMode && onEditorMode()
function onEditorMode() {
autosize()
setTimeout(() => autosize(), 50)
@@ -39,9 +53,9 @@
const { app, worldStore, mode, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
let css = initCss($app.css?.textcomponent, customCss)
let css = $state(initCss(app.css?.textcomponent, customCss))
let result: string | undefined = undefined
let result: string | undefined = $state(undefined)
if (
componentInput?.type == 'template' ||
@@ -108,16 +122,8 @@
}
}
let component = 'p'
let classes = ''
$: resolvedConfig.style && (component = getComponent())
$: resolvedConfig.style && (classes = getClasses())
$: initialValue =
componentInput?.type == 'template' || componentInput?.type == 'templatev2'
? componentInput.eval
: ''
$: editableValue = initialValue ?? ''
let component = $state('p')
let classes = $state('')
let rows = 1
@@ -140,6 +146,21 @@
// console.log(el, el?.scrollHeight)
}, 0)
}
run(() => {
editorMode && onEditorMode()
})
run(() => {
resolvedConfig.style && (component = getComponent())
})
run(() => {
resolvedConfig.style && (classes = getClasses())
})
let initialValue = $derived(
componentInput?.type == 'template' || componentInput?.type == 'templatev2'
? componentInput.eval
: ''
)
let editableValue = $derived(initialValue ?? '')
</script>
{#each Object.keys(components['textcomponent'].initialData.configuration) as key (key)}
@@ -157,22 +178,22 @@
{customCss}
{key}
bind:css={css[key]}
componentStyle={$app.css?.textcomponent}
componentStyle={app.css?.textcomponent}
/>
{/each}
<RunnableWrapper {outputs} {render} {componentInput} {id} bind:initializing bind:result>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div
class={twMerge('h-full w-full overflow-hidden', css.container?.class, 'wm-text-container')}
style={css?.container?.style}
on:dblclick={() => {
ondblclick={() => {
if (!editorMode) {
editorMode = true
document.getElementById(`text-${id}`)?.focus()
}
}}
on:keydown|stopPropagation
onkeydown={stopPropagation(bubble('keydown'))}
>
{#if $mode == 'dnd' && editorMode && (componentInput?.type == 'template' || componentInput?.type == 'templatev2')}
<AlignWrapper {verticalAlignment}>
@@ -187,20 +208,20 @@
horizontalAlignment === 'center'
? 'text-center'
: horizontalAlignment === 'right'
? 'text-right'
: 'text-left'
? 'text-right'
: 'text-left'
)}
on:pointerdown|stopPropagation
onpointerdown={stopPropagation(bubble('pointerdown'))}
style={css?.text?.style}
id={`text-${id}`}
on:pointerenter={() => {
onpointerenter={() => {
const elem = document.getElementById(`text-${id}`)
if (elem) {
elem.focus()
}
}}
{rows}
on:input={onInput}
oninput={onInput}
value={editableValue}
></textarea>
</AlignWrapper>
@@ -215,7 +236,7 @@
{/if}
</div>
{:else}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
class="flex flex-wrap gap-0.5 pb-0.5 w-full {$mode === 'dnd' &&
(componentInput?.type == 'template' || componentInput?.type == 'templatev2')
@@ -232,8 +253,8 @@
horizontalAlignment === 'center'
? 'text-center'
: horizontalAlignment === 'right'
? 'text-right'
: 'text-left'
? 'text-right'
: 'text-left'
)}
style={css?.text?.style}
>
@@ -369,7 +369,7 @@
const uuid = await executeRunnable(
runnable,
workspace,
$app.version,
app.version,
$userStore?.username,
$appPath,
id,
@@ -436,7 +436,7 @@
}
}
const oneOfRunnableInputs = isEditor ? collectOneOfFields(fields, $app) : {}
const oneOfRunnableInputs = isEditor ? collectOneOfFields(fields, app) : {}
const requestBody: ExecuteComponentData['requestBody'] = {
args: nonStaticRunnableInputs,
@@ -608,7 +608,7 @@
function handleInputClick(e: CustomEvent) {
const event = e as unknown as PointerEvent
!$connectingInput.opened && selectId(event, id, selectedComponent, $app)
!$connectingInput.opened && selectId(event, id, selectedComponent, app)
}
let cancellableRun: ((inlineScript?: InlineScript) => CancelablePromise<void>) | undefined =
@@ -12,23 +12,37 @@
import GroupWrapper from '../GroupWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
export let id: string
export let componentContainerHeight: number
export let customCss: ComponentCustomCSS<'containercomponent'> | undefined = undefined
export let render: boolean
export let groupFields: RichConfigurations | undefined = undefined
interface Props {
id: string
componentContainerHeight: number
customCss?: ComponentCustomCSS<'containercomponent'> | undefined
render: boolean
groupFields?: RichConfigurations | undefined
}
let {
id,
componentContainerHeight,
customCss = undefined,
render,
groupFields = undefined
}: Props = $props()
const { app, focusedGrid, selectedComponent, worldStore, connectingInput, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
let everRender = render
$: render && !everRender && (everRender = true)
let everRender = $state(render)
$effect(() => {
render && !everRender && (everRender = true)
})
let groupContext = writable({})
let outputs = initOutput($worldStore, id, { group: $groupContext })
$: outputs.group.set($groupContext, true)
$effect(() => {
outputs.group.set($groupContext, true)
})
function onFocus() {
$focusedGrid = {
@@ -48,7 +62,7 @@
}
})
let css = initCss($app.css?.containercomponent, customCss)
let css = $state(initCss(app.css?.containercomponent, customCss))
</script>
<InitializeComponent {id} />
@@ -59,7 +73,7 @@
{customCss}
{key}
bind:css={css[key]}
componentStyle={$app.css?.containercomponent}
componentStyle={app.css?.containercomponent}
/>
{/each}
@@ -71,7 +85,7 @@
{#if everRender}
<div class="w-full h-full">
{#if $app.subgrids?.[`${id}-0`]}
{#if app.subgrids?.[`${id}-0`]}
<GroupWrapper {id} context={groupContext}>
<SubGridEditor
visible={render}
@@ -90,7 +104,7 @@
</GroupWrapper>
{/if}
</div>
{:else if $app.subgrids?.[`${id}-0`]}
{:else if app.subgrids?.[`${id}-0`]}
<GroupWrapper {id} context={groupContext}>
<SubGridEditor visible={false} {id} subGridId={`${id}-0`} />
</GroupWrapper>
@@ -9,7 +9,7 @@
const { app } = getContext<AppViewerContext>('AppViewerContext')
let resourceOnly: boolean = true
let resourceOnly: boolean = $state(true)
</script>
<Alert type="info" title="Configurations">
@@ -19,7 +19,7 @@
<Toggle bind:checked={resourceOnly} options={{ right: 'Resource only' }} />
</div>
<div class="gap-4 flex flex-col pt-4">
{#each allItems($app.grid, $app.subgrids) as gridItem (gridItem.data.id)}
{#each allItems(app.grid, app.subgrids) as gridItem (gridItem.data.id)}
{#if gridItem?.data?.type === 'tablecomponent'}
<div>
<AppComponentInput bind:component={gridItem.data} {resourceOnly} />
@@ -52,10 +52,10 @@
{/each}
</div>
{#if $app?.hiddenInlineScripts?.length > 0}
{#if app?.hiddenInlineScripts?.length > 0}
<div class="font-bold text-lg">Background runnable inputs</div>
<div class="gap-4 flex flex-col pt-4">
{#each $app?.hiddenInlineScripts ?? [] as script, index (script.name)}
{#each app?.hiddenInlineScripts ?? [] as script, index (script.name)}
<div class="border p-2">
<div class="text-sm font-bold">{script.name}</div>
@@ -1,4 +1,6 @@
<script lang="ts">
import { run } from 'svelte/legacy'
import { push } from '$lib/history'
import { classNames } from '$lib/utils'
import { createEventDispatcher, getContext, onDestroy } from 'svelte'
@@ -21,18 +23,31 @@
import GridViewer from './GridViewer.svelte'
import GridEditorMenu from './GridEditorMenu.svelte'
export let containerHeight: number | undefined = undefined
export let containerWidth: number | undefined = undefined
let classes = ''
interface Props {
containerHeight?: number | undefined
containerWidth?: number | undefined
class?: string
style?: string
noPadding?: boolean
noYPadding?: boolean
subGridId: string
visible?: boolean
id: string
shouldHighlight?: boolean
}
export { classes as class }
export let style = ''
export let noPadding = false
export let noYPadding = false
export let subGridId: string
export let visible: boolean = true
export let id: string
export let shouldHighlight: boolean = true
let {
containerHeight = undefined,
containerWidth = undefined,
class: classes = '',
style = '',
noPadding = false,
noYPadding = false,
subGridId,
visible = true,
id,
shouldHighlight = true
}: Props = $props()
const dispatch = createEventDispatcher()
@@ -50,17 +65,19 @@
const editorContext = getContext<AppEditorContext>('AppEditorContext')
let isActive = false
let isActive = $state(false)
let sber = editorContext?.componentActive?.subscribe((x) => (isActive = x))
let everVisible = visible
let everVisible = $state(visible)
$: visible && !everVisible && (everVisible = true)
run(() => {
visible && !everVisible && (everVisible = true)
})
onDestroy(() => {
sber?.()
})
$: highlight = id === $focusedGrid?.parentComponentId && shouldHighlight
let highlight = $derived(id === $focusedGrid?.parentComponentId && shouldHighlight)
const onpointerdown = (e) => {
dispatch('focus')
@@ -68,21 +85,23 @@
function selectComponent(e: PointerEvent, id: string) {
if (!$connectingInput.opened) {
selectId(e, id, selectedComponent, $app)
selectId(e, id, selectedComponent, app)
}
}
function lock(dataItem: GridItem) {
let fComponent = findGridItem($app, dataItem.id)
let fComponent = findGridItem(app, dataItem.id)
if (fComponent) {
fComponent = toggleFixed(fComponent)
}
// $app = $app
}
let container: HTMLElement | undefined = undefined
let container: HTMLElement | undefined = $state(undefined)
$: maxRow = maxHeight($app.subgrids?.[subGridId] ?? [], containerHeight ?? 0, $breakpoint)
let maxRow = $derived(
maxHeight(app.subgrids?.[subGridId] ?? [], containerHeight ?? 0, $breakpoint)
)
export function moveComponentBetweenSubgrids(
componentId: string,
@@ -91,27 +110,27 @@
position?: { x: number; y: number }
) {
// Find the component in the source subgrid
const component = findGridItem($app, componentId)
const component = findGridItem(app, componentId)
if (!component) {
return
}
let parentGrid = findGridItemParentGrid($app, component.id)
let parentGrid = findGridItemParentGrid(app, component.id)
if (parentGrid) {
$app.subgrids &&
($app.subgrids[parentGrid] = $app.subgrids[parentGrid].filter(
app.subgrids &&
(app.subgrids[parentGrid] = app.subgrids[parentGrid].filter(
(item) => item.id !== component?.id
))
} else {
$app.grid = $app.grid.filter((item) => item.id !== component?.id)
app.grid = app.grid.filter((item) => item.id !== component?.id)
}
const gridItem = component
insertNewGridItem(
$app,
app,
(id) => ({ ...gridItem.data, id }),
{ parentComponentId: parentComponentId, subGridIndex: subGridIndex },
Object.fromEntries(gridColumns.map((column) => [column, gridItem[column]])),
@@ -123,8 +142,8 @@
true
)
// Update the app state
$app = { ...$app }
// // Update the app state
// $app = { ...$app }
if (parentGrid) {
$focusedGrid = {
@@ -140,27 +159,27 @@
export function moveToRoot(componentId: string, position?: { x: number; y: number }) {
// Find the component in the source subgrid
const component = findGridItem($app, componentId)
const component = findGridItem(app, componentId)
if (!component) {
return
}
let parentGrid = findGridItemParentGrid($app, component.id)
let parentGrid = findGridItemParentGrid(app, component.id)
if (parentGrid) {
$app.subgrids &&
($app.subgrids[parentGrid] = $app.subgrids[parentGrid].filter(
app.subgrids &&
(app.subgrids[parentGrid] = app.subgrids[parentGrid].filter(
(item) => item.id !== component?.id
))
} else {
$app.grid = $app.grid.filter((item) => item.id !== component?.id)
app.grid = app.grid.filter((item) => item.id !== component?.id)
}
const gridItem = component
insertNewGridItem(
$app,
app,
(id) => ({ ...gridItem.data, id }),
undefined,
Object.fromEntries(gridColumns.map((column) => [column, gridItem[column]])),
@@ -173,17 +192,17 @@
)
// Update the app state
$app = { ...$app }
// $app = { ...$app }
}
</script>
{#if everVisible || $app.eagerRendering}
{#if everVisible || app.eagerRendering}
<div
class="translate-x-0 translate-y-0 w-full subgrid {visible
? 'visible'
: 'invisible h-0 overflow-hidden'}"
bind:this={container}
on:pointerdown={onpointerdown}
{onpointerdown}
>
<div
class={twMerge(
@@ -206,18 +225,14 @@
>
<Grid
allIdsInPath={$allIdsInPath}
items={$app.subgrids?.[subGridId] ?? []}
items={app.subgrids?.[subGridId] ?? []}
on:redraw={(e) => {
push(editorContext?.history, $app)
if ($app.subgrids) {
$app.subgrids[subGridId] = e.detail
push(editorContext?.history, app)
if (app.subgrids) {
app.subgrids[subGridId] = e.detail
}
}}
selectedIds={$selectedComponent}
let:dataItem
let:overlapped
let:moveMode
let:componentDraggedId
scroller={container}
parentWidth={$parentWidth - 17}
{containerWidth}
@@ -227,7 +242,7 @@
if (!overlapped) {
moveToRoot(id, { x, y })
} else {
const overlappedComponent = findGridItem($app, overlapped)
const overlappedComponent = findGridItem(app, overlapped)
if (overlappedComponent && !isContainer(overlappedComponent.data.type)) {
return
@@ -250,87 +265,93 @@
}}
disableMove={!!$connectingInput.opened}
>
<ComponentWrapper
id={dataItem.id}
type={dataItem.data.type}
class={classNames(
'h-full w-full center-center',
$selectedComponent?.includes(dataItem.id) ? 'active-grid-item' : '',
'top-0'
)}
>
<GridEditorMenu id={dataItem.id}>
<Component
{overlapped}
fullHeight={dataItem?.[$breakpoint === 'sm' ? 3 : 12]?.fullHeight}
render={visible}
component={dataItem.data}
selected={Boolean($selectedComponent?.includes(dataItem.id))}
locked={isFixed(dataItem)}
on:lock={() => lock(dataItem)}
on:expand={() => {
const parentGridItem = findGridItem($app, id)
{#snippet children({ dataItem, overlapped, moveMode, componentDraggedId })}
<ComponentWrapper
id={dataItem.id}
type={dataItem.data.type}
class={classNames(
'h-full w-full center-center',
$selectedComponent?.includes(dataItem.id) ? 'active-grid-item' : '',
'top-0'
)}
>
<GridEditorMenu id={dataItem.id}>
<Component
{overlapped}
fullHeight={dataItem?.[$breakpoint === 'sm' ? 3 : 12]?.fullHeight}
render={visible}
component={dataItem.data}
selected={Boolean($selectedComponent?.includes(dataItem.id))}
locked={isFixed(dataItem)}
on:lock={() => lock(dataItem)}
on:expand={() => {
const parentGridItem = findGridItem(app, id)
if (!parentGridItem) {
return
}
if (!parentGridItem) {
return
}
$selectedComponent = [dataItem.id]
push(editorContext?.history, $app)
$selectedComponent = [dataItem.id]
push(editorContext?.history, app)
expandGriditem(
$app.subgrids?.[subGridId] ?? [],
dataItem.id,
$breakpoint,
parentGridItem
)
// $app = $app
}}
on:fillHeight={() => {
const gridItem = findGridItem($app, dataItem.id)
const b = $breakpoint === 'sm' ? 3 : 12
expandGriditem(
app.subgrids?.[subGridId] ?? [],
dataItem.id,
$breakpoint,
parentGridItem
)
// $app = $app
}}
on:fillHeight={() => {
const gridItem = findGridItem(app, dataItem.id)
const b = $breakpoint === 'sm' ? 3 : 12
if (gridItem?.[b]) {
gridItem[b].fullHeight = !gridItem[b].fullHeight
}
// $app = $app
}}
{moveMode}
{componentDraggedId}
/>
</GridEditorMenu>
</ComponentWrapper>
if (gridItem?.[b]) {
gridItem[b].fullHeight = !gridItem[b].fullHeight
}
// $app = $app
}}
{moveMode}
{componentDraggedId}
/>
</GridEditorMenu>
</ComponentWrapper>
{/snippet}
</Grid>
</div>
{:else}
<GridViewer
allIdsInPath={$allIdsInPath}
items={$app.subgrids?.[subGridId] ?? []}
let:dataItem
items={app.subgrids?.[subGridId] ?? []}
breakpoint={$breakpoint}
parentWidth={$parentWidth - 17}
{containerWidth}
{maxRow}
>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
on:pointerdown|stopPropagation={(e) => selectComponent(e, dataItem.id)}
class={classNames('h-full w-full center-center', 'top-0')}
>
<Component
fullHeight={dataItem?.[$breakpoint === 'sm' ? 3 : 12]?.fullHeight}
render={visible}
component={dataItem.data}
selected={Boolean($selectedComponent?.includes(dataItem.id))}
locked={isFixed(dataItem)}
/>
</div>
{#snippet children({ dataItem })}
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
onpointerdown={(e) => {
e.stopPropagation()
selectComponent(e, dataItem.id)
}}
class={classNames('h-full w-full center-center', 'top-0')}
>
<Component
fullHeight={dataItem?.[$breakpoint === 'sm' ? 3 : 12]?.fullHeight}
render={visible}
component={dataItem.data}
selected={Boolean($selectedComponent?.includes(dataItem.id))}
locked={isFixed(dataItem)}
/>
</div>
{/snippet}
</GridViewer>
{/if}
</div>
</div>
{:else if $app.lazyInitRequire == undefined}
{#each $app?.subgrids?.[subGridId] ?? [] as item}
{:else if app.lazyInitRequire == undefined}
{#each app?.subgrids?.[subGridId] ?? [] as item}
<Component selected={false} fullHeight={false} render={false} component={item.data} />
{/each}
{/if}
@@ -94,7 +94,11 @@
}: Props = $props()
</script>
<svelte:boundary>
<svelte:boundary
onerror={(e) => {
console.log(`error in rendering component ${component.id}`, e)
}}
>
{#if component.type === 'displaycomponent'}
<AppDisplayComponent
id={component.id}
@@ -91,9 +91,9 @@
title={name}
prefix={TITLE_PREFIX}
on:open={(e) => {
if ($app.css != undefined) {
if (type && e.detail && $app.css[type] == undefined) {
$app.css[type] = Object.fromEntries((ids ?? []).map(({ id }) => [id, {}]))
if (app.css != undefined) {
if (type && e.detail && app.css[type] == undefined) {
app.css[type] = Object.fromEntries((ids ?? []).map(({ id }) => [id, {}]))
}
}
}}
@@ -16,13 +16,13 @@
const { app } = getContext<AppViewerContext>('AppViewerContext')
let cssEditor: SimpleEditor | undefined = undefined
let alertHeight: number | undefined = undefined
let themeViewer: any = undefined
let selectedTab: 'css' | 'theme' = 'css'
let cssEditor: SimpleEditor | undefined = $state(undefined)
let alertHeight: number | undefined = $state(undefined)
let themeViewer: any = $state(undefined)
let selectedTab: 'css' | 'theme' = $state('css')
function insertSelector(selector: string) {
if ($app?.theme?.type === 'path') {
if (app?.theme?.type === 'path') {
sendUserToast(
'You cannot edit the theme because it is a path theme. Fork the theme to edit it.',
true
@@ -70,25 +70,25 @@
</div>
{/if}
<div style="height: calc(100% - {alertHeight || 0}px);">
{#if $app.theme?.type === 'inlined'}
{#if app.theme?.type === 'inlined'}
<SimpleEditor
class="h-full"
lang="css"
bind:code={$app.theme.css}
bind:code={app.theme.css}
fixedOverflowWidgets={true}
small
automaticLayout
bind:this={cssEditor}
/>
{:else}
<ThemeCodePreview theme={$app.theme}>
<ThemeCodePreview theme={app.theme}>
<div class="p-2 w-min">
<Button
size="xs"
color="dark"
on:click={async () => {
const theme = await resolveTheme($app.theme, $workspaceStore)
$app.theme = {
const theme = await resolveTheme(app.theme, $workspaceStore)
app.theme = {
type: 'inlined',
css: theme
}
@@ -32,9 +32,9 @@
function getSubgrids(item: GridItem) {
let allSubgrids = {}
let subgrids = getAllSubgridsAndComponentIds($app, item.data)[0]
let subgrids = getAllSubgridsAndComponentIds(app, item.data)[0]
for (let key of subgrids) {
allSubgrids[key] = $app.subgrids?.[key]
allSubgrids[key] = app.subgrids?.[key]
}
return allSubgrids
}
@@ -116,17 +116,17 @@
function collectStyles() {
const styles: string[] = []
// Getting global app styles
Object.values($app.css || {}).forEach((element) => {
Object.values(app.css || {}).forEach((element) => {
Object.values(element).filter(({ style }) => style && styles.push(style))
})
// Getting styles from individual components
$app.grid.map((component) => {
app.grid.map((component) => {
Object.values(component.data.customCss || {}).forEach(({ style }) => {
style && styles.push(style)
})
})
// Getting style from subgrids
Object.values($app.subgrids || {}).forEach((grid) => {
Object.values(app.subgrids || {}).forEach((grid) => {
grid.map((component) => {
Object.values(component.data.customCss || {}).forEach(({ style }) => {
style && styles.push(style)
@@ -193,7 +193,7 @@
mounted && (!value || value) && untrack(() => parseStyle())
})
$effect(() => {
$app && untrack(() => setTopColors())
app && untrack(() => setTopColors())
})
</script>
@@ -18,15 +18,15 @@
const { previewTheme, app } = getContext<AppViewerContext>('AppViewerContext')
let cssString: string | undefined = $app?.theme?.type === 'inlined' ? $app.theme.css : undefined
$: type = $app?.theme?.type
let cssString: string | undefined = app?.theme?.type === 'inlined' ? app.theme.css : undefined
let type = $derived(app?.theme?.type)
let themes: Array<{
name: string
path: string
}> = []
}> = $state([])
let loading: boolean = false
let loading: boolean = $state(false)
async function getThemes() {
loading = true
@@ -56,14 +56,14 @@
sendUserToast('Theme created:' + message)
$app.theme = {
app.theme = {
type: 'path',
path: theme.path
}
}
let nameField: string = ''
let previewThemePath: string | undefined = undefined
let nameField: string = $state('')
let previewThemePath: string | undefined = $state(undefined)
onMount(() => {
getThemes()
@@ -16,17 +16,20 @@
import ThemeDrawer from './ThemeDrawer.svelte'
import Dropdown from '$lib/components/DropdownV2.svelte'
export let previewThemePath: string | undefined = undefined
export let row: {
name: string
path: string
interface Props {
previewThemePath?: string | undefined
row: {
name: string
path: string
}
}
const { previewTheme, app } = getContext<AppViewerContext>('AppViewerContext')
let { previewThemePath = $bindable(undefined), row }: Props = $props()
let cssString: string | undefined = $app?.theme?.type === 'inlined' ? $app.theme.css : undefined
$: type = $app?.theme?.type
const { previewTheme, app } = $state(getContext<AppViewerContext>('AppViewerContext'))
let cssString: string | undefined = app?.theme?.type === 'inlined' ? app.theme.css : undefined
let type = $derived(app?.theme?.type)
const dispatch = createEventDispatcher()
@@ -41,7 +44,7 @@
}
})
$app.theme = {
app.theme = {
type: 'path',
path: row.path
}
@@ -71,7 +74,7 @@
})
stopPreview()
$app.theme = {
app.theme = {
type: 'path',
path: DEFAULT_THEME
}
@@ -111,7 +114,7 @@
const resolvedTheme = await resolveTheme(theme, $workspaceStore)
$app.theme = {
app.theme = {
type: 'inlined',
css: resolvedTheme
}
@@ -126,7 +129,7 @@
function apply() {
stopPreview()
$app.theme = {
app.theme = {
type: 'path',
path: row.path ?? ''
}
@@ -162,7 +165,7 @@
}
]
}
let themeDrawer: ThemeDrawer
let themeDrawer: ThemeDrawer | undefined = $state(undefined)
</script>
<tr class={twMerge(previewThemePath === row.path ? 'bg-blue-200' : '', 'transition-all')}>
@@ -179,7 +182,7 @@
<Badge color="blue" small>Default</Badge>
{/if}
{#if $app?.theme?.type === 'path' && $app.theme.path === row.path}
{#if app?.theme?.type === 'path' && app.theme.path === row.path}
<Badge color="green" small>Active</Badge>
{/if}
@@ -193,7 +196,7 @@
Update
</Button>
{/if}
{#if $app?.theme?.type !== 'path' || $app.theme.path !== row.path}
{#if app?.theme?.type !== 'path' || app.theme.path !== row.path}
<Button color="light" size="xs" on:click={preview} startIcon={{ icon: Eye }}>
Preview
</Button>
@@ -12,34 +12,38 @@
const { app, initialized } = getContext<AppViewerContext>('AppViewerContext')
$: unintitializedComponents = allItems($app.grid, $app.subgrids)
.map((x) => x.id)
.filter((x) => !$initialized.initializedComponents?.includes(x))
.sort()
let unintitializedComponents = $derived(
allItems(app.grid, app.subgrids)
.map((x) => x.id)
.filter((x) => !$initialized.initializedComponents?.includes(x))
.sort()
)
$: subgridsErrors = Object.keys($app.subgrids ?? {})
.map((x) => {
const parentId = x.split('-')[0]
const parent = findGridItem($app, parentId)
const subgrid = x.replace(`${parentId}-`, '')
if (subgrid == '-1') {
return {
subGridId: x,
error: 'Invalid subgrid index -1 '
let subgridsErrors = $derived(
Object.keys(app.subgrids ?? {})
.map((x) => {
const parentId = x.split('-')[0]
const parent = findGridItem(app, parentId)
const subgrid = x.replace(`${parentId}-`, '')
if (subgrid == '-1') {
return {
subGridId: x,
error: 'Invalid subgrid index -1 '
}
} else if (parent === undefined) {
return {
subGridId: x,
error: 'Parent not found'
}
} else if (parent?.data?.numberOfSubgrids === undefined) {
return {
subGridId: x,
error: 'Parent is not a container'
}
}
} else if (parent === undefined) {
return {
subGridId: x,
error: 'Parent not found'
}
} else if (parent?.data?.numberOfSubgrids === undefined) {
return {
subGridId: x,
error: 'Parent is not a container'
}
}
})
.filter(Boolean)
})
.filter(Boolean)
)
</script>
<div class="flex flex-col gap-8" style="all:none;">
@@ -79,7 +83,7 @@
<!-- Iterate over uninitializedComponents to display each component in the grid -->
{#each unintitializedComponents as c}
{@const item = findGridItem($app, c)}
{@const item = findGridItem(app, c)}
{#if !item}
<div>Item {c} not found</div>
{:else}
@@ -107,8 +111,8 @@
}}
size="xs2"
on:click={() => {
let parent = findGridItemParentGrid($app, c)
deleteGridItem($app, item.data, parent) // $app = $app
let parent = findGridItemParentGrid(app, c)
deleteGridItem(app, item.data, parent) // $app = $app
}}
>
Remove
@@ -162,9 +166,8 @@
}}
size="xs2"
on:click={() => {
if ($app.subgrids && s) {
delete $app.subgrids[s.subGridId]
$app = { ...$app }
if (app.subgrids && s) {
delete app.subgrids[s.subGridId]
}
}}
>
@@ -9,10 +9,10 @@
import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte'
const { app } = getContext<AppViewerContext>('AppViewerContext')
let code = $state(JSON.stringify($app.lazyInitRequire))
let code = $state(JSON.stringify(app.lazyInitRequire))
let selectedRendering = $state(
$app.eagerRendering ? 'eager' : $app.lazyInitRequire ? 'lazy' : 'semi-lazy'
app.eagerRendering ? 'eager' : app.lazyInitRequire ? 'lazy' : 'semi-lazy'
)
</script>
@@ -32,15 +32,15 @@
bind:selected={selectedRendering}
on:selected={(e) => {
if (e.detail == 'eager') {
$app.eagerRendering = true
$app.lazyInitRequire = undefined
app.eagerRendering = true
app.lazyInitRequire = undefined
} else if (e.detail == 'semi-lazy') {
$app.eagerRendering = undefined
$app.lazyInitRequire = undefined
app.eagerRendering = undefined
app.lazyInitRequire = undefined
} else {
$app.eagerRendering = undefined
$app.lazyInitRequire = []
code = JSON.stringify($app.lazyInitRequire)
app.eagerRendering = undefined
app.lazyInitRequire = []
code = JSON.stringify(app.lazyInitRequire)
}
}}
>
@@ -65,7 +65,7 @@
</Section>
{:else if selectedRendering == 'lazy'}
<Section label="Component ids to wait the initialization of before the initial refresh">
<JsonEditor bind:value={$app.lazyInitRequire} {code} />
<JsonEditor bind:value={app.lazyInitRequire} {code} />
<span class="text-tertiary text-xs">
{'e.g: ["a", "b"]'}, no need to put background runnables ids
</span>
@@ -7,18 +7,24 @@
const { connectingInput } = getContext<AppViewerContext>('AppViewerContext')
export let id: string
export let first: boolean = false
export let label: string
export let renderRec: boolean
interface Props {
id: string
first?: boolean
label: string
renderRec: boolean
}
let { id, first = false, label, renderRec }: Props = $props()
</script>
<OutputHeader render={renderRec} let:render renamable={false} {id} name={label} {first}>
<ComponentOutputViewer
{render}
componentId={id}
on:select={({ detail }) => {
$connectingInput = connectInput($connectingInput, id, detail)
}}
/>
<OutputHeader render={renderRec} renamable={false} {id} name={label} {first}>
{#snippet children({ render })}
<ComponentOutputViewer
{render}
componentId={id}
on:select={({ detail }) => {
$connectingInput = connectInput($connectingInput, id, detail)
}}
/>
{/snippet}
</OutputHeader>
@@ -30,8 +30,7 @@
stateId,
worldStore,
state: stateStore,
appPath,
app
appPath
} = getContext<AppViewerContext>('AppViewerContext')
interface Props {
@@ -6,9 +6,13 @@
import type { Runnable, StaticAppInput } from '../../inputType'
import { createEventDispatcher, getContext } from 'svelte'
export let runnable: HiddenRunnable
export let id: string
export let transformer: boolean
interface Props {
runnable: HiddenRunnable
id: string
transformer: boolean
}
let { runnable = $bindable(), id, transformer }: Props = $props()
const { runnableComponents, app } = getContext<AppViewerContext>('AppViewerContext')
async function fork(nrunnable: Runnable) {
@@ -69,7 +73,7 @@
/>
{:else}
<EmptyInlineScript
unusedInlineScripts={$app?.unusedInlineScripts}
unusedInlineScripts={app?.unusedInlineScripts}
on:pick={(e) => onPick(e.detail)}
on:delete
showScriptPicker
@@ -71,7 +71,7 @@
}
function appendMigrationsToCss(migrations: Map<string, string[]>) {
const theme = $app.theme
const theme = app.theme
if (theme?.type === 'path') {
sendUserToast(
@@ -111,7 +111,7 @@
theme.css = cssString
$app.theme = theme
app.theme = theme
}
}
@@ -167,7 +167,7 @@
</Badge>
</div>
{/if}
{#if component?.type && $app.css}
{#if component?.type && app.css}
{#each Object.keys(component.customCss ?? {}) as cssKey}
{#if component.customCss?.[cssKey].style != undefined && component.customCss[cssKey].style !== ''}
<div class="grid grid-cols-2 gap-2">
@@ -215,15 +215,15 @@
{/each}
{/if}
{#if hasStyles(component?.type ? $app.css?.[component?.type] : undefined)}
{#if hasStyles(component?.type ? app.css?.[component?.type] : undefined)}
<div class="leading-6 text-xs font-semibold">
Global: {component?.type ? ccomponents[component.type]?.name : ''}
</div>
{/if}
{#if component?.type && $app.css}
{#each Object.keys($app.css[component?.type] ?? {}) as cssKey}
{#if type && $app.css?.[type]?.[cssKey].style != undefined && $app.css[type]?.[cssKey].style !== ''}
{#if component?.type && app.css}
{#each Object.keys(app.css[component?.type] ?? {}) as cssKey}
{#if type && app.css?.[type]?.[cssKey].style != undefined && app.css[type]?.[cssKey].style !== ''}
<div class="grid grid-cols-2 gap-2">
<div>
<div class="flex flex-row justify-between items-center py-0.5">
@@ -236,9 +236,9 @@
color="dark"
size="xs"
on:click={() => {
if (type && $app.css?.[type]) {
setOrUpdateMigration(cssKey, $app.css[type][cssKey].style)
$app.css[type][cssKey].style = ''
if (type && app.css?.[type]) {
setOrUpdateMigration(cssKey, app.css[type][cssKey].style)
app.css[type][cssKey].style = ''
}
}}
endIcon={{ icon: MoveRight }}
@@ -247,14 +247,14 @@
</Button>
</div>
<div class="border p-2 rounded-md">
<Highlight code={$app.css[type][cssKey].style} language={css} />
<Highlight code={app.css[type][cssKey].style} language={css} />
</div>
</div>
<div class="">
<div class="leading-6 text-xs font-semibold my-1">Preview</div>
<div class="border rounded-md p-2">
<Highlight
code={`${getSelector(cssKey)} {\n\t${$app.css[type][cssKey].style}\n}`}
code={`${getSelector(cssKey)} {\n\t${app.css[type][cssKey].style}\n}`}
language={css}
/>
</div>
@@ -7,29 +7,35 @@
import typescript from 'svelte-highlight/languages/typescript'
import { Button } from '$lib/components/common'
import HighlightTheme from '$lib/components/HighlightTheme.svelte'
export let type: keyof typeof components
interface Props {
type: keyof typeof components
}
let { type }: Props = $props()
const componentControls = getComponentControl(type)
let collapsed: boolean = true
let collapsed: boolean = $state(true)
</script>
<HighlightTheme />
{#if componentControls?.length > 0}
<PanelSection title="Controls">
<div slot="action" class="flex justify-end flex-wrap gap-1">
<Button
color="light"
size="xs2"
btnClasses="text-2xs font-normal"
on:click={() => {
collapsed = !collapsed
}}
>
{collapsed ? 'Show' : 'Hide'} details
</Button>
</div>
{#snippet action()}
<div class="flex justify-end flex-wrap gap-1">
<Button
color="light"
size="xs2"
btnClasses="text-2xs font-normal"
on:click={() => {
collapsed = !collapsed
}}
>
{collapsed ? 'Show' : 'Hide'} details
</Button>
</div>
{/snippet}
{#if collapsed}
<div class="flex flex-row gap-1 flex-wrap">
@@ -17,7 +17,7 @@
let { componentInput = $bindable(), disableStatic = false, evalV2editor }: Props = $props()
const { onchange, connectingInput, app } = getContext<AppViewerContext>('AppViewerContext')
const { onchange, connectingInput } = getContext<AppViewerContext>('AppViewerContext')
const dispatch = createEventDispatcher()
@@ -47,7 +47,7 @@
function addGridItemContext(parentId: string) {
if (!parentId) return
const gridItem = findGridItem($app, parentId)
const gridItem = findGridItem(app, parentId)
addParentContextVariable(gridItem)
}
@@ -62,7 +62,7 @@
function findParentsContextVariables(id: string): void {
if (!id) return
const allParents = dfs($app.grid, id, $app.subgrids ?? {})
const allParents = dfs(app.grid, id, app.subgrids ?? {})
if (!allParents) return
@@ -21,8 +21,8 @@
export function removeGridElement() {
const id = $selectedComponent?.[0]
const componentSetting = findComponentSettings($app, id)
push(history, $app)
const componentSetting = findComponentSettings(app, id)
push(history, app)
const onDeleteComponentControl = id ? $componentControl[id]?.onDelete : undefined
if (onDeleteComponentControl) {
@@ -44,7 +44,7 @@
$selectedComponent = undefined
$focusedGrid = undefined
if (componentSetting?.item && !noGrid) {
let ids = deleteGridItem($app, componentSetting?.item.data, componentSetting?.parent)
let ids = deleteGridItem(app, componentSetting?.item.data, componentSetting?.parent)
for (const key of ids) {
delete $runnableComponents[key]
}
@@ -13,24 +13,32 @@
import { deleteGridItem } from '../appUtils'
import type { AppComponent } from '../component'
export let conditions: RichConfiguration[] = []
export let component: AppComponent
interface Props {
conditions?: RichConfiguration[]
component: AppComponent
}
let items = conditions.slice(0, -1).map((condition, index) => {
return { value: condition, id: generateRandomString(), originalIndex: index }
let { conditions = $bindable([]), component = $bindable() }: Props = $props()
let items = $state(
conditions.slice(0, -1).map((condition, index) => {
return { value: condition, id: generateRandomString(), originalIndex: index }
})
)
$effect.pre(() => {
conditions = items
.map((item) => item.value)
.concat([
{
type: 'evalv2',
expr: 'true',
fieldType: 'boolean',
connections: []
}
])
})
$: conditions = items
.map((item) => item.value)
.concat([
{
type: 'evalv2',
expr: 'true',
fieldType: 'boolean',
connections: []
}
])
const { app, runnableComponents, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
@@ -49,7 +57,7 @@
const newSubgrids = {}
for (let i = 0; i < items.length; i++) {
newSubgrids[`${component.id}-${i}`] =
$app!.subgrids![`${component.id}-${items[i].originalIndex}`] ?? []
app!.subgrids![`${component.id}-${items[i].originalIndex}`] ?? []
}
// update originalIndex
@@ -57,8 +65,8 @@
item.originalIndex = i
})
$app!.subgrids = {
...$app!.subgrids,
app!.subgrids = {
...app!.subgrids,
...newSubgrids
} // $app = $app
@@ -71,8 +79,8 @@
function deleteSubgrid(index: number) {
let subgrid = `${component.id}-${index}`
for (const item of $app!.subgrids![subgrid]) {
const components = deleteGridItem($app, item.data, subgrid)
for (const item of app!.subgrids![subgrid]) {
const components = deleteGridItem(app, item.data, subgrid)
for (const key in components) {
delete $runnableComponents[key]
}
@@ -80,7 +88,7 @@
$runnableComponents = $runnableComponents
for (let i = index; i < items.length; i++) {
$app!.subgrids![`${component.id}-${i}`] = $app!.subgrids![`${component.id}-${i + 1}`]
app!.subgrids![`${component.id}-${i}`] = app!.subgrids![`${component.id}-${i + 1}`]
}
// Remove the corresponding item from the items array
@@ -93,20 +101,20 @@
})
items = nitems
delete $app!.subgrids![`${component.id}-${items.length + 1}`] // $app = $app
delete app!.subgrids![`${component.id}-${items.length + 1}`] // $app = $app
}
function addCondition(): void {
const numberOfConditions = conditions.length
if (!$app.subgrids) {
$app.subgrids = {}
if (!app.subgrids) {
app.subgrids = {}
}
$app.subgrids[`${component.id}-${numberOfConditions}`] =
$app.subgrids[`${component.id}-${numberOfConditions - 1}`]
app.subgrids[`${component.id}-${numberOfConditions}`] =
app.subgrids[`${component.id}-${numberOfConditions - 1}`]
$app.subgrids[`${component.id}-${numberOfConditions - 1}`] = []
app.subgrids[`${component.id}-${numberOfConditions - 1}`] = []
const newCondition: AppInputSpec<'boolean', boolean> = {
type: 'evalv2',
@@ -139,8 +147,8 @@
flipDurationMs: 200,
dropTargetStyle: {}
}}
on:consider={handleConsider}
on:finalize={handleFinalize}
onconsider={handleConsider}
onfinalize={handleFinalize}
>
{#each items as item, index (item.id)}
{@const condition = item.value}
@@ -166,14 +174,14 @@
</div>
<div class="flex flex-col justify-center gap-2">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div on:click={() => deleteSubgrid(index)}>
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div onclick={() => deleteSubgrid(index)}>
<X size={16} />
</div>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div use:dragHandle class="w-4 h-4 handle" aria-label="drag-handle">
<GripVertical size={16} />
</div>
@@ -1,4 +1,7 @@
<script lang="ts">
import { createBubbler, stopPropagation } from 'svelte/legacy'
const bubble = createBubbler()
import Button from '$lib/components/common/button/Button.svelte'
import CloseButton from '$lib/components/common/CloseButton.svelte'
import { getContext, tick } from 'svelte'
@@ -11,27 +14,40 @@
import { GripVertical, Plus } from 'lucide-svelte'
import GridTabDisabled from './GridTabDisabled.svelte'
export let tabs: string[] = []
export let disabledTabs: RichConfiguration[] = []
export let canDisableTabs: boolean = false
export let word: string = 'Tab'
export let component: AppComponent
$: if (disabledTabs == undefined) {
disabledTabs = [
{ type: 'static', value: false, fieldType: 'boolean' },
{ type: 'static', value: false, fieldType: 'boolean' }
]
interface Props {
tabs?: string[]
disabledTabs?: RichConfiguration[]
canDisableTabs?: boolean
word?: string
component: AppComponent
}
let items = tabs.map((tab, index) => {
return { value: tab, id: generateRandomString(), originalIndex: index }
let {
tabs = $bindable([]),
disabledTabs = $bindable([]),
canDisableTabs = false,
word = 'Tab',
component = $bindable()
}: Props = $props()
$effect.pre(() => {
if (disabledTabs == undefined) {
disabledTabs = [
{ type: 'static', value: false, fieldType: 'boolean' },
{ type: 'static', value: false, fieldType: 'boolean' }
]
}
})
$: tabs = items.map((item) => item.value)
let items = $state(
tabs.map((tab, index) => {
return { value: tab, id: generateRandomString(), originalIndex: index }
})
)
$effect.pre(() => {
tabs = items.map((item) => item.value)
})
const { app, runnableComponents, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
@@ -39,11 +55,11 @@
function addTab() {
const numberOfTabs = items.length
if (!$app.subgrids) {
$app.subgrids = {}
if (!app.subgrids) {
app.subgrids = {}
}
$app.subgrids[`${component.id}-${numberOfTabs}`] = []
app.subgrids[`${component.id}-${numberOfTabs}`] = []
items = [
...items,
{
@@ -59,8 +75,8 @@
function deleteSubgrid(index: number) {
let subgrid = `${component.id}-${index}`
for (const item of $app!.subgrids![subgrid]) {
const components = deleteGridItem($app, item.data, subgrid)
for (const item of app!.subgrids![subgrid]) {
const components = deleteGridItem(app, item.data, subgrid)
for (const key in components) {
delete $runnableComponents[key]
}
@@ -68,7 +84,7 @@
$runnableComponents = $runnableComponents
for (let i = index; i < items.length - 1; i++) {
$app!.subgrids![`${component.id}-${i}`] = $app!.subgrids![`${component.id}-${i + 1}`]
app!.subgrids![`${component.id}-${i}`] = app!.subgrids![`${component.id}-${i + 1}`]
}
// Remove the corresponding item from the items array
@@ -84,7 +100,7 @@
})
items = items
delete $app!.subgrids![`${component.id}-${items.length}`] // $app = $app
delete app!.subgrids![`${component.id}-${items.length}`] // $app = $app
}
function handleConsider(e: CustomEvent): void {
@@ -109,7 +125,7 @@
const newSubgrids = {}
for (let i = 0; i < items.length; i++) {
newSubgrids[`${component.id}-${i}`] =
$app!.subgrids![`${component.id}-${items[i].originalIndex}`] ?? []
app!.subgrids![`${component.id}-${items[i].originalIndex}`] ?? []
}
const newDisabledTabs: RichConfiguration[] = []
@@ -123,8 +139,8 @@
item.originalIndex = i
})
$app!.subgrids = {
...$app!.subgrids,
app!.subgrids = {
...app!.subgrids,
...newSubgrids
} // $app = $app
@@ -147,15 +163,15 @@
flipDurationMs: 200,
dropTargetStyle: {}
}}
on:consider={handleConsider}
on:finalize={handleFinalize}
onconsider={handleConsider}
onfinalize={handleFinalize}
>
{#each items as item, index (item.id)}
<div class="border rounded-md p-2 mb-2 bg-surface">
<div class="w-full flex flex-row gap-2 items-center relative my-1">
<input
on:keydown|stopPropagation
on:input={(e) => updateItemValue(index, e)}
onkeydown={stopPropagation(bubble('keydown'))}
oninput={(e) => updateItemValue(index, e)}
type="text"
bind:value={items[index].value}
/>
@@ -164,9 +180,9 @@
</div>
<div class="flex flex-col justify-center gap-2">
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div use:dragHandle class="handle w-4 h-4" aria-label="drag-handle">
<GripVertical size={16} />
</div>
@@ -13,8 +13,7 @@
export let components: (BaseAppComponent & ButtonComponent)[]
export let id: string
const { selectedComponent, app, errorByComponent } =
getContext<AppViewerContext>('AppViewerContext')
const { selectedComponent, errorByComponent } = getContext<AppViewerContext>('AppViewerContext')
function addComponent() {
const actionId = getNextId(components.map((x) => x.id.split('_')[1]))
@@ -9,16 +9,22 @@
const { app } = getContext<AppViewerContext>('AppViewerContext')
export let appInput: ResultAppInput
export let appComponent: AppComponent
$: if (appInput.autoRefresh === undefined) {
appInput.autoRefresh = true
interface Props {
appInput: ResultAppInput
appComponent: AppComponent
}
let { appInput = $bindable(), appComponent = $bindable() }: Props = $props()
$effect.pre(() => {
if (appInput.autoRefresh === undefined) {
appInput.autoRefresh = true
}
})
function detach() {
if (appInput.runnable?.type === 'runnableByName' && appInput.runnable.inlineScript) {
$app.unusedInlineScripts.push({
app.unusedInlineScripts.push({
name: appInput.runnable.name,
inlineScript: appInput.runnable.inlineScript
}) // $app = $app
@@ -30,7 +36,7 @@
appInput = clearResultAppInput(appInput)
}
$: {
$effect.pre(() => {
if (appInput.recomputeOnInputChanged === undefined) {
appInput.recomputeOnInputChanged = true
}
@@ -39,11 +45,13 @@
appInput.recomputeOnInputChanged = !appInput.doNotRecomputeOnInputChanged
appInput.doNotRecomputeOnInputChanged = undefined
}
}
})
$: hasScript =
let hasScript = $derived(
appInput?.runnable?.type === 'runnableByPath' ||
(appInput?.runnable?.type === 'runnableByName' && appInput.runnable?.inlineScript !== undefined)
(appInput?.runnable?.type === 'runnableByName' &&
appInput.runnable?.inlineScript !== undefined)
)
function getActions(_hasScript: boolean): ActionType[] {
return [
@@ -66,7 +74,7 @@
]
}
$: actions = getActions(hasScript)
let actions = $derived(getActions(hasScript))
</script>
<ComponentScriptSettings bind:appInput bind:appComponent {hasScript} {actions} />
@@ -20,28 +20,29 @@
const { app, cssEditorOpen, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
let component: AppComponent | undefined
$: {
const newComponent = findComponentSettings($app, $selectedComponent?.[0])?.item?.data
let component: AppComponent | undefined = $state()
$effect.pre(() => {
const newComponent = findComponentSettings(app, $selectedComponent?.[0])?.item?.data
if (component != newComponent) {
component = newComponent
}
}
})
let tab: 'local' | 'global' = 'local'
let overrideGlobalCSS: (() => void) | undefined = undefined
let overrideLocalCSS: (() => void) | undefined = undefined
$: type = component?.type
let migrationModal: CssMigrationModal | undefined = undefined
let tab: 'local' | 'global' = $state('local')
let overrideGlobalCSS: (() => void) | undefined = $state(undefined)
let overrideLocalCSS: (() => void) | undefined = $state(undefined)
let type = $derived(component?.type)
let migrationModal: CssMigrationModal | undefined = $state(undefined)
$: customCssByComponentType =
component?.type && $app.css
? Object.entries($app.css[component.type] || {}).map(([id, v]) => ({
let customCssByComponentType = $derived(
component?.type && app.css
? Object.entries(app.css[component.type] || {}).map(([id, v]) => ({
id,
forceStyle: v?.style != undefined,
forceClass: v?.['class'] != undefined
}))
: undefined
)
function copyLocalToGlobal(name: string, value: ComponentCssProperty | undefined) {
if (!value) {
@@ -51,18 +52,16 @@
if (!type) return
if (hasStyleValue($app.css?.[type]?.[name])) {
if (hasStyleValue(app.css?.[type]?.[name])) {
overrideGlobalCSS = () => {
$app.css![type]![name] = JSON.parse(JSON.stringify(value))
app.set($app)
app.css![type]![name] = JSON.parse(JSON.stringify(value))
}
} else {
if (!$app.css![type]) {
if (!app.css![type]) {
initGlobalCss()
}
$app.css![type]![name] = JSON.parse(JSON.stringify(value))
app.set($app)
app.css![type]![name] = JSON.parse(JSON.stringify(value))
sendUserToast('Global CSS copied')
}
}
@@ -75,11 +74,9 @@
if (hasStyleValue(value)) {
overrideLocalCSS = () => {
component!.customCss![id] = JSON.parse(JSON.stringify(value))
app.set($app)
}
} else {
component!.customCss![id] = JSON.parse(JSON.stringify(value))
app.set($app)
sendUserToast('Local CSS copied')
}
}
@@ -88,21 +85,20 @@
function initGlobalCss() {
// If the global css is not initialised, we initialise it.
// Should only happen once per app
if (!$app.css) {
$app.css = {}
if (!app.css) {
app.css = {}
}
// If the global css for this component type is not initialised, we initialise it.
// Should only happen once per component type
if (
$app.css &&
app.css &&
component &&
!$app.css[component.type]?.style &&
!app.css[component.type]?.style &&
components[component.type] &&
$app.css[component.type] === undefined
app.css[component.type] === undefined
) {
$app.css[component.type] = JSON.parse(JSON.stringify(components[component.type].customCss))
app.set($app)
app.css[component.type] = JSON.parse(JSON.stringify(components[component.type].customCss))
}
}
@@ -196,13 +192,12 @@
wmClass={getSelector(name)}
componentType={component.type}
bind:value={component.customCss[name]}
on:change={() => app.set($app)}
shouldDisplayRight={hasStyleValue(component.customCss[name])}
on:right={() => {
copyLocalToGlobal(name, component?.customCss?.[name])
tab = 'global'
}}
overridding={hasStyleValue($app.css?.[component.type]?.[name]) &&
overridding={hasStyleValue(app.css?.[component.type]?.[name]) &&
hasStyleValue(component.customCss[name])}
/>
</div>
@@ -214,16 +209,16 @@
{#if type}
{#each customCssByComponentType ?? [] as { id, forceStyle, forceClass }}
<div class="w-full">
{#if $app.css && type && $app.css[type] && component?.customCss}
{#if app.css && type && app.css[type] && component?.customCss}
<CssPropertyWrapper
{forceStyle}
{forceClass}
{id}
bind:property={$app.css[type]}
bind:property={app.css[type]}
on:left={() => {
copyGlobalToLocal(
id,
component?.type ? $app?.css?.[component?.type]?.[id] : undefined
component?.type ? app?.css?.[component?.type]?.[id] : undefined
)
tab = 'local'
}}
@@ -1,4 +1,7 @@
<script lang="ts">
import { createBubbler } from 'svelte/legacy'
const bubble = createBubbler()
import { Badge } from '$lib/components/common'
import Button from '$lib/components/common/button/Button.svelte'
import { getNextId } from '$lib/components/flows/idUtils'
@@ -15,11 +18,15 @@
import TableActionsWizard from '$lib/components/wizards/TableActionsWizard.svelte'
import Alert from '$lib/components/common/alert/Alert.svelte'
export let components:
| (BaseAppComponent & (ButtonComponent | CheckboxComponent | SelectComponent))[]
| undefined
interface Props {
components:
| (BaseAppComponent & (ButtonComponent | CheckboxComponent | SelectComponent))[]
| undefined
actionsOrder?: RichConfiguration | undefined
id: string
}
export let actionsOrder: RichConfiguration | undefined = undefined
let { components = $bindable(), actionsOrder = $bindable(undefined), id }: Props = $props()
// Migration code:
onMount(() => {
@@ -28,16 +35,17 @@
}
})
let items =
let items = $state(
components?.map((tab, index) => {
return { value: tab, id: generateRandomString(), originalIndex: index }
}) ?? []
)
$: components = items.map((item) => item.value)
$effect.pre(() => {
components = items.map((item) => item.value)
})
export let id: string
const { selectedComponent, app, errorByComponent, hoverStore } =
const { selectedComponent, errorByComponent, hoverStore } =
getContext<AppViewerContext>('AppViewerContext')
function addComponent(typ: 'buttoncomponent' | 'checkboxcomponent' | 'selectcomponent') {
@@ -97,9 +105,9 @@
{#if components}
<PanelSection title={`Table Actions`}>
<svelte:fragment slot="action">
{#snippet action()}
<TableActionsWizard bind:actionsOrder selectedId={$selectedComponent?.[0] ?? ''} {components}>
<svelte:fragment slot="trigger">
{#snippet trigger()}
<Button
color="light"
size="xs2"
@@ -111,9 +119,9 @@
<ListOrdered size={16} />
</div>
</Button>
</svelte:fragment>
{/snippet}
</TableActionsWizard>
</svelte:fragment>
{/snippet}
{#if components.length == 0}
<span class="text-xs text-tertiary">No action buttons</span>
{/if}
@@ -124,27 +132,27 @@
flipDurationMs: 200,
dropTargetStyle: {}
}}
on:consider={handleConsider}
on:finalize={handleFinalize}
onconsider={handleConsider}
onfinalize={handleFinalize}
>
{#each items as item, index (item.id)}
{@const component = items[index].value}
<div animate:flip={{ duration: 200 }} class="flex flex-row gap-2 items-center mb-2">
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
<div
class={classNames(
'w-full text-xs text-semibold truncate py-1.5 px-2 cursor-pointer justify-between flex items-center border rounded-md',
'bg-surface hover:bg-surface-hover focus:border-primary text-secondary'
)}
on:click={() => {
onclick={() => {
$selectedComponent = [component.id]
}}
on:mouseover={() => {
onmouseover={() => {
$hoverStore = component.id
}}
on:keypress
onkeypress={bubble('keypress')}
>
<div class="flex flex-row gap-2 items-center">
<Badge color="dark-indigo">
@@ -57,10 +57,10 @@
function addSubGrid() {
const numberOfPanes = nodes.length
if (!$app.subgrids) {
$app.subgrids = {}
if (!app.subgrids) {
app.subgrids = {}
}
$app.subgrids[`${component.id}-${numberOfPanes}`] = []
app.subgrids[`${component.id}-${numberOfPanes}`] = []
component.numberOfSubgrids = nodes.length + 1
}
@@ -68,22 +68,22 @@
function deleteSubgrid(index: number) {
let subgrid = `${component.id}-${index}`
if (!$app.subgrids![subgrid]) {
if (!app.subgrids![subgrid]) {
return
}
for (const item of $app!.subgrids![subgrid]) {
const components = deleteGridItem($app, item.data, subgrid)
for (const item of app!.subgrids![subgrid]) {
const components = deleteGridItem(app, item.data, subgrid)
for (const key in components) {
delete $runnableComponents[key]
}
}
$runnableComponents = $runnableComponents
for (let i = index; i < nodes.length - 1; i++) {
$app!.subgrids![`${component.id}-${i}`] = $app!.subgrids![`${component.id}-${i + 1}`]
app!.subgrids![`${component.id}-${i}`] = app!.subgrids![`${component.id}-${i + 1}`]
}
nodes.splice(index, 1)
delete $app!.subgrids![`${component.id}-${nodes.length}`]
delete app!.subgrids![`${component.id}-${nodes.length}`]
nodes = nodes
component.numberOfSubgrids = nodes.length // $app = $app
@@ -126,9 +126,9 @@
bind:this={editor}
lang="javascript"
bind:code={
() => componentInput.expr ?? '',
() => componentInput?.expr ?? '',
(e) => {
if (componentInput.expr != e) {
if (componentInput?.expr != e) {
componentInput.expr = e
}
}
@@ -7,9 +7,13 @@
import SelectedRunnable from '../SelectedRunnable.svelte'
import type { AppEditorContext, AppViewerContext } from '$lib/components/apps/types'
export let appInput: ResultAppInput
export let defaultUserInput = false
export let appComponent: AppComponent
interface Props {
appInput: ResultAppInput
defaultUserInput?: boolean
appComponent: AppComponent
}
let { appInput = $bindable(), defaultUserInput = false, appComponent }: Props = $props()
const { selectedComponentInEditor } = getContext<AppEditorContext>('AppEditorContext')
const { app } = getContext<AppViewerContext>('AppViewerContext')
@@ -34,7 +38,7 @@
<SelectedRunnable {appComponent} bind:appInput />
{:else if appInput !== undefined}
<RunnableSelector
unusedInlineScripts={$app.unusedInlineScripts}
unusedInlineScripts={app.unusedInlineScripts}
hideCreateScript={appComponent.type === 'flowstatuscomponent'}
onlyFlow={appComponent.type === 'flowstatuscomponent'}
{defaultUserInput}
@@ -4,11 +4,15 @@
import { allItems } from '$lib/components/apps/utils'
import { getContext } from 'svelte'
export let componentInput: StaticInput<{ id: string; index: number }>
interface Props {
componentInput: StaticInput<{ id: string; index: number }>
}
let { componentInput = $bindable() }: Props = $props()
const { app } = getContext<AppViewerContext>('AppViewerContext')
const tabComponents = allItems($app.grid, $app.subgrids).filter(
const tabComponents = allItems(app.grid, app.subgrids).filter(
(component) =>
component.data.type === 'tabscomponent' ||
component.data.type === 'conditionalwrapper' ||
@@ -4,24 +4,33 @@
import { classNames, itemsExists } from '$lib/utils'
import { Plus, X } from 'lucide-svelte'
import { Button } from '$lib/components/common'
import { getContext } from 'svelte'
import { getContext, untrack } from 'svelte'
import type { App, AppViewerContext, InlineScript } from '$lib/components/apps/types'
import Tooltip from '$lib/components/Tooltip.svelte'
import { deepEqual } from 'fast-equals'
import { getAllGridItems } from '../../../appUtils'
export let triggerEvents: string[] = []
export let inlineScript: InlineScript | undefined = undefined
export let isFrontend: boolean = false
export let dependencies: string[] = []
export let shoudlDisplayChangeEvents: boolean = false
export let id: string
interface Props {
triggerEvents?: string[]
inlineScript?: InlineScript | undefined
isFrontend?: boolean
dependencies?: string[]
shoudlDisplayChangeEvents?: boolean
id: string
}
let {
triggerEvents = [],
inlineScript = $bindable(undefined),
isFrontend = false,
dependencies = [],
shoudlDisplayChangeEvents = false,
id
}: Props = $props()
const { connectingInput, app, stateId } = getContext<AppViewerContext>('AppViewerContext')
let onSuccessEvents: string[] = []
$: computeOnSuccessEvents($app, id)
let onSuccessEvents: string[] = $state([])
function computeOnSuccessEvents(app: App, _id: string) {
const nr: string[] = []
@@ -47,16 +56,6 @@
})
onSuccessEvents = nr
}
$: changeEvents = isFrontend
? inlineScript?.refreshOn
? inlineScript.refreshOn.map((x) => `${x.id}.${x.key}`)
: []
: dependencies
$: hasNoTriggers =
triggerEvents.length === 0 &&
(changeEvents.length === 0 || !shoudlDisplayChangeEvents) &&
onSuccessEvents.length == 0
const badgeClass = 'inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium border'
const colors = {
@@ -86,6 +85,24 @@
}
inlineScript = inlineScript // $app = $app
}
$effect.pre(() => {
;[app, id]
untrack(() => {
computeOnSuccessEvents(app, id)
})
})
let changeEvents = $derived(
isFrontend
? inlineScript?.refreshOn
? inlineScript.refreshOn.map((x) => `${x.id}.${x.key}`)
: []
: dependencies
)
let hasNoTriggers = $derived(
triggerEvents.length === 0 &&
(changeEvents.length === 0 || !shoudlDisplayChangeEvents) &&
onSuccessEvents.length == 0
)
</script>
{#if hasNoTriggers}
@@ -117,7 +134,7 @@
{#if isFrontend}
<button
class="bg-blue-300 ml-2 p-0.5 rounded-md hover:bg-blue-400 cursor-pointer"
on:click={() => {
onclick={() => {
if (inlineScript?.refreshOn) {
inlineScript.refreshOn = inlineScript.refreshOn.filter(
(x) => `${x.id}.${x.key}` !== changeEvent
@@ -172,7 +189,7 @@
'p-0.5 rounded-md hover:bg-blue-400 cursor-pointer !text-2xs text-secondary',
badgeClass
)}
on:click={() => {
onclick={() => {
if (inlineScript) {
if (!itemsExists(inlineScript.refreshOn, suggestion)) {
inlineScript.refreshOn = [...(inlineScript.refreshOn ?? []), suggestion]
@@ -1,4 +1,6 @@
<script lang="ts">
import { preventDefault, stopPropagation } from 'svelte/legacy'
import { createEventDispatcher, getContext, onMount } from 'svelte'
import type { AppEditorContext, AppViewerContext } from '../types'
import { writable } from 'svelte/store'
@@ -13,33 +15,57 @@
const dispatch = createEventDispatcher()
export let sensor
export let width
export let height
export let left
export let top
interface Props {
sensor: any
width: any
height: any
left: any
top: any
id: any
container: any
xPerPx: any
yPerPx: any
gapX: any
gapY: any
item: any
cols: any
nativeContainer: any
onTop: any
shadow?: { x: number; y: number; w: number; h: number } | undefined
overlapped?: string | undefined
moveMode?: 'move' | 'insert'
type?: string | undefined
fakeShadow?: GridShadow | undefined
disableMove?: boolean
mounted?: boolean
children?: import('svelte').Snippet
}
export let id
export let container
export let xPerPx
export let yPerPx
export let gapX
export let gapY
export let item
export let cols
export let nativeContainer
export let onTop
export let shadow: { x: number; y: number; w: number; h: number } | undefined = undefined
export let overlapped: string | undefined = undefined
export let moveMode: 'move' | 'insert' = 'move'
export let type: string | undefined = undefined
export let fakeShadow: GridShadow | undefined = undefined
export let disableMove: boolean = true
export let mounted: boolean = false
let {
sensor,
width,
height,
left,
top,
id,
container,
xPerPx,
yPerPx,
gapX,
gapY,
item,
cols,
nativeContainer,
onTop,
shadow = $bindable(undefined),
overlapped = undefined,
moveMode = 'move',
type = undefined,
fakeShadow = undefined,
disableMove = true,
mounted = false,
children
}: Props = $props()
const ctx = getContext<AppEditorContext>('AppEditorContext')
const { mode, app } = getContext<AppViewerContext>('AppViewerContext')
@@ -47,9 +73,9 @@
const scale = ctx ? ctx.scale : writable(100)
const divId = `component-${id}`
let shadowElement
let shadowElement = $state(undefined) as HTMLElement | undefined
let active = false
let active = $state(false)
let initX, initY
@@ -58,10 +84,10 @@
y: 0
}
let cordDiff = { x: 0, y: 0 }
let cordDiff = $state({ x: 0, y: 0 })
let newSize = { width, height }
let trans = false
let newSize = $state({ width, height })
let trans = $state(false)
let anima
@@ -114,6 +140,7 @@
shadowBound = irect
}
if (!rect) return
const xdragBound = rect.left + cordDiff.x
const ydragBound = rect.top + cordDiff.y
@@ -142,7 +169,7 @@
// Autoscroll
let _scrollTop = 0
let containerFrame
let rect
let rect = $state() as { top: number; left: number } | undefined
let scrollElement
const getContainerFrame = (element) => {
@@ -317,7 +344,7 @@
}
}
let element: HTMLElement | undefined = undefined
let element: HTMLElement | undefined = $state(undefined)
function computeShadow(clientX: number, clientY: number) {
const elementsAtPoint = document.elementsFromPoint(clientX, clientY)
@@ -384,7 +411,7 @@
return
}
const parent = findGridItemParentGrid($app, id)
const parent = findGridItemParentGrid(app, id)
if (overlapped && (overlapped === parent || parent?.startsWith(overlapped))) {
return
@@ -469,7 +496,7 @@
return true
}
const parent = findGridItemParentGrid($app, id)
const parent = findGridItemParentGrid(app, id)
if (parent === undefined) {
return overlapped === undefined
@@ -481,12 +508,12 @@
}
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div
bind:this={element}
draggable="false"
on:pointerdown|stopPropagation|preventDefault={pointerdown}
onpointerdown={(e) => stopPropagation(preventDefault((_) => pointerdown(e)))}
id={divId}
class="svlt-grid-item"
data-iscontainer={type ? isContainer(type) : false}
@@ -495,30 +522,26 @@
style="width: {xPerPx == 0 ? 0 : active ? newSize.width : width}px; height:{xPerPx == 0
? 0
: active
? newSize.height
: height}px;
? newSize.height
: height}px;
{xPerPx == 0 ? 'overflow: hidden;' : ''}
{onTop ? 'z-index: 1000;' : ''}
{active && rect
? `transform: translate(${cordDiff.x}px, ${cordDiff.y}px);top:${rect.top}px;left:${rect.left}px;z-index:10000;`
: trans
? `transform: translate(${cordDiff.x}px, ${cordDiff.y}px); position:absolute; transition: width 0.2s, height 0.2s;`
: `${
xPerPx > 0 && mounted ? 'transition: transform 0.1s, opacity 0.1s;' : ''
} transform: translate(${left}px, ${top}px); `} "
? `transform: translate(${cordDiff.x}px, ${cordDiff.y}px); position:absolute; transition: width 0.2s, height 0.2s;`
: `${
xPerPx > 0 && mounted ? 'transition: transform 0.1s, opacity 0.1s;' : ''
} transform: translate(${left}px, ${top}px); `} "
>
<slot />
{@render children?.()}
{#if moveMode === 'move' && !disableMove}
<div
class="svlt-grid-resizer-bottom"
on:pointerdown={(e) => resizePointerDown(e, 'vertical')}
<div class="svlt-grid-resizer-bottom" onpointerdown={(e) => resizePointerDown(e, 'vertical')}
></div>
<div
class="svlt-grid-resizer-side"
on:pointerdown={(e) => resizePointerDown(e, 'horizontal')}
<div class="svlt-grid-resizer-side" onpointerdown={(e) => resizePointerDown(e, 'horizontal')}
></div>
<div class="svlt-grid-resizer" on:pointerdown={(e) => resizePointerDown(e, 'both')}></div>
<div class="svlt-grid-resizer" onpointerdown={(e) => resizePointerDown(e, 'both')}></div>
{/if}
</div>
@@ -9,8 +9,12 @@
import type { Runnable } from '../apps/inputType'
import { getNextId } from '$lib/components/flows/idUtils'
export let selectedRunnable: string | undefined
export let runnables: Writable<Record<string, Runnable>>
interface Props {
selectedRunnable: string | undefined
runnables: Writable<Record<string, Runnable>>
}
let { selectedRunnable = $bindable(), runnables }: Props = $props()
function createBackgroundScript() {
const nid = getNextId(Object.keys($runnables ?? {}))
@@ -23,7 +27,6 @@
}
return r
})
console.log('BAR 2')
selectedRunnable = nid
}
@@ -31,7 +34,7 @@
</script>
<PanelSection title="Backend Runnables" id="app-editor-runnable-panel">
<svelte:fragment slot="action">
{#snippet action()}
<div class="flex flex-row gap-1">
<HideButton
direction="bottom"
@@ -55,7 +58,7 @@
<Plus size={14} class="!text-primary" />
</Button>
</div>
</svelte:fragment>
{/snippet}
<div class="w-full flex flex-col gap-6 py-1">
<div>
<div class="flex flex-col gap-1 w-full">
@@ -68,7 +71,7 @@
{selectedRunnable === id
? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50'
: 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}"
on:click={() => (selectedRunnable = id)}
onclick={() => (selectedRunnable = id)}
>
<span class="text-2xs truncate">{runnable?.name}</span>
<Badge color="indigo">{id}</Badge>
@@ -8,10 +8,14 @@
import { clickButtonBySelector } from '../utils'
import { updateProgress } from '$lib/tutorialUtils'
export let name: string
export let index: number
interface Props {
name: string
index: number
}
let tutorial: Tutorial | undefined = undefined
let { name, index }: Props = $props()
let tutorial: Tutorial | undefined = $state(undefined)
const { app, selectedComponent, focusedGrid } = getContext<AppViewerContext>('AppViewerContext')
const { history } = getContext<AppEditorContext>('AppEditorContext')
@@ -21,10 +25,10 @@
}
function addComponent(): void {
push(history, $app)
push(history, app)
const id = insertNewGridItem(
$app,
app,
appComponentFromType('textcomponent') as (id: string) => AppComponent,
$focusedGrid
)
@@ -12,11 +12,23 @@
CheckboxComponent,
SelectComponent
} from '../apps/editor/component'
export let actionsOrder: RichConfiguration | undefined = undefined
export let selectedId: string | undefined = undefined
export let components:
| (BaseAppComponent & (ButtonComponent | CheckboxComponent | SelectComponent))[]
| undefined
interface Props {
actionsOrder?: RichConfiguration | undefined
selectedId?: string | undefined
components:
| (BaseAppComponent & (ButtonComponent | CheckboxComponent | SelectComponent))[]
| undefined
trigger?: import('svelte').Snippet
}
let {
actionsOrder = $bindable(undefined),
selectedId = undefined,
components,
trigger
}: Props = $props()
const trigger_render = $derived(trigger)
</script>
<Popover
@@ -27,15 +39,15 @@
}}
closeButton
>
<svelte:fragment slot="trigger">
<slot name="trigger" />
</svelte:fragment>
<svelte:fragment slot="content">
{#snippet trigger()}
{@render trigger_render?.()}
{/snippet}
{#snippet content()}
<div class="w-96">
<PanelSection
title={`Manage actions programmatically`}
tooltip="
You can manage the order of the actions programmatically: You need to return an array of action ids in the order you want them to appear in the table. You can also hide actions by not including them in the array."
You can manage the order of the actions programmatically: You need to return an array of action ids in the order you want them to appear in the table. You can also hide actions by not including them in the array."
>
<div class="w-full flex gap-2 flex-col mt-2">
{#if actionsOrder}
@@ -93,5 +105,5 @@
</div>
</PanelSection>
</div>
</svelte:fragment>
{/snippet}
</Popover>