windmill-components 1.695.1 → 1.699.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 (180) hide show
  1. package/dist/sharedUtils/assets/tokens/colorTokensConfig.d.ts +2 -0
  2. package/dist/sharedUtils/base.d.ts +1 -0
  3. package/dist/sharedUtils/cloud.d.ts +1 -0
  4. package/dist/sharedUtils/common.d.ts +111 -0
  5. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/count.d.ts +5 -0
  6. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/delete.d.ts +5 -0
  7. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/insert.d.ts +5 -0
  8. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/select.d.ts +13 -0
  9. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/update.d.ts +11 -0
  10. package/dist/sharedUtils/components/apps/components/display/dbtable/utils.d.ts +95 -0
  11. package/dist/sharedUtils/components/apps/editor/appPolicy.d.ts +6 -0
  12. package/dist/sharedUtils/components/apps/editor/appUtilsCore.d.ts +7 -0
  13. package/dist/sharedUtils/components/apps/editor/appUtilsS3.d.ts +33 -0
  14. package/dist/sharedUtils/components/apps/editor/commonAppUtils.d.ts +10 -0
  15. package/dist/sharedUtils/components/apps/editor/component/components.d.ts +5371 -0
  16. package/dist/sharedUtils/components/apps/editor/component/default-codes.d.ts +3 -0
  17. package/dist/sharedUtils/components/apps/editor/component/index.d.ts +3 -0
  18. package/dist/sharedUtils/components/apps/editor/component/sets.d.ts +7 -0
  19. package/dist/sharedUtils/components/apps/editor/componentsPanel/componentDefaultProps.d.ts +3 -0
  20. package/dist/sharedUtils/components/apps/gridUtils.d.ts +14 -0
  21. package/dist/sharedUtils/components/apps/inputType.d.ts +178 -0
  22. package/dist/sharedUtils/components/apps/rx.d.ts +29 -0
  23. package/dist/sharedUtils/components/apps/sharedTypes.d.ts +21 -0
  24. package/dist/sharedUtils/components/apps/types.d.ts +274 -0
  25. package/dist/sharedUtils/components/assets/lib.d.ts +25 -0
  26. package/dist/sharedUtils/components/common/alert/model.d.ts +2 -0
  27. package/dist/sharedUtils/components/common/badge/model.d.ts +8 -0
  28. package/dist/sharedUtils/components/common/button/model.d.ts +45 -0
  29. package/dist/sharedUtils/components/common/fileInput/model.d.ts +1 -0
  30. package/dist/sharedUtils/components/common/index.d.ts +24 -0
  31. package/dist/sharedUtils/components/common/skeleton/model.d.ts +21 -0
  32. package/dist/sharedUtils/components/dbTypes.d.ts +14 -0
  33. package/dist/sharedUtils/components/diff_drawer.d.ts +26 -0
  34. package/dist/sharedUtils/components/ducklake.d.ts +1 -0
  35. package/dist/sharedUtils/components/flows/scheduleUtils.d.ts +7 -0
  36. package/dist/sharedUtils/components/icons/index.d.ts +101 -0
  37. package/dist/sharedUtils/components/random_positive_adjetive.d.ts +1 -0
  38. package/dist/sharedUtils/components/raw_apps/rawAppPolicy.d.ts +10 -0
  39. package/dist/sharedUtils/components/raw_apps/utils.d.ts +15 -0
  40. package/dist/sharedUtils/components/triggers/email/utils.d.ts +4 -0
  41. package/dist/sharedUtils/components/triggers/gcp/utils.d.ts +2 -0
  42. package/dist/sharedUtils/components/triggers/http/utils.d.ts +11 -0
  43. package/dist/sharedUtils/components/triggers/kafka/utils.d.ts +2 -0
  44. package/dist/sharedUtils/components/triggers/mqtt/utils.d.ts +2 -0
  45. package/dist/sharedUtils/components/triggers/nats/utils.d.ts +2 -0
  46. package/dist/sharedUtils/components/triggers/postgres/utils.d.ts +8 -0
  47. package/dist/sharedUtils/components/triggers/sqs/utils.d.ts +2 -0
  48. package/dist/sharedUtils/components/triggers/triggers.svelte.d.ts +32 -0
  49. package/dist/sharedUtils/components/triggers/utils.d.ts +80 -0
  50. package/dist/sharedUtils/components/triggers/websocket/utils.d.ts +2 -0
  51. package/dist/sharedUtils/components/triggers.d.ts +20 -0
  52. package/dist/sharedUtils/gen/core/ApiError.d.ts +10 -0
  53. package/dist/sharedUtils/gen/core/ApiRequestOptions.d.ts +13 -0
  54. package/dist/sharedUtils/gen/core/ApiResult.d.ts +7 -0
  55. package/dist/sharedUtils/gen/core/CancelablePromise.d.ts +26 -0
  56. package/dist/sharedUtils/gen/core/OpenAPI.d.ts +27 -0
  57. package/dist/sharedUtils/gen/core/request.d.ts +29 -0
  58. package/dist/sharedUtils/gen/index.d.ts +6 -0
  59. package/dist/sharedUtils/gen/schemas.gen.d.ts +7036 -0
  60. package/dist/sharedUtils/gen/services.gen.d.ts +6047 -0
  61. package/dist/sharedUtils/gen/types.gen.d.ts +21881 -0
  62. package/dist/sharedUtils/history.svelte.d.ts +9 -0
  63. package/dist/sharedUtils/hub.d.ts +49 -0
  64. package/dist/sharedUtils/jsr.json +6 -0
  65. package/dist/sharedUtils/lib.d.ts +5 -0
  66. package/dist/sharedUtils/lib.es.js +1588 -0
  67. package/dist/sharedUtils/package.json +12 -0
  68. package/dist/sharedUtils/schema.d.ts +3 -0
  69. package/dist/sharedUtils/stores.d.ts +97 -0
  70. package/dist/sharedUtils/svelte5Utils.svelte.d.ts +80 -0
  71. package/dist/sharedUtils/toast.d.ts +8 -0
  72. package/dist/sharedUtils/utils.d.ts +265 -0
  73. package/package/components/AppConnectInner.svelte +38 -5
  74. package/package/components/CompareWorkspaces.svelte +142 -486
  75. package/package/components/DisplayResult.svelte +39 -19
  76. package/package/components/Editor.svelte +5 -4
  77. package/package/components/Editor.svelte.d.ts +1 -0
  78. package/package/components/FilterSearchbar.svelte +3 -1
  79. package/package/components/FilterSearchbar.svelte.d.ts +1 -0
  80. package/package/components/FlowStatusViewerInner.svelte +23 -9
  81. package/package/components/ForkWorkspaceBanner.svelte +16 -0
  82. package/package/components/HistoricInputs.svelte +2 -1
  83. package/package/components/InstanceSetting.svelte +47 -5
  84. package/package/components/LogViewer.svelte +101 -71
  85. package/package/components/OnBehalfOfSelector.svelte +10 -7
  86. package/package/components/ParqetCsvTableRenderer.svelte +9 -4
  87. package/package/components/Path.svelte +10 -0
  88. package/package/components/ResourceEditor.svelte +198 -311
  89. package/package/components/ResourceEditor.svelte.d.ts +3 -3
  90. package/package/components/ResourceEditorDrawer.svelte +17 -6
  91. package/package/components/ResourceForm.svelte +235 -0
  92. package/package/components/ResourceForm.svelte.d.ts +25 -0
  93. package/package/components/RunsPage.svelte +1 -0
  94. package/package/components/S3FilePickerInner.svelte +22 -8
  95. package/package/components/ScriptBuilder.svelte +1 -0
  96. package/package/components/ScriptEditor.svelte +44 -7
  97. package/package/components/ScriptEditor.svelte.d.ts +1 -0
  98. package/package/components/ShareModal.svelte.d.ts +1 -1
  99. package/package/components/TaggedTextInput.svelte +4 -1
  100. package/package/components/TaggedTextInput.svelte.d.ts +2 -0
  101. package/package/components/VariableEditor.svelte +177 -199
  102. package/package/components/VariableEditor.svelte.d.ts +1 -2
  103. package/package/components/VariableForm.svelte +133 -0
  104. package/package/components/VariableForm.svelte.d.ts +22 -0
  105. package/package/components/WsSpecificVersions.svelte +39 -0
  106. package/package/components/WsSpecificVersions.svelte.d.ts +9 -0
  107. package/package/components/apps/editor/AppEditorHeaderDeploy.svelte.d.ts +1 -1
  108. package/package/components/common/fileDownload/FileDownload.svelte +16 -6
  109. package/package/components/common/table/AppRow.svelte +2 -1
  110. package/package/components/common/table/AppRow.svelte.d.ts +1 -0
  111. package/package/components/common/table/FlowRow.svelte +2 -1
  112. package/package/components/common/table/FlowRow.svelte.d.ts +1 -0
  113. package/package/components/common/table/RawAppRow.svelte +2 -1
  114. package/package/components/common/table/RawAppRow.svelte.d.ts +1 -0
  115. package/package/components/common/table/Row.svelte +11 -3
  116. package/package/components/common/table/Row.svelte.d.ts +2 -1
  117. package/package/components/common/table/RowIcon.svelte +18 -2
  118. package/package/components/common/table/RowIcon.svelte.d.ts +1 -1
  119. package/package/components/common/table/ScriptRow.svelte +2 -1
  120. package/package/components/common/table/ScriptRow.svelte.d.ts +1 -0
  121. package/package/components/copilot/autocomplete/Autocompletor.d.ts +3 -1
  122. package/package/components/copilot/autocomplete/Autocompletor.js +5 -2
  123. package/package/components/copilot/autocomplete/request.d.ts +1 -0
  124. package/package/components/copilot/autocomplete/request.js +1 -1
  125. package/package/components/copilot/chat/AIChatManager.svelte.js +14 -4
  126. package/package/components/copilot/chat/AiChatLayout.svelte +2 -0
  127. package/package/components/copilot/chat/ContextManager.svelte.d.ts +1 -0
  128. package/package/components/copilot/chat/CreatedResourceActionDrawers.svelte +129 -0
  129. package/package/components/copilot/chat/CreatedResourceActionDrawers.svelte.d.ts +4 -0
  130. package/package/components/copilot/chat/ToolExecutionDisplay.svelte +14 -6
  131. package/package/components/copilot/chat/ToolMessageActions.svelte +73 -0
  132. package/package/components/copilot/chat/ToolMessageActions.svelte.d.ts +7 -0
  133. package/package/components/copilot/chat/createdResourceActions.svelte.d.ts +6 -0
  134. package/package/components/copilot/chat/createdResourceActions.svelte.js +29 -0
  135. package/package/components/copilot/chat/script/core.d.ts +6 -2
  136. package/package/components/copilot/chat/script/core.js +13 -7
  137. package/package/components/copilot/chat/script/wacPrompt.test.d.ts +1 -0
  138. package/package/components/copilot/chat/script/wacPrompt.test.js +25 -0
  139. package/package/components/copilot/chat/shared.d.ts +12 -0
  140. package/package/components/copilot/chat/shared.test.js +23 -2
  141. package/package/components/copilot/chat/workspaceTools.js +34 -4
  142. package/package/components/flows/content/ScriptEditorDrawer.svelte +1 -0
  143. package/package/components/flows/idUtils.js +4 -1
  144. package/package/components/flows/stepsInputArgs.svelte.js +6 -1
  145. package/package/components/graph/wacToFlow.js +1 -1
  146. package/package/components/graph/wacToFlow.test.d.ts +1 -0
  147. package/package/components/graph/wacToFlow.test.js +17 -0
  148. package/package/components/home/Item.svelte +5 -1
  149. package/package/components/home/Item.svelte.d.ts +1 -0
  150. package/package/components/home/ItemsList.svelte +260 -3
  151. package/package/components/instanceSettings/SecretBackendConfig.svelte +492 -98
  152. package/package/components/propertyPicker/ObjectViewer.svelte +10 -4
  153. package/package/components/runs/runsFilter.d.ts +1 -1
  154. package/package/components/runs/useJobsLoader.svelte.d.ts +1 -0
  155. package/package/components/runs/useJobsLoader.svelte.js +8 -12
  156. package/package/components/scriptEditor/LogPanel.svelte +4 -1
  157. package/package/components/scriptEditor/LogPanel.svelte.d.ts +1 -0
  158. package/package/components/settings/WorkspaceOperatorSettings.svelte +1 -1
  159. package/package/components/sidebar/SidebarContent.svelte +40 -2
  160. package/package/components/sidebar/WorkspaceMenu.svelte +19 -5
  161. package/package/externalDomain.d.ts +2 -0
  162. package/package/externalDomain.js +16 -0
  163. package/package/gen/core/OpenAPI.js +1 -1
  164. package/package/gen/schemas.gen.d.ts +33 -4
  165. package/package/gen/schemas.gen.js +33 -4
  166. package/package/gen/services.gen.d.ts +20 -1
  167. package/package/gen/services.gen.js +40 -0
  168. package/package/gen/types.gen.d.ts +70 -3
  169. package/package/hubPaths.json +2 -2
  170. package/package/system_prompts/index.d.ts +1 -1
  171. package/package/system_prompts/index.js +22 -3
  172. package/package/system_prompts/prompts.d.ts +2 -2
  173. package/package/system_prompts/prompts.js +7 -4
  174. package/package/utils/downloadFile.d.ts +11 -0
  175. package/package/utils/downloadFile.js +48 -0
  176. package/package/utils_deployable.d.ts +162 -638
  177. package/package/utils_deployable.js +75 -143
  178. package/package/utils_workspace_deploy.d.ts +10 -4
  179. package/package/utils_workspace_deploy.js +167 -42
  180. package/package.json +7 -3
