windmill-components 1.208.0 → 1.216.0

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.
Files changed (152) hide show
  1. package/package/common.d.ts +29 -0
  2. package/package/common.js +20 -0
  3. package/package/components/ApiConnectForm.svelte +81 -1
  4. package/package/components/ArgEnum.svelte +23 -31
  5. package/package/components/ArgEnum.svelte.d.ts +1 -0
  6. package/package/components/ArgInfo.svelte +1 -1
  7. package/package/components/ArgInput.svelte +125 -26
  8. package/package/components/ArgInput.svelte.d.ts +1 -0
  9. package/package/components/DBSchemaExplorer.svelte +2 -2
  10. package/package/components/DiffEditor.svelte +1 -1
  11. package/package/components/DisplayResult.svelte +29 -2
  12. package/package/components/Editor.svelte +21 -8
  13. package/package/components/EditorBar.svelte +3 -0
  14. package/package/components/ErrorOrRecoveryHandler.svelte +6 -3
  15. package/package/components/FlowBuilder.svelte +90 -92
  16. package/package/components/FlowBuilderTutorials.svelte +1 -3
  17. package/package/components/FlowLoopIterationPreview.svelte +145 -0
  18. package/package/components/FlowLoopIterationPreview.svelte.d.ts +27 -0
  19. package/package/components/FlowPreviewContent.svelte +19 -9
  20. package/package/components/FlowStatusViewerInner.svelte +29 -20
  21. package/package/components/FlowStatusViewerInner.svelte.d.ts +1 -0
  22. package/package/components/FlowTimeline.svelte +7 -5
  23. package/package/components/FlowTimeline.svelte.d.ts +1 -0
  24. package/package/components/InputTransformForm.svelte +21 -10
  25. package/package/components/InstanceSettings.svelte +2 -2
  26. package/package/components/ItemPicker.svelte +27 -5
  27. package/package/components/LightweightArgInput.svelte +144 -78
  28. package/package/components/LightweightArgInput.svelte.d.ts +2 -0
  29. package/package/components/LightweightSchemaForm.svelte +2 -3
  30. package/package/components/LogViewer.svelte +29 -6
  31. package/package/components/NumberTypeNarrowing.svelte +21 -1
  32. package/package/components/NumberTypeNarrowing.svelte.d.ts +2 -0
  33. package/package/components/RunForm.svelte +38 -6
  34. package/package/components/S3FilePicker.svelte +354 -0
  35. package/package/components/S3FilePicker.svelte.d.ts +26 -0
  36. package/package/components/SchemaEditor.svelte +2 -15
  37. package/package/components/SchemaEditor.svelte.d.ts +1 -1
  38. package/package/components/SchemaForm.svelte +3 -1
  39. package/package/components/SchemaModal.svelte +55 -2
  40. package/package/components/SchemaModal.svelte.d.ts +1 -16
  41. package/package/components/ScriptBuilder.svelte +1 -1
  42. package/package/components/SimpleEditor.svelte +45 -31
  43. package/package/components/StringTypeNarrowing.svelte +38 -2
  44. package/package/components/StringTypeNarrowing.svelte.d.ts +1 -0
  45. package/package/components/TemplateEditor.svelte +72 -62
  46. package/package/components/TestJobLoader.svelte +0 -1
  47. package/package/components/UserSettings.svelte +6 -3
  48. package/package/components/WorkspaceGroup.svelte +3 -0
  49. package/package/components/apps/components/display/AppImage.svelte +7 -1
  50. package/package/components/apps/components/display/AppStatCard.svelte +125 -0
  51. package/package/components/apps/components/display/AppStatCard.svelte.d.ts +22 -0
  52. package/package/components/apps/components/display/table/AppTable.svelte +1 -1
  53. package/package/components/apps/components/helpers/ResolveStyle.svelte +1 -1
  54. package/package/components/apps/editor/AppEditor.svelte +1 -1
  55. package/package/components/apps/editor/AppEditorHeader.svelte +14 -4
  56. package/package/components/apps/editor/AppEditorTutorial.svelte +8 -1
  57. package/package/components/apps/editor/AppPreview.svelte +1 -0
  58. package/package/components/apps/editor/AppReportsDrawer.svelte +491 -0
  59. package/package/components/apps/editor/AppReportsDrawer.svelte.d.ts +17 -0
  60. package/package/components/apps/editor/component/Component.svelte +8 -0
  61. package/package/components/apps/editor/component/components.d.ts +150 -61
  62. package/package/components/apps/editor/component/components.js +89 -2
  63. package/package/components/apps/editor/component/sets.js +2 -1
  64. package/package/components/apps/editor/componentsPanel/CssProperty.svelte +184 -145
  65. package/package/components/apps/editor/componentsPanel/cssUtils.d.ts +0 -4
  66. package/package/components/apps/editor/componentsPanel/cssUtils.js +0 -25
  67. package/package/components/apps/editor/componentsPanel/quickStyleProperties.js +2 -1
  68. package/package/components/apps/editor/componentsPanel/tailwindUtils.d.ts +1 -0
  69. package/package/components/apps/editor/componentsPanel/tailwindUtils.js +4474 -0
  70. package/package/components/apps/editor/contextPanel/ComponentOutput.svelte +0 -1
  71. package/package/components/apps/editor/contextPanel/SubGridOutput.svelte +1 -2
  72. package/package/components/apps/editor/settingsPanel/OneOfInputSpecsEditor.svelte +1 -0
  73. package/package/components/apps/editor/settingsPanel/QuickAddColumn.svelte +1 -1
  74. package/package/components/apps/types.d.ts +2 -0
  75. package/package/components/apps/utils.d.ts +1 -0
  76. package/package/components/apps/utils.js +15 -0
  77. package/package/components/build_workers.js +9 -14
  78. package/package/components/common/alert/Alert.svelte +12 -10
  79. package/package/components/common/skeleton/Skeleton.svelte +11 -6
  80. package/package/components/common/skeleton/Skeleton.svelte.d.ts +1 -0
  81. package/package/components/copilot/CodeCompletionStatus.svelte +37 -0
  82. package/package/components/copilot/CodeCompletionStatus.svelte.d.ts +14 -0
  83. package/package/components/copilot/FlowCopilotDrawer.svelte +5 -2
  84. package/package/components/copilot/FlowCopilotStatus.svelte +1 -1
  85. package/package/components/copilot/RegexGen.svelte +172 -0
  86. package/package/components/copilot/RegexGen.svelte.d.ts +16 -0
  87. package/package/components/copilot/ScriptFix.svelte +1 -8
  88. package/package/components/copilot/ScriptGen.svelte +13 -7
  89. package/package/components/copilot/TestOpenaiKey.svelte +1 -1
  90. package/package/components/copilot/completion.js +5 -0
  91. package/package/components/copilot/flow.d.ts +13 -3
  92. package/package/components/copilot/flow.js +98 -32
  93. package/package/components/copilot/lib.d.ts +5 -5
  94. package/package/components/copilot/lib.js +3 -2
  95. package/package/components/copilot/prompts/edit.yaml +11 -9
  96. package/package/components/copilot/prompts/editPrompt.js +5 -5
  97. package/package/components/copilot/prompts/fix.yaml +11 -9
  98. package/package/components/copilot/prompts/fixPrompt.js +5 -5
  99. package/package/components/copilot/prompts/gen.yaml +73 -28
  100. package/package/components/copilot/prompts/genPrompt.js +14 -14
  101. package/package/components/flows/content/FlowLoop.svelte +25 -1
  102. package/package/components/flows/content/FlowSettings.svelte +42 -3
  103. package/package/components/flows/content/ScriptEditorDrawer.svelte +2 -7
  104. package/package/components/flows/header/FlowPreviewButtons.svelte +1 -0
  105. package/package/components/flows/map/InsertModuleButton.svelte +1 -1
  106. package/package/components/flows/map/VirtualItem.svelte.d.ts +1 -0
  107. package/package/components/graph/FlowGraph.svelte +1 -0
  108. package/package/components/graph/svelvet/types/index.js +1 -1
  109. package/package/components/instanceSettings.js +1 -1
  110. package/package/components/propertyPicker/ObjectViewer.svelte +28 -2
  111. package/package/components/runs/RunRow.svelte +1 -1
  112. package/package/components/runs/RunsFilter.svelte +329 -172
  113. package/package/components/runs/RunsFilter.svelte.d.ts +2 -0
  114. package/package/components/settings/WorkspaceUserSettings.svelte +94 -70
  115. package/package/components/sidebar/SidebarContent.svelte +71 -15
  116. package/package/components/sidebar/UserMenu.svelte +2 -2
  117. package/package/components/sidebar/WorkspaceMenu.svelte +16 -14
  118. package/package/components/tutorials/SkipTutorials.svelte +32 -0
  119. package/package/components/tutorials/SkipTutorials.svelte.d.ts +16 -0
  120. package/package/components/tutorials/Tutorial.svelte +46 -18
  121. package/package/components/tutorials/TutorialControls.svelte +45 -0
  122. package/package/components/tutorials/TutorialControls.svelte.d.ts +20 -0
  123. package/package/consts.d.ts +3 -0
  124. package/package/consts.js +3 -0
  125. package/package/gen/core/OpenAPI.js +1 -1
  126. package/package/gen/index.d.ts +7 -0
  127. package/package/gen/index.js +3 -0
  128. package/package/gen/models/FlowValue.d.ts +1 -0
  129. package/package/gen/models/LargeFileStorage.d.ts +9 -0
  130. package/package/gen/models/LargeFileStorage.js +11 -0
  131. package/package/gen/models/PolarsClientKwargs.d.ts +3 -0
  132. package/package/gen/models/PolarsClientKwargs.js +5 -0
  133. package/package/gen/models/S3Resource.d.ts +9 -0
  134. package/package/gen/models/S3Resource.js +5 -0
  135. package/package/gen/models/WindmillFileMetadata.d.ts +7 -0
  136. package/package/gen/models/WindmillFileMetadata.js +5 -0
  137. package/package/gen/models/WindmillFilePreview.d.ts +13 -0
  138. package/package/gen/models/WindmillFilePreview.js +14 -0
  139. package/package/gen/models/WindmillLargeFile.d.ts +3 -0
  140. package/package/gen/models/WindmillLargeFile.js +5 -0
  141. package/package/gen/services/HelpersService.d.ts +84 -0
  142. package/package/gen/services/HelpersService.js +107 -0
  143. package/package/gen/services/UserService.d.ts +9 -9
  144. package/package/gen/services/UserService.js +15 -15
  145. package/package/gen/services/WorkspaceService.d.ts +42 -0
  146. package/package/gen/services/WorkspaceService.js +58 -0
  147. package/package/infer.js +5 -5
  148. package/package/stores.d.ts +2 -0
  149. package/package/stores.js +2 -0
  150. package/package/utils.d.ts +2 -1
  151. package/package/utils.js +19 -0
  152. package/package.json +5 -6
