windmill-components 1.28.4 → 1.28.7
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/ArgInput.svelte +15 -7
- package/components/Editor.svelte +43 -31
- package/components/FlowBuilder.svelte +5 -3
- package/components/FlowEditor.svelte +8 -5
- package/components/FlowEditor.svelte.d.ts +1 -0
- package/components/FlowPreview.svelte +13 -10
- package/components/FlowPreview.svelte.d.ts +0 -2
- package/components/FlowPreviewContent.svelte +6 -6
- package/components/FlowStatusViewer.svelte +3 -0
- package/components/FlowViewer.svelte +15 -12
- package/components/InputTransformForm.svelte +2 -2
- package/components/InputTransformsViewer.svelte +1 -1
- package/components/ModuleStep.svelte +5 -7
- package/components/ModuleStep.svelte.d.ts +0 -2
- package/components/ObjectResourceInput.svelte +2 -2
- package/components/RadioButton.svelte +4 -2
- package/components/SchemaEditor.svelte +7 -3
- package/components/SchemaEditorProperty.svelte +9 -7
- package/components/SchemaViewer.svelte +5 -1
- package/components/ScriptEditor.svelte +7 -1
- package/components/flows/DynamicInputHelpBox.svelte +15 -10
- package/components/flows/DynamicInputHelpBox.svelte.d.ts +3 -1
- package/components/flows/FlowInputs.svelte +18 -4
- package/components/flows/FlowSettings.svelte +12 -2
- package/components/flows/FlowSettings.svelte.d.ts +1 -0
- package/logout.d.ts +1 -1
- package/logout.js +11 -9
- package/package.json +1 -1
|
@@ -114,7 +114,7 @@ export let inputCat = 'string';
|
|
|
114
114
|
$: inputCat = computeInputCat(type, format, itemsType?.type, enum_, contentEncoding);
|
|
115
115
|
</script>
|
|
116
116
|
|
|
117
|
-
<div class="flex flex-col w-full">
|
|
117
|
+
<div class="flex flex-col w-full mb-2">
|
|
118
118
|
<div>
|
|
119
119
|
{#if displayHeader}
|
|
120
120
|
<FieldHeader {label} {required} {type} {contentEncoding} {format} {itemsType} />
|
|
@@ -158,13 +158,18 @@ $: inputCat = computeInputCat(type, format, itemsType?.type, enum_, contentEncod
|
|
|
158
158
|
{/if}
|
|
159
159
|
|
|
160
160
|
<div class="grid grid-cols-2">
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
{error === '' ? '
|
|
166
|
-
|
|
161
|
+
{#if description || error}
|
|
162
|
+
<div class="text-sm italic pb-1">
|
|
163
|
+
{description}
|
|
164
|
+
</div>
|
|
165
|
+
<div class="text-right text-xs {error === '' ? 'text-white' : 'font-bold text-red-600'}">
|
|
166
|
+
{error === '' ? '...' : error}
|
|
167
|
+
</div>
|
|
168
|
+
{:else}
|
|
169
|
+
<div class="mt-1" />
|
|
170
|
+
{/if}
|
|
167
171
|
</div>
|
|
172
|
+
|
|
168
173
|
<div class="flex space-x-1">
|
|
169
174
|
{#if inputCat == 'number'}
|
|
170
175
|
<input
|
|
@@ -266,6 +271,9 @@ $: inputCat = computeInputCat(type, format, itemsType?.type, enum_, contentEncod
|
|
|
266
271
|
lang="sql"
|
|
267
272
|
bind:code={value}
|
|
268
273
|
class="two-lines-editor"
|
|
274
|
+
on:change={async () => {
|
|
275
|
+
dispatch('input', { rawValue: value, isRaw: false })
|
|
276
|
+
}}
|
|
269
277
|
/>
|
|
270
278
|
</div>
|
|
271
279
|
{:else if inputCat == 'base64'}
|
package/components/Editor.svelte
CHANGED
|
@@ -130,6 +130,8 @@ function format() {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
+
let command = undefined;
|
|
134
|
+
let monacoServices = undefined;
|
|
133
135
|
export async function reloadWebsocket() {
|
|
134
136
|
await closeWebsockets();
|
|
135
137
|
if (lang == 'python' || deno) {
|
|
@@ -138,8 +140,9 @@ export async function reloadWebsocket() {
|
|
|
138
140
|
const { toSocket, WebSocketMessageReader, WebSocketMessageWriter } = await import('vscode-ws-jsonrpc');
|
|
139
141
|
const vscode = await import('vscode');
|
|
140
142
|
const { RequestType } = await import('vscode-jsonrpc');
|
|
143
|
+
// install Monaco language client services
|
|
141
144
|
const { MonacoServices } = await import('monaco-languageclient');
|
|
142
|
-
MonacoServices.install();
|
|
145
|
+
monacoServices = MonacoServices.install();
|
|
143
146
|
function createLanguageClient(transports, name, initializationOptions) {
|
|
144
147
|
const client = new MonacoLanguageClient({
|
|
145
148
|
name: name,
|
|
@@ -179,31 +182,17 @@ export async function reloadWebsocket() {
|
|
|
179
182
|
async function connectToLanguageServer(url, name, options) {
|
|
180
183
|
try {
|
|
181
184
|
const webSocket = new WebSocket(url);
|
|
182
|
-
webSocket.onopen = () => {
|
|
185
|
+
webSocket.onopen = async () => {
|
|
183
186
|
const socket = toSocket(webSocket);
|
|
184
187
|
const reader = new WebSocketMessageReader(socket);
|
|
185
188
|
const writer = new WebSocketMessageWriter(socket);
|
|
186
189
|
const languageClient = createLanguageClient({ reader, writer }, name, options);
|
|
187
190
|
websockets.push([languageClient, webSocket]);
|
|
188
|
-
|
|
189
|
-
lastWsAttempt = new Date();
|
|
190
|
-
nbWsAttempt = 0;
|
|
191
|
-
if (name == 'deno') {
|
|
192
|
-
vscode.commands.getCommands().then((v) => {
|
|
193
|
-
if (!v.includes('deno.cache')) {
|
|
194
|
-
vscode.commands.registerCommand('deno.cache', (uris = []) => {
|
|
195
|
-
languageClient.sendRequest(new RequestType('deno/cache'), {
|
|
196
|
-
referrer: { uri },
|
|
197
|
-
uris: uris.map((uri) => ({ uri }))
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
reader.onClose(() => {
|
|
191
|
+
reader.onClose(async () => {
|
|
204
192
|
try {
|
|
205
193
|
console.log('CLOSE');
|
|
206
|
-
|
|
194
|
+
websocketAlive[name] = false;
|
|
195
|
+
await languageClient.stop();
|
|
207
196
|
}
|
|
208
197
|
catch (err) {
|
|
209
198
|
console.error(err);
|
|
@@ -212,6 +201,27 @@ export async function reloadWebsocket() {
|
|
|
212
201
|
socket.onClose((_code, _reason) => {
|
|
213
202
|
websocketAlive[name] = false;
|
|
214
203
|
});
|
|
204
|
+
try {
|
|
205
|
+
console.log('started client');
|
|
206
|
+
await languageClient.start();
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
console.log('err at client');
|
|
210
|
+
console.error(err);
|
|
211
|
+
throw new Error(err);
|
|
212
|
+
}
|
|
213
|
+
lastWsAttempt = new Date();
|
|
214
|
+
nbWsAttempt = 0;
|
|
215
|
+
if (name == 'deno') {
|
|
216
|
+
command && command.dispose();
|
|
217
|
+
command = undefined;
|
|
218
|
+
command = vscode.commands.registerCommand('deno.cache', (uris = []) => {
|
|
219
|
+
languageClient.sendRequest(new RequestType('deno/cache'), {
|
|
220
|
+
referrer: { uri },
|
|
221
|
+
uris: uris.map((uri) => ({ uri }))
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
}
|
|
215
225
|
websocketAlive[name] = true;
|
|
216
226
|
};
|
|
217
227
|
}
|
|
@@ -297,12 +307,20 @@ export async function reloadWebsocket() {
|
|
|
297
307
|
}
|
|
298
308
|
}
|
|
299
309
|
async function closeWebsockets() {
|
|
310
|
+
command && command.dispose();
|
|
311
|
+
command = undefined;
|
|
312
|
+
monacoServices && monacoServices.dispose();
|
|
313
|
+
monacoServices = undefined;
|
|
300
314
|
for (const x of websockets) {
|
|
301
315
|
try {
|
|
302
316
|
await x[0].stop();
|
|
303
317
|
x[1].close();
|
|
304
318
|
}
|
|
305
319
|
catch (err) {
|
|
320
|
+
try {
|
|
321
|
+
x[1].close();
|
|
322
|
+
}
|
|
323
|
+
catch (err) { }
|
|
306
324
|
console.log('error disposing websocket', err);
|
|
307
325
|
}
|
|
308
326
|
}
|
|
@@ -329,9 +347,6 @@ async function loadMonaco() {
|
|
|
329
347
|
minimap: {
|
|
330
348
|
enabled: false
|
|
331
349
|
},
|
|
332
|
-
scrollbar: {
|
|
333
|
-
alwaysConsumeMouseWheel: false
|
|
334
|
-
},
|
|
335
350
|
lightbulb: {
|
|
336
351
|
enabled: true
|
|
337
352
|
}
|
|
@@ -392,18 +407,15 @@ async function loadMonaco() {
|
|
|
392
407
|
}
|
|
393
408
|
}
|
|
394
409
|
if (lang == 'python' || deno) {
|
|
395
|
-
// install Monaco language client services
|
|
396
410
|
reloadWebsocket();
|
|
397
411
|
}
|
|
398
412
|
return () => {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
console.log('error disposing editor', err);
|
|
406
|
-
}
|
|
413
|
+
try {
|
|
414
|
+
closeWebsockets();
|
|
415
|
+
editor && editor.dispose();
|
|
416
|
+
}
|
|
417
|
+
catch (err) {
|
|
418
|
+
console.log('error disposing editor', err);
|
|
407
419
|
}
|
|
408
420
|
};
|
|
409
421
|
}
|
|
@@ -16,6 +16,7 @@ import ScriptSchema from './ScriptSchema.svelte';
|
|
|
16
16
|
export let initialPath = '';
|
|
17
17
|
let pathError = '';
|
|
18
18
|
let scheduleArgs;
|
|
19
|
+
let previewArgs;
|
|
19
20
|
let scheduleEnabled;
|
|
20
21
|
let scheduleCron;
|
|
21
22
|
let previewOpen = false;
|
|
@@ -123,7 +124,7 @@ onDestroy(() => {
|
|
|
123
124
|
</script>
|
|
124
125
|
|
|
125
126
|
<div class="flex flex-row w-full h-full justify-between">
|
|
126
|
-
<div class={`flex flex-col mb-96 m-auto w-1/2`}>
|
|
127
|
+
<div class={`flex flex-col mb-96 m-auto w-full sm:w-3/4 lg:w-2/3 xl:w-1/2`}>
|
|
127
128
|
<!-- Nav between steps-->
|
|
128
129
|
<div class="justify-between flex flex-row w-full my-4">
|
|
129
130
|
<Breadcrumb>
|
|
@@ -176,6 +177,7 @@ onDestroy(() => {
|
|
|
176
177
|
bind:scheduleEnabled
|
|
177
178
|
bind:scheduleCron
|
|
178
179
|
bind:scheduleArgs
|
|
180
|
+
bind:previewArgs
|
|
179
181
|
/>
|
|
180
182
|
<Button
|
|
181
183
|
disabled={pathIsEmpty($flowStore.path)}
|
|
@@ -205,9 +207,9 @@ onDestroy(() => {
|
|
|
205
207
|
<div class={`relative h-screen w-1/3 ${previewOpen ? '' : 'hidden'}`}>
|
|
206
208
|
<div class="absolute top-0 h-full">
|
|
207
209
|
{#if $flowStore && step === 1}
|
|
208
|
-
<div class="fixed border-l-2 right-0 h-screen w-1/3">
|
|
210
|
+
<div class="fixed border-l-2 right-0 h-screen w-1/2 sm:w-1/3">
|
|
209
211
|
<FlowPreviewContent
|
|
210
|
-
bind:args={
|
|
212
|
+
bind:args={previewArgs}
|
|
211
213
|
on:close={() => (previewOpen = !previewOpen)}
|
|
212
214
|
on:change={(e) => {
|
|
213
215
|
previewResults.set(jobsToResults(e.detail))
|
|
@@ -14,6 +14,7 @@ export let initialPath = '';
|
|
|
14
14
|
export let scheduleArgs = {};
|
|
15
15
|
export let scheduleEnabled = false;
|
|
16
16
|
export let scheduleCron = '0 */5 * * *';
|
|
17
|
+
export let previewArgs = {};
|
|
17
18
|
let scheduleLoaded = false;
|
|
18
19
|
async function loadSchedule() {
|
|
19
20
|
if (!scheduleLoaded) {
|
|
@@ -30,6 +31,7 @@ async function loadSchedule() {
|
|
|
30
31
|
scheduleEnabled = schedule.enabled;
|
|
31
32
|
scheduleCron = schedule.schedule;
|
|
32
33
|
scheduleArgs = schedule.args ?? {};
|
|
34
|
+
previewArgs = JSON.parse(JSON.stringify(scheduleArgs));
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
37
|
}
|
|
@@ -37,7 +39,6 @@ $: if ($flowStore && $workspaceStore && initialPath != '') {
|
|
|
37
39
|
loadSchedule();
|
|
38
40
|
}
|
|
39
41
|
let open = 0;
|
|
40
|
-
let args = {};
|
|
41
42
|
</script>
|
|
42
43
|
|
|
43
44
|
{#if $flowStore}
|
|
@@ -46,19 +47,21 @@ let args = {};
|
|
|
46
47
|
bind:pathError
|
|
47
48
|
bind:initialPath
|
|
48
49
|
bind:scheduleArgs
|
|
50
|
+
{previewArgs}
|
|
49
51
|
bind:scheduleCron
|
|
50
52
|
bind:scheduleEnabled
|
|
51
53
|
bind:open
|
|
52
54
|
/>
|
|
53
55
|
<FlowInput />
|
|
54
56
|
{#each $flowStore?.value.modules as mod, i}
|
|
55
|
-
<ModuleStep bind:open bind:mod bind:args
|
|
57
|
+
<ModuleStep bind:open bind:mod bind:args={previewArgs} {i} />
|
|
56
58
|
{#if i == 0 && $mode == 'pull'}
|
|
57
59
|
<div class="flex justify-center bg-white shadow p-2">
|
|
58
60
|
<p>
|
|
59
|
-
Starting from here, the flow for loop over items from the
|
|
60
|
-
<br />
|
|
61
|
-
|
|
61
|
+
Starting from here, the flow for loop over items from the 1st step's result right above.
|
|
62
|
+
<br />For-loops insertable at other points is not supported yet but coming soon
|
|
63
|
+
(See
|
|
64
|
+
<a href="https://github.com/windmill-labs/windmill/issues/350">#350</a>.)
|
|
62
65
|
</p>
|
|
63
66
|
<Tooltip>
|
|
64
67
|
This flow being in 'Pull' mode, the rest of the flow will for loop over the list of
|
|
@@ -5,7 +5,7 @@ import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons';
|
|
|
5
5
|
import { createEventDispatcher, onDestroy } from 'svelte';
|
|
6
6
|
import Icon from 'svelte-awesome';
|
|
7
7
|
import FlowJobResult from './FlowJobResult.svelte';
|
|
8
|
-
import {
|
|
8
|
+
import { runFlowPreview } from './flows/utils';
|
|
9
9
|
import FlowStatusViewer from './FlowStatusViewer.svelte';
|
|
10
10
|
import RunForm from './RunForm.svelte';
|
|
11
11
|
import Tabs from './Tabs.svelte';
|
|
@@ -13,7 +13,6 @@ const dispatch = createEventDispatcher();
|
|
|
13
13
|
export let i;
|
|
14
14
|
export let flow;
|
|
15
15
|
export let schemas = [];
|
|
16
|
-
export let mode;
|
|
17
16
|
export let args = {};
|
|
18
17
|
let stepArgs = {};
|
|
19
18
|
let tab = 'upto';
|
|
@@ -27,8 +26,7 @@ $: dispatch('change', jobs);
|
|
|
27
26
|
export async function runPreview(args) {
|
|
28
27
|
viewPreview = true;
|
|
29
28
|
intervalId && clearInterval(intervalId);
|
|
30
|
-
let newFlow =
|
|
31
|
-
newFlow = tab == 'upto' ? truncateFlow(newFlow) : extractStep(newFlow);
|
|
29
|
+
let newFlow = tab == 'upto' ? truncateFlow(flow) : setInputTransformFromArgs(extractStep(flow), args);
|
|
32
30
|
jobId = await runFlowPreview(args, newFlow);
|
|
33
31
|
jobs = [];
|
|
34
32
|
intervalId = setInterval(loadJob, 1000);
|
|
@@ -43,14 +41,19 @@ function extractStep(flow) {
|
|
|
43
41
|
const localFlow = JSON.parse(JSON.stringify(flow));
|
|
44
42
|
localFlow.value.modules = flow.value.modules.slice(i, i + 1);
|
|
45
43
|
localFlow.schema = schemas[i];
|
|
46
|
-
stepArgs = {};
|
|
47
|
-
Object.entries(flow.value.modules[i].input_transform).forEach((x) => {
|
|
48
|
-
if (x[1].type == 'static') {
|
|
49
|
-
stepArgs[x[0]] = x[1].value;
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
44
|
return localFlow;
|
|
53
45
|
}
|
|
46
|
+
function setInputTransformFromArgs(flow, args) {
|
|
47
|
+
let input_transform = {};
|
|
48
|
+
Object.entries(args).forEach(([key, value]) => {
|
|
49
|
+
input_transform[key] = {
|
|
50
|
+
type: 'static',
|
|
51
|
+
value: value
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
flow.value.modules[0].input_transform = input_transform;
|
|
55
|
+
return flow;
|
|
56
|
+
}
|
|
54
57
|
async function loadJob() {
|
|
55
58
|
try {
|
|
56
59
|
job = await JobService.getJob({ workspace: $workspaceStore, id: jobId });
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
2
|
import type { Schema } from '../common';
|
|
3
3
|
import { type Flow } from '../gen';
|
|
4
|
-
import type { FlowMode } from './flows/flowStore';
|
|
5
4
|
declare const __propDef: {
|
|
6
5
|
props: {
|
|
7
6
|
i: number;
|
|
8
7
|
flow: Flow;
|
|
9
8
|
schemas?: Schema[] | undefined;
|
|
10
|
-
mode: FlowMode;
|
|
11
9
|
args?: Record<string, any> | undefined;
|
|
12
10
|
runPreview?: ((args: any) => Promise<void>) | undefined;
|
|
13
11
|
};
|
|
@@ -41,8 +41,8 @@ onDestroy(() => {
|
|
|
41
41
|
});
|
|
42
42
|
</script>
|
|
43
43
|
|
|
44
|
-
<div class="flex flex-col space-y-4 h-screen bg-white
|
|
45
|
-
<div class="flex flex-col space-y-4 p-6 border-b-2">
|
|
44
|
+
<div class="flex flex-col space-y-4 h-screen bg-white">
|
|
45
|
+
<div class="flex flex-col space-y-4 p-6 border-b-2 overflow-y-auto grow">
|
|
46
46
|
<div class="flex justify-between">
|
|
47
47
|
<h3 class="text-lg leading-6 font-bold text-gray-900">Flow Preview</h3>
|
|
48
48
|
|
|
@@ -51,11 +51,11 @@ onDestroy(() => {
|
|
|
51
51
|
</Button>
|
|
52
52
|
</div>
|
|
53
53
|
<SchemaForm schema={$flowStore.schema} bind:isValid bind:args />
|
|
54
|
-
<Button disabled={!isValid} class="blue-button" on:click={() => runPreview(args)} size="md">
|
|
55
|
-
Preview
|
|
56
|
-
</Button>
|
|
57
54
|
</div>
|
|
58
|
-
<
|
|
55
|
+
<Button disabled={!isValid} class="blue-button mx-4" on:click={() => runPreview(args)} size="md">
|
|
56
|
+
Preview
|
|
57
|
+
</Button>
|
|
58
|
+
<div class="h-full overflow-y-auto mb-16 grow">
|
|
59
59
|
{#if job}
|
|
60
60
|
<div class="w-full">
|
|
61
61
|
<FlowStatusViewer {job} bind:jobs />
|
|
@@ -41,7 +41,7 @@ function toAny(x) {
|
|
|
41
41
|
{#if tab == 'ui'}
|
|
42
42
|
<div class="flow-root w-full pb-4">
|
|
43
43
|
{#if !embedded}
|
|
44
|
-
<h2 class="
|
|
44
|
+
<h2 class="my-4">{flow.summary}</h2>
|
|
45
45
|
<SvelteMarkdown source={flow.description ?? ''} />
|
|
46
46
|
|
|
47
47
|
<p class="font-black text-lg w-full my-4">
|
|
@@ -113,17 +113,19 @@ function toAny(x) {
|
|
|
113
113
|
View code and inputs {open[i] ? '(-)' : '(+)'}</button
|
|
114
114
|
>
|
|
115
115
|
{#if open[i]}
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
116
|
+
<div class="border border-black p-2 bg-gray-50 divide-y">
|
|
117
|
+
<InputTransformsViewer inputTransforms={mod?.input_transform} />
|
|
118
|
+
<div class="w-full h-full mt-6">
|
|
119
|
+
<iframe
|
|
120
|
+
style="height: 400px;"
|
|
121
|
+
class="w-full h-full text-sm"
|
|
122
|
+
title="embedded script from hub"
|
|
123
|
+
frameborder="0"
|
|
124
|
+
src="https://hub.windmill.dev/embed/script/{mod?.value?.path?.substring(
|
|
125
|
+
4
|
|
126
|
+
)}"
|
|
127
|
+
/>
|
|
128
|
+
</div>
|
|
127
129
|
</div>
|
|
128
130
|
{/if}
|
|
129
131
|
</div>
|
|
@@ -173,5 +175,6 @@ function toAny(x) {
|
|
|
173
175
|
<Highlight language={json} code={JSON.stringify(flowFiltered, null, 4)} />
|
|
174
176
|
</div>
|
|
175
177
|
{:else if tab == 'schema'}
|
|
178
|
+
<div class="my-4" />
|
|
176
179
|
<SchemaViewer schema={flow.schema} />
|
|
177
180
|
{/if}
|
|
@@ -78,7 +78,7 @@ $: checked = propertyType == 'javascript';
|
|
|
78
78
|
</script>
|
|
79
79
|
|
|
80
80
|
{#if arg != undefined}
|
|
81
|
-
<div class="flex justify-between items-center">
|
|
81
|
+
<div class="flex justify-between items-center mb-2">
|
|
82
82
|
<div class="flex items-center">
|
|
83
83
|
<FieldHeader
|
|
84
84
|
label={argName}
|
|
@@ -199,7 +199,7 @@ $: checked = propertyType == 'javascript';
|
|
|
199
199
|
/>
|
|
200
200
|
</div>
|
|
201
201
|
</OverlayPropertyPicker>
|
|
202
|
-
<DynamicInputHelpBox />
|
|
202
|
+
<DynamicInputHelpBox {i} />
|
|
203
203
|
{/if}
|
|
204
204
|
{:else}
|
|
205
205
|
<p>Not recognized arg type {arg.type}</p>
|
|
@@ -10,7 +10,7 @@ export let inputTransforms;
|
|
|
10
10
|
<span class="font-black text-gray-700">{key}</span>: {#if val.type == 'static'}<ObjectViewer
|
|
11
11
|
json={val.value}
|
|
12
12
|
/>{:else}
|
|
13
|
-
<span class="inline-
|
|
13
|
+
<span class="inline-highlight">
|
|
14
14
|
<Highlight offsetTop={0} language={typescript} code={val.expr} />
|
|
15
15
|
</span>
|
|
16
16
|
{/if}
|
|
@@ -9,12 +9,11 @@ import FlowPreview from './FlowPreview.svelte';
|
|
|
9
9
|
import FlowBox from './flows/FlowBox.svelte';
|
|
10
10
|
import FlowInputs from './flows/FlowInputs.svelte';
|
|
11
11
|
import FlowModuleHeader from './flows/FlowModuleHeader.svelte';
|
|
12
|
-
import { addModule, createInlineScriptModule, flowStore, loadSchema, pickScript, schemasStore } from './flows/flowStore';
|
|
12
|
+
import { addModule, createInlineScriptModule, flowStore, loadSchema, mode, pickScript, schemasStore } from './flows/flowStore';
|
|
13
13
|
import { getPickableProperties, jobsToResults } from './flows/utils';
|
|
14
14
|
import SchemaForm from './SchemaForm.svelte';
|
|
15
15
|
import Tooltip from './Tooltip.svelte';
|
|
16
16
|
export let open;
|
|
17
|
-
export let mode;
|
|
18
17
|
export let i;
|
|
19
18
|
export let mod;
|
|
20
19
|
export let args = {};
|
|
@@ -24,9 +23,9 @@ let pickableProperties = undefined;
|
|
|
24
23
|
let bigEditor = false;
|
|
25
24
|
$: schema = $schemasStore[i];
|
|
26
25
|
$: shouldPick = 'path' in mod.value && mod.value.path === '' && !('language' in mod.value);
|
|
27
|
-
$: pickableProperties = getPickableProperties($flowStore?.schema, args, $previewResults, mode, i);
|
|
26
|
+
$: pickableProperties = getPickableProperties($flowStore?.schema, args, $previewResults, $mode, i);
|
|
28
27
|
$: extraLib = buildExtraLib(schemaToTsType($flowStore?.schema), i === 0 ? schemaToTsType($flowStore?.schema) : objectToTsType($previewResults[i]));
|
|
29
|
-
const isTrigger = mode === 'pull' && i === 0;
|
|
28
|
+
const isTrigger = $mode === 'pull' && i === 0;
|
|
30
29
|
</script>
|
|
31
30
|
|
|
32
31
|
<button
|
|
@@ -75,14 +74,14 @@ const isTrigger = mode === 'pull' && i === 0;
|
|
|
75
74
|
<FlowInputs
|
|
76
75
|
{isTrigger}
|
|
77
76
|
on:pick={(e) => pickScript(e.detail.path, i)}
|
|
78
|
-
on:new={(e) => createInlineScriptModule(e.detail.language, i, mode)}
|
|
77
|
+
on:new={(e) => createInlineScriptModule(e.detail.language, i, $mode)}
|
|
79
78
|
/>
|
|
80
79
|
{/if}
|
|
81
80
|
{#if mod.value.type === 'rawscript'}
|
|
82
81
|
<div class="mb-2 overflow-hidden">
|
|
83
82
|
<EditorBar {editor} {websocketAlive} lang={mod.value.language ?? 'deno'} />
|
|
84
83
|
</div>
|
|
85
|
-
<div>
|
|
84
|
+
<div on:mouseleave={() => loadSchema(i)}>
|
|
86
85
|
<Editor
|
|
87
86
|
bind:websocketAlive
|
|
88
87
|
bind:this={editor}
|
|
@@ -127,7 +126,6 @@ const isTrigger = mode === 'pull' && i === 0;
|
|
|
127
126
|
bind:args
|
|
128
127
|
flow={$flowStore}
|
|
129
128
|
{i}
|
|
130
|
-
{mode}
|
|
131
129
|
schemas={$schemasStore}
|
|
132
130
|
on:change={(e) => {
|
|
133
131
|
previewResults.set(jobsToResults(e.detail))
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
2
|
import { type FlowModule } from '../gen';
|
|
3
|
-
import { type FlowMode } from './flows/flowStore';
|
|
4
3
|
declare const __propDef: {
|
|
5
4
|
props: {
|
|
6
5
|
open: number;
|
|
7
|
-
mode: FlowMode;
|
|
8
6
|
i: number;
|
|
9
7
|
mod: FlowModule;
|
|
10
8
|
args?: Record<string, any> | undefined;
|
|
@@ -42,8 +42,8 @@ function valueToPath() {
|
|
|
42
42
|
$: value && valueToPath();
|
|
43
43
|
</script>
|
|
44
44
|
|
|
45
|
-
<div class="flex flex-row w-full gap-2">
|
|
46
|
-
<div class="shrink
|
|
45
|
+
<div class="flex flex-row w-full flex-wrap gap-x-2">
|
|
46
|
+
<div class="shrink">
|
|
47
47
|
<RadioButton
|
|
48
48
|
options={[
|
|
49
49
|
[`Resource (${resourceTypeName})`, 'resource'],
|
|
@@ -12,7 +12,7 @@ const dispatch = createEventDispatcher();
|
|
|
12
12
|
{#each options as [label, val]}
|
|
13
13
|
<label
|
|
14
14
|
class:item-button-selected={val == value}
|
|
15
|
-
class="item-button text-center text-sm h-full p-2 grow"
|
|
15
|
+
class="item-button text-center text-sm h-full p-2 grow whitespace-nowrap"
|
|
16
16
|
>
|
|
17
17
|
<input
|
|
18
18
|
type="radio"
|
|
@@ -23,7 +23,9 @@ const dispatch = createEventDispatcher();
|
|
|
23
23
|
on:click={() => dispatch('change', val)}
|
|
24
24
|
/>
|
|
25
25
|
<p>
|
|
26
|
-
{#if typeof label !== 'string'}
|
|
26
|
+
{#if typeof label !== 'string'}
|
|
27
|
+
{label.title}
|
|
28
|
+
<Tooltip>{label.desc}</Tooltip>
|
|
27
29
|
{:else}{label}{/if}
|
|
28
30
|
</p>
|
|
29
31
|
</label>
|
|
@@ -126,7 +126,7 @@ function switchTab() {
|
|
|
126
126
|
</script>
|
|
127
127
|
|
|
128
128
|
<div class="flex flex-col">
|
|
129
|
-
<div class="flex justify-between">
|
|
129
|
+
<div class="flex justify-between gap-x-2">
|
|
130
130
|
<Button
|
|
131
131
|
on:click={() => {
|
|
132
132
|
modalProperty = Object.assign({}, DEFAULT_PROPERTY)
|
|
@@ -176,8 +176,12 @@ function switchTab() {
|
|
|
176
176
|
<SchemaEditorProperty {property} />
|
|
177
177
|
</td>
|
|
178
178
|
<td>{property.description}</td>
|
|
179
|
-
<td>{JSON.stringify(property.default)
|
|
180
|
-
<td
|
|
179
|
+
<td>{property.default ? JSON.stringify(property.default) : ''}</td>
|
|
180
|
+
<td
|
|
181
|
+
>{#if schema.required.includes(name)}
|
|
182
|
+
<span class="text-red-600 font-bold text-lg">*</span>
|
|
183
|
+
{/if}</td
|
|
184
|
+
>
|
|
181
185
|
<td class="justify-end flex">
|
|
182
186
|
<Button
|
|
183
187
|
color="red"
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
export let property;
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
|
-
<
|
|
6
|
-
{
|
|
7
|
-
|
|
8
|
-
{
|
|
9
|
-
{
|
|
10
|
-
|
|
11
|
-
{
|
|
5
|
+
<div class="flex flex-row flex-wrap gap-1">
|
|
6
|
+
<Badge color="blue">{property.type?.toUpperCase() ?? 'ANY'}</Badge>
|
|
7
|
+
{#if property.format}
|
|
8
|
+
<Badge color="green">{property.format?.toUpperCase()}</Badge>
|
|
9
|
+
{/if}
|
|
10
|
+
{#if property.contentEncoding}
|
|
11
|
+
<Badge color="indigo">{property.contentEncoding?.toUpperCase()}</Badge>
|
|
12
|
+
{/if}
|
|
13
|
+
</div>
|
|
@@ -58,7 +58,11 @@ let viewJsonSchema = false;
|
|
|
58
58
|
>{property.format ?? ''}
|
|
59
59
|
{property.contentEncoding ? `(encoding: ${property.contentEncoding})` : ''}</td
|
|
60
60
|
>
|
|
61
|
-
<td
|
|
61
|
+
<td
|
|
62
|
+
>{#if schema.required.includes(name)}
|
|
63
|
+
<span class="text-red-600 font-bold text-lg">*</span>
|
|
64
|
+
{/if}</td
|
|
65
|
+
>
|
|
62
66
|
</tr>
|
|
63
67
|
{/each}
|
|
64
68
|
</tbody>
|
|
@@ -206,7 +206,13 @@ onDestroy(() => {
|
|
|
206
206
|
<div class="header">
|
|
207
207
|
<EditorBar {editor} {lang} {websocketAlive} />
|
|
208
208
|
</div>
|
|
209
|
-
<div
|
|
209
|
+
<div
|
|
210
|
+
class="flex-1 overflow-hidden border p-2 rounded"
|
|
211
|
+
on:mouseleave={() => {
|
|
212
|
+
code = getEditor().getCode()
|
|
213
|
+
inferSchema()
|
|
214
|
+
}}
|
|
215
|
+
>
|
|
210
216
|
<Editor
|
|
211
217
|
{code}
|
|
212
218
|
bind:websocketAlive
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script>import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons';
|
|
2
2
|
import Icon from 'svelte-awesome';
|
|
3
3
|
import { slide } from 'svelte/transition';
|
|
4
|
+
export let i = 1;
|
|
4
5
|
$: opened = false;
|
|
5
6
|
</script>
|
|
6
7
|
|
|
@@ -25,29 +26,29 @@ $: opened = false;
|
|
|
25
26
|
>
|
|
26
27
|
<p class="font-bold">Dynamic arg help</p>
|
|
27
28
|
<p>
|
|
28
|
-
When a field is "
|
|
29
|
-
corresponding
|
|
29
|
+
When a field is using the "Raw Javascript Editor", its value is computed dynamically as the
|
|
30
|
+
evaluation of its corresponding javascript snippet.
|
|
30
31
|
</p>
|
|
31
|
-
That snippet can be single line:
|
|
32
|
+
That snippet can be a single line:
|
|
32
33
|
<pre><code>last_result.myarg</code></pre>
|
|
33
|
-
or multiline:
|
|
34
|
+
or a multiline:
|
|
34
35
|
<pre><code
|
|
35
36
|
>let x = 5;
|
|
36
37
|
x + 2</code
|
|
37
38
|
></pre>
|
|
38
39
|
<p>
|
|
39
|
-
If it is multiline, the
|
|
40
|
+
If it is multiline, the statement before the final expression <b
|
|
40
41
|
>MUST END WITH ; and a newline</b
|
|
41
42
|
>
|
|
42
43
|
</p>
|
|
43
44
|
The snippet can also be a string template:
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
<code
|
|
46
|
+
>`Hello ${params.name}, all your base ${previous_result.base_name} belong
|
|
47
|
+
to us`</code
|
|
48
|
+
>
|
|
48
49
|
However, the last line must always be the final expression.
|
|
49
50
|
<p>
|
|
50
|
-
The snippet can use any
|
|
51
|
+
The snippet can use any javascript primitives, and the following flow specific objects and
|
|
51
52
|
functions:
|
|
52
53
|
</p>
|
|
53
54
|
<ul class="ml-4">
|
|
@@ -68,5 +69,9 @@ belong to us`</code
|
|
|
68
69
|
<b>resource(path)</b>: the function returning the resource at a given path as an object
|
|
69
70
|
</li>
|
|
70
71
|
</ul>
|
|
72
|
+
<p>To re-enable editor assistance, import the helper functions types using:</p>
|
|
73
|
+
<code
|
|
74
|
+
>{`import { previous_result, flow_input, step, variable, resource, params } from 'windmill@${i}'`}</code
|
|
75
|
+
>
|
|
71
76
|
</div>
|
|
72
77
|
{/if}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>import { RawScript } from '../../gen';
|
|
2
|
-
import { faCode } from '@fortawesome/free-solid-svg-icons';
|
|
2
|
+
import { faCode, faRepeat } from '@fortawesome/free-solid-svg-icons';
|
|
3
3
|
import { createEventDispatcher } from 'svelte';
|
|
4
4
|
import FlowScriptPicker from './pickers/FlowScriptPicker.svelte';
|
|
5
5
|
import PickHubScript from './pickers/PickHubScript.svelte';
|
|
@@ -12,20 +12,34 @@ const dispatch = createEventDispatcher();
|
|
|
12
12
|
<PickScript {isTrigger} on:pick />
|
|
13
13
|
<PickHubScript {isTrigger} on:pick />
|
|
14
14
|
<FlowScriptPicker
|
|
15
|
-
label=
|
|
15
|
+
label={`Create a for-loop here (coming soon)`}
|
|
16
|
+
disabled={true}
|
|
17
|
+
icon={faRepeat}
|
|
18
|
+
iconColor="text-blue-500"
|
|
19
|
+
/>
|
|
20
|
+
|
|
21
|
+
<FlowScriptPicker
|
|
22
|
+
label={`New Postgres SQL query`}
|
|
16
23
|
icon={faCode}
|
|
17
24
|
iconColor="text-blue-800"
|
|
18
|
-
on:click={() => dispatch('
|
|
25
|
+
on:click={() => dispatch('pick', { path: 'hub/130/execute_custom_query_postgresql' })}
|
|
19
26
|
/>
|
|
20
27
|
|
|
21
28
|
<FlowScriptPicker
|
|
22
29
|
disabled={isTrigger}
|
|
23
30
|
label="New Python {isTrigger ? 'trigger ' : ''}script (3.10)"
|
|
24
31
|
icon={faCode}
|
|
25
|
-
iconColor="text-
|
|
32
|
+
iconColor="text-green-500"
|
|
26
33
|
on:click={() => dispatch('new', { language: RawScript.language.PYTHON3 })}
|
|
27
34
|
tooltip={isTrigger
|
|
28
35
|
? 'Python is not supported for trigger scripts yet but is supported for every other steps'
|
|
29
36
|
: undefined}
|
|
30
37
|
/>
|
|
38
|
+
|
|
39
|
+
<FlowScriptPicker
|
|
40
|
+
label="New Typescript {isTrigger ? 'trigger ' : ''}script (Deno)"
|
|
41
|
+
icon={faCode}
|
|
42
|
+
iconColor="text-blue-800"
|
|
43
|
+
on:click={() => dispatch('new', { language: RawScript.language.DENO })}
|
|
44
|
+
/>
|
|
31
45
|
</div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script>import { sendUserToast } from '../../utils';
|
|
2
2
|
import { faFileExport, faFileImport, faGlobe } from '@fortawesome/free-solid-svg-icons';
|
|
3
|
-
import { Dropdown, DropdownItem } from 'flowbite-svelte';
|
|
3
|
+
import { Button, Dropdown, DropdownItem } from 'flowbite-svelte';
|
|
4
4
|
import Icon from 'svelte-awesome';
|
|
5
5
|
import Editor from '../Editor.svelte';
|
|
6
6
|
import FlowViewer from '../FlowViewer.svelte';
|
|
@@ -19,6 +19,7 @@ import Tooltip from './../Tooltip.svelte';
|
|
|
19
19
|
import FlowBoxHeader from './FlowBoxHeader.svelte';
|
|
20
20
|
export let pathError = '';
|
|
21
21
|
export let initialPath = '';
|
|
22
|
+
export let previewArgs = {};
|
|
22
23
|
export let scheduleArgs = {};
|
|
23
24
|
export let scheduleEnabled = false;
|
|
24
25
|
export let scheduleCron = '0 */5 * * *';
|
|
@@ -161,12 +162,21 @@ let jsonValue = '';
|
|
|
161
162
|
right: 'enabled'
|
|
162
163
|
}}
|
|
163
164
|
/>
|
|
164
|
-
<div class="p-2
|
|
165
|
+
<div class="p-2 my-2 rounded" class:bg-gray-300={!scheduleEnabled}>
|
|
165
166
|
{#if !scheduleEnabled}
|
|
166
167
|
<span class="font-black">No next scheduled run when disabled</span>
|
|
167
168
|
{/if}
|
|
168
169
|
<CronInput bind:schedule={scheduleCron} />
|
|
169
170
|
</div>
|
|
171
|
+
<div class="flex flex-row-reverse">
|
|
172
|
+
<Button
|
|
173
|
+
color="alternative"
|
|
174
|
+
size="sm"
|
|
175
|
+
on:click={() => (scheduleArgs = JSON.parse(JSON.stringify(previewArgs)))}
|
|
176
|
+
>
|
|
177
|
+
Copy from preview arguments
|
|
178
|
+
</Button>
|
|
179
|
+
</div>
|
|
170
180
|
<SchemaForm schema={$flowStore.schema} bind:args={scheduleArgs} />
|
|
171
181
|
</CollapseLink>
|
|
172
182
|
{/if}
|
|
@@ -3,6 +3,7 @@ declare const __propDef: {
|
|
|
3
3
|
props: {
|
|
4
4
|
pathError?: string | undefined;
|
|
5
5
|
initialPath?: string | undefined;
|
|
6
|
+
previewArgs?: Record<string, any> | undefined;
|
|
6
7
|
scheduleArgs?: Record<string, any> | undefined;
|
|
7
8
|
scheduleEnabled?: boolean | undefined;
|
|
8
9
|
scheduleCron?: string | undefined;
|
package/logout.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare function logoutWithRedirect(rd?: string): void;
|
|
2
|
-
export declare function logout(
|
|
2
|
+
export declare function logout(): Promise<void>;
|
package/logout.js
CHANGED
|
@@ -6,22 +6,24 @@ function clearCookies() {
|
|
|
6
6
|
document.cookie.split(";").forEach(function (c) { document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/"); });
|
|
7
7
|
}
|
|
8
8
|
export function logoutWithRedirect(rd) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
if (rd?.split('?')[0] != '/user/login') {
|
|
10
|
+
const error = document.cookie.includes('token')
|
|
11
|
+
? `error=${encodeURIComponent('You have been logged out because your session has expired.')}&`
|
|
12
|
+
: '';
|
|
13
|
+
clearCookies();
|
|
14
|
+
goto(`/user/login?${error}${rd ? 'rd=' + encodeURIComponent(rd) : ''}`);
|
|
15
|
+
}
|
|
14
16
|
}
|
|
15
|
-
export async function logout(
|
|
17
|
+
export async function logout() {
|
|
16
18
|
try {
|
|
17
19
|
clearStores();
|
|
18
20
|
await UserService.logout();
|
|
19
21
|
clearCookies();
|
|
20
|
-
goto(`/user/login${logoutMessage ? '?error=' + encodeURIComponent(logoutMessage) : ''}`);
|
|
21
|
-
sendUserToast('you have been logged out');
|
|
22
22
|
}
|
|
23
23
|
catch (error) {
|
|
24
|
-
goto('/user/login');
|
|
25
24
|
console.error(error);
|
|
25
|
+
clearCookies();
|
|
26
26
|
}
|
|
27
|
+
goto(`/user/login`);
|
|
28
|
+
sendUserToast('you have been logged out');
|
|
27
29
|
}
|