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.
@@ -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
- <div class="text-sm italic pb-1">
162
- {description}
163
- </div>
164
- <div class="text-right text-xs {error === '' ? 'text-white' : 'font-bold text-red-600'}">
165
- {error === '' ? '...' : error}
166
- </div>
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'}
@@ -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
- languageClient.start();
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
- languageClient.stop();
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
- if (editor) {
400
- try {
401
- closeWebsockets();
402
- editor.dispose();
403
- }
404
- catch (err) {
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={scheduleArgs}
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 {i} mode={$mode} />
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 1rst step's result right above
60
- &nbsp; <br />We do not support any other kind of for-loop at the moment but we will very
61
- soon (See <a href="https://github.com/windmill-labs/windmill/issues/350">#350</a>)
61
+ Starting from here, the flow for loop over items from the 1st step's result right above.
62
+ &nbsp; <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
@@ -6,6 +6,7 @@ declare const __propDef: {
6
6
  scheduleArgs?: Record<string, any> | undefined;
7
7
  scheduleEnabled?: boolean | undefined;
8
8
  scheduleCron?: string | undefined;
9
+ previewArgs?: Record<string, any> | undefined;
9
10
  };
10
11
  events: {
11
12
  [evt: string]: CustomEvent<any>;
@@ -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 { flowToMode, runFlowPreview } from './flows/utils';
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 = flowToMode(flow, mode);
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
- <div class="h-full overflow-y-auto mb-16">
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 />
@@ -185,6 +185,9 @@ $: $workspaceStore && job && loadResults();
185
185
  >
186
186
  {#if forloop_selected == job.id}
187
187
  <svelte:self {job} />
188
+ {#if `result` in job}
189
+ <FlowJobResult {job} />
190
+ {/if}
188
191
  {/if}
189
192
  {/each}
190
193
  </div>
@@ -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="mt-4">{flow.summary}</h2>
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
- <InputTransformsViewer inputTransforms={mod?.input_transform} />
117
- <div class="w-full h-full">
118
- <iframe
119
- style="height: 400px;"
120
- class="w-full h-full text-sm"
121
- title="embedded script from hub"
122
- frameborder="0"
123
- src="https://hub.windmill.dev/embed/script/{mod?.value?.path?.substring(
124
- 4
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-block inline-highlight">
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 w-40">
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'}{label.title} <Tooltip>{label.desc}</Tooltip>
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) ?? ''}</td>
180
- <td>{schema.required.includes(name) ? 'Required' : 'Optional'}</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
- <Badge color="blue">{property.type?.toUpperCase() ?? 'ANY'}</Badge>
6
- {#if property.format}
7
- <Badge color="green">{property.format?.toUpperCase()}</Badge>
8
- {/if}
9
- {#if property.contentEncoding}
10
- <Badge color="indigo">{property.contentEncoding?.toUpperCase()}</Badge>
11
- {/if}
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>{schema.required.includes(name) ? 'required' : 'optional'}</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 class="flex-1 overflow-hidden border p-2 rounded">
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 "dynamic", its value is computed dynamically as the evaluation of its
29
- corresponding typescript snippet.
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 last statement before the final expression<b
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
- <pre><code
45
- >`Hello $&#123;params.name&#125;, all your base $&#123;previous_result.base_name&#125;
46
- belong to us`</code
47
- ></pre>
45
+ <code
46
+ >`Hello $&#123;params.name&#125;, all your base $&#123;previous_result.base_name&#125; 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 typescript primitives, and the following flow specific objects and
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,6 +1,8 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
2
  declare const __propDef: {
3
- props: {};
3
+ props: {
4
+ i?: number | undefined;
5
+ };
4
6
  events: {
5
7
  [evt: string]: CustomEvent<any>;
6
8
  };
@@ -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="New Typescript {isTrigger ? 'trigger ' : ''}script (Deno)"
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('new', { language: RawScript.language.DENO })}
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-yellow-500"
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 mt-2 rounded" class:bg-gray-300={!scheduleEnabled}>
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(logoutMessage?: string): Promise<void>;
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
- const error = document.cookie.includes('token')
10
- ? `error=${encodeURIComponent('You have been logged out because your session has expired.')}&`
11
- : '';
12
- clearCookies();
13
- goto(`/user/login?${error}${rd ? 'rd=' + encodeURIComponent(rd) : ''}`);
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(logoutMessage) {
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windmill-components",
3
- "version": "1.28.4",
3
+ "version": "1.28.7",
4
4
  "devDependencies": {
5
5
  "@playwright/test": "^1.24.2",
6
6
  "@sveltejs/adapter-static": "^1.0.0-next.37",