@@ -3,6 +3,7 @@ import { Highlight } from 'svelte-highlight';
3
3
  import { json } from 'svelte-highlight/languages';
4
4
  import { copyToClipboard, parseS3Object, roughSizeOfObject } from '../utils';
5
5
  import { base } from '../base';
6
+ import { downloadViaClient, shouldDownloadViaClient } from '../utils/downloadFile';
6
7
  import { Button, Drawer, DrawerContent } from './common';
7
8
  import { ClipboardCopy, Download, PanelRightOpen, Table2, Braces, Highlighter, ArrowDownFromLine, Loader2 } from 'lucide-svelte';
8
9
  import Portal from './Portal.svelte';
@@ -72,6 +73,21 @@ function isTableRowObjectInner(json, hasHeaders) {
72
73
  }));
73
74
  }
74
75
  let largeObject = $state(undefined);
76
+ let resultApiPath = $derived(workspaceId && jobId
77
+ ? nodeId
78
+ ? `/w/${workspaceId}/jobs/result_by_id/${jobId}/${nodeId}`
79
+ : `/w/${workspaceId}/jobs_u/completed/get_result/${jobId}`
80
+ : undefined);
81
+ let resultDownloadHref = $derived(resultApiPath
82
+ ? `${base}/api${resultApiPath}`
83
+ : `data:text/json;charset=utf-8,${encodeURIComponent(toJsonStr(result))}`);
84
+ let resultDownloadName = $derived(`${filename ?? 'result'}.json`);
85
+ async function onResultDownload(e) {
86
+ if (!resultApiPath || !shouldDownloadViaClient())
87
+ return;
88
+ e.preventDefault();
89
+ await downloadViaClient(resultApiPath, resultDownloadName);
90
+ }
75
91
  function checkIfS3(result, keys) {
76
92
  return keys.includes('s3') && typeof result.s3 === 'string';
77
93
  }
