windmill-components 1.511.1 → 1.522.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 (232) hide show
  1. package/package/components/AppConnectInner.svelte.d.ts +1 -1
  2. package/package/components/ArgInput.svelte +42 -14
  3. package/package/components/ArgInput.svelte.d.ts +2 -10
  4. package/package/components/AssignableTagsInner.svelte +5 -0
  5. package/package/components/AuthSettings.svelte +4 -2
  6. package/package/components/AuthSettings.svelte.d.ts +1 -0
  7. package/package/components/DBManagerDrawer.svelte +154 -151
  8. package/package/components/DBManagerDrawer.svelte.d.ts +2 -2
  9. package/package/components/DBTable.svelte +3 -3
  10. package/package/components/DBTable.svelte.d.ts +1 -0
  11. package/package/components/DBTableEditor.svelte +7 -7
  12. package/package/components/DBTableEditor.svelte.d.ts +1 -1
  13. package/package/components/DeployWorkspace.svelte +1 -1
  14. package/package/components/DisplayResult.svelte +34 -8
  15. package/package/components/DisplayResult.svelte.d.ts +4 -1
  16. package/package/components/DynSelect.svelte +58 -34
  17. package/package/components/DynSelect.svelte.d.ts +3 -11
  18. package/package/components/EditableSchemaForm.svelte +126 -6
  19. package/package/components/EditableSchemaForm.svelte.d.ts +5 -1
  20. package/package/components/Editor.svelte +1 -1
  21. package/package/components/EditorBar.svelte +82 -4
  22. package/package/components/ErrorOrRecoveryHandler.svelte +76 -8
  23. package/package/components/ErrorOrRecoveryHandler.svelte.d.ts +2 -1
  24. package/package/components/ExploreAssetButton.svelte +14 -4
  25. package/package/components/ExploreAssetButton.svelte.d.ts +1 -0
  26. package/package/components/FlowJobResult.svelte +3 -3
  27. package/package/components/FlowJobResult.svelte.d.ts +1 -0
  28. package/package/components/FlowPreviewContent.svelte +9 -1
  29. package/package/components/FlowPreviewResult.svelte +4 -1
  30. package/package/components/FlowPreviewResult.svelte.d.ts +1 -0
  31. package/package/components/FlowStatusViewerInner.svelte +21 -3
  32. package/package/components/FlowStatusViewerInner.svelte.d.ts +7 -1
  33. package/package/components/FolderEditor.svelte +1 -1
  34. package/package/components/GitDiffPreview.svelte +14 -18
  35. package/package/components/GitDiffPreview.svelte.d.ts +2 -8
  36. package/package/components/GitHubAppIntegration.svelte +3 -1
  37. package/package/components/IdEditorInput.svelte +25 -22
  38. package/package/components/IdEditorInput.svelte.d.ts +11 -23
  39. package/package/components/InstanceSetting.svelte +7 -2
  40. package/package/components/InstanceSettings.svelte +1 -0
  41. package/package/components/JobLoader.svelte +48 -5
  42. package/package/components/JobLoader.svelte.d.ts +7 -2
  43. package/package/components/Login.svelte +8 -2
  44. package/package/components/MemoryFootprintViewer.svelte +1 -1
  45. package/package/components/ModulePreviewResultViewer.svelte +2 -2
  46. package/package/components/MoveDrawer.svelte.d.ts +2 -2
  47. package/package/components/NextcloudSetting.svelte +84 -0
  48. package/package/components/NextcloudSetting.svelte.d.ts +7 -0
  49. package/package/components/ObjectResourceInput.svelte +3 -2
  50. package/package/components/ObjectResourceInput.svelte.d.ts +1 -0
  51. package/package/components/ParqetCsvTableRenderer.svelte +1 -1
  52. package/package/components/ResourceEditor.svelte +1 -1
  53. package/package/components/ResourcePicker.svelte +8 -1
  54. package/package/components/ResourcePicker.svelte.d.ts +1 -0
  55. package/package/components/ResultStreamDisplay.svelte +5 -0
  56. package/package/components/ResultStreamDisplay.svelte.d.ts +5 -0
  57. package/package/components/RunForm.svelte +9 -1
  58. package/package/components/SchemaForm.svelte +2 -2
  59. package/package/components/SchemaForm.svelte.d.ts +2 -10
  60. package/package/components/ScriptBuilder.svelte +13 -8
  61. package/package/components/ScriptBuilder.svelte.d.ts +1 -1
  62. package/package/components/ScriptEditor.svelte.d.ts +1 -1
  63. package/package/components/ScriptWrapper.svelte +1 -1
  64. package/package/components/ShareModal.svelte.d.ts +1 -1
  65. package/package/components/SimpleAgTable.svelte +2 -0
  66. package/package/components/SimpleAgTable.svelte.d.ts +2 -0
  67. package/package/components/SqlRepl.svelte +21 -7
  68. package/package/components/SqlRepl.svelte.d.ts +2 -2
  69. package/package/components/StringTypeNarrowing.svelte.d.ts +1 -1
  70. package/package/components/WorkerTagSelect.svelte +70 -1
  71. package/package/components/apps/components/display/AppDisplayComponent.svelte +13 -1
  72. package/package/components/apps/components/display/AppText.svelte +2 -2
  73. package/package/components/apps/components/display/dbtable/AppDbExplorer.svelte +8 -1
  74. package/package/components/apps/components/display/dbtable/InsertRow.svelte +5 -4
  75. package/package/components/apps/components/display/dbtable/queries/count.js +11 -1
  76. package/package/components/apps/components/display/dbtable/queries/createTable.d.ts +1 -1
  77. package/package/components/apps/components/display/dbtable/queries/createTable.js +3 -3
  78. package/package/components/apps/components/display/dbtable/queries/delete.js +7 -0
  79. package/package/components/apps/components/display/dbtable/queries/insert.js +2 -0
  80. package/package/components/apps/components/display/dbtable/queries/select.js +14 -0
  81. package/package/components/apps/components/display/dbtable/queries/update.js +7 -0
  82. package/package/components/apps/components/display/dbtable/utils.d.ts +6 -5
  83. package/package/components/apps/components/display/dbtable/utils.js +52 -28
  84. package/package/components/apps/components/display/table/AppAggridExplorerTable.svelte +1 -1
  85. package/package/components/apps/components/display/table/AppAggridInfiniteTable.svelte +1 -0
  86. package/package/components/apps/components/display/table/AppAggridInfiniteTable.svelte.d.ts +1 -0
  87. package/package/components/apps/components/display/table/AppAggridTable.svelte +5 -4
  88. package/package/components/apps/components/display/table/AppAggridTable.svelte.d.ts +1 -0
  89. package/package/components/apps/components/display/table/utils.js +7 -4
  90. package/package/components/apps/components/helpers/HiddenComponent.svelte +2 -2
  91. package/package/components/apps/components/helpers/RunnableComponent.svelte +4 -1
  92. package/package/components/apps/components/helpers/RunnableComponent.svelte.d.ts +2 -1
  93. package/package/components/apps/components/inputs/AppS3FileInput.svelte +2 -2
  94. package/package/components/apps/components/layout/AppDecisionTree.svelte +1 -1
  95. package/package/components/apps/components/layout/AppStepper.svelte +1 -1
  96. package/package/components/apps/components/layout/AppTabs.svelte +1 -1
  97. package/package/components/apps/editor/AppEditorHeader.svelte +13 -2
  98. package/package/components/apps/editor/GridViewer.svelte +1 -0
  99. package/package/components/apps/editor/RunnableJobPanelInner.svelte +2 -1
  100. package/package/components/apps/editor/contextPanel/components/IdEditor.svelte +7 -7
  101. package/package/components/apps/editor/contextPanel/components/IdEditor.svelte.d.ts +7 -19
  102. package/package/components/apps/editor/contextPanel/components/OutputHeader.svelte +8 -12
  103. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte.d.ts +1 -1
  104. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptEditorDrawer.svelte.d.ts +1 -1
  105. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptRunnableByPath.svelte.d.ts +1 -1
  106. package/package/components/apps/editor/settingsPanel/DecisionTreeGraphEditor.svelte +3 -3
  107. package/package/components/apps/editor/settingsPanel/decisionTree/DecisionTreePreview.svelte +1 -3
  108. package/package/components/assets/AssetsDropdownButton.svelte +1 -1
  109. package/package/components/assets/JobAssetsViewer.svelte +2 -2
  110. package/package/components/assets/lib.js +4 -0
  111. package/package/components/auditLogs/AuditLogsFilters.svelte +7 -9
  112. package/package/components/common/button/Button.svelte +4 -3
  113. package/package/components/common/button/Button.svelte.d.ts +1 -0
  114. package/package/components/common/confirmationModal/ConfirmationModal.svelte +6 -5
  115. package/package/components/common/confirmationModal/ConfirmationModal.svelte.d.ts +6 -11
  116. package/package/components/common/confirmationModal/asyncConfirmationModal.svelte.d.ts +26 -0
  117. package/package/components/common/confirmationModal/asyncConfirmationModal.svelte.js +50 -0
  118. package/package/components/common/modal/Modal.svelte +2 -5
  119. package/package/components/common/tabs/TabsV2.svelte +2 -1
  120. package/package/components/common/tabs/TabsV2.svelte.d.ts +1 -0
  121. package/package/components/copilot/chat/AIChatManager.svelte.js +61 -7
  122. package/package/components/copilot/chat/ContextTextarea.svelte +1 -1
  123. package/package/components/copilot/chat/script/core.js +28 -29
  124. package/package/components/copilot/chat/shared.d.ts +1 -1
  125. package/package/components/copilot/chat/shared.js +8 -2
  126. package/package/components/custom_ui.d.ts +2 -0
  127. package/package/components/dbOps.d.ts +20 -8
  128. package/package/components/dbOps.js +85 -40
  129. package/package/components/details/DetailPageHeader.svelte +0 -2
  130. package/package/components/flows/content/FlowInput.svelte +5 -0
  131. package/package/components/flows/content/FlowModuleScript.svelte +0 -1
  132. package/package/components/flows/idUtils.js +2 -1
  133. package/package/components/flows/map/FlowModuleSchemaItem.svelte +3 -3
  134. package/package/components/flows/map/FlowModuleSchemaMap.svelte +5 -0
  135. package/package/components/flows/map/InsertModuleButton.svelte +4 -1
  136. package/package/components/flows/propPicker/OutputBadge.svelte +5 -1
  137. package/package/components/flows/propPicker/OutputPickerInner.svelte +9 -5
  138. package/package/components/flows/propPicker/OutputPickerInner.svelte.d.ts +6 -2
  139. package/package/components/flows/propPicker/StepHistory.svelte +4 -1
  140. package/package/components/git_sync/DetectionFlow.svelte +202 -0
  141. package/package/components/git_sync/DetectionFlow.svelte.d.ts +6 -0
  142. package/package/components/git_sync/GitSyncContext.svelte.d.ts +82 -0
  143. package/package/components/git_sync/GitSyncContext.svelte.js +461 -0
  144. package/package/components/git_sync/GitSyncModalManager.svelte +99 -0
  145. package/package/components/git_sync/GitSyncModalManager.svelte.d.ts +18 -0
  146. package/package/components/git_sync/GitSyncRepositoryCard.svelte +339 -0
  147. package/package/components/git_sync/GitSyncRepositoryCard.svelte.d.ts +6 -0
  148. package/package/components/git_sync/GitSyncRepositoryList.svelte +17 -0
  149. package/package/components/git_sync/GitSyncRepositoryList.svelte.d.ts +18 -0
  150. package/package/components/git_sync/GitSyncSection.svelte +89 -0
  151. package/package/components/git_sync/GitSyncSection.svelte.d.ts +3 -0
  152. package/package/components/git_sync/GitSyncSuccessModal.svelte +58 -0
  153. package/package/components/git_sync/GitSyncSuccessModal.svelte.d.ts +7 -0
  154. package/package/components/git_sync/PullWorkspaceModal.svelte +575 -0
  155. package/package/components/git_sync/PullWorkspaceModal.svelte.d.ts +15 -0
  156. package/package/components/git_sync/PushWorkspaceModal.svelte +320 -0
  157. package/package/components/git_sync/PushWorkspaceModal.svelte.d.ts +12 -0
  158. package/package/components/graph/FlowGraphV2.svelte +5 -1
  159. package/package/components/graph/graphBuilder.svelte.js +1 -1
  160. package/package/components/graph/renderers/nodes/AssetNode.svelte +4 -4
  161. package/package/components/icons/AssetDucklakeIcon.svelte +28 -0
  162. package/package/components/icons/AssetDucklakeIcon.svelte.d.ts +9 -0
  163. package/package/components/icons/AssetGenericIcon.svelte +3 -0
  164. package/package/components/icons/DucklakeIcon.svelte +18 -0
  165. package/package/components/icons/DucklakeIcon.svelte.d.ts +6 -0
  166. package/package/components/instanceSettings.js +11 -3
  167. package/package/components/runs/JobPreview.svelte +2 -2
  168. package/package/components/runs/NoWorkerWithTagWarning.svelte +3 -3
  169. package/package/components/runs/RunsFilter.svelte.d.ts +1 -1
  170. package/package/components/schema/FlowPropertyEditor.svelte +3 -2
  171. package/package/components/schema/FlowPropertyEditor.svelte.d.ts +1 -1
  172. package/package/components/schema/PropertyEditor.svelte +0 -2
  173. package/package/components/schema/PropertyEditor.svelte.d.ts +1 -1
  174. package/package/components/schema/SchemaFormDND.svelte +2 -1
  175. package/package/components/schema/SchemaFormDND.svelte.d.ts +2 -0
  176. package/package/components/scriptEditor/LogPanel.svelte +5 -3
  177. package/package/components/scriptEditor/LogPanel.svelte.d.ts +5 -1
  178. package/package/components/select/Select.svelte +7 -4
  179. package/package/components/select/Select.svelte.d.ts +5 -0
  180. package/package/components/select/SelectDropdown.svelte +2 -1
  181. package/package/components/select/SelectDropdown.svelte.d.ts +3 -0
  182. package/package/components/sidebar/changelogs.js +5 -0
  183. package/package/components/table/AutoDataTable.svelte +6 -4
  184. package/package/components/table/AutoDataTable.svelte.d.ts +1 -0
  185. package/package/components/table/DataTable.svelte +12 -10
  186. package/package/components/table/DataTable.svelte.d.ts +1 -0
  187. package/package/components/triggers/TriggerRetriesAndErrorHandler.svelte.d.ts +2 -2
  188. package/package/components/triggers/gcp/GcpTriggerEditorConfigSection.svelte +1 -1
  189. package/package/components/triggers/gcp/GcpTriggerEditorConfigSection.svelte.d.ts +2 -1
  190. package/package/components/triggers/gcp/GcpTriggerEditorInner.svelte +50 -11
  191. package/package/components/triggers/gcp/utils.js +1 -0
  192. package/package/components/triggers/http/utils.js +1 -1
  193. package/package/components/triggers/kafka/utils.js +1 -1
  194. package/package/components/triggers/mqtt/utils.js +1 -1
  195. package/package/components/triggers/nats/utils.js +1 -1
  196. package/package/components/triggers/postgres/utils.js +1 -1
  197. package/package/components/triggers/sqs/utils.js +1 -1
  198. package/package/components/triggers/utils.js +2 -1
  199. package/package/components/triggers/webhook/WebhooksConfigSection.svelte +24 -26
  200. package/package/components/triggers/webhook/WebhooksPanel.svelte +1 -15
  201. package/package/components/triggers/websocket/utils.js +1 -1
  202. package/package/components/workspaceSettings/AISettings.svelte +52 -36
  203. package/package/components/workspaceSettings/DucklakeSettings.svelte +321 -0
  204. package/package/components/workspaceSettings/DucklakeSettings.svelte.d.ts +23 -0
  205. package/package/components/workspaceSettings/GitSyncFilterSettings.svelte +122 -499
  206. package/package/components/workspaceSettings/GitSyncFilterSettings.svelte.d.ts +8 -10
  207. package/package/consts.js +2 -1
  208. package/package/gen/core/OpenAPI.js +1 -1
  209. package/package/gen/schemas.gen.d.ts +7 -6
  210. package/package/gen/schemas.gen.js +7 -6
  211. package/package/gen/services.gen.d.ts +19 -1
  212. package/package/gen/services.gen.js +38 -0
  213. package/package/gen/types.gen.d.ts +78 -3
  214. package/package/git-sync.d.ts +36 -0
  215. package/package/git-sync.js +1 -0
  216. package/package/hub.d.ts +1 -0
  217. package/package/hubPaths.json +5 -2
  218. package/package/infer.js +3 -2
  219. package/package/script_helpers.d.ts +2 -2
  220. package/package/script_helpers.js +29 -11
  221. package/package/services/JobManager.d.ts +28 -0
  222. package/package/services/JobManager.js +114 -0
  223. package/package/stores.d.ts +1 -1
  224. package/package/utils.d.ts +18 -1
  225. package/package/utils.js +55 -2
  226. package/package.json +5 -4
  227. package/package/components/InitGitRepoPopover.svelte +0 -410
  228. package/package/components/InitGitRepoPopover.svelte.d.ts +0 -13
  229. package/package/components/PullGitRepoPopover.svelte +0 -355
  230. package/package/components/PullGitRepoPopover.svelte.d.ts +0 -18
  231. package/package/inferArgSig.d.ts +0 -42
  232. package/package/inferArgSig.js +0 -198