@@ -17,7 +17,7 @@ import { MonacoLanguageClient } from 'monaco-languageclient';
17
17
  import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc';
18
18
  import { CloseAction, ErrorAction, RequestType, NotificationType } from 'vscode-languageclient';
19
19
  import { MonacoBinding } from 'y-monaco';
20
- import { dbSchemas, copilotInfo } from '../stores';
20
+ import { dbSchemas, copilotInfo, codeCompletionSessionEnabled } from '../stores';
21
21
  import { createHash as randomHash, editorConfig, langToExt, updateOptions } from '../editorUtils';
22
22
  import { buildWorkerDefinition } from './build_workers';
23
23
  import { workspaceStore } from '../stores';
@@ -181,14 +181,22 @@ export async function format() {
181
181
  }
182
182
  let command = undefined;
183
183
  let sqlSchemaCompletor = undefined;
184
- function updateSchema(lang, args) {
185
- const schemaRes = lang === 'graphql' ? args.api : args.database;
186
- if (typeof schemaRes === 'string') {
187
- dbSchema = $dbSchemas[schemaRes.replace('$res:', '')];
184
+ let oldSchemaRes = '';
185
+ function updateSchema() {
186
+ const newSchemaRes = lang === 'graphql' ? args?.api : args?.database;
187
+ if (typeof newSchemaRes === 'string') {
188
+ const newSchema = $dbSchemas[newSchemaRes.replace('$res:', '')];
189
+ if (newSchema && newSchemaRes !== oldSchemaRes) {
190
+ oldSchemaRes = newSchemaRes;
191
+ dbSchema = newSchema;
192
+ return;
193
+ }
188
194
  }
195
+ dbSchema = undefined;
196
+ oldSchemaRes = '';
189
197
  }
190
- $: args && updateSchema(lang, args);
191
- $: dbSchema && ['sql', 'graphql'].includes(lang) && addDBSchemaCompletions();
198
+ $: lang && args && $dbSchemas && updateSchema();
199
+ $: initialized && dbSchema && ['sql', 'graphql'].includes(lang) && addDBSchemaCompletions();
192
200
  $: (!dbSchema || lang !== 'sql') && sqlSchemaCompletor && sqlSchemaCompletor.dispose();
193
201
  $: (!dbSchema || lang !== 'graphql') && graphqlService && graphqlService.setSchemaConfig([]);
194
202
  function addDBSchemaCompletions() {
@@ -305,6 +313,9 @@ function addCopilotSuggestions() {
305
313
  if (copilotTs === thisTs) {
306
314
  abortController?.abort();
307
315
  abortController = new AbortController();
316
+ token.onCancellationRequested(() => {
317
+ abortController?.abort();
318
+ });
308
319
  const insertText = await editorCodeCompletion(textUntilPosition, textAfterPosition, lang, abortController);
309
320
  if (insertText) {
310
321
  items = [
@@ -325,8 +336,10 @@ function addCopilotSuggestions() {
325
336
  }
326
337
  $: $copilotInfo.exists_openai_resource_path &&
327
338
  $copilotInfo.code_completion_enabled &&
339
+ $codeCompletionSessionEnabled &&
328
340
  initialized &&
329
341
  addCopilotSuggestions();
342
+ $: !$codeCompletionSessionEnabled && copilotCompletor && copilotCompletor.dispose();
330
343
  const outputChannel = {
331
344
  name: 'Language Server Client',
332
345
  appendLine: (msg) => {
@@ -708,7 +721,7 @@ $: if (yContent && awareness && modelRef && editor) {
708
721
  let initialized = false;
709
722
  async function loadMonaco() {
710
723
  try {
711
- console.error("Loading Monaco's language client");
724
+ console.log("Loading Monaco's language client");
712
725
  await initializeVscode();
713
726
  }
714
727
  catch (e) {
@@ -24,6 +24,7 @@ import { capitalize, toCamel } from '../utils';
24
24
  import ScriptVersionHistory from './ScriptVersionHistory.svelte';
25
25
  import ScriptGen from './copilot/ScriptGen.svelte';
26
26
  import { getResetCode } from '../script_helpers';
27
+ import CodeCompletionStatus from './copilot/CodeCompletionStatus.svelte';
27
28
  export let lang;
28
29
  export let editor;
29
30
  export let websocketAlive;
@@ -502,6 +503,8 @@ let historyBrowserDrawerOpen = false;
502
503
 
503
504
  <ScriptGen {editor} {diffEditor} {lang} {iconOnly} {args} />
504
505
 
506
+ <CodeCompletionStatus />
507
+
505
508
  <!-- <Popover
506
509
  notClickable
507
510
  placement="bottom"
@@ -4,7 +4,7 @@ import ScriptPicker from './ScriptPicker.svelte';
4
4
  import Toggle from './Toggle.svelte';
5
5
  import { enterpriseLicense, workspaceStore } from '../stores';
6
6
  import { emptySchema, emptyString, sendUserToast, tryEvery } from '../utils';
7
- import { JobService, Script, ScriptService, WorkspaceService } from '../gen';
7
+ import { FlowService, JobService, Script, ScriptService, WorkspaceService } from '../gen';
8
8
  import { inferArgs } from '../infer';
9
9
  import { CheckCircle2, Loader2, RotateCw, XCircle } from 'lucide-svelte';
10
10
  const slackRecoveryHandler = 'hub/2430/slack/schedule-recovery-handler-slack';
@@ -75,6 +75,7 @@ async function sendSlackMessage(channel) {
75
75
  });
76
76
  }
77
77
  async function loadHandlerScriptArgs(p, defaultArgs = []) {
78
+ console.log(p);
78
79
  try {
79
80
  let schema = emptySchema();
80
81
  if (p.startsWith('hub/')) {
@@ -89,8 +90,10 @@ async function loadHandlerScriptArgs(p, defaultArgs = []) {
89
90
  }
90
91
  }
91
92
  else {
92
- const script = await ScriptService.getScriptByPath({ workspace: $workspaceStore, path: p });
93
- schema = script.schema;
93
+ let scriptOrFlow = customHandlerKind === 'script'
94
+ ? await ScriptService.getScriptByPath({ workspace: $workspaceStore, path: p })
95
+ : await FlowService.getFlowByPath({ workspace: $workspaceStore, path: p });
96
+ schema = scriptOrFlow.schema;
94
97
  }
95
98
  if (schema && schema.properties) {
96
99
  for (let key in schema.properties) {
@@ -23,7 +23,7 @@ import { stepCopilot, glueCopilot } from './copilot/flow';
23
23
  import FlowCopilotDrawer from './copilot/FlowCopilotDrawer.svelte';
24
24
  import FlowCopilotStatus from './copilot/FlowCopilotStatus.svelte';
25
25
  import { fade } from 'svelte/transition';
26
- import { loadFlowModuleState } from './flows/flowStateUtils';
26
+ import { loadFlowModuleState, pickScript } from './flows/flowStateUtils';
27
27
  import FlowCopilotInputsModal from './copilot/FlowCopilotInputsModal.svelte';
28
28
  import { snakeCase } from 'lodash';
29
29
  import FlowBuilderTutorials from './FlowBuilderTutorials.svelte';
@@ -168,33 +168,19 @@ async function saveFlow() {
168
168
  }
169
169
  else {
170
170
  localStorage.removeItem(`flow-${initialPath}`);
171
- await FlowService.updateFlow({
172
- workspace: $workspaceStore,
173
- path: initialPath,
174
- requestBody: {
175
- path: $pathStore,
176
- summary: flow.summary,
177
- description: flow.description ?? '',
178
- value: flow.value,
179
- schema: flow.schema,
180
- tag: flow.tag,
181
- dedicated_worker: flow.dedicated_worker,
182
- ws_error_handler_muted: flow.ws_error_handler_muted
183
- }
184
- });
185
171
  const scheduleExists = await ScheduleService.existsSchedule({
186
172
  workspace: $workspaceStore ?? '',
187
- path: $pathStore
173
+ path: initialPath
188
174
  });
189
175
  if (scheduleExists) {
190
176
  const schedule = await ScheduleService.getSchedule({
191
177
  workspace: $workspaceStore ?? '',
192
- path: $pathStore
178
+ path: initialPath
193
179
  });
194
180
  if (JSON.stringify(schedule.args) != JSON.stringify(args) || schedule.schedule != cron) {
195
181
  await ScheduleService.updateSchedule({
196
182
  workspace: $workspaceStore ?? '',
197
- path: $pathStore,
183
+ path: initialPath,
198
184
  requestBody: {
199
185
  schedule: formatCron(cron),
200
186
  timezone,
@@ -205,14 +191,28 @@ async function saveFlow() {
205
191
  if (enabled != schedule.enabled) {
206
192
  await ScheduleService.setScheduleEnabled({
207
193
  workspace: $workspaceStore ?? '',
208
- path: $pathStore,
194
+ path: initialPath,
209
195
  requestBody: { enabled }
210
196
  });
211
197
  }
212
198
  }
213
199
  else if (enabled) {
214
- await createSchedule($pathStore);
200
+ await createSchedule(initialPath);
215
201
  }
202
+ await FlowService.updateFlow({
203
+ workspace: $workspaceStore,
204
+ path: initialPath,
205
+ requestBody: {
206
+ path: $pathStore,
207
+ summary: flow.summary,
208
+ description: flow.description ?? '',
209
+ value: flow.value,
210
+ schema: flow.schema,
211
+ tag: flow.tag,
212
+ dedicated_worker: flow.dedicated_worker,
213
+ ws_error_handler_muted: flow.ws_error_handler_muted
214
+ }
215
+ });
216
216
  }
217
217
  savedFlow = {
218
218
  ...cloneDeep($flowStore),
@@ -367,10 +367,11 @@ let flowCopilotContext = {
367
367
  drawerStore: writable(undefined),
368
368
  modulesStore: writable([]),
369
369
  currentStepStore: writable(undefined),
370
- genFlow: undefined
370
+ genFlow: undefined,
371
+ shouldUpdatePropertyType: writable({})
371
372
  };
372
373
  setContext('FlowCopilotContext', flowCopilotContext);
373
- const { drawerStore: copilotDrawerStore, modulesStore: copilotModulesStore, currentStepStore: copilotCurrentStepStore } = flowCopilotContext;
374
+ const { drawerStore: copilotDrawerStore, modulesStore: copilotModulesStore, currentStepStore: copilotCurrentStepStore, shouldUpdatePropertyType } = flowCopilotContext;
374
375
  let doneTs = 0;
375
376
  async function getHubCompletions(text, idx, type) {
376
377
  try {
@@ -382,8 +383,7 @@ async function getHubCompletions(text, idx, type) {
382
383
  kind: type
383
384
  })).map((s) => ({
384
385
  ...s,
385
- path: `hub/${s.version_id}/${s.app}/${s.summary.toLowerCase().replaceAll(/\s+/g, '_')}`,
386
- summary: `${s.summary} (${s.app})`
386
+ path: `hub/${s.version_id}/${s.app}/${s.summary.toLowerCase().replaceAll(/\s+/g, '_')}`
387
387
  }));
388
388
  if (ts < doneTs)
389
389
  return;
@@ -445,7 +445,7 @@ function applyCopilotFlowInputs() {
445
445
  }
446
446
  function clearFlowInputsFromStep(id) {
447
447
  const module = dfs(id, $flowStore)[0];
448
- if (module?.value.type === 'rawscript') {
448
+ if (module?.value.type === 'rawscript' || module?.value.type === 'script') {
449
449
  // clear step inputs that start with flow_input. but not flow_input.iter
450
450
  for (const key in module.value.input_transforms) {
451
451
  const input = module.value.input_transforms[key];
@@ -456,6 +456,7 @@ function clearFlowInputsFromStep(id) {
456
456
  type: 'static',
457
457
  value: undefined
458
458
  };
459
+ $shouldUpdatePropertyType[key] = 'static';
459
460
  }
460
461
  }
461
462
  }
@@ -498,12 +499,6 @@ async function genFlow(idx, flowModules, stepOnly = false) {
498
499
  }
499
500
  $scheduleStore.enabled = true;
500
501
  }
501
- let hubScript = undefined;
502
- if (module.source === 'hub' && module.selectedCompletion) {
503
- hubScript = await ScriptService.getHubScriptByPath({
504
- path: module.selectedCompletion.path
505
- });
506
- }
507
502
  const flowModule = {
508
503
  id: module.id,
509
504
  stop_after_if: module.type === 'trigger'
@@ -515,12 +510,22 @@ async function genFlow(idx, flowModules, stepOnly = false) {
515
510
  value: {
516
511
  input_transforms: {},
517
512
  content: '',
518
- language: (hubScript ? hubScript.language : module.lang ?? 'bun'),
513
+ language: (module.lang ?? 'bun'),
519
514
  type: 'rawscript'
520
515
  },
521
- summary: module.selectedCompletion?.summary ?? module.description
516
+ summary: module.description
522
517
  };
523
- $flowStateStore[module.id] = emptyFlowModuleState();
518
+ let isHubStep = false;
519
+ if (module.source === 'hub' && module.selectedCompletion) {
520
+ isHubStep = true;
521
+ const [hubScriptModule, hubScriptState] = await pickScript(module.selectedCompletion.path, `${module.selectedCompletion.summary} (${module.selectedCompletion.app})`, module.id, undefined);
522
+ flowModule.value = hubScriptModule.value;
523
+ flowModule.summary = hubScriptModule.summary;
524
+ $flowStateStore[module.id] = hubScriptState;
525
+ }
526
+ else {
527
+ $flowStateStore[module.id] = emptyFlowModuleState();
528
+ }
524
529
  if (stepOnly) {
525
530
  flowModules.splice(idx, 0, flowModule);
526
531
  }
@@ -545,6 +550,7 @@ async function genFlow(idx, flowModules, stepOnly = false) {
545
550
  flowModules.push(flowModule);
546
551
  }
547
552
  $copilotDrawerStore?.closeDrawer();
553
+ await tick();
548
554
  select(module.id);
549
555
  await tick();
550
556
  await tick();
@@ -557,45 +563,59 @@ async function genFlow(idx, flowModules, stepOnly = false) {
557
563
  }
558
564
  const prevNodeId = getPreviousIds(module.id, $flowStore, false)[0];
559
565
  const pastModule = dfs(prevNodeId, $flowStore, false)[0];
560
- if (hubScript) {
561
- module.editor?.setCode(hubScript.content);
566
+ if (!module.source) {
567
+ throw new Error('Invalid copilot module source');
562
568
  }
563
- else if (module.source === 'custom') {
569
+ if (module.source === 'custom') {
564
570
  const deltaStore = writable('');
565
571
  const unsubscribe = deltaStore.subscribe(async (delta) => {
566
572
  module.editor?.append(delta);
567
573
  });
568
574
  abortController = new AbortController();
569
- await stepCopilot(module, deltaStore, pastModule?.value.type === 'rawscript' ? pastModule.value.content : '', pastModule?.value.type === 'rawscript' ? pastModule.value.language : undefined, pastModule === undefined, isFirstInLoop, abortController);
575
+ await stepCopilot(module, deltaStore, $workspaceStore, pastModule?.value.type === 'rawscript' || pastModule?.value.type === 'script'
576
+ ? pastModule
577
+ : undefined, isFirstInLoop, abortController);
570
578
  unsubscribe();
571
579
  }
572
- else {
573
- throw new Error('Invalid copilot module source');
574
- }
575
580
  copilotStatus = "Generating inputs for step '" + module.id + "'...";
576
581
  await sleep(500); // make sure code was parsed
577
582
  try {
578
- if (flowModule.value.type === 'rawscript') {
583
+ if ((flowModule.value.type === 'rawscript' || flowModule.value.type === 'script') &&
584
+ (pastModule === undefined ||
585
+ pastModule.value.type === 'rawscript' ||
586
+ pastModule.value.type === 'script')) {
579
587
  const stepSchema = JSON.parse(JSON.stringify($flowStateStore[module.id].schema)); // deep copy
580
- if (module.source === 'hub' &&
581
- pastModule !== undefined &&
582
- $copilotInfo.exists_openai_resource_path) {
588
+ if (isHubStep && pastModule !== undefined && $copilotInfo.exists_openai_resource_path) {
583
589
  // ask AI to set step inputs
584
590
  abortController = new AbortController();
585
- const inputs = await glueCopilot(Object.keys(flowModule.value.input_transforms), pastModule.value.type === 'rawscript' ? pastModule.value.content : '', pastModule.value.type === 'rawscript' ? pastModule.value.language : undefined, isFirstInLoop, abortController);
591
+ const { inputs, allExprs } = await glueCopilot(flowModule.value.input_transforms, $workspaceStore, pastModule, isFirstInLoop, abortController);
586
592
  // create flow inputs used by AI for autocompletion
587
593
  copilotFlowInputs = {};
588
594
  copilotFlowRequiredInputs = [];
589
- Object.entries(inputs).forEach(([key, expr]) => {
590
- const snakeKey = snakeCase(key);
591
- if (key in stepSchema.properties &&
592
- expr.includes('flow_input.') &&
593
- !expr.includes('flow_input.iter') &&
594
- (!$flowStore.schema || !(snakeKey in $flowStore.schema.properties)) // prevent overriding flow inputs
595
- ) {
596
- copilotFlowInputs[snakeKey] = stepSchema.properties[snakeKey];
597
- if (stepSchema.required.includes(snakeKey)) {
598
- copilotFlowRequiredInputs.push(snakeKey);
595
+ Object.entries(allExprs).forEach(([key, expr]) => {
596
+ if (expr.includes('flow_input.') && !expr.includes('flow_input.iter.')) {
597
+ const flowInputKey = expr.match(/flow_input\.([A-Za-z0-9_]+)/)?.[1];
598
+ if (flowInputKey !== undefined &&
599
+ (!$flowStore.schema || !(flowInputKey in $flowStore.schema.properties)) // prevent overriding flow inputs
600
+ ) {
601
+ if (key in stepSchema.properties) {
602
+ copilotFlowInputs[flowInputKey] = stepSchema.properties[key];
603
+ if (stepSchema.required.includes(key)) {
604
+ copilotFlowRequiredInputs.push(flowInputKey);
605
+ }
606
+ }
607
+ else {
608
+ // when the key is nested (e.g. body.content)
609
+ const [firstKey, ...rest] = key.split('.');
610
+ const restKey = rest.join('.');
611
+ const firstKeyProperties = stepSchema.properties[firstKey]?.properties;
612
+ if (firstKeyProperties !== undefined && restKey in firstKeyProperties) {
613
+ copilotFlowInputs[flowInputKey] = firstKeyProperties[restKey];
614
+ if (firstKeyProperties[restKey].required?.includes(flowInputKey)) {
615
+ copilotFlowRequiredInputs.push(flowInputKey);
616
+ }
617
+ }
618
+ }
599
619
  }
600
620
  }
601
621
  });
@@ -606,12 +626,13 @@ async function genFlow(idx, flowModules, stepOnly = false) {
606
626
  Object.entries(inputs).forEach(([key, expr]) => {
607
627
  flowModule.value.input_transforms[key] = {
608
628
  type: 'javascript',
609
- expr: expr.replaceAll(/flow_input\.([A-Za-z0-9_]+)/g, (_, p1) => 'flow_input.' + p1)
629
+ expr
610
630
  };
631
+ $shouldUpdatePropertyType[key] = 'javascript';
611
632
  });
612
633
  }
613
634
  else {
614
- if (module.source === 'hub' &&
635
+ if (isHubStep &&
615
636
  pastModule !== undefined &&
616
637
  !$copilotInfo.exists_openai_resource_path) {
617
638
  sendUserToast('For better input generation, enable Windmill AI in the workspace settings', true);
@@ -650,10 +671,21 @@ async function genFlow(idx, flowModules, stepOnly = false) {
650
671
  : 'flow_input.' + snakeKey
651
672
  : 'flow_input.' + snakeKey
652
673
  };
674
+ $shouldUpdatePropertyType[key] = 'javascript';
653
675
  }
654
676
  }
655
677
  $flowStore = $flowStore; // force rerendering
656
678
  }
679
+ else {
680
+ if (pastModule !== undefined &&
681
+ pastModule.value.type !== 'rawscript' &&
682
+ pastModule.value.type !== 'script') {
683
+ sendUserToast(`Linking to previous step ${pastModule.id} of type ${pastModule.value.type} is not yet supported`, true);
684
+ }
685
+ else {
686
+ sendUserToast('Something went wrong, could not generate step inputs', true);
687
+ }
688
+ }
657
689
  }
658
690
  catch (err) {
659
691
  console.error(err);
@@ -697,40 +729,6 @@ async function finishCopilotFlowBuilder() {
697
729
  copilotLoading = true;
698
730
  select('Input');
699
731
  $copilotCurrentStepStore = 'Input';
700
- copilotStatus = 'Setting flow inputs...';
701
- // filter out unused flow inputs
702
- const flowInputs = {};
703
- const required = new Set();
704
- function getFlowInputs(modules) {
705
- for (const module of modules) {
706
- if (module.value.type === 'rawscript') {
707
- for (const moduleAttr of Object.keys(module.value.input_transforms)) {
708
- const input = module.value.input_transforms[moduleAttr];
709
- if (input.type === 'javascript' &&
710
- input.expr.includes('flow_input.') &&
711
- !input.expr.includes('flow_input.iter')) {
712
- const flowAttr = input.expr.split('.')[1];
713
- const schema = $flowStateStore[module.id].schema;
714
- const schemaProperty = Object.entries(schema.properties).find((x) => x[0] === moduleAttr)?.[1];
715
- if (schemaProperty) {
716
- flowInputs[flowAttr] = schemaProperty;
717
- required.add(flowAttr);
718
- }
719
- }
720
- }
721
- }
722
- else if (module.value.type === 'forloopflow') {
723
- getFlowInputs(module.value.modules);
724
- }
725
- }
726
- }
727
- getFlowInputs($flowStore.value.modules);
728
- $flowStore.schema = {
729
- $schema: 'https://json-schema.org/draft/2020-12/schema',
730
- properties: flowInputs,
731
- required: Array.from(required),
732
- type: 'object'
733
- };
734
732
  copilotStatus = "Done! Just check the flow's inputs and you're good to go!";
735
733
  $copilotCurrentStepStore = undefined;
736
734
  copilotLoading = false;
@@ -21,9 +21,7 @@ let flowTutorials = undefined;
21
21
  variant="border"
22
22
  id="tutorials-button"
23
23
  startIcon={{ icon: BookOpen }}
24
- >
25
- Tutorials
26
- </Button>
24
+ />
27
25
  </svelte:fragment>
28
26
  <svelte:fragment slot="items">
29
27
  <TutorialItem
@@ -0,0 +1,145 @@
1
+ <script>import { Job, JobService } from '../gen';
2
+ import { workspaceStore } from '../stores';
3
+ import { Button, Kbd } from './common';
4
+ import { createEventDispatcher, getContext } from 'svelte';
5
+ import { runFlowPreview } from './flows/utils';
6
+ import SchemaForm from './SchemaForm.svelte';
7
+ import FlowStatusViewer from '../components/FlowStatusViewer.svelte';
8
+ import FlowProgressBar from './flows/FlowProgressBar.svelte';
9
+ import { Play, RefreshCw, X } from 'lucide-svelte';
10
+ import { getModifierKey } from '../utils';
11
+ export let open;
12
+ export let jobId = undefined;
13
+ export let job = undefined;
14
+ export let modules;
15
+ export let previewArgs = {};
16
+ const schema = {
17
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
18
+ properties: {
19
+ iter: {
20
+ type: 'object',
21
+ properties: {
22
+ index: {
23
+ type: 'number'
24
+ },
25
+ value: {
26
+ type: 'object'
27
+ }
28
+ }
29
+ }
30
+ },
31
+ required: [],
32
+ type: 'object'
33
+ };
34
+ let selectedJobStep = undefined;
35
+ let isRunning = false;
36
+ let jobProgressReset;
37
+ export function test() {
38
+ runPreview(previewArgs, undefined);
39
+ }
40
+ const { flowStateStore, pathStore } = getContext('FlowEditorContext');
41
+ const dispatch = createEventDispatcher();
42
+ export async function runPreview(args, restartedFrom) {
43
+ jobProgressReset();
44
+ const newFlow = { value: { modules }, summary: '' };
45
+ jobId = await runFlowPreview(args, newFlow, $pathStore, restartedFrom);
46
+ isRunning = true;
47
+ }
48
+ function onKeyDown(event) {
49
+ if (open) {
50
+ switch (event.key) {
51
+ case 'Enter':
52
+ if (event.ctrlKey || event.metaKey) {
53
+ event.preventDefault();
54
+ runPreview(previewArgs, undefined);
55
+ }
56
+ break;
57
+ }
58
+ }
59
+ }
60
+ $: if (job?.type === 'CompletedJob') {
61
+ isRunning = false;
62
+ }
63
+ </script>
64
+
65
+ <svelte:window on:keydown={onKeyDown} />
66
+
67
+ <div class="flex flex-col space-y-2 h-screen bg-surface px-6 py-2 w-full" id="flow-preview-content">
68
+ <div class="flex flex-row justify-between w-full items-center gap-x-2">
69
+ <div class="w-8">
70
+ <Button
71
+ on:click={() => dispatch('close')}
72
+ startIcon={{ icon: X }}
73
+ iconOnly
74
+ size="sm"
75
+ color="light"
76
+ btnClasses="hover:bg-surface-hover bg-surface-secondaryw-8 h-8 rounded-full p-0"
77
+ />
78
+ </div>
79
+
80
+ {#if isRunning}
81
+ <Button
82
+ color="red"
83
+ on:click={async () => {
84
+ isRunning = false
85
+ try {
86
+ jobId &&
87
+ (await JobService.cancelQueuedJob({
88
+ workspace: $workspaceStore ?? '',
89
+ id: jobId,
90
+ requestBody: {}
91
+ }))
92
+ } catch {}
93
+ }}
94
+ size="sm"
95
+ btnClasses="w-full max-w-lg"
96
+ loading={true}
97
+ clickableWhileLoading
98
+ >
99
+ Cancel
100
+ </Button>
101
+ {:else}
102
+ <Button
103
+ variant="contained"
104
+ startIcon={{ icon: isRunning ? RefreshCw : Play }}
105
+ color="dark"
106
+ size="sm"
107
+ btnClasses="w-full max-w-lg"
108
+ on:click={() => runPreview(previewArgs, undefined)}
109
+ id="flow-editor-test-flow-drawer"
110
+ >
111
+ Test iteration &nbsp;<Kbd small isModifier>{getModifierKey()}</Kbd>
112
+ <Kbd small><span class="text-lg font-bold">⏎</span></Kbd>
113
+ </Button>
114
+ {/if}
115
+ <div />
116
+ </div>
117
+ <div class="w-full flex flex-col gap-y-1">
118
+ <FlowProgressBar {job} bind:reset={jobProgressReset} />
119
+ </div>
120
+ <div class="overflow-y-auto grow pr-4">
121
+ <div class="max-h-1/2 overflow-auto border-b">
122
+ <SchemaForm
123
+ noVariablePicker
124
+ compact
125
+ class="py-4 max-w-3xl"
126
+ {schema}
127
+ bind:args={previewArgs}
128
+ />
129
+ </div>
130
+ <div class="pt-4 grow">
131
+ {#if jobId}
132
+ <FlowStatusViewer
133
+ {flowStateStore}
134
+ {jobId}
135
+ on:jobsLoaded={({ detail }) => {
136
+ job = detail
137
+ }}
138
+ bind:selectedJobStep
139
+ />
140
+ {:else}
141
+ <div class="italic text-tertiary h-full grow"> Flow status will be displayed here </div>
142
+ {/if}
143
+ </div>
144
+ </div>
145
+ </div>
@@ -0,0 +1,27 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import { Job, type FlowModule, type RestartedFrom } from '../gen';
3
+ declare const __propDef: {
4
+ props: {
5
+ open: boolean;
6
+ jobId?: string | undefined;
7
+ job?: Job | undefined;
8
+ modules: FlowModule[];
9
+ previewArgs?: Record<string, any> | undefined;
10
+ test?: (() => void) | undefined;
11
+ runPreview?: ((args: Record<string, any>, restartedFrom: RestartedFrom | undefined) => Promise<void>) | undefined;
12
+ };
13
+ events: {
14
+ close: CustomEvent<any>;
15
+ } & {
16
+ [evt: string]: CustomEvent<any>;
17
+ };
18
+ slots: {};
19
+ };
20
+ export type FlowLoopIterationPreviewProps = typeof __propDef.props;
21
+ export type FlowLoopIterationPreviewEvents = typeof __propDef.events;
22
+ export type FlowLoopIterationPreviewSlots = typeof __propDef.slots;
23
+ export default class FlowLoopIterationPreview extends SvelteComponent<FlowLoopIterationPreviewProps, FlowLoopIterationPreviewEvents, FlowLoopIterationPreviewSlots> {
24
+ get test(): () => void;
25
+ get runPreview(): (args: Record<string, any>, restartedFrom: RestartedFrom | undefined) => Promise<void>;
26
+ }
27
+ export {};