windmill-components 1.504.6 → 1.511.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 (233) hide show
  1. package/package/ata/index.js +1 -1
  2. package/package/components/AppConnectInner.svelte +184 -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 +115 -88
  10. package/package/components/Editor.svelte.d.ts +30 -55
  11. package/package/components/EditorBar.svelte +2 -2
  12. package/package/components/ErrorOrRecoveryHandler.svelte +73 -67
  13. package/package/components/ErrorOrRecoveryHandler.svelte.d.ts +8 -24
  14. package/package/components/FlowBuilder.svelte +11 -2
  15. package/package/components/FlowJobResult.svelte +12 -17
  16. package/package/components/FlowJobResult.svelte.d.ts +5 -18
  17. package/package/components/FlowPreviewContent.svelte +13 -10
  18. package/package/components/FlowPreviewContent.svelte.d.ts +1 -1
  19. package/package/components/FlowPreviewResult.svelte +14 -6
  20. package/package/components/FlowStatusViewer.svelte +11 -24
  21. package/package/components/FlowStatusViewer.svelte.d.ts +19 -18
  22. package/package/components/FlowStatusViewerInner.svelte +110 -131
  23. package/package/components/FlowStatusViewerInner.svelte.d.ts +20 -18
  24. package/package/components/GitDiffPreview.svelte +55 -0
  25. package/package/components/GitDiffPreview.svelte.d.ts +13 -0
  26. package/package/components/HistoricInputs.svelte +2 -2
  27. package/package/components/HttpAgentWorkerDrawer.svelte +1 -1
  28. package/package/components/InitGitRepoPopover.svelte +410 -0
  29. package/package/components/InitGitRepoPopover.svelte.d.ts +13 -0
  30. package/package/components/InstanceSetting.svelte +21 -9
  31. package/package/components/InstanceSettings.svelte +16 -3
  32. package/package/components/JobLoader.svelte +567 -0
  33. package/package/components/JobLoader.svelte.d.ts +53 -0
  34. package/package/components/JobLogs.svelte +6 -4
  35. package/package/components/JobLogs.svelte.d.ts +5 -18
  36. package/package/components/JsonEditor.svelte +11 -11
  37. package/package/components/JsonEditor.svelte.d.ts +14 -56
  38. package/package/components/Label.svelte +6 -11
  39. package/package/components/Label.svelte.d.ts +14 -39
  40. package/package/components/LightweightResourcePicker.svelte +18 -39
  41. package/package/components/LightweightResourcePicker.svelte.d.ts +6 -22
  42. package/package/components/LogViewer.svelte +35 -41
  43. package/package/components/LogViewer.svelte.d.ts +6 -20
  44. package/package/components/ModulePreviewResultViewer.svelte +3 -1
  45. package/package/components/ModulePreviewResultViewer.svelte.d.ts +1 -0
  46. package/package/components/ModuleTest.svelte +16 -11
  47. package/package/components/NumberTypeNarrowing.svelte +13 -16
  48. package/package/components/NumberTypeNarrowing.svelte.d.ts +4 -18
  49. package/package/components/PullGitRepoPopover.svelte +355 -0
  50. package/package/components/PullGitRepoPopover.svelte.d.ts +18 -0
  51. package/package/components/ResourceTypePicker.svelte +20 -17
  52. package/package/components/ResourceTypePicker.svelte.d.ts +7 -6
  53. package/package/components/S3FilePicker.svelte +5 -3
  54. package/package/components/SavedInputs.svelte +2 -2
  55. package/package/components/ScriptBuilder.svelte +4 -3
  56. package/package/components/ScriptEditor.svelte +34 -31
  57. package/package/components/ScriptEditor.svelte.d.ts +3 -3
  58. package/package/components/Section.svelte +7 -20
  59. package/package/components/Section.svelte.d.ts +20 -47
  60. package/package/components/ServiceLogsInner.svelte +2 -1
  61. package/package/components/ServiceLogsInner.svelte.d.ts +1 -0
  62. package/package/components/SimpleEditor.svelte +4 -4
  63. package/package/components/SimpleEditor.svelte.d.ts +1 -0
  64. package/package/components/SqlRepl.svelte +0 -1
  65. package/package/components/Subsection.svelte +10 -12
  66. package/package/components/Subsection.svelte.d.ts +15 -39
  67. package/package/components/UserSettings.svelte +1 -1
  68. package/package/components/WorkerGroup.svelte +260 -165
  69. package/package/components/WorkerGroup.svelte.d.ts +2 -0
  70. package/package/components/WorkerTagPicker.svelte +3 -3
  71. package/package/components/WorkerTagSelect.svelte +33 -4
  72. package/package/components/apps/components/buttons/AppButton.svelte +7 -1
  73. package/package/components/apps/components/buttons/AppButton.svelte.d.ts +1 -0
  74. package/package/components/apps/components/display/AppCustomComponent.svelte +1 -1
  75. package/package/components/apps/components/display/AppDisplayComponentByJobId.svelte +16 -11
  76. package/package/components/apps/components/display/AppJobIdLogComponent.svelte +13 -10
  77. package/package/components/apps/components/display/AppMenu.svelte +5 -0
  78. package/package/components/apps/components/display/dbtable/AppDbExplorer.svelte +3 -3
  79. package/package/components/apps/components/display/dbtable/DeleteRow.svelte +3 -3
  80. package/package/components/apps/components/display/dbtable/InsertRowRunnable.svelte +3 -3
  81. package/package/components/apps/components/display/dbtable/UpdateCell.svelte +3 -3
  82. package/package/components/apps/components/display/table/AppAggridInfiniteTable.svelte +3 -3
  83. package/package/components/apps/components/helpers/RunnableComponent.svelte +65 -54
  84. package/package/components/apps/components/helpers/RunnableComponent.svelte.d.ts +5 -5
  85. package/package/components/apps/components/inputs/AppUserResource.svelte +26 -8
  86. package/package/components/apps/editor/AppEditorHeader.svelte +11 -5
  87. package/package/components/apps/editor/AppJobsDrawer.svelte +5 -5
  88. package/package/components/apps/editor/RunnableJobPanel.svelte +4 -4
  89. package/package/components/apps/editor/component/components.d.ts +12 -0
  90. package/package/components/apps/editor/component/components.js +19 -7
  91. package/package/components/assets/AssetButtons.svelte +38 -0
  92. package/package/components/assets/AssetButtons.svelte.d.ts +15 -0
  93. package/package/components/assets/AssetsDropdownButton.svelte +60 -72
  94. package/package/components/assets/AssetsDropdownButton.svelte.d.ts +3 -4
  95. package/package/components/assets/AssetsUsageDrawer.svelte +10 -10
  96. package/package/components/assets/JobAssetsViewer.svelte +79 -0
  97. package/package/components/assets/JobAssetsViewer.svelte.d.ts +7 -0
  98. package/package/components/assets/README_DEV.md +0 -0
  99. package/package/components/assets/lib.d.ts +9 -1
  100. package/package/components/assets/lib.js +48 -7
  101. package/package/components/common/fileUpload/FileUpload.svelte +126 -84
  102. package/package/components/common/fileUpload/FileUpload.svelte.d.ts +13 -3
  103. package/package/components/common/fileUpload/S3ArgInput.svelte +111 -0
  104. package/package/components/common/fileUpload/S3ArgInput.svelte.d.ts +21 -0
  105. package/package/components/common/table/ScriptRow.svelte +3 -1
  106. package/package/components/copilot/AIFormSettings.svelte +3 -4
  107. package/package/components/copilot/AIFormSettings.svelte.d.ts +5 -19
  108. package/package/components/copilot/autocomplete/Autocompletor.d.ts +3 -1
  109. package/package/components/copilot/autocomplete/Autocompletor.js +269 -35
  110. package/package/components/copilot/autocomplete/request.d.ts +3 -0
  111. package/package/components/copilot/autocomplete/request.js +15 -7
  112. package/package/components/copilot/chat/AIChatDisplay.svelte +8 -0
  113. package/package/components/copilot/chat/AIChatManager.svelte.js +13 -8
  114. package/package/components/copilot/chat/flow/ModuleAcceptReject.svelte +5 -5
  115. package/package/components/copilot/chat/flow/core.d.ts +1 -1
  116. package/package/components/copilot/chat/flow/core.js +2 -38
  117. package/package/components/copilot/chat/navigator/apiTools.d.ts +8 -0
  118. package/package/components/copilot/chat/navigator/apiTools.js +95 -15
  119. package/package/components/copilot/chat/navigator/core.d.ts +1 -1
  120. package/package/components/copilot/chat/navigator/core.js +2 -1
  121. package/package/components/copilot/chat/script/core.d.ts +11 -2
  122. package/package/components/copilot/chat/script/core.js +165 -23
  123. package/package/components/copilot/chat/shared.d.ts +10 -0
  124. package/package/components/copilot/chat/shared.js +56 -0
  125. package/package/components/copilot/lib.d.ts +1 -0
  126. package/package/components/copilot/lib.js +30 -9
  127. package/package/components/custom_ui.d.ts +1 -0
  128. package/package/components/flows/FlowAssetsHandler.svelte +133 -0
  129. package/package/components/flows/FlowAssetsHandler.svelte.d.ts +14 -0
  130. package/package/components/flows/content/FlowModuleCache.svelte +4 -4
  131. package/package/components/flows/content/FlowModuleCache.svelte.d.ts +4 -18
  132. package/package/components/flows/content/FlowModuleComponent.svelte +16 -19
  133. package/package/components/flows/content/FlowModuleDeleteAfterUse.svelte +3 -4
  134. package/package/components/flows/content/FlowModuleDeleteAfterUse.svelte.d.ts +4 -18
  135. package/package/components/flows/content/FlowModuleSleep.svelte +6 -7
  136. package/package/components/flows/content/FlowModuleSleep.svelte.d.ts +4 -18
  137. package/package/components/flows/content/FlowModuleSuspend.svelte +19 -17
  138. package/package/components/flows/content/FlowModuleSuspend.svelte.d.ts +4 -18
  139. package/package/components/flows/content/FlowModuleTimeout.svelte +4 -4
  140. package/package/components/flows/content/FlowModuleTimeout.svelte.d.ts +4 -18
  141. package/package/components/flows/flowStore.d.ts +1 -1
  142. package/package/components/flows/map/FlowModuleSchemaItem.svelte +1 -0
  143. package/package/components/flows/propPicker/OutputPicker.svelte +9 -4
  144. package/package/components/flows/scheduleUtils.js +1 -1
  145. package/package/components/flows/types.d.ts +2 -1
  146. package/package/components/graph/FlowGraphV2.svelte +8 -104
  147. package/package/components/graph/FlowGraphV2.svelte.d.ts +0 -2
  148. package/package/components/graph/graphBuilder.svelte.d.ts +6 -3
  149. package/package/components/graph/graphBuilder.svelte.js +35 -9
  150. package/package/components/graph/renderers/edges/BaseEdge.svelte +2 -5
  151. package/package/components/graph/renderers/edges/BaseEdge.svelte.d.ts +1 -0
  152. package/package/components/graph/renderers/nodes/AssetNode.svelte +23 -20
  153. package/package/components/graph/renderers/nodes/AssetNode.svelte.d.ts +5 -10
  154. package/package/components/graph/renderers/nodes/AssetsOverflowedNode.svelte +1 -1
  155. package/package/components/graph/util.js +1 -1
  156. package/package/components/home/ItemsList.svelte +2 -0
  157. package/package/components/icons/AssetGenericIcon.svelte +0 -3
  158. package/package/components/jobs/JobPreview.svelte +10 -6
  159. package/package/components/raw_apps/RawAppInlineScriptRunnable.svelte +13 -12
  160. package/package/components/runs/BatchReRunOptionsPane.svelte +5 -1
  161. package/package/components/runs/JobPreview.svelte +26 -16
  162. package/package/components/runs/{JobLoader.svelte.d.ts → JobsLoader.svelte.d.ts} +3 -3
  163. package/package/components/runs/NoWorkerWithTagWarning.svelte +2 -2
  164. package/package/components/runs/NoWorkerWithTagWarning.svelte.d.ts +1 -0
  165. package/package/components/runs/RunsFilter.svelte.d.ts +1 -1
  166. package/package/components/scriptEditor/LogPanel.svelte +3 -2
  167. package/package/components/script_builder.d.ts +2 -2
  168. package/package/components/settings/CreateToken.svelte +76 -41
  169. package/package/components/settings/CreateToken.svelte.d.ts +1 -1
  170. package/package/components/settings/ScopeSelector.svelte +613 -0
  171. package/package/components/settings/ScopeSelector.svelte.d.ts +8 -0
  172. package/package/components/settings/TokenDisplay.svelte +103 -0
  173. package/package/components/settings/TokenDisplay.svelte.d.ts +10 -0
  174. package/package/components/settings/TokensTable.svelte +70 -349
  175. package/package/components/sidebar/CriticalAlertModal.svelte +3 -0
  176. package/package/components/triggers/DeleteTriggerButton.svelte +1 -1
  177. package/package/components/triggers/TriggerEditorToolbar.svelte +3 -3
  178. package/package/components/triggers/TriggerRetriesAndErrorHandler.svelte +55 -0
  179. package/package/components/triggers/TriggerRetriesAndErrorHandler.svelte.d.ts +13 -0
  180. package/package/components/triggers/TriggersEditor.svelte +45 -3
  181. package/package/components/triggers/TriggersWrapper.svelte +2 -2
  182. package/package/components/triggers/gcp/GcpTriggerEditorInner.svelte +47 -6
  183. package/package/components/triggers/gcp/utils.js +9 -1
  184. package/package/components/triggers/http/OpenAPISpecGenerator.svelte +3 -2
  185. package/package/components/triggers/http/RouteEditorConfigSection.svelte +26 -23
  186. package/package/components/triggers/http/RouteEditorConfigSection.svelte.d.ts +5 -19
  187. package/package/components/triggers/http/RouteEditorInner.svelte +219 -175
  188. package/package/components/triggers/http/RouteEditorInner.svelte.d.ts +6 -2
  189. package/package/components/triggers/http/utils.js +9 -3
  190. package/package/components/triggers/kafka/KafkaTriggerEditorInner.svelte +47 -6
  191. package/package/components/triggers/kafka/utils.js +9 -1
  192. package/package/components/triggers/mqtt/MqttEditorConfigSection.svelte +4 -132
  193. package/package/components/triggers/mqtt/MqttEditorConfigSection.svelte.d.ts +2 -5
  194. package/package/components/triggers/mqtt/MqttTriggerEditorInner.svelte +182 -13
  195. package/package/components/triggers/mqtt/utils.js +9 -1
  196. package/package/components/triggers/nats/NatsTriggerEditorInner.svelte +47 -6
  197. package/package/components/triggers/nats/utils.js +9 -1
  198. package/package/components/triggers/postgres/PostgresTriggerEditorInner.svelte +41 -2
  199. package/package/components/triggers/postgres/utils.js +9 -1
  200. package/package/components/triggers/schedules/ScheduleEditorInner.svelte +38 -92
  201. package/package/components/triggers/sqs/SqsTriggerEditorInner.svelte +47 -6
  202. package/package/components/triggers/sqs/utils.js +9 -1
  203. package/package/components/triggers/utils.js +12 -0
  204. package/package/components/triggers/websocket/WebsocketTriggerEditorInner.svelte +47 -6
  205. package/package/components/triggers/websocket/utils.js +11 -1
  206. package/package/components/workspaceSettings/AISettings.svelte +0 -2
  207. package/package/components/workspaceSettings/FilterList.svelte +56 -0
  208. package/package/components/workspaceSettings/FilterList.svelte.d.ts +8 -0
  209. package/package/components/workspaceSettings/GitSyncFilterSettings.svelte +785 -0
  210. package/package/components/workspaceSettings/GitSyncFilterSettings.svelte.d.ts +18 -0
  211. package/package/gen/core/OpenAPI.js +1 -1
  212. package/package/gen/schemas.gen.d.ts +305 -23
  213. package/package/gen/schemas.gen.js +305 -23
  214. package/package/gen/services.gen.d.ts +33 -1
  215. package/package/gen/services.gen.js +66 -2
  216. package/package/gen/types.gen.d.ts +216 -11
  217. package/package/history.svelte.js +0 -2
  218. package/package/hub.d.ts +1 -0
  219. package/package/hubPaths.json +5 -2
  220. package/package/infer.js +16 -10
  221. package/package/svelte5Utils.svelte.d.ts +1 -0
  222. package/package/svelte5Utils.svelte.js +25 -18
  223. package/package/toast.js +10 -0
  224. package/package/utils.d.ts +3 -2
  225. package/package/utils.js +20 -5
  226. package/package.json +11 -11
  227. package/package/components/ResultJobLoader.svelte +0 -219
  228. package/package/components/ResultJobLoader.svelte.d.ts +0 -52
  229. package/package/components/TestJobLoader.svelte +0 -274
  230. package/package/components/TestJobLoader.svelte.d.ts +0 -43
  231. package/package/components/icons/AssetVarIcon.svelte +0 -31
  232. package/package/components/icons/AssetVarIcon.svelte.d.ts +0 -9
  233. /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,28 @@ 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('');
