windmill-components 1.504.6 → 1.510.1

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 (196) hide show
  1. package/package/ata/index.js +1 -1
  2. package/package/components/AppConnectInner.svelte +161 -29
  3. package/package/components/ArgInput.svelte +33 -103
  4. package/package/components/AuthSettings.svelte +45 -1
  5. package/package/components/Dev.svelte +31 -24
  6. package/package/components/DisplayResult.svelte +53 -26
  7. package/package/components/DisplayResult.svelte.d.ts +1 -1
  8. package/package/components/DynSelect.svelte +3 -3
  9. package/package/components/Editor.svelte +7 -4
  10. package/package/components/EditorBar.svelte +2 -2
  11. package/package/components/ErrorOrRecoveryHandler.svelte +73 -67
  12. package/package/components/ErrorOrRecoveryHandler.svelte.d.ts +8 -24
  13. package/package/components/FlowBuilder.svelte +11 -2
  14. package/package/components/FlowJobResult.svelte +12 -17
  15. package/package/components/FlowJobResult.svelte.d.ts +5 -18
  16. package/package/components/FlowPreviewContent.svelte +13 -10
  17. package/package/components/FlowPreviewContent.svelte.d.ts +1 -1
  18. package/package/components/FlowPreviewResult.svelte +14 -6
  19. package/package/components/FlowStatusViewer.svelte +11 -24
  20. package/package/components/FlowStatusViewer.svelte.d.ts +19 -18
  21. package/package/components/FlowStatusViewerInner.svelte +110 -131
  22. package/package/components/FlowStatusViewerInner.svelte.d.ts +20 -18
  23. package/package/components/GitDiffPreview.svelte +55 -0
  24. package/package/components/GitDiffPreview.svelte.d.ts +13 -0
  25. package/package/components/HistoricInputs.svelte +2 -2
  26. package/package/components/InitGitRepoPopover.svelte +410 -0
  27. package/package/components/InitGitRepoPopover.svelte.d.ts +13 -0
  28. package/package/components/InstanceSetting.svelte +21 -9
  29. package/package/components/InstanceSettings.svelte +16 -3
  30. package/package/components/JobLoader.svelte +567 -0
  31. package/package/components/JobLoader.svelte.d.ts +53 -0
  32. package/package/components/JobLogs.svelte +6 -4
  33. package/package/components/JobLogs.svelte.d.ts +5 -18
  34. package/package/components/LightweightResourcePicker.svelte +18 -39
  35. package/package/components/LightweightResourcePicker.svelte.d.ts +6 -22
  36. package/package/components/LogViewer.svelte +35 -41
  37. package/package/components/LogViewer.svelte.d.ts +6 -20
  38. package/package/components/ModulePreviewResultViewer.svelte +3 -1
  39. package/package/components/ModulePreviewResultViewer.svelte.d.ts +1 -0
  40. package/package/components/ModuleTest.svelte +16 -11
  41. package/package/components/PullGitRepoPopover.svelte +355 -0
  42. package/package/components/PullGitRepoPopover.svelte.d.ts +18 -0
  43. package/package/components/S3FilePicker.svelte +5 -3
  44. package/package/components/SavedInputs.svelte +2 -2
  45. package/package/components/ScriptBuilder.svelte +4 -3
  46. package/package/components/ScriptEditor.svelte +34 -31
  47. package/package/components/ScriptEditor.svelte.d.ts +3 -3
  48. package/package/components/ServiceLogsInner.svelte +2 -1
  49. package/package/components/ServiceLogsInner.svelte.d.ts +1 -0
  50. package/package/components/UserSettings.svelte +1 -1
  51. package/package/components/WorkerTagSelect.svelte +32 -3
  52. package/package/components/apps/components/buttons/AppButton.svelte +7 -1
  53. package/package/components/apps/components/buttons/AppButton.svelte.d.ts +1 -0
  54. package/package/components/apps/components/display/AppCustomComponent.svelte +1 -1
  55. package/package/components/apps/components/display/AppDisplayComponentByJobId.svelte +16 -11
  56. package/package/components/apps/components/display/AppJobIdLogComponent.svelte +13 -10
  57. package/package/components/apps/components/display/AppMenu.svelte +5 -0
  58. package/package/components/apps/components/display/dbtable/AppDbExplorer.svelte +3 -3
  59. package/package/components/apps/components/display/dbtable/DeleteRow.svelte +3 -3
  60. package/package/components/apps/components/display/dbtable/InsertRowRunnable.svelte +3 -3
  61. package/package/components/apps/components/display/dbtable/UpdateCell.svelte +3 -3
  62. package/package/components/apps/components/display/table/AppAggridInfiniteTable.svelte +3 -3
  63. package/package/components/apps/components/helpers/RunnableComponent.svelte +65 -54
  64. package/package/components/apps/components/helpers/RunnableComponent.svelte.d.ts +5 -5
  65. package/package/components/apps/components/inputs/AppUserResource.svelte +26 -8
  66. package/package/components/apps/editor/AppEditorHeader.svelte +11 -5
  67. package/package/components/apps/editor/AppJobsDrawer.svelte +5 -5
  68. package/package/components/apps/editor/RunnableJobPanel.svelte +4 -4
  69. package/package/components/apps/editor/component/components.d.ts +12 -0
  70. package/package/components/apps/editor/component/components.js +19 -7
  71. package/package/components/assets/AssetButtons.svelte +38 -0
  72. package/package/components/assets/AssetButtons.svelte.d.ts +15 -0
  73. package/package/components/assets/AssetsDropdownButton.svelte +60 -72
  74. package/package/components/assets/AssetsDropdownButton.svelte.d.ts +3 -4
  75. package/package/components/assets/AssetsUsageDrawer.svelte +10 -10
  76. package/package/components/assets/JobAssetsViewer.svelte +79 -0
  77. package/package/components/assets/JobAssetsViewer.svelte.d.ts +7 -0
  78. package/package/components/assets/README_DEV.md +0 -0
  79. package/package/components/assets/lib.d.ts +9 -1
  80. package/package/components/assets/lib.js +48 -7
  81. package/package/components/common/fileUpload/FileUpload.svelte +126 -84
  82. package/package/components/common/fileUpload/FileUpload.svelte.d.ts +13 -3
  83. package/package/components/common/fileUpload/S3ArgInput.svelte +111 -0
  84. package/package/components/common/fileUpload/S3ArgInput.svelte.d.ts +21 -0
  85. package/package/components/common/table/ScriptRow.svelte +3 -1
  86. package/package/components/copilot/autocomplete/Autocompletor.js +23 -5
  87. package/package/components/copilot/chat/AIChatDisplay.svelte +8 -0
  88. package/package/components/copilot/chat/AIChatManager.svelte.js +13 -8
  89. package/package/components/copilot/chat/flow/ModuleAcceptReject.svelte +5 -5
  90. package/package/components/copilot/chat/flow/core.d.ts +1 -1
  91. package/package/components/copilot/chat/flow/core.js +2 -38
  92. package/package/components/copilot/chat/navigator/apiTools.d.ts +8 -0
  93. package/package/components/copilot/chat/navigator/apiTools.js +95 -15
  94. package/package/components/copilot/chat/navigator/core.d.ts +1 -1
  95. package/package/components/copilot/chat/navigator/core.js +2 -1
  96. package/package/components/copilot/chat/script/core.d.ts +11 -2
  97. package/package/components/copilot/chat/script/core.js +135 -1
  98. package/package/components/copilot/chat/shared.d.ts +10 -0
  99. package/package/components/copilot/chat/shared.js +56 -0
  100. package/package/components/copilot/lib.d.ts +1 -0
  101. package/package/components/copilot/lib.js +27 -9
  102. package/package/components/custom_ui.d.ts +1 -0
  103. package/package/components/flows/FlowAssetsHandler.svelte +133 -0
  104. package/package/components/flows/FlowAssetsHandler.svelte.d.ts +14 -0
  105. package/package/components/flows/content/FlowModuleComponent.svelte +16 -18
  106. package/package/components/flows/flowStore.d.ts +1 -1
  107. package/package/components/flows/map/FlowModuleSchemaItem.svelte +1 -0
  108. package/package/components/flows/propPicker/OutputPicker.svelte +9 -4
  109. package/package/components/flows/scheduleUtils.js +1 -1
  110. package/package/components/flows/types.d.ts +2 -1
  111. package/package/components/graph/FlowGraphV2.svelte +8 -104
  112. package/package/components/graph/FlowGraphV2.svelte.d.ts +0 -2
  113. package/package/components/graph/graphBuilder.svelte.d.ts +6 -3
  114. package/package/components/graph/graphBuilder.svelte.js +35 -9
  115. package/package/components/graph/renderers/edges/BaseEdge.svelte +2 -5
  116. package/package/components/graph/renderers/edges/BaseEdge.svelte.d.ts +1 -0
  117. package/package/components/graph/renderers/nodes/AssetNode.svelte +23 -20
  118. package/package/components/graph/renderers/nodes/AssetNode.svelte.d.ts +5 -10
  119. package/package/components/graph/renderers/nodes/AssetsOverflowedNode.svelte +1 -1
  120. package/package/components/graph/util.js +1 -1
  121. package/package/components/home/ItemsList.svelte +2 -0
  122. package/package/components/icons/AssetGenericIcon.svelte +0 -3
  123. package/package/components/jobs/JobPreview.svelte +10 -6
  124. package/package/components/raw_apps/RawAppInlineScriptRunnable.svelte +13 -12
  125. package/package/components/runs/BatchReRunOptionsPane.svelte +5 -1
  126. package/package/components/runs/JobPreview.svelte +26 -16
  127. package/package/components/runs/{JobLoader.svelte.d.ts → JobsLoader.svelte.d.ts} +3 -3
  128. package/package/components/runs/NoWorkerWithTagWarning.svelte +2 -2
  129. package/package/components/runs/NoWorkerWithTagWarning.svelte.d.ts +1 -0
  130. package/package/components/runs/RunsFilter.svelte.d.ts +1 -1
  131. package/package/components/scriptEditor/LogPanel.svelte +3 -2
  132. package/package/components/script_builder.d.ts +2 -2
  133. package/package/components/settings/CreateToken.svelte +76 -41
  134. package/package/components/settings/CreateToken.svelte.d.ts +1 -1
  135. package/package/components/settings/ScopeSelector.svelte +613 -0
  136. package/package/components/settings/ScopeSelector.svelte.d.ts +8 -0
  137. package/package/components/settings/TokenDisplay.svelte +103 -0
  138. package/package/components/settings/TokenDisplay.svelte.d.ts +10 -0
  139. package/package/components/settings/TokensTable.svelte +70 -349
  140. package/package/components/sidebar/CriticalAlertModal.svelte +3 -0
  141. package/package/components/triggers/DeleteTriggerButton.svelte +1 -1
  142. package/package/components/triggers/TriggerEditorToolbar.svelte +3 -3
  143. package/package/components/triggers/TriggerRetriesAndErrorHandler.svelte +55 -0
  144. package/package/components/triggers/TriggerRetriesAndErrorHandler.svelte.d.ts +13 -0
  145. package/package/components/triggers/TriggersEditor.svelte +45 -3
  146. package/package/components/triggers/TriggersWrapper.svelte +2 -2
  147. package/package/components/triggers/gcp/GcpTriggerEditorInner.svelte +43 -2
  148. package/package/components/triggers/gcp/utils.js +9 -1
  149. package/package/components/triggers/http/OpenAPISpecGenerator.svelte +1 -0
  150. package/package/components/triggers/http/RouteEditorInner.svelte +208 -164
  151. package/package/components/triggers/http/RouteEditorInner.svelte.d.ts +6 -2
  152. package/package/components/triggers/http/utils.js +9 -3
  153. package/package/components/triggers/kafka/KafkaTriggerEditorInner.svelte +43 -2
  154. package/package/components/triggers/kafka/utils.js +9 -1
  155. package/package/components/triggers/mqtt/MqttEditorConfigSection.svelte +4 -132
  156. package/package/components/triggers/mqtt/MqttEditorConfigSection.svelte.d.ts +2 -5
  157. package/package/components/triggers/mqtt/MqttTriggerEditorInner.svelte +178 -9
  158. package/package/components/triggers/mqtt/utils.js +9 -1
  159. package/package/components/triggers/nats/NatsTriggerEditorInner.svelte +43 -2
  160. package/package/components/triggers/nats/utils.js +9 -1
  161. package/package/components/triggers/postgres/PostgresTriggerEditorInner.svelte +41 -2
  162. package/package/components/triggers/postgres/utils.js +9 -1
  163. package/package/components/triggers/schedules/ScheduleEditorInner.svelte +34 -88
  164. package/package/components/triggers/sqs/SqsTriggerEditorInner.svelte +43 -2
  165. package/package/components/triggers/sqs/utils.js +9 -1
  166. package/package/components/triggers/utils.js +12 -0
  167. package/package/components/triggers/websocket/WebsocketTriggerEditorInner.svelte +43 -2
  168. package/package/components/triggers/websocket/utils.js +11 -1
  169. package/package/components/workspaceSettings/AISettings.svelte +0 -2
  170. package/package/components/workspaceSettings/FilterList.svelte +56 -0
  171. package/package/components/workspaceSettings/FilterList.svelte.d.ts +8 -0
  172. package/package/components/workspaceSettings/GitSyncFilterSettings.svelte +785 -0
  173. package/package/components/workspaceSettings/GitSyncFilterSettings.svelte.d.ts +18 -0
  174. package/package/gen/core/OpenAPI.js +1 -1
  175. package/package/gen/schemas.gen.d.ts +305 -23
  176. package/package/gen/schemas.gen.js +305 -23
  177. package/package/gen/services.gen.d.ts +33 -1
  178. package/package/gen/services.gen.js +66 -2
  179. package/package/gen/types.gen.d.ts +216 -11
  180. package/package/history.svelte.js +0 -2
  181. package/package/hub.d.ts +1 -0
  182. package/package/hubPaths.json +5 -2
  183. package/package/infer.js +16 -10
  184. package/package/svelte5Utils.svelte.d.ts +1 -0
  185. package/package/svelte5Utils.svelte.js +25 -18
  186. package/package/toast.js +10 -0
  187. package/package/utils.d.ts +3 -2
  188. package/package/utils.js +20 -5
  189. package/package.json +11 -11
  190. package/package/components/ResultJobLoader.svelte +0 -219
  191. package/package/components/ResultJobLoader.svelte.d.ts +0 -52
  192. package/package/components/TestJobLoader.svelte +0 -274
  193. package/package/components/TestJobLoader.svelte.d.ts +0 -43
  194. package/package/components/icons/AssetVarIcon.svelte +0 -31
  195. package/package/components/icons/AssetVarIcon.svelte.d.ts +0 -9
  196. /package/package/components/runs/{JobLoader.svelte → JobsLoader.svelte} +0 -0
