windmill-components 1.60.2 → 1.60.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/AppConnect.svelte +4 -0
- package/components/ArgInput.svelte +0 -1
- package/components/ArgInput.svelte.d.ts +0 -2
- package/components/DisplayResult.svelte +9 -6
- package/components/FlowMetadata.svelte +19 -3
- package/components/FlowPreviewContent.svelte +15 -9
- package/components/FolderEditor.svelte +1 -1
- package/components/InputTransformForm.svelte +1 -2
- package/components/JobArgs.svelte +1 -1
- package/components/ModulePreview.svelte +2 -1
- package/components/Popover.model.d.ts +4 -0
- package/components/Popover.model.js +3 -0
- package/components/Popover.svelte +0 -2
- package/components/Popover.svelte.d.ts +2 -1
- package/components/ResourceEditor.svelte +11 -1
- package/components/ResourcePicker.svelte +10 -1
- package/components/RunForm.svelte +41 -37
- package/components/RunForm.svelte.d.ts +1 -0
- package/components/ScriptBuilder.svelte +3 -1
- package/components/ScriptEditor.svelte +1 -0
- package/components/TemplateEditor.svelte +14 -1
- package/components/TestJobLoader.svelte +1 -1
- package/components/Tooltip.svelte +8 -3
- package/components/Tooltip.svelte.d.ts +5 -0
- package/components/UserSettings.svelte +14 -25
- package/components/apps/components/buttons/AppButton.svelte +16 -0
- package/components/apps/components/dataDisplay/AppHtml.svelte +22 -14
- package/components/apps/components/dataDisplay/AppHtml.svelte.d.ts +0 -2
- package/components/apps/components/dataDisplay/VegaLiteHtml.svelte +53 -0
- package/components/apps/components/dataDisplay/VegaLiteHtml.svelte.d.ts +23 -0
- package/components/apps/components/helpers/InputValue.svelte +24 -5
- package/components/apps/components/helpers/InputValue.svelte.d.ts +1 -0
- package/components/apps/components/helpers/RunnableComponent.svelte +5 -2
- package/components/apps/components/selectInputs/AppSelect.svelte +11 -3
- package/components/apps/components/table/AppTable.svelte +16 -12
- package/components/apps/editor/AppEditor.svelte +7 -2
- package/components/apps/editor/AppPreview.svelte +26 -4
- package/components/apps/editor/AppPreview.svelte.d.ts +2 -0
- package/components/apps/editor/ComponentEditor.svelte +7 -0
- package/components/apps/editor/componentsPanel/ComponentList.svelte +2 -1
- package/components/apps/editor/componentsPanel/data.js +39 -0
- package/components/apps/editor/contextPanel/ContextPanel.svelte +3 -2
- package/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte +4 -1
- package/components/apps/editor/inlineScriptsPanel/InlineScriptsPanelList.svelte +8 -56
- package/components/apps/editor/inlineScriptsPanel/utils.d.ts +15 -0
- package/components/apps/editor/inlineScriptsPanel/utils.js +28 -0
- package/components/apps/editor/settingsPanel/ComponentPanel.svelte +9 -14
- package/components/apps/editor/settingsPanel/ComponentPanel.svelte.d.ts +0 -3
- package/components/apps/editor/settingsPanel/InputsSpecEditor.svelte +6 -2
- package/components/apps/editor/settingsPanel/InputsSpecEditor.svelte.d.ts +4 -2
- package/components/apps/editor/settingsPanel/InputsSpecsEditor.svelte +8 -7
- package/components/apps/editor/settingsPanel/InputsSpecsEditor.svelte.d.ts +1 -1
- package/components/apps/editor/settingsPanel/Recompute.svelte +1 -1
- package/components/apps/editor/settingsPanel/TableActions.svelte +7 -2
- package/components/apps/editor/settingsPanel/common/PanelSection.svelte +10 -1
- package/components/apps/editor/settingsPanel/common/PanelSection.svelte.d.ts +1 -0
- package/components/apps/editor/settingsPanel/inputEditor/EvalInputEditor.svelte +25 -0
- package/components/apps/editor/settingsPanel/inputEditor/EvalInputEditor.svelte.d.ts +19 -0
- package/components/apps/editorUtils.js +39 -0
- package/components/apps/inputType.d.ts +8 -1
- package/components/apps/types.d.ts +5 -3
- package/components/apps/utils.d.ts +2 -0
- package/components/apps/utils.js +15 -0
- package/components/common/button/Button.svelte +1 -1
- package/components/common/kbd/Kbd.svelte +6 -6
- package/components/common/table/Row.svelte +1 -1
- package/components/flows/content/CapturePayload.svelte +3 -3
- package/components/flows/content/FlowModuleComponent.svelte +4 -2
- package/components/flows/utils.js +1 -1
- package/components/propertyPicker/PropPicker.svelte +7 -1
- package/package.json +7 -3
- package/script_helpers.d.ts +3 -3
- package/script_helpers.js +18 -19
|
@@ -2,22 +2,30 @@
|
|
|
2
2
|
import RunnableWrapper from '../helpers/RunnableWrapper.svelte';
|
|
3
3
|
export let id;
|
|
4
4
|
export let componentInput;
|
|
5
|
-
export let horizontalAlignment = 'left';
|
|
6
|
-
export let verticalAlignment = undefined;
|
|
7
5
|
export let configuration;
|
|
8
6
|
export const staticOutputs = ['result', 'loading'];
|
|
9
7
|
let result = undefined;
|
|
8
|
+
let h = undefined;
|
|
9
|
+
let w = undefined;
|
|
10
10
|
</script>
|
|
11
11
|
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
<div
|
|
13
|
+
on:pointerdown={(e) => {
|
|
14
|
+
e?.preventDefault()
|
|
15
|
+
}}
|
|
16
|
+
class="h-full w-full"
|
|
17
|
+
bind:clientHeight={h}
|
|
18
|
+
bind:clientWidth={w}
|
|
19
|
+
>
|
|
20
|
+
<RunnableWrapper autoRefresh flexWrap bind:componentInput {id} bind:result>
|
|
21
|
+
{#key result}
|
|
22
|
+
<iframe
|
|
23
|
+
frameborder="0"
|
|
24
|
+
style="height: {h}px; width: {w}px"
|
|
25
|
+
class="p-0"
|
|
26
|
+
title="sandbox"
|
|
27
|
+
srcdoc={result ? '<scr' + `ipt src="/tailwind.css"></script>` + result : 'No html'}
|
|
28
|
+
/>
|
|
29
|
+
{/key}
|
|
30
|
+
</RunnableWrapper>
|
|
31
|
+
</div>
|
|
@@ -4,8 +4,6 @@ declare const __propDef: {
|
|
|
4
4
|
props: {
|
|
5
5
|
id: string;
|
|
6
6
|
componentInput: AppInput | undefined;
|
|
7
|
-
horizontalAlignment?: 'left' | 'center' | 'right' | undefined;
|
|
8
|
-
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined;
|
|
9
7
|
configuration: Record<string, AppInput>;
|
|
10
8
|
staticOutputs?: string[] | undefined;
|
|
11
9
|
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script>import { Loader2 } from 'lucide-svelte';
|
|
2
|
+
import { parse } from 'path';
|
|
3
|
+
import { onMount } from 'svelte';
|
|
4
|
+
import AlignWrapper from '../helpers/AlignWrapper.svelte';
|
|
5
|
+
import InputValue from '../helpers/InputValue.svelte';
|
|
6
|
+
import RunnableWrapper from '../helpers/RunnableWrapper.svelte';
|
|
7
|
+
export let id;
|
|
8
|
+
export let componentInput;
|
|
9
|
+
export let configuration;
|
|
10
|
+
export const staticOutputs = ['result', 'loading'];
|
|
11
|
+
let result = undefined;
|
|
12
|
+
let divEl = null;
|
|
13
|
+
let vegaEmbed;
|
|
14
|
+
onMount(async () => {
|
|
15
|
+
if (divEl) {
|
|
16
|
+
//@ts-ignore
|
|
17
|
+
await import('https://cdn.jsdelivr.net/npm/vega@5.22.1');
|
|
18
|
+
//@ts-ignore
|
|
19
|
+
await import('https://cdn.jsdelivr.net/npm/vega-lite@5.6.0');
|
|
20
|
+
//@ts-ignore
|
|
21
|
+
await import('https://cdn.jsdelivr.net/npm/vega-embed@6.21.0');
|
|
22
|
+
vegaEmbed = window['vegaEmbed'];
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
let h = undefined;
|
|
26
|
+
let w = undefined;
|
|
27
|
+
let canvas = false;
|
|
28
|
+
$: vegaEmbed &&
|
|
29
|
+
result &&
|
|
30
|
+
divEl &&
|
|
31
|
+
h &&
|
|
32
|
+
w &&
|
|
33
|
+
vegaEmbed(divEl, { ...result, ...{ width: w - 100 } }, {
|
|
34
|
+
mode: 'vega-lite',
|
|
35
|
+
actions: false,
|
|
36
|
+
renderer: canvas ? 'canvas' : 'svg',
|
|
37
|
+
height: h - 75,
|
|
38
|
+
width: w - 75
|
|
39
|
+
});
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<InputValue {id} input={configuration.canvas} bind:value={canvas} />
|
|
43
|
+
|
|
44
|
+
<div class="w-full h-full" bind:clientHeight={h} bind:clientWidth={w}>
|
|
45
|
+
<RunnableWrapper flexWrap bind:componentInput {id} bind:result>
|
|
46
|
+
{#if !vegaEmbed}
|
|
47
|
+
<div class="p-2">
|
|
48
|
+
<Loader2 class="animate-spin" />
|
|
49
|
+
</div>
|
|
50
|
+
{/if}
|
|
51
|
+
<div on:pointerdown bind:this={divEl} />
|
|
52
|
+
</RunnableWrapper>
|
|
53
|
+
</div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { AppInput } from '../../inputType';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
id: string;
|
|
6
|
+
componentInput: AppInput | undefined;
|
|
7
|
+
configuration: Record<string, AppInput>;
|
|
8
|
+
staticOutputs?: string[] | undefined;
|
|
9
|
+
};
|
|
10
|
+
events: {
|
|
11
|
+
pointerdown: PointerEvent;
|
|
12
|
+
} & {
|
|
13
|
+
[evt: string]: CustomEvent<any>;
|
|
14
|
+
};
|
|
15
|
+
slots: {};
|
|
16
|
+
};
|
|
17
|
+
export type VegaLiteHtmlProps = typeof __propDef.props;
|
|
18
|
+
export type VegaLiteHtmlEvents = typeof __propDef.events;
|
|
19
|
+
export type VegaLiteHtmlSlots = typeof __propDef.slots;
|
|
20
|
+
export default class VegaLiteHtml extends SvelteComponentTyped<VegaLiteHtmlProps, VegaLiteHtmlEvents, VegaLiteHtmlSlots> {
|
|
21
|
+
get staticOutputs(): string[];
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -1,28 +1,44 @@
|
|
|
1
1
|
<script>import { isCodeInjection } from '../../../flows/utils';
|
|
2
|
-
import {
|
|
2
|
+
import { getContext } from 'svelte';
|
|
3
3
|
import { accessPropertyByPath } from '../../utils';
|
|
4
4
|
export let input;
|
|
5
5
|
export let value;
|
|
6
6
|
export let id = undefined;
|
|
7
7
|
export let row = {};
|
|
8
|
+
export let error = '';
|
|
8
9
|
const { worldStore } = getContext('AppEditorContext');
|
|
9
10
|
$: state = $worldStore?.state;
|
|
10
11
|
$: input && $worldStore && row && handleConnection();
|
|
11
|
-
$: input &&
|
|
12
|
+
$: input && input.type == 'template' && $state && (value = getValue(input));
|
|
13
|
+
$: input && input.type == 'eval' && $state && (value = evalExpr(input));
|
|
12
14
|
function handleConnection() {
|
|
13
15
|
if (input.type === 'connected') {
|
|
14
16
|
$worldStore?.connect(input, onValueChange);
|
|
15
17
|
}
|
|
16
18
|
else if (input.type === 'row') {
|
|
17
|
-
setTimeout(() => (value = row[input['column']]), 0);
|
|
19
|
+
setTimeout(() => (value = row?.[input['column']]), 0);
|
|
18
20
|
}
|
|
19
21
|
else if (input.type === 'static' || input.type == 'template') {
|
|
20
22
|
setTimeout(() => (value = getValue(input)), 0);
|
|
21
23
|
}
|
|
24
|
+
else if (input.type == 'eval') {
|
|
25
|
+
setTimeout(() => ((value = evalExpr(input)), 0));
|
|
26
|
+
}
|
|
22
27
|
else {
|
|
23
28
|
setTimeout(() => (value = undefined), 0);
|
|
24
29
|
}
|
|
25
30
|
}
|
|
31
|
+
function evalExpr(input) {
|
|
32
|
+
try {
|
|
33
|
+
const r = eval_like(input.expr, computeGlobalContext());
|
|
34
|
+
error = '';
|
|
35
|
+
return r;
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
error = e.message;
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
26
42
|
function computeGlobalContext() {
|
|
27
43
|
return Object.fromEntries(Object.entries($worldStore?.outputsById ?? {})
|
|
28
44
|
.filter(([k, _]) => k != id)
|
|
@@ -31,12 +47,15 @@ function computeGlobalContext() {
|
|
|
31
47
|
key,
|
|
32
48
|
Object.fromEntries(Object.entries(value ?? {}).map((x) => [x[0], x[1].peak()]))
|
|
33
49
|
];
|
|
34
|
-
})
|
|
50
|
+
})
|
|
51
|
+
.concat(row ? [['row', row]] : []));
|
|
35
52
|
}
|
|
36
53
|
export function getValue(input) {
|
|
37
54
|
if (input.type === 'template' && isCodeInjection(input.eval)) {
|
|
38
55
|
try {
|
|
39
|
-
|
|
56
|
+
const r = eval_like('`' + input.eval + '`', computeGlobalContext());
|
|
57
|
+
error = '';
|
|
58
|
+
return r;
|
|
40
59
|
}
|
|
41
60
|
catch (e) {
|
|
42
61
|
return e.message;
|
|
@@ -6,6 +6,7 @@ declare const __propDef: {
|
|
|
6
6
|
value: string | number | boolean | Record<string | number, any> | undefined;
|
|
7
7
|
id?: string | undefined;
|
|
8
8
|
row?: Record<string, any> | undefined;
|
|
9
|
+
error?: string | undefined;
|
|
9
10
|
getValue?: ((input: AppInput) => any) | undefined;
|
|
10
11
|
};
|
|
11
12
|
events: {
|
|
@@ -257,12 +257,15 @@ let lastStartedAt = Date.now();
|
|
|
257
257
|
<div class="p-2">
|
|
258
258
|
<Alert type="error" title="Error during execution">
|
|
259
259
|
See "Debug Runs" on the top right for more details
|
|
260
|
-
<pre
|
|
260
|
+
<pre
|
|
261
|
+
title={JSON.stringify(result.error, null, 4)}
|
|
262
|
+
class=" mt-2 text-2xs whitespace-pre-wrap">{JSON.stringify(result.error, null, 4)}</pre
|
|
263
|
+
>
|
|
261
264
|
</Alert>
|
|
262
265
|
<slot />
|
|
263
266
|
</div>
|
|
264
267
|
{:else}
|
|
265
|
-
<div class="
|
|
268
|
+
<div class="block w-full h-full">
|
|
266
269
|
<slot />
|
|
267
270
|
</div>
|
|
268
271
|
{/if}
|
|
@@ -12,10 +12,13 @@ let label;
|
|
|
12
12
|
let items;
|
|
13
13
|
let itemKey;
|
|
14
14
|
$: outputs = $worldStore?.outputsById[id];
|
|
15
|
-
function onChange(
|
|
16
|
-
|
|
15
|
+
function onChange(e) {
|
|
16
|
+
e?.stopPropagation();
|
|
17
|
+
window.dispatchEvent(new Event('pointerup'));
|
|
18
|
+
outputs?.result.set(e.detail?.[itemKey] || undefined);
|
|
17
19
|
}
|
|
18
|
-
|
|
20
|
+
let value = undefined;
|
|
21
|
+
$: items?.[0]?.['value'] != value && (value = items?.[0]?.['value']);
|
|
19
22
|
</script>
|
|
20
23
|
|
|
21
24
|
<InputValue {id} input={configuration.label} bind:value={label} />
|
|
@@ -28,7 +31,12 @@ const dispatch = createEventDispatcher();
|
|
|
28
31
|
class="select"
|
|
29
32
|
on:clear={onChange}
|
|
30
33
|
on:change={onChange}
|
|
34
|
+
on:focus={(e) => {
|
|
35
|
+
e?.stopPropagation()
|
|
36
|
+
window.dispatchEvent(new Event('pointerup'))
|
|
37
|
+
}}
|
|
31
38
|
{items}
|
|
39
|
+
{value}
|
|
32
40
|
placeholder="Select an item"
|
|
33
41
|
on:click={() => {
|
|
34
42
|
if (!$connectingInput.opened) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script>import { getContext } from 'svelte';
|
|
1
|
+
<script>import { getContext, onMount } from 'svelte';
|
|
2
2
|
import InputValue from '../helpers/InputValue.svelte';
|
|
3
3
|
import RunnableWrapper from '../helpers/RunnableWrapper.svelte';
|
|
4
4
|
import { writable } from 'svelte/store';
|
|
@@ -31,15 +31,21 @@ let table = createSvelteTable(options);
|
|
|
31
31
|
const { worldStore, staticOutputs: staticOutputsStore } = getContext('AppEditorContext');
|
|
32
32
|
let selectedRowIndex = -1;
|
|
33
33
|
function toggleRow(row, rowIndex) {
|
|
34
|
-
if (selectedRowIndex
|
|
35
|
-
selectedRowIndex = -1;
|
|
36
|
-
outputs.selectedRow.set(null);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
34
|
+
if (selectedRowIndex !== rowIndex) {
|
|
39
35
|
selectedRowIndex = rowIndex;
|
|
40
36
|
outputs?.selectedRow.set(row.original);
|
|
41
37
|
}
|
|
42
38
|
}
|
|
39
|
+
let mounted = false;
|
|
40
|
+
onMount(() => {
|
|
41
|
+
mounted = true;
|
|
42
|
+
});
|
|
43
|
+
$: selectedRowIndex === -1 &&
|
|
44
|
+
Array.isArray(result) &&
|
|
45
|
+
result.length > 0 &&
|
|
46
|
+
// We need to wait until the component is mounted so the world is created
|
|
47
|
+
mounted &&
|
|
48
|
+
toggleRow({ original: result[0] }, 0);
|
|
43
49
|
function setOptions(filteredResult) {
|
|
44
50
|
if (!Array.isArray(result)) {
|
|
45
51
|
return;
|
|
@@ -101,7 +107,7 @@ $: result && rerender();
|
|
|
101
107
|
|
|
102
108
|
<div class="overflow-x-auto flex-1 w-full">
|
|
103
109
|
<table class="relative w-full border-b border-b-gray-200">
|
|
104
|
-
<thead class="sticky top-0 bg-gray-50 text-left">
|
|
110
|
+
<thead class="sticky top-0 z-40 bg-gray-50 text-left">
|
|
105
111
|
{#each $table.getHeaderGroups() as headerGroup}
|
|
106
112
|
<tr class="divide-x">
|
|
107
113
|
{#each headerGroup.headers as header}
|
|
@@ -121,9 +127,7 @@ $: result && rerender();
|
|
|
121
127
|
{/each}
|
|
122
128
|
{#if actionButtons.length > 0}
|
|
123
129
|
<th class="!p-0">
|
|
124
|
-
<span class="block px-4 py-4 text-sm font-semibold border-b">
|
|
125
|
-
Actions
|
|
126
|
-
</span>
|
|
130
|
+
<span class="block px-4 py-4 text-sm font-semibold border-b"> Actions </span>
|
|
127
131
|
</th>
|
|
128
132
|
{/if}
|
|
129
133
|
</tr>
|
|
@@ -133,11 +137,11 @@ $: result && rerender();
|
|
|
133
137
|
{#each $table.getRowModel().rows as row, rowIndex (row.id)}
|
|
134
138
|
<tr
|
|
135
139
|
class={classNames(
|
|
140
|
+
'last-of-type:!border-b-0',
|
|
136
141
|
selectedRowIndex === rowIndex
|
|
137
142
|
? 'bg-blue-100 hover:bg-blue-200'
|
|
138
143
|
: 'hover:bg-blue-50',
|
|
139
|
-
'divide-x',
|
|
140
|
-
'border-b w-full',
|
|
144
|
+
'divide-x w-full',
|
|
141
145
|
selectedRowIndex === rowIndex
|
|
142
146
|
? 'divide-blue-200 hover:divide-blue-300'
|
|
143
147
|
: 'divide-gray-200'
|
|
@@ -19,6 +19,7 @@ import InlineScriptsPanel from './inlineScriptsPanel/InlineScriptsPanel.svelte';
|
|
|
19
19
|
import SettingsPanel from './SettingsPanel.svelte';
|
|
20
20
|
import { fly } from 'svelte/transition';
|
|
21
21
|
import UnsavedConfirmationModal from '../../common/confirmationModal/UnsavedConfirmationModal.svelte';
|
|
22
|
+
import { page } from '$app/stores';
|
|
22
23
|
export let app;
|
|
23
24
|
export let path;
|
|
24
25
|
export let initialMode = 'dnd';
|
|
@@ -73,7 +74,11 @@ let mounted = false;
|
|
|
73
74
|
onMount(() => {
|
|
74
75
|
mounted = true;
|
|
75
76
|
});
|
|
76
|
-
$: context = {
|
|
77
|
+
$: context = {
|
|
78
|
+
email: $userStore?.email,
|
|
79
|
+
username: $userStore?.username,
|
|
80
|
+
query: Object.fromEntries($page.url.searchParams.entries())
|
|
81
|
+
};
|
|
77
82
|
$: mounted && ($worldStore = buildWorld($staticOutputs, $worldStore, context));
|
|
78
83
|
$: previewing = $mode === 'preview';
|
|
79
84
|
$: width = $breakpoint === 'sm' ? 'min-w-[400px] max-w-[656px]' : 'min-w-[710px] w-full';
|
|
@@ -170,7 +175,7 @@ else {
|
|
|
170
175
|
{#if $connectingInput.opened}
|
|
171
176
|
<div
|
|
172
177
|
class="fixed top-32 p-2 z-50 flex justify-center items-center"
|
|
173
|
-
transition:fly={{ duration: 100, y: -100 }}
|
|
178
|
+
transition:fly|local={{ duration: 100, y: -100 }}
|
|
174
179
|
>
|
|
175
180
|
<Alert title="Connecting" type="info">
|
|
176
181
|
<div class="flex gap-2 flex-col">
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
<script>import { onMount, setContext } from 'svelte';
|
|
2
|
+
import { fade } from 'svelte/transition';
|
|
3
|
+
import { cubicOut } from 'svelte/easing';
|
|
2
4
|
import { writable } from 'svelte/store';
|
|
3
5
|
import { buildWorld } from '../rx';
|
|
4
6
|
import GridEditor from './GridEditor.svelte';
|
|
5
7
|
import { classNames } from '../../../utils';
|
|
8
|
+
import Button from '../../common/button/Button.svelte';
|
|
9
|
+
import { Unlock } from 'lucide-svelte';
|
|
6
10
|
export let app;
|
|
7
11
|
export let appPath;
|
|
8
12
|
export let breakpoint;
|
|
@@ -12,6 +16,7 @@ export let workspace;
|
|
|
12
16
|
export let isEditor;
|
|
13
17
|
export let context;
|
|
14
18
|
export let noBackend = false;
|
|
19
|
+
export let isLocked = false;
|
|
15
20
|
const appStore = writable(app);
|
|
16
21
|
const worldStore = writable(undefined);
|
|
17
22
|
const staticOutputs = writable({});
|
|
@@ -48,12 +53,29 @@ onMount(() => {
|
|
|
48
53
|
});
|
|
49
54
|
$: mounted && ($worldStore = buildWorld($staticOutputs, undefined, context));
|
|
50
55
|
$: width = $breakpoint === 'sm' ? 'max-w-[640px]' : 'w-full ';
|
|
56
|
+
$: lockedClasses = isLocked ? '!max-h-[400px] overflow-hidden pointer-events-none' : '';
|
|
51
57
|
</script>
|
|
52
58
|
|
|
53
|
-
<div class="
|
|
54
|
-
{
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
<div class="relative">
|
|
60
|
+
<div class="{$$props.class} {lockedClasses} h-full max-h-[calc(100%-41px)] overflow-auto
|
|
61
|
+
w-full {app.fullscreen ? '' : 'max-w-6xl'} mx-auto">
|
|
62
|
+
{#if $appStore.grid}
|
|
63
|
+
<div class={classNames('mx-auto pb-4', width)}>
|
|
64
|
+
<GridEditor {policy} />
|
|
65
|
+
</div>
|
|
66
|
+
{/if}
|
|
67
|
+
</div>
|
|
68
|
+
{#if isLocked}
|
|
69
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
70
|
+
<div
|
|
71
|
+
transition:fade|local={{ duration: 200, easing: cubicOut }}
|
|
72
|
+
on:click={() => isLocked = false}
|
|
73
|
+
class="absolute inset-0 center-center bg-black/20 z-50 backdrop-blur-[1px] cursor-pointer"
|
|
74
|
+
>
|
|
75
|
+
<Button on:click={() => isLocked = false}>
|
|
76
|
+
Unlock preview
|
|
77
|
+
<Unlock size={18} class="ml-1" strokeWidth={2.5} />
|
|
78
|
+
</Button>
|
|
57
79
|
</div>
|
|
58
80
|
{/if}
|
|
59
81
|
</div>
|
|
@@ -4,6 +4,7 @@ import type { App, EditorBreakpoint } from '../types';
|
|
|
4
4
|
import type { Policy } from '../../../gen';
|
|
5
5
|
declare const __propDef: {
|
|
6
6
|
props: {
|
|
7
|
+
[x: string]: any;
|
|
7
8
|
app: App;
|
|
8
9
|
appPath: string;
|
|
9
10
|
breakpoint: Writable<EditorBreakpoint>;
|
|
@@ -13,6 +14,7 @@ declare const __propDef: {
|
|
|
13
14
|
isEditor: boolean;
|
|
14
15
|
context: Record<string, any>;
|
|
15
16
|
noBackend?: boolean | undefined;
|
|
17
|
+
isLocked?: boolean | undefined;
|
|
16
18
|
};
|
|
17
19
|
events: {
|
|
18
20
|
[evt: string]: CustomEvent<any>;
|
|
@@ -17,6 +17,7 @@ import AppScatterChart from '../components/dataDisplay/AppScatterChart.svelte';
|
|
|
17
17
|
import AppTimeseries from '../components/dataDisplay/AppTimeseries.svelte';
|
|
18
18
|
import AppHtml from '../components/dataDisplay/AppHtml.svelte';
|
|
19
19
|
import AppSliderInputs from '../components/numberInputs/AppSliderInputs.svelte';
|
|
20
|
+
import VegaLiteHtml from '../components/dataDisplay/VegaLiteHtml.svelte';
|
|
20
21
|
export let component;
|
|
21
22
|
export let selected;
|
|
22
23
|
export let locked = false;
|
|
@@ -74,6 +75,12 @@ const { staticOutputs, mode, connectingInput } = getContext('AppEditorContext');
|
|
|
74
75
|
bind:componentInput={component.componentInput}
|
|
75
76
|
bind:staticOutputs={$staticOutputs[component.id]}
|
|
76
77
|
/>
|
|
78
|
+
{:else if component.type === 'vegalitecomponent'}
|
|
79
|
+
<VegaLiteHtml
|
|
80
|
+
{...component}
|
|
81
|
+
bind:componentInput={component.componentInput}
|
|
82
|
+
bind:staticOutputs={$staticOutputs[component.id]}
|
|
83
|
+
/>
|
|
77
84
|
{:else if component.type === 'scatterchartcomponent'}
|
|
78
85
|
<AppScatterChart
|
|
79
86
|
{...component}
|
|
@@ -29,7 +29,8 @@ function getRecommendedDimensionsByComponent(componentType, column) {
|
|
|
29
29
|
'barchartcomponent',
|
|
30
30
|
'piechartcomponent',
|
|
31
31
|
'displaycomponent',
|
|
32
|
-
'scatterchartcomponent'
|
|
32
|
+
'scatterchartcomponent',
|
|
33
|
+
'vegalitecomponent'
|
|
33
34
|
],
|
|
34
35
|
'3:10-6:10': ['tablecomponent']
|
|
35
36
|
};
|
|
@@ -167,6 +167,11 @@ const buttons = {
|
|
|
167
167
|
onlyStatic: true,
|
|
168
168
|
optionValuesKey: 'buttonSizeOptions',
|
|
169
169
|
value: 'xs'
|
|
170
|
+
},
|
|
171
|
+
disabled: {
|
|
172
|
+
fieldType: 'boolean',
|
|
173
|
+
type: 'eval',
|
|
174
|
+
expr: 'false'
|
|
170
175
|
}
|
|
171
176
|
},
|
|
172
177
|
card: false
|
|
@@ -227,6 +232,40 @@ const display = {
|
|
|
227
232
|
configuration: {},
|
|
228
233
|
card: false
|
|
229
234
|
},
|
|
235
|
+
{
|
|
236
|
+
softWrap: false,
|
|
237
|
+
id: 'vegalitecomponent',
|
|
238
|
+
type: 'vegalitecomponent',
|
|
239
|
+
componentInput: {
|
|
240
|
+
type: 'static',
|
|
241
|
+
fieldType: 'object',
|
|
242
|
+
value: {
|
|
243
|
+
data: {
|
|
244
|
+
values: [
|
|
245
|
+
{ a: 'A', b: 28 },
|
|
246
|
+
{ a: 'B', b: 55 },
|
|
247
|
+
{ a: 'C', b: 43 },
|
|
248
|
+
{ a: 'D', b: 91 },
|
|
249
|
+
]
|
|
250
|
+
},
|
|
251
|
+
mark: 'bar',
|
|
252
|
+
encoding: {
|
|
253
|
+
x: { field: 'a', type: 'ordinal' },
|
|
254
|
+
y: { field: 'b', type: 'quantitative' }
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
configuration: {
|
|
259
|
+
canvas: {
|
|
260
|
+
type: 'static',
|
|
261
|
+
onlyStatic: true,
|
|
262
|
+
fieldType: 'boolean',
|
|
263
|
+
value: false,
|
|
264
|
+
tooltip: "use the canvas renderer instead of the svg one for more interactive plots"
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
card: false
|
|
268
|
+
},
|
|
230
269
|
{
|
|
231
270
|
softWrap: true,
|
|
232
271
|
horizontalAlignment: 'left',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
<script>import {
|
|
1
|
+
<script>import { page } from '$app/stores';
|
|
2
|
+
import { classNames } from '../../../../utils';
|
|
2
3
|
import { getContext } from 'svelte';
|
|
3
4
|
import { key } from 'svelte-awesome/icons';
|
|
4
5
|
import { displayData } from '../../utils';
|
|
@@ -32,7 +33,7 @@ function getComponentNameById(componentId) {
|
|
|
32
33
|
return 'Table action';
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
|
-
$: panels = [['ctx', ['email', 'username']]].concat(Object.entries($staticOutputs));
|
|
36
|
+
$: panels = [['ctx', ['email', 'username', 'query']]].concat(Object.entries($staticOutputs));
|
|
36
37
|
</script>
|
|
37
38
|
|
|
38
39
|
<PanelSection noPadding titlePadding="px-4 pt-2" title="Outputs">
|
|
@@ -38,7 +38,7 @@ let runLoading = false;
|
|
|
38
38
|
|
|
39
39
|
<InlineScriptEditorDrawer {editor} bind:this={inlineScriptEditorDrawer} bind:inlineScript />
|
|
40
40
|
|
|
41
|
-
<div class="h-full flex flex-col gap-1" transition:fly={{ duration: 50 }}>
|
|
41
|
+
<div class="h-full flex flex-col gap-1" transition:fly|local={{ duration: 50 }}>
|
|
42
42
|
<div class="flex justify-between w-full gap-1 px-2 pt-1 flex-row items-center">
|
|
43
43
|
{#if name !== undefined}
|
|
44
44
|
<input bind:value={name} placeholder="Inline script name" />
|
|
@@ -119,6 +119,9 @@ let runLoading = false;
|
|
|
119
119
|
on:change={async (e) => {
|
|
120
120
|
if (inlineScript) {
|
|
121
121
|
const oldSchema = JSON.stringify(inlineScript.schema)
|
|
122
|
+
if (inlineScript.schema == undefined) {
|
|
123
|
+
inlineScript.schema = emptySchema()
|
|
124
|
+
}
|
|
122
125
|
await inferInlineScriptSchema(inlineScript?.language, e.detail, inlineScript.schema)
|
|
123
126
|
if (JSON.stringify(inlineScript.schema) != oldSchema) {
|
|
124
127
|
inlineScript = inlineScript
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { classNames } from '../../../../utils';
|
|
3
3
|
import { getContext } from 'svelte';
|
|
4
4
|
import PanelSection from '../settingsPanel/common/PanelSection.svelte';
|
|
5
|
+
import { getAppScripts } from './utils';
|
|
5
6
|
export let selectedScriptComponentId = undefined;
|
|
6
7
|
const { app, selectedComponent, lazyGrid } = getContext('AppEditorContext');
|
|
7
8
|
function selectInlineScript(id) {
|
|
@@ -10,56 +11,7 @@ function selectInlineScript(id) {
|
|
|
10
11
|
$selectedComponent = selectedScriptComponentId;
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
|
-
$:
|
|
14
|
-
const component = gridComponent.data;
|
|
15
|
-
if (component.type === 'tablecomponent') {
|
|
16
|
-
component.actionButtons.forEach((actionButton) => {
|
|
17
|
-
if (actionButton.componentInput?.type === 'runnable') {
|
|
18
|
-
if (actionButton.componentInput.runnable?.type === 'runnableByName') {
|
|
19
|
-
acc.push({
|
|
20
|
-
name: actionButton.componentInput.runnable.name,
|
|
21
|
-
id: actionButton.id
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
const componentInput = component.componentInput;
|
|
28
|
-
if (componentInput?.type === 'runnable') {
|
|
29
|
-
if (componentInput.runnable?.type === 'runnableByName') {
|
|
30
|
-
acc.push({
|
|
31
|
-
name: componentInput.runnable.name,
|
|
32
|
-
id: gridComponent.id
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return acc;
|
|
37
|
-
}, []);
|
|
38
|
-
$: runnablesByPath = $lazyGrid.reduce((acc, gridComponent) => {
|
|
39
|
-
const component = gridComponent.data;
|
|
40
|
-
if (component.type === 'tablecomponent') {
|
|
41
|
-
component.actionButtons.forEach((actionButton) => {
|
|
42
|
-
if (actionButton.componentInput?.type === 'runnable') {
|
|
43
|
-
if (actionButton.componentInput.runnable?.type === 'runnableByPath') {
|
|
44
|
-
acc.push({
|
|
45
|
-
name: actionButton.componentInput.runnable.path,
|
|
46
|
-
id: actionButton.id
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
const componentInput = component.componentInput;
|
|
53
|
-
if (componentInput?.type === 'runnable') {
|
|
54
|
-
if (componentInput.runnable?.type === 'runnableByPath') {
|
|
55
|
-
acc.push({
|
|
56
|
-
name: componentInput.runnable.path,
|
|
57
|
-
id: gridComponent.id
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return acc;
|
|
62
|
-
}, []);
|
|
14
|
+
$: runnables = getAppScripts($lazyGrid);
|
|
63
15
|
// When seleced component changes, update selectedScriptComponentId
|
|
64
16
|
$: {
|
|
65
17
|
if (selectedComponent) {
|
|
@@ -71,9 +23,9 @@ $: {
|
|
|
71
23
|
<div class="min-h-full flex flex-col gap-4">
|
|
72
24
|
<PanelSection title="Inline scripts" smallPadding>
|
|
73
25
|
<div class="flex flex-col gap-2 w-full">
|
|
74
|
-
{#if
|
|
26
|
+
{#if runnables.inline.length > 0}
|
|
75
27
|
<div class="flex gap-2 flex-col ">
|
|
76
|
-
{#each
|
|
28
|
+
{#each runnables.inline as { name, id }, index (index)}
|
|
77
29
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
78
30
|
<div
|
|
79
31
|
class="{classNames(
|
|
@@ -109,17 +61,17 @@ $: {
|
|
|
109
61
|
</div>
|
|
110
62
|
{/if}
|
|
111
63
|
|
|
112
|
-
{#if
|
|
64
|
+
{#if runnables.inline.length == 0 && $app.unusedInlineScripts?.length == 0}
|
|
113
65
|
<div class="text-sm text-gray-500">No inline scripts</div>
|
|
114
66
|
{/if}
|
|
115
67
|
</div>
|
|
116
68
|
</PanelSection>
|
|
117
69
|
|
|
118
|
-
<PanelSection title="
|
|
70
|
+
<PanelSection title="Imported scripts" smallPadding>
|
|
119
71
|
<div class="flex flex-col gap-2 w-full">
|
|
120
|
-
{#if
|
|
72
|
+
{#if runnables.imported.length > 0}
|
|
121
73
|
<div class="flex gap-2 flex-col ">
|
|
122
|
-
{#each
|
|
74
|
+
{#each runnables.imported as { name, id }, index (index)}
|
|
123
75
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
124
76
|
<div
|
|
125
77
|
class="{classNames(
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AppComponent, GridItem } from "../../types";
|
|
2
|
+
export interface AppScriptsList {
|
|
3
|
+
inline: {
|
|
4
|
+
name: string;
|
|
5
|
+
id: string;
|
|
6
|
+
}[];
|
|
7
|
+
imported: {
|
|
8
|
+
name: string;
|
|
9
|
+
id: string;
|
|
10
|
+
}[];
|
|
11
|
+
}
|
|
12
|
+
export declare function getAppScripts(grid: GridItem[]): FilledItem<{
|
|
13
|
+
data: AppComponent;
|
|
14
|
+
id: string;
|
|
15
|
+
}>;
|