@@ -567,7 +567,7 @@ async function showDiff(kind, path) {
567
567
  <div class="mt-6"></div>
568
568
 
569
569
  {#if !$enterpriseLicense}
570
- <Alert type="error" title="Enterprise license required"
570
+ <Alert type="warning" title="Enterprise license required"
571
571
  >Deploy to staging/prod from the web UI is only available with an enterprise license</Alert
572
572
  >
573
573
  {:else if notSet == true}
@@ -25,13 +25,14 @@ import HighlightTheme from './HighlightTheme.svelte';
25
25
  import { getContext, hasContext, createEventDispatcher, onDestroy } from 'svelte';
26
26
  import { toJsonStr } from '../utils';
27
27
  import { userStore } from '../stores';
28
+ import ResultStreamDisplay from './ResultStreamDisplay.svelte';
28
29
  const IMG_MAX_SIZE = 10000000;
29
30
  const TABLE_MAX_SIZE = 5000000;
30
31
  const DISPLAY_MAX_SIZE = 100000;
31
32
  const dispatch = createEventDispatcher();
32
33
  let resultKind = $state();
33
34
  let hasBigInt = $state(false);
34
- let { result, requireHtmlApproval = false, filename = undefined, disableExpand = false, jobId = undefined, workspaceId = undefined, hideAsJson = false, noControls = false, drawerOpen = $bindable(false), nodeId = undefined, language = undefined, appPath = undefined, customUi = undefined, isTest = true, externalToolbarAvailable = false, forceJson = $bindable(false), copilot_fix, children } = $props();
35
+ let { result, requireHtmlApproval = false, filename = undefined, disableExpand = false, jobId = undefined, workspaceId = undefined, hideAsJson = false, noControls = false, drawerOpen = $bindable(false), nodeId = undefined, language = undefined, appPath = undefined, customUi = undefined, isTest = true, externalToolbarAvailable = false, forceJson = $bindable(false), result_stream = undefined, fixTableSizingToParent = false, copilot_fix, children, loading = false } = $props();
35
36
  let enableHtml = $state(false);
36
37
  let s3FileDisplayRawMode = $state(false);
37
38
  function isTableRow(result) {
@@ -352,7 +353,15 @@ $effect(() => {
352
353
  </script>
353
354
 
354
355
  <HighlightTheme />
355
- {#if is_render_all}
356
+
357
+ {#if result_stream && result == undefined}
358
+ <div class="flex flex-col w-full gap-2">
359
+ <div class="flex items-center gap-2 text-tertiary">
360
+ <Loader2 class="animate-spin" size={16} /> Streaming result
361
+ </div>
362
+ <ResultStreamDisplay {result_stream} />
363
+ </div>
364
+ {:else if is_render_all}
356
365
  <div class="flex flex-col w-full gap-2">
357
366
  {#if !noControls}
358
367
  <div class="text-tertiary text-sm">
@@ -392,7 +401,9 @@ $effect(() => {
392
401
  <div class="text-red-400">Non displayable object</div>
393
402
  {:else}
394
403
  <div
395
- class="inline-highlight relative grow {['plain', 'markdown'].includes(resultKind ?? '')
404
+ class="inline-highlight relative grow flex flex-col h-full {['plain', 'markdown'].includes(
405
+ resultKind ?? ''
406
+ )
396
407
  ? ''
397
408
  : 'min-h-[160px]'}"
398
409
  >
@@ -447,16 +458,31 @@ $effect(() => {
447
458
  {/if}
448
459
  </div>
449
460
  </div>
450
- <div class="grow">
461
+ <div class="grow relative">
451
462
  {#if !forceJson && resultKind === 'table-col'}
452
463
  {@const data = 'table-col' in result ? result['table-col'] : result}
453
- <AutoDataTable objects={objectOfArraysToObjects(data)} />
464
+ <AutoDataTable
465
+ class={fixTableSizingToParent
466
+ ? 'absolute inset-0 [&>div]:h-full [&>div]:min-h-[10rem]'
467
+ : ''}
468
+ objects={objectOfArraysToObjects(data)}
469
+ />
454
470
  {:else if !forceJson && resultKind === 'table-row'}
455
471
  {@const data = 'table-row' in result ? result['table-row'] : result}
456
- <AutoDataTable objects={arrayOfRowsToObjects(data)} />
472
+ <AutoDataTable
473
+ class={fixTableSizingToParent
474
+ ? 'absolute inset-0 [&>div]:h-full [&>div]:min-h-[10rem]'
475
+ : ''}
476
+ objects={arrayOfRowsToObjects(data)}
477
+ />
457
478
  {:else if !forceJson && resultKind === 'table-row-object'}
458
479
  {@const data = 'table-row-object' in result ? result['table-row-object'] : result}
459
- <AutoDataTable objects={handleArrayOfObjectsHeaders(data)} />
480
+ <AutoDataTable
481
+ class={fixTableSizingToParent
482
+ ? 'absolute inset-0 [&>div]:h-full [&>div]:min-h-[10rem]'
483
+ : ''}
484
+ objects={handleArrayOfObjectsHeaders(data)}
485
+ />
460
486
  {:else if !forceJson && resultKind === 'html'}
461
487
  <div class="h-full">
462
488
  {#if !requireHtmlApproval || enableHtml}
@@ -538,7 +564,7 @@ $effect(() => {
538
564
  {:else if !forceJson && resultKind === 'plain'}<div class="h-full text-2xs"
539
565
  ><pre class="whitespace-pre-wrap"
540
566
  >{typeof result === 'string' ? result : result?.['result']}</pre
541
- >{#if !noControls}
567
+ >{#if !noControls && !loading}
542
568
  <div class="flex">
543
569
  <Button
544
570
  on:click={() =>
@@ -11,12 +11,15 @@ interface Props {
11
11
  noControls?: boolean;
12
12
  drawerOpen?: boolean;
13
13
  nodeId?: string | undefined;
14
+ loading?: boolean | undefined;
14
15
  language?: string | undefined;
15
16
  appPath?: string | undefined;
16
17
  customUi?: DisplayResultUi | undefined;
17
18
  isTest?: boolean;
18
19
  externalToolbarAvailable?: boolean;
19
20
  forceJson?: boolean;
21
+ result_stream?: string | undefined;
22
+ fixTableSizingToParent?: boolean;
20
23
  copilot_fix?: import('svelte').Snippet;
21
24
  children?: import('svelte').Snippet;
22
25
  }
@@ -40,6 +43,6 @@ declare const DisplayResult: $$__sveltets_2_IsomorphicComponent<Props, {
40
43
  }, {}, {
41
44
  openDrawer: () => void;
42
45
  getToolbarLocation: () => "external" | "self" | undefined;
43
- }, "drawerOpen" | "forceJson">;
46
+ }, "forceJson" | "drawerOpen">;
44
47
  type DisplayResult = InstanceType<typeof DisplayResult>;
45
48
  export default DisplayResult;
@@ -15,63 +15,87 @@ function validSelectObject(x) {
15
15
  </script>
16
16
 
17
17
  <script lang="ts">import { usePromise } from '../svelte5Utils.svelte';
18
- import { deepEqual } from 'fast-equals';
19
- import JobLoader from './JobLoader.svelte';
18
+ import JobLoader, {} from './JobLoader.svelte';
20
19
  import Select from './select/Select.svelte';
21
20
  import Tooltip from './Tooltip.svelte';
22
21
  import { Loader2 } from 'lucide-svelte';
22
+ import {} from '../utils';
23
+ import { deepEqual } from 'fast-equals';
23
24
  import { untrack } from 'svelte';
24
- import { readFieldsRecursively } from '../utils';
25
- let { value = $bindable(), helperScript, entrypoint, args: _args, name } = $props();
26
- let args = $state(structuredClone($state.snapshot(_args)));
27
- $effect(() => {
28
- readFieldsRecursively(_args, { excludeField: [name] });
29
- untrack(() => !deepEqual(args, _args) && (args = $state.snapshot(_args)));
30
- });
25
+ let { value = $bindable(), helperScript, entrypoint, otherArgs: otherArgs } = $props();
26
+ let resultJobLoader = $state();
27
+ let _items = usePromise(getItemsFromOptions, { clearValueOnRefresh: false });
28
+ let items = $derived(_items.value);
29
+ let filterText = $state('');
30
+ let open = $state(false);
31
31
  async function getItemsFromOptions() {
32
32
  return new Promise((resolve, reject) => {
33
33
  let cb = {
34
- done(res) {
35
- if (!res || !Array.isArray(res)) {
36
- reject('Result was not an array');
34
+ doneResult({ result }) {
35
+ if (!result || !Array.isArray(result)) {
36
+ if (result?.error?.message && result?.error?.name) {
37
+ reject('Error in DynSelect function execution: ' +
38
+ result?.error?.name +
39
+ ' - ' +
40
+ result?.error?.message);
41
+ }
42
+ else {
43
+ reject('Result was not an array but ' + JSON.stringify(result, null, 2));
44
+ }
37
45
  return;
38
46
  }
39
- if (res.length == 0)
47
+ if (result.length == 0)
40
48
  resolve([]);
41
- if (res.every((x) => typeof x == 'string')) {
42
- res = res.map((x) => ({ label: x, value: x }));
49
+ if (result.every((x) => typeof x == 'string')) {
50
+ result = result.map((x) => ({ label: x, value: x }));
43
51
  }
44
- else if (res.find((x) => validSelectObject(x) != undefined)) {
45
- reject(validSelectObject(res.find((x) => validSelectObject(x) != undefined)));
46
- }
47
- else {
48
- if (filterText != undefined && filterText != '')
49
- res = res.filter((x) => x['label'].includes(filterText));
50
- resolve(res);
52
+ else if (result.find((x) => validSelectObject(x) != undefined)) {
53
+ reject(validSelectObject(result.find((x) => validSelectObject(x) != undefined)));
54
+ return;
51
55
  }
56
+ resolve(result);
52
57
  },
53
58
  cancel: () => reject(),
54
- error: (err) => reject(err)
59
+ doneError({ id, error }) {
60
+ reject(error);
61
+ }
55
62
  };
56
63
  helperScript?.type == 'inline'
57
- ? resultJobLoader?.runPreview(helperScript?.path ?? 'NO_PATH', helperScript.code, helperScript.lang, { ...args, filterText, _ENTRYPOINT_OVERRIDE: entrypoint }, undefined, undefined, undefined, cb)
58
- : resultJobLoader?.runScriptByHash(helperScript?.hash ?? 'NO_HASH', { ...args, filterText, _ENTRYPOINT_OVERRIDE: entrypoint }, cb);
64
+ ? resultJobLoader?.runPreview(helperScript?.path ?? 'NO_PATH', helperScript.code, helperScript.lang, { ...otherArgs, filterText, _ENTRYPOINT_OVERRIDE: entrypoint }, undefined, undefined, undefined, cb)
65
+ : resultJobLoader?.runScriptByHash(helperScript?.hash ?? 'NO_HASH', { ...otherArgs, filterText, _ENTRYPOINT_OVERRIDE: entrypoint }, cb);
59
66
  });
60
67
  }
61
- let _items = usePromise(getItemsFromOptions);
62
- let items = $derived(_items.value);
68
+ let neverLoaded = $state(true);
69
+ $effect(() => {
70
+ if (_items.value && value) {
71
+ if (!_items.value.find((x) => x.value == value)) {
72
+ value = undefined;
73
+ }
74
+ }
75
+ });
76
+ let lastArgs = $state.snapshot(otherArgs);
77
+ let timeout = $state();
78
+ let nargs = $state($state.snapshot(otherArgs));
79
+ $effect(() => {
80
+ otherArgs;
81
+ untrack(() => clearTimeout(timeout));
82
+ timeout = setTimeout(() => {
83
+ nargs = $state.snapshot(otherArgs);
84
+ }, 1000);
85
+ });
63
86
  $effect(() => {
64
87
  ;
65
- [args, name, entrypoint, helperScript, filterText];
66
- untrack(() => _items.refresh());
88
+ [filterText, entrypoint, helperScript];
89
+ if (resultJobLoader && (open || neverLoaded || !deepEqual(lastArgs, nargs))) {
90
+ neverLoaded = false;
91
+ lastArgs = $state.snapshot(otherArgs);
92
+ _items.refresh();
93
+ }
67
94
  });
68
- let resultJobLoader = $state();
69
- let filterText = $state('');
70
- let open = $state(false);
71
95
  </script>
72
96
 
73
97
  {#if helperScript}
74
- <JobLoader bind:this={resultJobLoader} />
98
+ <JobLoader onlyResult bind:this={resultJobLoader} />
75
99
 
76
100
  <div class="w-full flex-col flex">
77
101
  <Select
@@ -85,7 +109,7 @@ let open = $state(false);
85
109
  />
86
110
  {#if _items.error}
87
111
  <div class="text-red-400 text-2xs">
88
- error: <Tooltip>{JSON.stringify(_items.error)}</Tooltip>
112
+ error: <Tooltip>{_items.error}</Tooltip>
89
113
  </div>
90
114
  {/if}
91
115
  </div>
@@ -1,17 +1,9 @@
1
- import type { Script } from '../gen';
1
+ import { type DynamicSelect } from '../utils';
2
2
  interface Props {
3
3
  value?: any;
4
- helperScript?: {
5
- type: 'inline';
6
- path?: string;
7
- lang: Script['language'];
8
- code: string;
9
- } | {
10
- type: 'hash';
11
- hash: string;
12
- };
4
+ helperScript?: DynamicSelect.HelperScript;
13
5
  entrypoint: string;
14
- args?: Record<string, any>;
6
+ otherArgs?: Record<string, any>;
15
7
  name: string;
16
8
  }
17
9
  declare const DynSelect: import("svelte").Component<Props, {}, "value">;
@@ -17,18 +17,38 @@ import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte
17
17
  import Label from './Label.svelte';
18
18
  import { sendUserToast } from '../toast';
19
19
  import Toggle from './Toggle.svelte';
20
- import { emptyString } from '../utils';
20
+ import { DynamicSelect, emptyString } from '../utils';
21
21
  import Popover from './meltComponents/Popover.svelte';
22
22
  import SchemaFormDnd from './schema/SchemaFormDND.svelte';
23
23
  import { deepEqual } from 'fast-equals';
24
24
  import { tweened } from 'svelte/motion';
25
+ import Section from './Section.svelte';
26
+ import Editor from './Editor.svelte';
25
27
  // export let openEditTab: () => void = () => {}
26
28
  const dispatch = createEventDispatcher();
27
- let { schema = $bindable(), hiddenArgs = [], args = $bindable(undefined), shouldHideNoInputs = false, noVariablePicker = false, flexWrap = false, uiOnly = false, isFlowInput = false, noPreview = false, jsonEnabled = true, isAppInput = false, displayWebhookWarning = false, onlyMaskPassword = false, dndType = undefined, editTab, previewSchema = undefined, editPanelInitialSize = undefined, editPanelSize = $bindable(0), diff = {}, disableDnd = false, shouldDispatchChanges = false, isValid = $bindable(true), customUi = undefined, pannelExtraButtonWidth = 0, class: clazz = '', openEditTab, addProperty, runButton, extraTab } = $props();
29
+ let { schema = $bindable(), hiddenArgs = [], args = $bindable(undefined), shouldHideNoInputs = false, noVariablePicker = false, flexWrap = false, uiOnly = false, isFlowInput = false, noPreview = false, jsonEnabled = true, isAppInput = false, displayWebhookWarning = false, onlyMaskPassword = false, dndType = undefined, editTab, previewSchema = undefined, editPanelInitialSize = undefined, editPanelSize = $bindable(0), diff = {}, disableDnd = false, shouldDispatchChanges = false, isValid = $bindable(true), customUi = undefined, pannelExtraButtonWidth = 0, class: clazz = '', dynSelectCode = $bindable(), dynSelectLang = $bindable(), showDynSelectOpt = false, openEditTab, addProperty, runButton, extraTab } = $props();
28
30
  $effect.pre(() => {
29
31
  if (args == undefined) {
30
32
  args = {};
31
33
  }
34
+ if (dynSelectLang === undefined) {
35
+ dynSelectLang = schema?.['x-windmill-dyn-select-lang'] || 'bun';
36
+ }
37
+ if (dynSelectCode === undefined) {
38
+ dynSelectCode = schema?.['x-windmill-dyn-select-code'] || '';
39
+ }
40
+ });
41
+ $effect(() => {
42
+ if (schema && dynSelectCode !== undefined && dynSelectLang !== undefined) {
43
+ if (dynSelectCode && dynSelectCode.trim()) {
44
+ schema['x-windmill-dyn-select-code'] = dynSelectCode.trim();
45
+ schema['x-windmill-dyn-select-lang'] = dynSelectLang;
46
+ }
47
+ else {
48
+ delete schema['x-windmill-dyn-select-code'];
49
+ delete schema['x-windmill-dyn-select-lang'];
50
+ }
51
+ }
32
52
  });
33
53
  export function setDefaults() {
34
54
  const nargs = {};
@@ -95,9 +115,11 @@ function computeSelected(property) {
95
115
  ? property.type
96
116
  : property.format === 'resource-s3_object'
97
117
  ? 'S3'
98
- : property.oneOf && property.oneOf.length >= 2
99
- ? 'oneOf'
100
- : 'object';
118
+ : property.format?.startsWith('dynselect-')
119
+ ? 'dynselect'
120
+ : property.oneOf && property.oneOf.length >= 2
121
+ ? 'oneOf'
122
+ : 'object';
101
123
  }
102
124
  export function openField(key) {
103
125
  opened = key;
@@ -150,6 +172,7 @@ let jsonView = $state(customUi?.jsonOnly == true);
150
172
  let schemaString = $state(JSON.stringify(schema, null, '\t'));
151
173
  let error = $state(undefined);
152
174
  let editor = $state(undefined);
175
+ let dynamicSelectEditor = $state(undefined);
153
176
  export function updateJson() {
154
177
  schemaString = JSON.stringify(schema, null, '\t');
155
178
  editor?.setCode(schemaString);
@@ -191,6 +214,37 @@ $effect(() => {
191
214
  $effect(() => {
192
215
  !!editTab ? openEditTabFn() : closeEditTab();
193
216
  });
217
+ let dynSelectFunctions = $derived(Object.entries(schema?.properties ?? {})
218
+ .filter(([_, property]) => {
219
+ const props = property;
220
+ return (props.type === 'object' &&
221
+ (props.format?.startsWith('dynselect-') || props.format?.startsWith('dynselect_')));
222
+ })
223
+ .map(([fieldName, _]) => fieldName.replace(/\s+/g, '_')));
224
+ let typeOptions = [
225
+ ['String', 'string'],
226
+ ['Number', 'number'],
227
+ ['Integer', 'integer'],
228
+ ['Object', 'object'],
229
+ ['OneOf', 'oneOf'],
230
+ ['Array', 'array'],
231
+ ['Boolean', 'boolean'],
232
+ ['S3 Object', 'S3']
233
+ ];
234
+ if (showDynSelectOpt) {
235
+ typeOptions.push(['DynSelect', 'dynselect']);
236
+ }
237
+ function initDynSelectFn(lang) {
238
+ const generateFn = DynamicSelect.getGenerateTemplateFn(lang);
239
+ return Object.entries(schema?.properties ?? {})
240
+ .map(([functionName]) => generateFn(functionName))
241
+ .join('');
242
+ }
243
+ function updateDynSelectCode(functionName, lang = 'bun') {
244
+ const generateFn = DynamicSelect.getGenerateTemplateFn(lang);
245
+ const code = generateFn(functionName);
246
+ dynSelectCode = dynSelectCode ? dynSelectCode.concat(code) : code;
247
+ }
194
248
  </script>
195
249
 
196
250
  <div class="w-full h-full">
@@ -249,6 +303,11 @@ $effect(() => {
249
303
  }
250
304
  tick().then(() => dispatch('change', schema))
251
305
  }}
306
+ helperScript={{
307
+ type: 'inline',
308
+ code: dynSelectCode!,
309
+ lang: dynSelectLang!
310
+ }}
252
311
  prettifyHeader={isAppInput}
253
312
  disabled={!!previewSchema}
254
313
  {diff}
@@ -263,6 +322,57 @@ $effect(() => {
263
322
  />
264
323
 
265
324
  {@render runButton?.()}
325
+
326
+ <div class="h-full">
327
+ {#if dynSelectFunctions.length > 0}
328
+ <Section
329
+ label="Dynamic select functions"
330
+ collapsable={true}
331
+ collapsed={false}
332
+ class="text-sm"
333
+ >
334
+ <div class="flex flex-col gap-2 h-full">
335
+ {#if dynSelectFunctions.length > 0}
336
+ <div class="bg-blue-50 dark:bg-blue-900/20 p-3 rounded-md">
337
+ <div class="text-sm font-medium text-blue-800 dark:text-blue-200 mb-2">
338
+ Expected Functions for Dynamic Select Fields:
339
+ </div>
340
+ <ul class="text-xs text-blue-700 dark:text-blue-300 space-y-1">
341
+ {#each dynSelectFunctions as functionName}
342
+ <li class="font-mono bg-blue-100 dark:bg-blue-800/30 px-2 py-1 rounded">
343
+ {functionName}()
344
+ </li>
345
+ {/each}
346
+ </ul>
347
+ </div>
348
+ {/if}
349
+ <ToggleButtonGroup
350
+ bind:selected={dynSelectLang}
351
+ on:selected={({ detail }) => {
352
+ dynSelectCode = initDynSelectFn(detail)
353
+ }}
354
+ >
355
+ {#snippet children({ item })}
356
+ <ToggleButton value="bun" label="Typescript (Bun)" {item} />
357
+ <ToggleButton value="python3" label="Python" {item} />
358
+ {/snippet}
359
+ </ToggleButtonGroup>
360
+ {#key dynSelectLang}
361
+ <div class="border w-full h-full">
362
+ <Editor
363
+ bind:this={dynamicSelectEditor}
364
+ class="flex flex-1 grow h-80 w-full"
365
+ scriptLang={dynSelectLang}
366
+ useWebsockets={false}
367
+ automaticLayout
368
+ bind:code={dynSelectCode}
369
+ />
370
+ </div>
371
+ {/key}
372
+ </div>
373
+ </Section>
374
+ {/if}
375
+ </div>
266
376
  </div>
267
377
  </div>
268
378
  </Pane>
@@ -424,6 +534,7 @@ $effect(() => {
424
534
  (v) => {
425
535
  const isS3 = v == 'S3'
426
536
  const isOneOf = v == 'oneOf'
537
+ const isDynSelect = v == 'dynselect'
427
538
 
428
539
  const emptyProperty = {
429
540
  contentEncoding: undefined,
@@ -449,6 +560,15 @@ $effect(() => {
449
560
  type: 'object',
450
561
  format: 'resource-s3_object'
451
562
  }
563
+ } else if (isDynSelect) {
564
+ const functionName = argName.replace(/\s+/g, '_')
565
+ schema.properties[argName] = {
566
+ ...emptyProperty,
567
+ type: 'object',
568
+ format: 'dynselect-' + functionName
569
+ }
570
+ updateDynSelectCode(argName, dynSelectLang)
571
+ dynamicSelectEditor?.setCode(dynSelectCode || '')
452
572
  } else if (isOneOf) {
453
573
  schema.properties[argName] = {
454
574
  ...emptyProperty,
@@ -498,7 +618,7 @@ $effect(() => {
498
618
  }}
499
619
  >
500
620
  {#snippet children({ item })}
501
- {#each [['String', 'string'], ['Number', 'number'], ['Integer', 'integer'], ['Object', 'object'], ['OneOf', 'oneOf'], ['Array', 'array'], ['Boolean', 'boolean'], ['S3 Object', 'S3']] as x}
621
+ {#each typeOptions as x}
502
622
  <ToggleButton value={x[1]} label={x[0]} {item} />
503
623
  {/each}
504
624
  {/snippet}
@@ -1,4 +1,5 @@
1
1
  import type { Schema } from '../common';
2
+ import { type ScriptLang } from '../gen';
2
3
  import type { SchemaDiff } from './schema/schemaUtils.svelte';
3
4
  import type { EditableSchemaFormUi } from './custom_ui';
4
5
  interface Props {
@@ -27,6 +28,9 @@ interface Props {
27
28
  customUi?: EditableSchemaFormUi | undefined;
28
29
  pannelExtraButtonWidth?: number;
29
30
  class?: string;
31
+ dynSelectCode?: string | undefined;
32
+ dynSelectLang?: ScriptLang | undefined;
33
+ showDynSelectOpt?: boolean;
30
34
  openEditTab?: import('svelte').Snippet;
31
35
  addProperty?: import('svelte').Snippet;
32
36
  runButton?: import('svelte').Snippet;
@@ -59,6 +63,6 @@ declare const EditableSchemaForm: $$__sveltets_2_IsomorphicComponent<Props, {
59
63
  openField: (key: string) => void;
60
64
  deleteField: (key: string) => void;
61
65
  updateJson: () => void;
62
- }, "args" | "schema" | "isValid" | "editPanelSize">;
66
+ }, "args" | "schema" | "isValid" | "editPanelSize" | "dynSelectCode" | "dynSelectLang">;
63
67
  type EditableSchemaForm = InstanceType<typeof EditableSchemaForm>;
64
68
  export default EditableSchemaForm;
@@ -138,7 +138,7 @@ const dispatch = createEventDispatcher();
138
138
  let graphqlService = undefined;
139
139
  let dbSchema = $state(undefined);
140
140
  let destroyed = false;
141
- const uri = computeUri(filePath, scriptLang);
141
+ const uri = computeUri(untrack(() => filePath), scriptLang);
142
142
  console.log('uri', uri);
143
143
  function computeUri(filePath, scriptLang) {
144
144
  let file;
@@ -2,7 +2,7 @@
2
2
  </script>
3
3
 
4
4
  <script lang="ts">import { run } from 'svelte/legacy';
5
- import { ResourceService, VariableService } from '../gen';
5
+ import { ResourceService, VariableService, WorkspaceService } from '../gen';
6
6
  import { workspaceStore } from '../stores';
7
7
  import { base } from '../base';
8
8
  import ItemPicker from './ItemPicker.svelte';
@@ -20,7 +20,7 @@ import { createEventDispatcher, untrack } from 'svelte';
20
20
  import { sendUserToast } from '../toast';
21
21
  import { getScriptByPath, scriptLangToEditorLang } from '../scripts';
22
22
  import Toggle from './Toggle.svelte';
23
- import { DiffIcon, DollarSign, File, History, Library, Link, Package, Plus, RotateCw, Save, Users } from 'lucide-svelte';
23
+ import { DatabaseIcon, DiffIcon, DollarSign, File, History, Library, Link, Package, Plus, RotateCw, Save, Users } from 'lucide-svelte';
24
24
  import { capitalize, formatS3Object, toCamel } from '../utils';
25
25
  import ScriptVersionHistory from './ScriptVersionHistory.svelte';
26
26
  import ScriptGen from './copilot/ScriptGen.svelte';
@@ -29,6 +29,7 @@ import Popover from './Popover.svelte';
29
29
  import ResourceEditorDrawer from './ResourceEditorDrawer.svelte';
30
30
  import EditorSettings from './EditorSettings.svelte';
31
31
  import S3FilePicker from './S3FilePicker.svelte';
32
+ import DucklakeIcon from './icons/DucklakeIcon.svelte';
32
33
  let { lang, editor, websocketAlive, iconOnly = false, validCode = true, kind = 'script', template = 'script', collabMode = false, collabLive = false, collabUsers = [], scriptPath = undefined, diffEditor = undefined, args, noHistory = false, saveToWorkspace = false, customUi = {}, lastDeployedCode = undefined, diffMode = false, showHistoryDrawer = $bindable(false), right, openAiChat = false } = $props();
33
34
  let contextualVariablePicker = $state();
34
35
  let variablePicker = $state();
@@ -37,6 +38,8 @@ let resourceTypePicker = $state();
37
38
  let variableEditor = $state();
38
39
  let resourceEditor = $state();
39
40
  let s3FilePicker = $state();
41
+ let ducklakePicker = $state();
42
+ let databasePicker = $state();
40
43
  let showContextVarPicker = $derived([
41
44
  'python3',
42
45
  'bash',
@@ -82,12 +85,13 @@ let showResourcePicker = $derived([
82
85
  'rust',
83
86
  'csharp',
84
87
  'nu',
85
- 'java',
86
- 'duckdb'
88
+ 'java'
87
89
  // for related places search: ADD_NEW_LANG
88
90
  ].includes(lang ?? ''));
89
91
  let showS3Picker = $derived(['duckdb', 'python3'].includes(lang ?? '') ||
90
92
  ['typescript', 'javascript'].includes(scriptLangToEditorLang(lang)));
93
+ let showDucklakePicker = $derived(['duckdb'].includes(lang ?? ''));
94
+ let showDatabasePicker = $derived(['duckdb'].includes(lang ?? ''));
91
95
  let showResourceTypePicker = $derived(['typescript', 'javascript'].includes(scriptLangToEditorLang(lang)) ||
92
96
  lang === 'python3' ||
93
97
  lang === 'php');
@@ -551,6 +555,48 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
551
555
  <ResourceEditorDrawer bind:this={resourceEditor} on:refresh={resourcePicker.openDrawer} />
552
556
  <VariableEditor bind:this={variableEditor} on:create={variablePicker.openDrawer} />
553
557
 
558
+ {#if showDucklakePicker}
559
+ <ItemPicker
560
+ bind:this={ducklakePicker}
561
+ pickCallback={async (_, name) => {
562
+ const connStr = name == 'main' ? 'ducklake' : `ducklake://${name}`
563
+ editor?.insertAtCursor(`ATTACH '${connStr}' AS dl; USE dl;\n`)
564
+ }}
565
+ tooltip="Attach a Ducklake in your DuckDB script. Ducklake allows you to manipulate large data on S3 blob files through a traditional SQL interface."
566
+ documentationLink="https://www.windmill.dev/docs/core_concepts/ducklake"
567
+ itemName="ducklake"
568
+ loadItems={async () =>
569
+ (await WorkspaceService.listDucklakes({ workspace: $workspaceStore ?? 'NO_W' })).map(
570
+ (path) => ({ path })
571
+ )}
572
+ />
573
+ {/if}
574
+
575
+ {#if showDatabasePicker}
576
+ <ItemPicker
577
+ bind:this={databasePicker}
578
+ pickCallback={(path, _, resType) => {
579
+ if (!editor) return
580
+ if (lang == 'duckdb') {
581
+ let t = { postgresql: 'postgres', mysql: 'mysql', bigquery: 'bigquery' }[resType]
582
+ editor.insertAtCursor(`ATTACH 'res://${path}' AS db (TYPE ${t});`)
583
+ }
584
+ sendUserToast(`${path} inserted at cursor`)
585
+ }}
586
+ tooltip="Attach a database resource in your script. This allows you to query data from the database using SQL."
587
+ documentationLink="https://www.windmill.dev/docs/core_concepts/resources_and_types"
588
+ itemName="Database"
589
+ buttons={{ 'Edit/View': (x) => resourceEditor?.initEdit(x) }}
590
+ extraField="description"
591
+ extraField2="resource_type"
592
+ loadItems={async () =>
593
+ await ResourceService.listResource({
594
+ workspace: $workspaceStore ?? 'NO_W',
595
+ resourceType: 'postgresql,mysql,bigquery'
596
+ })}
597
+ ></ItemPicker>
598
+ {/if}
599
+
554
600
  <S3FilePicker
555
601
  bind:this={s3FilePicker}
556
602
  readOnlyMode={false}
@@ -664,6 +710,38 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
664
710
  </Button>
665
711
  {/if}
666
712
 
713
+ {#if showDatabasePicker && customUi?.database != false}
714
+ <Button
715
+ aiId="editor-bar-add-database"
716
+ aiDescription="Add database"
717
+ title="Add database"
718
+ color="light"
719
+ on:click={() => databasePicker?.openDrawer()}
720
+ size="xs"
721
+ btnClasses="!font-medium text-tertiary"
722
+ spacingSize="md"
723
+ startIcon={{ icon: DatabaseIcon }}
724
+ {iconOnly}
725
+ >+Database
726
+ </Button>
727
+ {/if}
728
+
729
+ {#if showDucklakePicker && customUi?.ducklake != false}
730
+ <Button
731
+ aiId="editor-bar-use-ducklake"
732
+ aiDescription="Use Ducklake"
733
+ title="Use Ducklake"
734
+ color="light"
735
+ on:click={() => ducklakePicker?.openDrawer()}
736
+ size="xs"
737
+ btnClasses="!font-medium text-tertiary"
738
+ spacingSize="md"
739
+ startIcon={{ icon: DucklakeIcon }}
740
+ {iconOnly}
741
+ >+Ducklake
742
+ </Button>
743
+ {/if}
744
+
667
745
  {#if customUi?.reset != false}
668
746
  <Button
669
747
  aiId="editor-bar-reset-content"