@@ -860,12 +876,9 @@ $effect(() => {
860
876
  {#if largeObject}
861
877
  <div class="text-xs text-emphasis"
862
878
  ><a
863
- download="{filename ?? 'result'}.json"
864
- href={workspaceId && jobId
865
- ? nodeId
866
- ? `${base}/api/w/${workspaceId}/jobs/result_by_id/${jobId}/${nodeId}`
867
- : `${base}/api/w/${workspaceId}/jobs_u/completed/get_result/${jobId}`
868
- : `data:text/json;charset=utf-8,${encodeURIComponent(toJsonStr(result))}`}
879
+ download={resultDownloadName}
880
+ href={resultDownloadHref}
881
+ onclick={onResultDownload}
869
882
  >
870
883
  Download {filename ? '' : 'as JSON'}
871
884
  </a>
@@ -933,19 +946,26 @@ $effect(() => {
933
946
  <DrawerContent title="Expanded Result" on:close={jsonViewer.closeDrawer}>
934
947
  {#snippet actions()}
935
948
  {#if customUi?.disableDownload !== true}
936
- <Button
937
- download="{filename ?? 'result'}.json"
938
- href={workspaceId && jobId
939
- ? nodeId
940
- ? `${base}/api/w/${workspaceId}/jobs/result_by_id/${jobId}/${nodeId}`
941
- : `${base}/api/w/${workspaceId}/jobs_u/completed/get_result/${jobId}`
942
- : `data:text/json;charset=utf-8,${encodeURIComponent(toJsonStr(result))}`}
943
- startIcon={{ icon: Download }}
944
- variant="subtle"
945
- unifiedSize="md"
946
- >
947
- Download
948
- </Button>
949
+ {#if resultApiPath && shouldDownloadViaClient()}
950
+ <Button
951
+ on:click={() => downloadViaClient(resultApiPath!, resultDownloadName)}
952
+ startIcon={{ icon: Download }}
953
+ variant="subtle"
954
+ unifiedSize="md"
955
+ >
956
+ Download
957
+ </Button>
958
+ {:else}
959
+ <Button
960
+ download={resultDownloadName}
961
+ href={resultDownloadHref}
962
+ startIcon={{ icon: Download }}
963
+ variant="subtle"
964
+ unifiedSize="md"
965
+ >
966
+ Download
967
+ </Button>
968
+ {/if}
949
969
  {/if}
950
970
  <Button
951
971
  on:click={() => copyToClipboard(toJsonStr(result))}
@@ -58,7 +58,7 @@ import { resource, useDebounce, watch } from 'runed';
58
58
  // import EditorTheme from './EditorTheme.svelte'
59
59
  let divEl = $state(null);
60
60
  let editor = $state(null);
61
- let { code = $bindable(), cmdEnterAction = undefined, formatAction = undefined, automaticLayout = true, websocketAlive = $bindable(), shouldBindKey = true, fixedOverflowWidgets = true, path = undefined, yContent = undefined, awareness = undefined, folding = false, args = undefined, useWebsockets = true, small = false, scriptLang, disabled = false, lineNumbersMinChars = 3, files = {}, extraLib = undefined, changeTimeout = 500, loadAsync = false, key = undefined, class: clazz = undefined, moduleId = undefined, enablePreprocessorSnippet = false, rawAppRunnableKey = undefined, preparedAssetsSqlQueries, customTag } = $props();
61
+ let { code = $bindable(), cmdEnterAction = undefined, formatAction = undefined, automaticLayout = true, websocketAlive = $bindable(), shouldBindKey = true, fixedOverflowWidgets = true, path = undefined, yContent = undefined, awareness = undefined, folding = false, args = undefined, useWebsockets = true, small = false, scriptLang, workflowAsCode = false, disabled = false, lineNumbersMinChars = 3, files = {}, extraLib = undefined, changeTimeout = 500, loadAsync = false, key = undefined, class: clazz = undefined, moduleId = undefined, enablePreprocessorSnippet = false, rawAppRunnableKey = undefined, preparedAssetsSqlQueries, customTag } = $props();
62
62
  $effect.pre(() => {
63
63
  if (websocketAlive == undefined) {
64
64
  websocketAlive = {
@@ -627,11 +627,11 @@ function addChatHandler(editor) {
627
627
  }
628
628
  }
629
629
  let autocompletor = $state(undefined);
630
- function addAutoCompletor(editor, scriptLang) {
630
+ function addAutoCompletor(editor, scriptLang, workflowAsCode) {
631
631
  if (autocompletor) {
632
632
  autocompletor.dispose();
633
633
  }
634
- autocompletor = new Autocompletor(editor, scriptLang);
634
+ autocompletor = new Autocompletor(editor, scriptLang, { workflowAsCode });
635
635
  }
636
636
  const outputChannel = {
637
637
  name: 'Language Server Client',
@@ -1543,13 +1543,14 @@ $effect(() => {
1543
1543
  (!dbSchema || lang !== 'graphql') && untrack(() => disposeGaphqlService());
1544
1544
  });
1545
1545
  $effect(() => {
1546
+ const currentWorkflowAsCode = workflowAsCode;
1546
1547
  $copilotInfo.enabled &&
1547
1548
  $codeCompletionSessionEnabled &&
1548
1549
  Autocompletor.isProviderModelSupported($copilotInfo.codeCompletionModel) &&
1549
1550
  initialized &&
1550
1551
  editor &&
1551
1552
  scriptLang &&
1552
- untrack(() => editor && addAutoCompletor(editor, scriptLang));
1553
+ untrack(() => editor && addAutoCompletor(editor, scriptLang, currentWorkflowAsCode));
1553
1554
  });
1554
1555
  $effect(() => {
1555
1556
  $copilotInfo.enabled && initialized && editor && untrack(() => editor && addChatHandler(editor));
@@ -23,6 +23,7 @@ interface Props {
23
23
  useWebsockets?: boolean;
24
24
  small?: boolean;
25
25
  scriptLang: Preview['language'] | 'bunnative' | 'tsx' | 'jsx' | 'json' | undefined;
26
+ workflowAsCode?: boolean;
26
27
  disabled?: boolean;
27
28
  lineNumbersMinChars?: number;
28
29
  files?: Record<string, {
@@ -185,7 +185,7 @@ import Button from './common/button/Button.svelte';
185
185
  import Badge from './common/badge/Badge.svelte';
186
186
  import InlineCalendarInput, { fromCalendarDate, toCalendarDate } from './common/InlineCalendarInput.svelte';
187
187
  import { ButtonType } from './common';
188
- let { schema, value: valueInput = $bindable(), presets: _presets = [], class: className, placeholder = 'Filter...' } = $props();
188
+ let { schema, value: valueInput = $bindable(), presets: _presets = [], class: className, placeholder = 'Filter...', autofocus } = $props();
189
189
  let _value = new DebouncedTempValue(() => clone(valueInput), (v) => !errors.length && (valueInput = clone(v)), (t) => Object.entries(t));
190
190
  let value = $derived(_value.current);
191
191
  let errors = $derived(validateFilterInstance(schema, value));
@@ -493,6 +493,8 @@ function appendFilterAsText(presetValue) {
493
493
  inputSizeClasses.md
494
494
  )}
495
495
  {placeholder}
496
+ onKeyDown={() => (open = true)}
497
+ {autofocus}
496
498
  />
497
499
  {#if asText.val}
498
500
  <CloseButton small class="mr-1.5" onClick={() => (_value.current = {})} />
@@ -81,6 +81,7 @@ type Props<SchemaT extends FilterSchemaRec> = {
81
81
  }[];
82
82
  class?: string;
83
83
  placeholder?: string;
84
+ autofocus?: boolean;
84
85
  };
85
86
  declare const FilterSearchbar: import("svelte").Component<Props<FilterSchemaRec>, {}, "value">;
86
87
  type FilterSearchbar = ReturnType<typeof FilterSearchbar>;
@@ -12,6 +12,7 @@ import Tabs from './common/tabs/Tabs.svelte';
12
12
  import {} from './graph';
13
13
  import ModuleStatus from './ModuleStatus.svelte';
14
14
  import { clone, isScriptPreview, msToSec, readFieldsRecursively, truncateRev } from '../utils';
15
+ import { downloadViaClient, shouldDownloadViaClient } from '../utils/downloadFile';
15
16
  import JobArgs from './JobArgs.svelte';
16
17
  import { ChevronDown, Download, ExternalLink, Hourglass } from 'lucide-svelte';
17
18
  import { deepEqual } from 'fast-equals';
@@ -1481,16 +1482,29 @@ let totalEventsWaiting = $derived(Object.values(suspendStatus?.val ?? {}).reduce
1481
1482
  style="min-height: {minTabHeight}px"
1482
1483
  >
1483
1484
  {#if !hideDownloadLogs && !isReplay && job?.id}
1485
+ {@const logsApiPath = `/w/${workspace}/jobs_u/get_flow_all_logs/${job.id}`}
1486
+ {@const logsName = `windmill_flow_logs_${job.id}.txt`}
1484
1487
  <div class="flex justify-end p-1">
1485
- <Button
1486
- href="{base}/api/w/{workspace}/jobs_u/get_flow_all_logs/{job.id}"
1487
- download="windmill_flow_logs_{job.id}.txt"
1488
- color="light"
1489
- size="xs"
1490
- startIcon={{ icon: Download }}
1491
- >
1492
- Download all logs
1493
- </Button>
1488
+ {#if shouldDownloadViaClient()}
1489
+ <Button
1490
+ on:click={() => downloadViaClient(logsApiPath, logsName)}
1491
+ color="light"
1492
+ size="xs"
1493
+ startIcon={{ icon: Download }}
1494
+ >
1495
+ Download all logs
1496
+ </Button>
1497
+ {:else}
1498
+ <Button
1499
+ href="{base}/api{logsApiPath}"
1500
+ download={logsName}
1501
+ color="light"
1502
+ size="xs"
1503
+ startIcon={{ icon: Download }}
1504
+ >
1505
+ Download all logs
1506
+ </Button>
1507
+ {/if}
1494
1508
  </div>
1495
1509
  {/if}
1496
1510
  <FlowLogViewerWrapper
@@ -213,6 +213,22 @@ function forkAheadBehindMessage(changesAhead, changesBehind) {
213
213
  : ''}
214
214
  </span>
215
215
  {/if}
216
+ {#if comparison.summary.schedules_changed > 0}
217
+ <span class="text-blue-700 dark:text-blue-100">
218
+ {comparison.summary.schedules_changed} schedule{comparison.summary
219
+ .schedules_changed !== 1
220
+ ? 's'
221
+ : ''}
222
+ </span>
223
+ {/if}
224
+ {#if comparison.summary.triggers_changed > 0}
225
+ <span class="text-blue-700 dark:text-blue-100">
226
+ {comparison.summary.triggers_changed} trigger{comparison.summary
227
+ .triggers_changed !== 1
228
+ ? 's'
229
+ : ''}
230
+ </span>
231
+ {/if}
216
232
  </div>
217
233
 
218
234
  {#if ciTestTotal > 0}
@@ -81,7 +81,8 @@ let jobsLoader = useJobsLoader(() => ({
81
81
  syncQueuedRunsCount: false,
82
82
  refreshRate: 10000,
83
83
  currentWorkspace: $workspaceStore ?? '',
84
- skip: !runnableId
84
+ skip: !runnableId,
85
+ excludesEntrypointOverride: true
85
86
  }));
86
87
  let jobs = $derived(jobsLoader?.jobs ?? []);
87
88
  </script>
@@ -29,6 +29,7 @@ import SettingCard from './instanceSettings/SettingCard.svelte';
29
29
  let { setting, version, values, loading = true, openSmtpSettings, oauths, warning } = $props();
30
30
  const dispatch = createEventDispatcher();
31
31
  let latestKeyRenewalAttempt = $state(null);
32
+ let offlineCapStatus = $state(null);
32
33
  function showSetting(setting, values) {
33
34
  if (setting == 'dev_instance') {
34
35
  if (values['license_key'] == undefined) {
@@ -42,6 +43,14 @@ let opening = $state(false);
42
43
  async function reloadKeyrenewalAttemptInfo() {
43
44
  latestKeyRenewalAttempt = await SettingService.getLatestKeyRenewalAttempt();
44
45
  }
46
+ async function reloadLicenseStatus() {
47
+ try {
48
+ offlineCapStatus = (await SettingService.getOfflineLicenseStatus());
49
+ }
50
+ catch {
51
+ offlineCapStatus = null;
52
+ }
53
+ }
45
54
  async function reloadLicenseKey() {
46
55
  $values['license_key'] = await SettingService.getGlobal({
47
56
  key: 'license_key'
@@ -49,7 +58,10 @@ async function reloadLicenseKey() {
49
58
  }
50
59
  $effect(() => {
51
60
  if (setting.key == 'license_key') {
52
- untrack(() => reloadKeyrenewalAttemptInfo());
61
+ untrack(() => {
62
+ reloadKeyrenewalAttemptInfo();
63
+ reloadLicenseStatus();
64
+ });
53
65
  }
54
66
  });
55
67
  export async function renewLicenseKey() {
@@ -393,7 +405,7 @@ $effect(() => {
393
405
  </div>
394
406
  {/if}
395
407
  {/if}
396
- {#if latestKeyRenewalAttempt}
408
+ {#if latestKeyRenewalAttempt && !offlineCapStatus}
397
409
  {@const attemptedAt = new Date(latestKeyRenewalAttempt.attempted_at).toLocaleString()}
398
410
  {@const isTrial = latestKeyRenewalAttempt.result.startsWith('error: trial:')}
399
411
  <div class="relative">
@@ -463,11 +475,41 @@ $effect(() => {
463
475
  </div>
464
476
  {/if}
465
477
 
478
+ {#if offlineCapStatus}
479
+ {@const cap = offlineCapStatus}
480
+ {@const seatsOver = cap.seats_used > cap.seats_cap}
481
+ {@const cuOver = cap.cu_over_cap}
482
+ <div class="mt-1 flex flex-row items-center gap-2 text-xs">
483
+ <div class="flex flex-row items-center gap-1">
484
+ {#if seatsOver}
485
+ <BadgeX class="text-red-600" size={12} />
486
+ {:else}
487
+ <BadgeCheck class="text-green-600" size={12} />
488
+ {/if}
489
+ <span class={seatsOver ? 'text-red-600' : 'text-green-600'}>
490
+ Seats: {cap.seats_used.toFixed(1)} / {cap.seats_cap}
491
+ </span>
492
+ </div>
493
+ <div class="flex flex-row items-center gap-1">
494
+ {#if cuOver}
495
+ <BadgeX class="text-red-600" size={12} />
496
+ {:else}
497
+ <BadgeCheck class="text-green-600" size={12} />
498
+ {/if}
499
+ <span class={cuOver ? 'text-red-600' : 'text-green-600'}>
500
+ CUs: {cap.current_cu.toFixed(2)} / {cap.cu_cap.toFixed(2)}
501
+ </span>
502
+ </div>
503
+ </div>
504
+ {/if}
505
+
466
506
  {#if valid || expiration}
467
507
  <div class="flex flex-row gap-2 mt-1">
468
- <Button on:click={renewLicenseKey} loading={renewing} size="xs" variant="accent"
469
- >Renew key
470
- </Button>
508
+ {#if !offlineCapStatus}
509
+ <Button on:click={renewLicenseKey} loading={renewing} size="xs" variant="accent"
510
+ >Renew key
511
+ </Button>
512
+ {/if}
471
513
  <Button variant="accent" size="xs" loading={opening} on:click={openCustomerPortal}>
472
514
  Open customer portal
473
515
  </Button>
@@ -8,10 +8,12 @@ const s3LogPrefixes = [
8
8
  const S3_LOG_SEARCH_LIMIT = 2000;
9
9
  </script>
10
10
 
11
- <script lang="ts">import { ClipboardCopy, Download, Expand, Loader2 } from 'lucide-svelte';
11
+ <script lang="ts">import { ClipboardCopy, Download, Expand, Loader2, Timer, Cpu } from 'lucide-svelte';
12
12
  import { Button, Drawer, DrawerContent } from './common';
13
13
  import { copyToClipboard } from '../utils';
14
14
  import { base } from '../base';
15
+ import { withExternalDomain } from '../externalDomain';
16
+ import { downloadViaClient, shouldDownloadViaClient } from '../utils/downloadFile';
15
17
  import { workspaceStore } from '../stores';
16
18
  import { AnsiUp } from 'ansi_up';
17
19
  import NoWorkerWithTagWarning from './runs/NoWorkerWithTagWarning.svelte';
@@ -24,7 +26,7 @@ let { content, isLoading, duration = undefined, mem = undefined, wrapperClass =
24
26
  const ansi_up = $state(new AnsiUp());
25
27
  ansi_up.use_classes = true;
26
28
  let scroll = $state(true);
27
- let div = $state(null);
29
+ let preEl = $state(null);
28
30
  // let downloadStartUrl: string | undefined = undefined
29
31
  let LOG_INC = 10000;
30
32
  let LOG_LIMIT = $state(LOG_INC);
@@ -95,8 +97,7 @@ function truncateContent(jobContent, loadedFromObjectStore, limit) {
95
97
  return content;
96
98
  }
97
99
  export function scrollToBottom() {
98
- // console.log('scrollToBottom', scroll, div)
99
- scroll && setTimeout(() => div?.scroll({ top: div?.scrollHeight, behavior: 'smooth' }), 100);
100
+ scroll && setTimeout(() => preEl?.scroll({ top: preEl?.scrollHeight, behavior: 'smooth' }), 100);
100
101
  }
101
102
  let logViewer = $state();
102
103
  async function getStoreLogs() {
@@ -132,6 +133,15 @@ $effect.pre(() => {
132
133
  scroll = true;
133
134
  }
134
135
  });
136
+ let logsApiPath = $derived(`/w/${$workspaceStore}/jobs_u/get_logs/${jobId}`);
137
+ let downloadHref = $derived(withExternalDomain(`${base}/api${logsApiPath}`));
138
+ let downloadName = $derived(`windmill_logs_${jobId}.txt`);
139
+ async function onDownloadClick(e) {
140
+ if (!shouldDownloadViaClient())
141
+ return;
142
+ e.preventDefault();
143
+ await downloadViaClient(logsApiPath, downloadName);
144
+ }
135
145
  let truncatedContent = $derived(truncateContent(content, loadedFromObjectStore, LOG_LIMIT));
136
146
  let prefixInfo = $derived(findPrefixInfo(truncatedContent));
137
147
  let downloadStartUrl = $derived(findStartUrl(truncatedContent, prefixInfo));
@@ -169,17 +179,30 @@ let html = $derived.by(() => {
169
179
  <DrawerContent title="Expanded Logs" on:close={logViewer.closeDrawer}>
170
180
  {#snippet actions()}
171
181
  {#if jobId && download}
172
- <Button
173
- href="{base}/api/w/{$workspaceStore}/jobs_u/get_logs/{jobId}"
174
- download="windmill_logs_{jobId}.txt"
175
- color="light"
176
- size="xs"
177
- startIcon={{
178
- icon: Download
179
- }}
180
- >
181
- Download
182
- </Button>
182
+ {#if shouldDownloadViaClient()}
183
+ <Button
184
+ on:click={() => downloadViaClient(logsApiPath, downloadName)}
185
+ color="light"
186
+ size="xs"
187
+ startIcon={{
188
+ icon: Download
189
+ }}
190
+ >
191
+ Download
192
+ </Button>
193
+ {:else}
194
+ <Button
195
+ href={downloadHref}
196
+ download={downloadName}
197
+ color="light"
198
+ size="xs"
199
+ startIcon={{
200
+ icon: Download
201
+ }}
202
+ >
203
+ Download
204
+ </Button>
205
+ {/if}
183
206
  {/if}
184
207
 
185
208
  <Button
@@ -199,12 +222,12 @@ let html = $derived.by(() => {
199
222
  >{#if content}{@const len =
200
223
  (content?.length ?? 0) +
201
224
  (loadedFromObjectStore?.length ?? 0)}{#if splitHtml}{@html splitHtml.before}<button
202
- onclick={getStoreLogs}
203
- >Show more... <Tooltip>{tooltipText(prefixInfo)}</Tooltip></button
204
- >{@html splitHtml.after}{:else if downloadStartUrl}<button
205
225
  onclick={getStoreLogs}
206
226
  >Show more... <Tooltip>{tooltipText(prefixInfo)}</Tooltip></button
207
- ><br />{@html html}{:else if len > LOG_LIMIT}(truncated to the last {LOG_LIMIT} characters)...<br
227
+ >{@html splitHtml.after}{:else if downloadStartUrl}<button onclick={getStoreLogs}
228
+ >Show more... <Tooltip>{tooltipText(prefixInfo)}</Tooltip></button
229
+ ><br
230
+ />{@html html}{:else if len > LOG_LIMIT}(truncated to the last {LOG_LIMIT} characters)...<br
208
231
  /><button onclick={() => showMoreTruncate(len)}>Show more..</button><br
209
232
  />{@html html}{:else}{@html html}{/if}{:else if isLoading}Waiting for job to start...{:else}No logs are available yet{/if}</pre
210
233
  >
@@ -215,19 +238,58 @@ let html = $derived.by(() => {
215
238
  <div class="w-full h-full {wrapperClass}">
216
239
  <div class="w-full h-full relative">
217
240
  <div
218
- bind:this={div}
219
- class="w-full h-full overflow-auto bg-surface-secondary pt-4 {noMaxH ? '' : 'max-h-screen'}"
241
+ class="w-full h-full bg-surface-secondary flex flex-col {noMaxH ? '' : 'max-h-screen'}"
220
242
  data-nav-id={navigationId}
221
243
  >
222
- <div class="absolute z-10 top-0 right-0 flex flex-row-reverse justify-between text-xs">
223
- <div class="flex gap-2">
244
+ <div
245
+ class="flex gap-2 ml-2 {small ? 'py-1' : 'py-2'} border-b overflow-x-auto overflow-y-hidden"
246
+ >
247
+ {#if isLoading}
248
+ <div class="flex gap-2 items-center">
249
+ <Loader2 class="animate-spin" />
250
+ {#if tag}
251
+ <div class="flex flex-row items-center gap-1">
252
+ <div class="text-secondary text-2xs">{tagLabel ?? 'tag'}: {tag}</div>
253
+ <NoWorkerWithTagWarning {tagLabel} {tag} />
254
+ </div>
255
+ {/if}
256
+ {#if jobId}
257
+ <QueuePosition {jobId} />
258
+ {/if}
259
+ </div>
260
+ {:else if duration}
261
+ <span
262
+ class={twMerge(
263
+ 'flex items-center gap-1 text-secondary dark:text-gray-400',
264
+ small ? '!text-2xs' : '!text-xs'
265
+ )}
266
+ title="Duration"
267
+ >
268
+ <Timer size={small ? 10 : 12} />
269
+ {duration}ms
270
+ </span>
271
+ {/if}
272
+ {#if mem}
273
+ <span
274
+ class={twMerge(
275
+ 'flex items-center gap-1 text-secondary dark:text-gray-400',
276
+ small ? '!text-2xs' : '!text-xs'
277
+ )}
278
+ title="Memory peak"
279
+ >
280
+ <Cpu size={small ? 10 : 12} />
281
+ {(mem / 1024).toPrecision(4)}MB
282
+ </span>
283
+ {/if}
284
+ <div class="flex gap-2 justify-end flex-1">
224
285
  {#if jobId && download}
225
286
  <div class="flex items-center">
226
287
  <a
227
288
  class="text-primary pb-0.5"
228
289
  target="_blank"
229
- href="{base}/api/w/{$workspaceStore}/jobs_u/get_logs/{jobId}"
230
- download="windmill_logs_{jobId}.txt"
290
+ href={downloadHref}
291
+ download={downloadName}
292
+ onclick={onDownloadClick}
231
293
  ><Download size="14" />
232
294
  </a>
233
295
  </div>
@@ -235,66 +297,34 @@ let html = $derived.by(() => {
235
297
  <button onclick={logViewer.openDrawer}><Expand size="12" /></button>
236
298
  {#if !noAutoScroll}
237
299
  <label
238
- class="{small
239
- ? ''
240
- : 'py-2'} pr-2 text-2xs flex gap-2 font-normal text-primary items-center"
300
+ class="pr-2 text-2xs flex gap-2 font-normal text-primary items-center whitespace-nowrap"
241
301
  >
242
- Auto scroll
302
+ auto-scroll
243
303
  <input class="windmillapp" type="checkbox" bind:checked={scroll} />
244
304
  </label>
245
305
  {/if}
246
306
  </div>
247
307
  </div>
248
- {#if isLoading}
249
- <div class="flex gap-2 absolute top-2 left-2 items-center z-10">
250
- <Loader2 class="animate-spin" />
251
- {#if tag}
252
- <div class="flex flex-row items-center gap-1">
253
- <div class="text-primary text-2xs">{tagLabel ?? 'tag'}: {tag}</div>
254
- <NoWorkerWithTagWarning {tagLabel} {tag} />
255
- </div>
256
- {/if}
257
- {#if jobId}
258
- <QueuePosition {jobId} />
259
- {/if}
260
- </div>
261
- {:else if duration}
262
- <span
263
- class={twMerge(
264
- 'absolute text-primary dark:text-gray-400',
265
- small ? '!text-2xs' : '!text-xs',
266
- small ? 'top-0' : 'top-2',
267
- noPadding ? '' : 'left-2'
268
- )}>took {duration}ms</span
269
- >
270
- {/if}
271
- {#if mem}
272
- <span
273
- class="absolute {small ? '!text-2xs' : '!text-xs'} text-primary dark:text-gray-400 {small
274
- ? 'top-0'
275
- : 'top-2'} left-36">mem peak: {(mem / 1024).toPrecision(4)}MB</span
276
- >
277
- {/if}
278
308
  <pre
309
+ bind:this={preEl}
279
310
  class={twMerge(
280
- 'whitespace-pre break-words w-full ',
311
+ 'whitespace-pre break-words w-full flex-1 overflow-auto',
281
312
  small ? '!text-2xs' : '!text-xs',
282
313
  noPadding ? '' : 'p-2'
283
314
  )}
284
315
  >{#if content}{@const len =
285
- (content?.length ?? 0) +
286
- (loadedFromObjectStore?.length ?? 0)}{#if splitHtml}<span>{@html splitHtml.before}</span><button
287
- onclick={getStoreLogs}
288
- >Show more... &nbsp;<Tooltip>{tooltipText(prefixInfo)}</Tooltip></button
289
- ><span>{@html splitHtml.after}</span
290
- >{:else if downloadStartUrl}<button
316
+ (content?.length ?? 0) + (loadedFromObjectStore?.length ?? 0)}{#if splitHtml}<span
317
+ >{@html splitHtml.before}</span
318
+ ><button onclick={getStoreLogs}
319
+ >Show more... &nbsp;<Tooltip>{tooltipText(prefixInfo)}</Tooltip></button
320
+ ><span>{@html splitHtml.after}</span>{:else if downloadStartUrl}<button
291
321
  onclick={getStoreLogs}
292
322
  >Show more... &nbsp;<Tooltip>{tooltipText(prefixInfo)}</Tooltip></button
293
- ><br /><span>{@html html}</span
294
- >{:else if len > LOG_LIMIT}<button onclick={() => showMoreTruncate(len)}
295
- >Show more..</button
296
- >&nbsp;({LOG_LIMIT}/{len} chars)<br /><span>{@html html}</span
297
- >{:else}<span>{@html html}</span>{/if}{:else if !isLoading}<span>{customEmptyMessage}</span>{/if}</pre
323
+ ><br /><span>{@html html}</span>{:else if len > LOG_LIMIT}<button
324
+ onclick={() => showMoreTruncate(len)}>Show more..</button
325
+ >&nbsp;({LOG_LIMIT}/{len} chars)<br /><span>{@html html}</span>{:else}<span
326
+ >{@html html}</span
327
+ >{/if}{:else if !isLoading}<span>{customEmptyMessage}</span>{/if}</pre
298
328
  >
299
329
  </div>
300
330
  </div>
@@ -1,13 +1,16 @@
1
- <script lang="ts" module>/**
1
+ <script lang="ts" module>import { isTriggerOrScheduleKind } from 'windmill-utils-internal';
2
+ /**
2
3
  * Check if an item needs on_behalf_of selection.
3
4
  * Shows the selector when the source item has an on_behalf_of value set.
4
5
  */
5
6
  export function needsOnBehalfOfSelection(kind, sourceValue) {
6
- if (kind !== 'flow' &&
7
- kind !== 'script' &&
8
- kind !== 'app' &&
9
- kind !== 'raw_app' &&
10
- kind !== 'trigger')
7
+ const supported = kind === 'flow' ||
8
+ kind === 'script' ||
9
+ kind === 'app' ||
10
+ kind === 'raw_app' ||
11
+ kind === 'trigger' ||
12
+ isTriggerOrScheduleKind(kind);
13
+ if (!supported)
11
14
  return false;
12
15
  return !!sourceValue;
13
16
  }
@@ -20,7 +23,7 @@ import { userStore } from '../stores';
20
23
  import { UserService } from '../gen';
21
24
  import TextInput from './text_input/TextInput.svelte';
22
25
  let { targetWorkspace, targetValue, selected, onSelect, kind, canPreserve, customValue, isDeployment = true, folderDefault = undefined } = $props();
23
- const isTrigger = $derived(kind === 'trigger');
26
+ const isTrigger = $derived(kind === 'trigger' || isTriggerOrScheduleKind(kind));
24
27
  let label = $derived(isTrigger
25
28
  ? 'Set the user this will be permissioned as:'
26
29
  : 'Set the user this will be run on behalf of:');
@@ -6,6 +6,7 @@ import { twMerge } from 'tailwind-merge';
6
6
  import DarkModeObserver from './DarkModeObserver.svelte';
7
7
  import { HelpersService } from '../gen';
8
8
  import { base } from '../base';
9
+ import { downloadViaClient, shouldDownloadViaClient } from '../utils/downloadFile';
9
10
  import { enterpriseLicense, workspaceStore } from '../stores';
10
11
  import { Download } from 'lucide-svelte';
11
12
  import { Loader2 } from 'lucide-svelte';
@@ -171,13 +172,17 @@ run(() => {
171
172
  </div>
172
173
  {/if}
173
174
  {#if !disable_download && !s3resource.endsWith('.csv')}
175
+ {@const csvApiPath = `/w/${workspaceId}/job_helpers/download_s3_parquet_file_as_csv?file_key=${encodeURIComponent(s3resource)}${storage ? `&storage=${storage}` : ''}`}
176
+ {@const csvName = (s3resource.split('/').pop() ?? 'download') + '.csv'}
174
177
  <a
175
178
  target="_blank"
176
- href="{base}/api/w/{workspaceId}/job_helpers/download_s3_parquet_file_as_csv?file_key={encodeURIComponent(
177
- s3resource
178
- )}{storage ? `&storage=${storage}` : ''}"
179
+ href="{base}/api{csvApiPath}"
179
180
  class="text-secondary w-full text-right underline text-2xs whitespace-nowrap"
180
- ><div class="flex flex-row-reverse gap-2 items-center"><Download size={12} /> CSV</div></a
181
+ onclick={async (e) => {
182
+ if (!shouldDownloadViaClient()) return
183
+ e.preventDefault()
184
+ await downloadViaClient(csvApiPath, csvName)
185
+ }}><div class="flex flex-row-reverse gap-2 items-center"><Download size={12} /> CSV</div></a
181
186
  >
182
187
  {/if}
183
188