@@ -223,7 +223,7 @@ function getDTName(s) {
223
223
  if (s.indexOf('@') === 0 && s.indexOf('/') !== -1) {
224
224
  // we have a scoped module, e.g. @bla/foo
225
225
  // which should be converted to bla__foo
226
- s = s.substr(1).replace('/', '__');
226
+ s = s.substring(1).replace('/', '__');
227
227
  }
228
228
  return s;
229
229
  }
@@ -19,6 +19,7 @@ import Toggle from './Toggle.svelte';
19
19
  import { Pen } from 'lucide-svelte';
20
20
  import GfmMarkdown from './GfmMarkdown.svelte';
21
21
  import { apiTokenApps, forceSecretValue, linkedSecretValue } from './app_connect';
22
+ import Tooltip from './Tooltip.svelte';
22
23
  let { step = $bindable(1), resourceType = $bindable(''), isGoogleSignin = $bindable(false), disabled = $bindable(false), manual = $bindable(true), express = false } = $props();
23
24
  let isValid = $state(true);
24
25
  const nativeLanguagesCategory = [
@@ -52,8 +53,27 @@ function computeLinkedSecret(resourceType, argsKeys, passwords) {
52
53
  }
53
54
  let scopes = $state([]);
54
55
  let extra_params = [];
56
+ let responseExtra = $state({});
55
57
  let path = $state('');
56
58
  let description = $state('');
59
+ /**
60
+ * Client credentials OAuth flow support
61
+ * @description Determines if the selected OAuth provider supports client_credentials grant type
62
+ * alongside the traditional authorization_code flow
63
+ */
64
+ let supportsClientCredentials = $state(false);
65
+ /**
66
+ * OAuth flow selection
67
+ * @description Controls which OAuth flow to use:
68
+ * - false: authorization_code flow (interactive, requires user consent)
69
+ * - true: client_credentials flow (server-to-server, no user interaction)
70
+ */
71
+ let useClientCredentials = $state(false);
72
+ /**
73
+ * Client credentials for resource-level OAuth
74
+ */
75
+ let clientId = $state('');
76
+ let clientSecret = $state('');
57
77
  let resourceTypeInfo = $state(undefined);
58
78
  let pathError = $state('');
59
79
  export async function open(rt) {
@@ -65,6 +85,11 @@ export async function open(rt) {
65
85
  description = '';
66
86
  resourceType = rt ?? '';
67
87
  valueToken = undefined;
88
+ // Reset client credentials state
89
+ supportsClientCredentials = false;
90
+ useClientCredentials = false;
91
+ clientId = '';
92
+ clientSecret = '';
68
93
  await loadConnects();
69
94
  manual = !connects?.includes(resourceType);
70
95
  if (manual && express) {
@@ -106,13 +131,15 @@ run(() => {
106
131
  disabled =
107
132
  (step == 1 && resourceType == '') ||
108
133
  (step == 2 &&
109
- value == '' &&
110
- args &&
111
- args['token'] == '' &&
112
- args['password'] == '' &&
113
- args['api_key'] == '' &&
114
- args['key'] == '' &&
115
- linkedSecret != undefined) ||
134
+ (manual
135
+ ? value == '' &&
136
+ args &&
137
+ args['token'] == '' &&
138
+ args['password'] == '' &&
139
+ args['api_key'] == '' &&
140
+ args['key'] == '' &&
141
+ linkedSecret != undefined
142
+ : false)) ||
116
143
  step == 3 ||
117
144
  (step == 4 && pathError != '') ||
118
145
  !isValid;
@@ -187,6 +214,7 @@ function processPopupData(data) {
187
214
  resourceType = data.resource_type;
188
215
  value = data.res.access_token;
189
216
  valueToken = data.res;
217
+ responseExtra = data.extra ?? {};
190
218
  step = 4;
191
219
  if (express) {
192
220
  path = `u/${$userStore?.username}/${resourceType}_${new Date().getTime()}`;
@@ -198,6 +226,11 @@ async function getScopesAndParams() {
198
226
  const connect = await OauthService.getOauthConnect({ client: resourceType });
199
227
  scopes = connect.scopes ?? [];
200
228
  extra_params = Object.entries(connect.extra_params ?? {});
229
+ /**
230
+ * Check if the OAuth provider supports client_credentials grant type
231
+ * This determines whether to show the OAuth flow selection UI
232
+ */
233
+ supportsClientCredentials = connect.grant_types?.includes('client_credentials') ?? false;
201
234
  }
202
235
  async function getResourceTypeInfo() {
203
236
  resourceTypeInfo = await ResourceService.getResourceType({
@@ -227,20 +260,61 @@ export async function next() {
227
260
  step += 1;
228
261
  }
229
262
  else if (step == 2 && !manual) {
230
- const url = new URL(`/api/oauth/connect/${resourceType}`, window.location.origin);
231
- url.searchParams.append('scopes', scopes.join('+'));
232
- if (extra_params.length > 0) {
233
- extra_params.forEach(([key, value]) => url.searchParams.append(key, value));
263
+ if (useClientCredentials) {
264
+ /**
265
+ * Client credentials flow: Direct API call to backend
266
+ * No popup window or user interaction required
267
+ * Uses instance-level OAuth credentials for server-to-server auth
268
+ */
269
+ try {
270
+ // Trim whitespace from credentials to avoid false negatives
271
+ const trimmedClientId = clientId.trim();
272
+ const trimmedClientSecret = clientSecret.trim();
273
+ // Validate required fields
274
+ if (!trimmedClientId || !trimmedClientSecret) {
275
+ sendUserToast('Client ID and Client Secret are required for client credentials flow', true);
276
+ return;
277
+ }
278
+ const tokenResponse = await OauthService.connectClientCredentials({
279
+ client: resourceType,
280
+ requestBody: {
281
+ scopes: scopes,
282
+ cc_client_id: trimmedClientId,
283
+ cc_client_secret: trimmedClientSecret
284
+ }
285
+ });
286
+ // Process the token response like in popup flow
287
+ value = tokenResponse.access_token;
288
+ valueToken = {
289
+ ...tokenResponse,
290
+ grant_type: 'client_credentials' // Mark this token as client_credentials
291
+ };
292
+ step = 4;
293
+ if (express) {
294
+ path = `u/${$userStore?.username}/${resourceType}_${new Date().getTime()}`;
295
+ next();
296
+ }
297
+ }
298
+ catch (error) {
299
+ sendUserToast(`Failed to connect with client credentials: ${error.body || error.message}`, true);
300
+ }
301
+ }
302
+ else {
303
+ /**
304
+ * Authorization code flow: Traditional OAuth popup window
305
+ * Requires user interaction and consent
306
+ * Opens popup for user to authenticate with OAuth provider
307
+ */
308
+ const url = new URL(`/api/oauth/connect/${resourceType}`, window.location.origin);
309
+ url.searchParams.append('scopes', scopes.join('+'));
310
+ if (extra_params.length > 0) {
311
+ extra_params.forEach(([key, value]) => url.searchParams.append(key, value));
312
+ }
313
+ window.addEventListener('message', popupListener);
314
+ window.addEventListener('storage', handleStorageEvent);
315
+ window.open(url.toString(), '_blank', 'popup=true');
316
+ step += 1;
234
317
  }
235
- // if (!newPageOAuth) {
236
- // window.location.href = url.toString()
237
- // } else {
238
- window.addEventListener('message', popupListener);
239
- window.addEventListener('storage', handleStorageEvent);
240
- window.open(url.toString(), '_blank', 'popup=true');
241
- step += 1;
242
- // dispatch('close')
243
- // }
244
318
  }
245
319
  else {
246
320
  if (!path) {
@@ -266,15 +340,25 @@ export async function next() {
266
340
  args['account_identifier'] = account_identifier[1];
267
341
  }
268
342
  }
343
+ else if (resourceType === 'quickbooks' && responseExtra['realmId']) {
344
+ args['realmId'] = responseExtra['realmId'];
345
+ }
269
346
  let account = undefined;
270
347
  if (valueToken?.expires_in != undefined) {
348
+ const accountData = {
349
+ refresh_token: valueToken.refresh_token ?? '',
350
+ expires_in: valueToken.expires_in,
351
+ client: resourceType,
352
+ grant_type: valueToken.grant_type || 'authorization_code'
353
+ };
354
+ // Add client credentials if using client_credentials flow
355
+ if (useClientCredentials) {
356
+ accountData.cc_client_id = clientId.trim();
357
+ accountData.cc_client_secret = clientSecret.trim();
358
+ }
271
359
  account = Number(await OauthService.createAccount({
272
360
  workspace: $workspaceStore,
273
- requestBody: {
274
- refresh_token: valueToken.refresh_token ?? '',
275
- expires_in: valueToken.expires_in,
276
- client: resourceType
277
- }
361
+ requestBody: accountData
278
362
  }));
279
363
  }
280
364
  const resourceValue = args;
@@ -532,14 +616,58 @@ let editScopes = $state(false);
532
616
  {#if manual == false && resourceType != ''}
533
617
  <h1 class="mb-4">{resourceType}</h1>
534
618
  <div class="my-4 text-secondary"
535
- >Click connect to create a resource backed by an oauth connection, whose token is fetched
536
- from the external services and refreshed automatically if needed before expiration (using
537
- its refresh token)</div
619
+ >Create a resource backed by an OAuth connection, whose token is fetched from the external
620
+ services and refreshed automatically if needed before expiration.</div
538
621
  >
539
622
  <h4 class="mb-2">Description</h4>
540
623
  <div class="text-sm mb-8">
541
624
  <Markdown md={urlize(resourceTypeInfo?.description ?? '', 'md')} />
542
625
  </div>
626
+
627
+ {#if supportsClientCredentials}
628
+ <div style="margin-bottom: 16px;">
629
+ <h3 class="mb-4">Authentication Method</h3>
630
+ <div style="display: flex; align-items: center; gap: 8px;">
631
+ <input
632
+ type="checkbox"
633
+ style="width: 16px; height: 16px; margin: 0;"
634
+ bind:checked={useClientCredentials}
635
+ />
636
+ <span style="font-size: 14px; font-weight: 600;">Use Client Credentials Flow</span>
637
+ <Tooltip>
638
+ Server-to-server authentication without user interaction.
639
+ <br /><br />
640
+ Provide your own OAuth client credentials for this resource.
641
+ </Tooltip>
642
+ </div>
643
+
644
+ {#if useClientCredentials}
645
+ <div style="margin-top: 16px;">
646
+ <label style="display: block; margin-bottom: 8px;">
647
+ <span style="font-weight: 600;">Client ID</span>
648
+ <input
649
+ type="text"
650
+ bind:value={clientId}
651
+ placeholder="Enter OAuth client ID"
652
+ class="w-full p-2 border border-gray-300 rounded mt-1"
653
+ required
654
+ />
655
+ </label>
656
+ <label style="display: block;">
657
+ <span style="font-weight: 600;">Client Secret</span>
658
+ <input
659
+ type="password"
660
+ bind:value={clientSecret}
661
+ placeholder="Enter OAuth client secret"
662
+ class="w-full p-2 border border-gray-300 rounded mt-1"
663
+ required
664
+ />
665
+ </label>
666
+ </div>
667
+ {/if}
668
+ </div>
669
+ {/if}
670
+
543
671
  <h3 class="mb-4 flex gap-4"
544
672
  >Scopes <button
545
673
  onclick={() => {
@@ -559,7 +687,11 @@ let editScopes = $state(false);
559
687
  {/if}
560
688
  {/if}
561
689
  {:else if step == 3 && !manual && !express}
562
- Finish connection in popup window
690
+ {#if useClientCredentials}
691
+ Connecting with client credentials...
692
+ {:else}
693
+ Finish connection in popup window
694
+ {/if}
563
695
  {:else}
564
696
  <Path
565
697
  initialPath=""
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">import { preventDefault, stopPropagation, createBubbler } from 'svelte/legacy';
2
2
  const bubble = createBubbler();
3
3
  import { setInputCat as computeInputCat, debounce, emptyString, getSchemaFromProperties } from '../utils';
4
- import { DollarSign, Pipette, Plus, X, Check, Loader2 } from 'lucide-svelte';
4
+ import { DollarSign, Plus, X, Check, Loader2 } from 'lucide-svelte';
5
5
  import { createEventDispatcher, onDestroy, onMount, tick, untrack } from 'svelte';
6
6
  import { fade } from 'svelte/transition';
7
7
  import { Button, SecondsInput } from './common';
@@ -14,9 +14,7 @@ import { twMerge } from 'tailwind-merge';
14
14
  import ArgEnum from './ArgEnum.svelte';
15
15
  import DateTimeInput from './DateTimeInput.svelte';
16
16
  import DateInput from './DateInput.svelte';
17
- import S3FilePicker from './S3FilePicker.svelte';
18
17
  import CurrencyInput from './apps/components/inputs/currency/CurrencyInput.svelte';
19
- import FileUpload from './common/fileUpload/FileUpload.svelte';
20
18
  import autosize from '../autosize';
21
19
  import PasswordArgInput from './PasswordArgInput.svelte';
22
20
  import Password from './Password.svelte';
@@ -28,6 +26,7 @@ import { deepEqual } from 'fast-equals';
28
26
  import DynSelect from './DynSelect.svelte';
29
27
  import MultiSelect from './select/MultiSelect.svelte';
30
28
  import { safeSelectItems } from './select/utils.svelte';
29
+ import S3ArgInput from './common/fileUpload/S3ArgInput.svelte';
31
30
  let { label = '', value = $bindable(), defaultValue = $bindable(undefined), description = $bindable(undefined), format = $bindable(undefined), contentEncoding = undefined, type = undefined, oneOf = $bindable(undefined), required = false, pattern = $bindable(undefined), valid = $bindable(undefined), enum_ = $bindable(undefined), disabled = false, itemsType = $bindable(undefined), displayHeader = true, properties = $bindable(undefined), nestedRequired = undefined, autofocus = null, compact = false, password = false, pickForField = $bindable(undefined), variableEditor = undefined, itemPicker = undefined, noMargin = false, extra = {}, minW = true, prettifyHeader = false, resourceTypes, disablePortal = false, showSchemaExplorer = false, simpleTooltip = undefined, customErrorMessage = undefined, onlyMaskPassword = false, nullable = false, title = $bindable(undefined), placeholder = $bindable(undefined), order = $bindable(undefined), editor = $bindable(undefined), orderEditable = false, shouldDispatchChanges = false, noDefaultOnSelectFirst = false, helperScript = undefined, otherArgs = {}, lightHeader = false, diffStatus = undefined, hideNested = false, nestedParent = undefined, nestedClasses = '', displayType = true, css = undefined, appPath = undefined, computeS3ForceViewerPolicies = undefined, workspace = undefined, actions } = $props();
32
31
  $effect(() => {
33
32
  if (description == undefined) {
@@ -72,8 +71,6 @@ function onOneOfChange() {
72
71
  const dispatch = createEventDispatcher();
73
72
  let ignoreValueUndefined = $state(false);
74
73
  let error = $state('');
75
- let s3FilePicker = $state();
76
- let s3FileUploadRawMode = $state(false);
77
74
  let isListJson = $state(false);
78
75
  let hasIsListJsonChanged = $state(false);
79
76
  let el = $state(undefined);
@@ -326,16 +323,6 @@ onDestroy(() => {
326
323
  });
327
324
  </script>
328
325
 
329
- <S3FilePicker
330
- bind:this={s3FilePicker}
331
- bind:selectedFileKey={value}
332
- on:close={() => {
333
- rawValue = JSON.stringify(value, null, 2)
334
- editor?.setCode(rawValue)
335
- }}
336
- readOnlyMode={false}
337
- />
338
-
339
326
  <!-- svelte-ignore a11y_autofocus -->
340
327
  <div
341
328
  class={twMerge(
@@ -458,6 +445,22 @@ onDestroy(() => {
458
445
  <span>&nbsp; Not set</span>
459
446
  {/if}
460
447
  </div>
448
+ {:else if (inputCat == 'resource-object' && format && format.split('-').length > 1 && format
449
+ .replace('resource-', '')
450
+ .replace('_', '')
451
+ .toLowerCase() == 's3object') || (inputCat == 'list' && (itemsType?.resourceType === 's3_object' || itemsType?.resourceType === 's3object'))}
452
+ <S3ArgInput
453
+ multiple={inputCat == 'list'}
454
+ bind:value
455
+ {defaultValue}
456
+ {setNewValueFromCode}
457
+ {workspace}
458
+ onFocus={() => dispatch('focus')}
459
+ onBlur={() => dispatch('blur')}
460
+ bind:editor
461
+ {appPath}
462
+ {computeS3ForceViewerPolicies}
463
+ />
461
464
  {:else if inputCat == 'list' && !isListJson}
462
465
  <div class="w-full flex gap-4">
463
466
  <div class="w-full">
@@ -471,38 +474,24 @@ onDestroy(() => {
471
474
  reorderable
472
475
  />
473
476
  </div>
474
- {:else if itemsType?.enum != undefined && Array.isArray(itemsType?.enum) && (Array.isArray(value) || value == undefined)}
477
+ {:else if enum_ && (Array.isArray(value) || value == undefined)}
475
478
  <div class="items-start">
476
479
  <MultiSelect
477
480
  {disabled}
478
481
  bind:value
479
- items={safeSelectItems(itemsType?.enum)}
482
+ items={safeSelectItems(enum_)}
480
483
  onOpen={() => dispatch('focus')}
481
484
  reorderable
482
485
  />
483
486
  </div>
484
- {:else if itemsType?.type == 'object' && itemsType?.resourceType == 's3object'}
485
- <div class="w-full">
486
- <FileUpload
487
- {appPath}
488
- computeForceViewerPolicies={computeS3ForceViewerPolicies}
489
- {workspace}
490
- allowMultiple={true}
491
- randomFileKey={true}
492
- on:addition={(evt) => {
493
- value = [
494
- ...value,
495
- {
496
- s3: evt.detail?.path ?? '',
497
- filename: evt.detail?.filename ?? ''
498
- }
499
- ]
500
- }}
501
- on:deletion={(evt) => {
502
- value = value.filter((v) => v.s3 !== evt.detail?.path)
503
- }}
504
- defaultValue={defaultValue?.map((v) => v.s3)}
505
- initialValue={value}
487
+ {:else if itemsType?.enum != undefined && Array.isArray(itemsType?.enum) && (Array.isArray(value) || value == undefined)}
488
+ <div class="items-start">
489
+ <MultiSelect
490
+ {disabled}
491
+ bind:value
492
+ items={safeSelectItems(itemsType?.enum)}
493
+ onOpen={() => dispatch('focus')}
494
+ reorderable
506
495
  />
507
496
  </div>
508
497
  {:else}
@@ -575,6 +564,7 @@ onDestroy(() => {
575
564
  {onlyMaskPassword}
576
565
  {disablePortal}
577
566
  {disabled}
567
+ {prettifyHeader}
578
568
  schema={getSchemaFromProperties(itemsType?.properties)}
579
569
  bind:args={value[i]}
580
570
  />
@@ -678,70 +668,6 @@ onDestroy(() => {
678
668
  }}
679
669
  {showSchemaExplorer}
680
670
  />
681
- {:else if inputCat == 'resource-object' && format && format.split('-').length > 1 && format
682
- .replace('resource-', '')
683
- .replace('_', '')
684
- .toLowerCase() == 's3object'}
685
- <div class="flex flex-col w-full gap-1">
686
- <Toggle
687
- class="flex justify-end"
688
- bind:checked={s3FileUploadRawMode}
689
- size="xs"
690
- options={{ left: 'Raw S3 object input' }}
691
- />
692
- {#if s3FileUploadRawMode}
693
- {#await import('./JsonEditor.svelte')}
694
- <Loader2 class="animate-spin" />
695
- {:then Module}
696
- <Module.default
697
- bind:editor
698
- on:focus={(e) => {
699
- dispatch('focus')
700
- }}
701
- on:blur={(e) => {
702
- dispatch('blur')
703
- }}
704
- code={JSON.stringify(value ?? defaultValue ?? { s3: '' }, null, 2)}
705
- on:changeValue={(e) => {
706
- setNewValueFromCode(e.detail)
707
- }}
708
- />
709
- {/await}
710
- {:else}
711
- <FileUpload
712
- {appPath}
713
- computeForceViewerPolicies={computeS3ForceViewerPolicies}
714
- {workspace}
715
- allowMultiple={false}
716
- randomFileKey={true}
717
- on:addition={(evt) => {
718
- value = {
719
- s3: evt.detail?.path ?? '',
720
- filename: evt.detail?.filename ?? ''
721
- }
722
- }}
723
- on:deletion={(evt) => {
724
- value = {
725
- s3: ''
726
- }
727
- }}
728
- defaultValue={defaultValue?.s3}
729
- initialValue={value}
730
- />
731
- {/if}
732
- <Button
733
- variant="border"
734
- color="light"
735
- size="xs"
736
- btnClasses="mt-1"
737
- on:click={() => {
738
- s3FilePicker?.open?.(value)
739
- }}
740
- startIcon={{ icon: Pipette }}
741
- >
742
- Choose an object from the catalog
743
- </Button>
744
- </div>
745
671
  {:else if inputCat == 'object' || inputCat == 'resource-object' || isListJson}
746
672
  {#if oneOf && oneOf.length >= 2}
747
673
  <div class="flex flex-col gap-2 w-full">
@@ -781,6 +707,7 @@ onDestroy(() => {
781
707
  {onlyMaskPassword}
782
708
  {disablePortal}
783
709
  {disabled}
710
+ {prettifyHeader}
784
711
  bind:schema={
785
712
  () => ({
786
713
  properties: obj.properties ?? {},
@@ -811,6 +738,7 @@ onDestroy(() => {
811
738
  {onlyMaskPassword}
812
739
  {disablePortal}
813
740
  {disabled}
741
+ {prettifyHeader}
814
742
  hiddenArgs={['label', 'kind']}
815
743
  schema={{
816
744
  properties: obj.properties,
@@ -886,6 +814,7 @@ onDestroy(() => {
886
814
  {onlyMaskPassword}
887
815
  {disablePortal}
888
816
  {disabled}
817
+ {prettifyHeader}
889
818
  bind:schema={
890
819
  () => ({
891
820
  properties,
@@ -921,6 +850,7 @@ onDestroy(() => {
921
850
  {onlyMaskPassword}
922
851
  {disablePortal}
923
852
  {disabled}
853
+ {prettifyHeader}
924
854
  schema={{
925
855
  properties,
926
856
  order,
@@ -15,6 +15,7 @@ import { capitalize } from '../utils';
15
15
  import Toggle from './Toggle.svelte';
16
16
  import { ExternalLink, Plus } from 'lucide-svelte';
17
17
  import AzureOauthSettings from './AzureOauthSettings.svelte';
18
+ import Tooltip from './Tooltip.svelte';
18
19
  let { snowflakeAccountIdentifier = $bindable(), oauths = $bindable(), requirePreexistingUserForOauth = $bindable(), scim } = $props();
19
20
  $effect(() => {
20
21
  if (snowflakeAccountIdentifier == undefined) {
@@ -213,6 +214,49 @@ let tab = $state('sso');
213
214
  <span class="text-primary font-semibold text-sm">Client Secret</span>
214
215
  <input type="text" placeholder="Client Secret" bind:value={oauths[k]['secret']} />
215
216
  </label>
217
+ {#if k === 'visma' || !windmillBuiltins.includes(k)}
218
+ <div style="margin-bottom: 8px;">
219
+ <div style="display: flex; align-items: center; gap: 8px;">
220
+ <input
221
+ type="checkbox"
222
+ style="width: 16px; height: 16px; margin: 0;"
223
+ checked={oauths?.[k]?.['grant_types']?.includes('client_credentials') ??
224
+ false}
225
+ onchange={(e) => {
226
+ const target = e.target as HTMLInputElement
227
+ if (oauths && oauths[k]) {
228
+ if (!oauths[k]['grant_types']) {
229
+ oauths[k]['grant_types'] = ['authorization_code']
230
+ }
231
+ if (target.checked) {
232
+ if (!oauths[k]['grant_types'].includes('client_credentials')) {
233
+ oauths[k]['grant_types'] = [
234
+ ...oauths[k]['grant_types'],
235
+ 'client_credentials'
236
+ ]
237
+ }
238
+ } else {
239
+ oauths[k]['grant_types'] = oauths[k]['grant_types'].filter(
240
+ (gt) => gt !== 'client_credentials'
241
+ )
242
+ }
243
+ }
244
+ }}
245
+ />
246
+ <span style="font-size: 14px; font-weight: 600;"
247
+ >Support Client Credentials Flow</span
248
+ >
249
+ <Tooltip>
250
+ Enables server-to-server authentication without user interaction. Use for
251
+ automated scripts and background jobs.
252
+ <br /><br />
253
+ When enabled, users can provide their own client credentials at the resource
254
+ level. The Client ID and Secret configured above are only used for the traditional
255
+ OAuth flow (popup window).
256
+ </Tooltip>
257
+ </div>
258
+ </div>
259
+ {/if}
216
260
  {#if k === 'azure_oauth'}
217
261
  <AzureOauthSettings bind:connect_config={oauths[k]['connect_config']} />
218
262
  {:else if !windmillBuiltins.includes(k) && k != 'slack'}
@@ -265,7 +309,7 @@ let tab = $state('sso');
265
309
  on:click={() => {
266
310
  if (oauths) {
267
311
  let name = oauth_name == 'custom' ? resourceName : oauth_name
268
- oauths[name ?? ''] = { id: '', secret: '' }
312
+ oauths[name ?? ''] = { id: '', secret: '', grant_types: ['authorization_code'] }
269
313
  }
270
314
  resourceName = ''
271
315
  }}