77
+ let tokenUrl = $state('');
57
78
  let resourceTypeInfo = $state(undefined);
58
79
  let pathError = $state('');
59
80
  export async function open(rt) {
@@ -65,6 +86,12 @@ export async function open(rt) {
65
86
  description = '';
66
87
  resourceType = rt ?? '';
67
88
  valueToken = undefined;
89
+ // Reset client credentials state
90
+ supportsClientCredentials = false;
91
+ useClientCredentials = false;
92
+ clientId = '';
93
+ clientSecret = '';
94
+ tokenUrl = '';
68
95
  await loadConnects();
69
96
  manual = !connects?.includes(resourceType);
70
97
  if (manual && express) {
@@ -106,13 +133,15 @@ run(() => {
106
133
  disabled =
107
134
  (step == 1 && resourceType == '') ||
108
135
  (step == 2 &&
109
- value == '' &&
110
- args &&
111
- args['token'] == '' &&
112
- args['password'] == '' &&
113
- args['api_key'] == '' &&
114
- args['key'] == '' &&
115
- linkedSecret != undefined) ||
136
+ (manual
137
+ ? value == '' &&
138
+ args &&
139
+ args['token'] == '' &&
140
+ args['password'] == '' &&
141
+ args['api_key'] == '' &&
142
+ args['key'] == '' &&
143
+ linkedSecret != undefined
144
+ : false)) ||
116
145
  step == 3 ||
117
146
  (step == 4 && pathError != '') ||
118
147
  !isValid;
@@ -187,6 +216,7 @@ function processPopupData(data) {
187
216
  resourceType = data.resource_type;
188
217
  value = data.res.access_token;
189
218
  valueToken = data.res;
219
+ responseExtra = data.extra ?? {};
190
220
  step = 4;
191
221
  if (express) {
192
222
  path = `u/${$userStore?.username}/${resourceType}_${new Date().getTime()}`;
@@ -198,6 +228,11 @@ async function getScopesAndParams() {
198
228
  const connect = await OauthService.getOauthConnect({ client: resourceType });
199
229
  scopes = connect.scopes ?? [];
200
230
  extra_params = Object.entries(connect.extra_params ?? {});
231
+ /**
232
+ * Check if the OAuth provider supports client_credentials grant type
233
+ * This determines whether to show the OAuth flow selection UI
234
+ */
235
+ supportsClientCredentials = connect.grant_types?.includes('client_credentials') ?? false;
201
236
  }
202
237
  async function getResourceTypeInfo() {
203
238
  resourceTypeInfo = await ResourceService.getResourceType({
@@ -227,20 +262,66 @@ export async function next() {
227
262
  step += 1;
228
263
  }
229
264
  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));
265
+ if (useClientCredentials) {
266
+ /**
267
+ * Client credentials flow: Direct API call to backend
268
+ * No popup window or user interaction required
269
+ * Uses instance-level OAuth credentials for server-to-server auth
270
+ */
271
+ try {
272
+ // Trim whitespace from credentials to avoid false negatives
273
+ const trimmedClientId = clientId.trim();
274
+ const trimmedClientSecret = clientSecret.trim();
275
+ // Validate required fields
276
+ if (!trimmedClientId || !trimmedClientSecret) {
277
+ sendUserToast('Client ID and Client Secret are required for client credentials flow', true);
278
+ return;
279
+ }
280
+ const requestBody = {
281
+ scopes: scopes,
282
+ cc_client_id: trimmedClientId,
283
+ cc_client_secret: trimmedClientSecret
284
+ };
285
+ // Add token URL override if provided
286
+ if (tokenUrl.trim()) {
287
+ requestBody.cc_token_url = tokenUrl.trim();
288
+ }
289
+ const tokenResponse = await OauthService.connectClientCredentials({
290
+ client: resourceType,
291
+ requestBody
292
+ });
293
+ // Process the token response like in popup flow
294
+ value = tokenResponse.access_token;
295
+ valueToken = {
296
+ ...tokenResponse,
297
+ grant_type: 'client_credentials' // Mark this token as client_credentials
298
+ };
299
+ step = 4;
300
+ if (express) {
301
+ path = `u/${$userStore?.username}/${resourceType}_${new Date().getTime()}`;
302
+ next();
303
+ }
304
+ }
305
+ catch (error) {
306
+ sendUserToast(`Failed to connect with client credentials: ${error.body || error.message}`, true);
307
+ }
308
+ }
309
+ else {
310
+ /**
311
+ * Authorization code flow: Traditional OAuth popup window
312
+ * Requires user interaction and consent
313
+ * Opens popup for user to authenticate with OAuth provider
314
+ */
315
+ const url = new URL(`/api/oauth/connect/${resourceType}`, window.location.origin);
316
+ url.searchParams.append('scopes', scopes.join('+'));
317
+ if (extra_params.length > 0) {
318
+ extra_params.forEach(([key, value]) => url.searchParams.append(key, value));
319
+ }
320
+ window.addEventListener('message', popupListener);
321
+ window.addEventListener('storage', handleStorageEvent);
322
+ window.open(url.toString(), '_blank', 'popup=true');
323
+ step += 1;
234
324
  }
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
325
  }
245
326
  else {
246
327
  if (!path) {
@@ -266,15 +347,29 @@ export async function next() {
266
347
  args['account_identifier'] = account_identifier[1];
267
348
  }
268
349
  }
350
+ else if (resourceType === 'quickbooks' && responseExtra['realmId']) {
351
+ args['realmId'] = responseExtra['realmId'];
352
+ }
269
353
  let account = undefined;
270
354
  if (valueToken?.expires_in != undefined) {
355
+ const accountData = {
356
+ refresh_token: valueToken.refresh_token ?? '',
357
+ expires_in: valueToken.expires_in,
358
+ client: resourceType,
359
+ grant_type: valueToken.grant_type || 'authorization_code'
360
+ };
361
+ // Add client credentials if using client_credentials flow
362
+ if (useClientCredentials) {
363
+ accountData.cc_client_id = clientId.trim();
364
+ accountData.cc_client_secret = clientSecret.trim();
365
+ // Add token URL override if provided
366
+ if (tokenUrl.trim()) {
367
+ accountData.cc_token_url = tokenUrl.trim();
368
+ }
369
+ }
271
370
  account = Number(await OauthService.createAccount({
272
371
  workspace: $workspaceStore,
273
- requestBody: {
274
- refresh_token: valueToken.refresh_token ?? '',
275
- expires_in: valueToken.expires_in,
276
- client: resourceType
277
- }
372
+ requestBody: accountData
278
373
  }));
279
374
  }
280
375
  const resourceValue = args;
@@ -532,14 +627,70 @@ let editScopes = $state(false);
532
627
  {#if manual == false && resourceType != ''}
533
628
  <h1 class="mb-4">{resourceType}</h1>
534
629
  <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
630
+ >Create a resource backed by an OAuth connection, whose token is fetched from the external
631
+ services and refreshed automatically if needed before expiration.</div
538
632
  >
539
633
  <h4 class="mb-2">Description</h4>
540
634
  <div class="text-sm mb-8">
541
635
  <Markdown md={urlize(resourceTypeInfo?.description ?? '', 'md')} />
542
636
  </div>
637
+
638
+ {#if supportsClientCredentials}
639
+ <div style="margin-bottom: 16px;">
640
+ <h3 class="mb-4">Authentication Method</h3>
641
+ <div style="display: flex; align-items: center; gap: 8px;">
642
+ <input
643
+ type="checkbox"
644
+ style="width: 16px; height: 16px; margin: 0;"
645
+ bind:checked={useClientCredentials}
646
+ />
647
+ <span style="font-size: 14px; font-weight: 600;">Use Client Credentials Flow</span>
648
+ <Tooltip>
649
+ Server-to-server authentication without user interaction.
650
+ <br /><br />
651
+ Provide your own OAuth client credentials for this resource.
652
+ </Tooltip>
653
+ </div>
654
+
655
+ {#if useClientCredentials}
656
+ <div style="margin-top: 16px;">
657
+ <label style="display: block; margin-bottom: 8px;">
658
+ <span style="font-weight: 600;">Client ID</span>
659
+ <input
660
+ type="text"
661
+ bind:value={clientId}
662
+ placeholder="Enter OAuth client ID"
663
+ class="w-full p-2 border border-gray-300 rounded mt-1"
664
+ required
665
+ />
666
+ </label>
667
+ <label style="display: block;">
668
+ <span style="font-weight: 600;">Client Secret</span>
669
+ <input
670
+ type="password"
671
+ bind:value={clientSecret}
672
+ placeholder="Enter OAuth client secret"
673
+ class="w-full p-2 border border-gray-300 rounded mt-1"
674
+ required
675
+ />
676
+ </label>
677
+ <label style="display: block; margin-top: 8px;">
678
+ <span style="font-weight: 600;">Token URL Override (Optional)</span>
679
+ <input
680
+ type="url"
681
+ bind:value={tokenUrl}
682
+ placeholder="Custom token endpoint URL"
683
+ class="w-full p-2 border border-gray-300 rounded mt-1"
684
+ />
685
+ <div style="font-size: 12px; color: #666; margin-top: 4px;">
686
+ Override the instance-level token URL for this resource
687
+ </div>
688
+ </label>
689
+ </div>
690
+ {/if}
691
+ </div>
692
+ {/if}
693
+
543
694
  <h3 class="mb-4 flex gap-4"
544
695
  >Scopes <button
545
696
  onclick={() => {
@@ -559,7 +710,11 @@ let editScopes = $state(false);
559
710
  {/if}
560
711
  {/if}
561
712
  {:else if step == 3 && !manual && !express}
562
- Finish connection in popup window
713
+ {#if useClientCredentials}
714
+ Connecting with client credentials...
715
+ {:else}
716
+ Finish connection in popup window
717
+ {/if}
563
718
  {:else}
564
719
  <Path
565
720
  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
  }}