windmill-components 1.504.5 → 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 (202) 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/schema/AddPropertyFormV2.svelte +42 -33
  132. package/package/components/schema/AddPropertyFormV2.svelte.d.ts +1 -0
  133. package/package/components/schema/AddPropertyV2.svelte +2 -1
  134. package/package/components/schema/AddPropertyV2.svelte.d.ts +1 -0
  135. package/package/components/schema/EditableSchemaWrapper.svelte +3 -1
  136. package/package/components/schema/editable_schema_wrapper.d.ts +3 -0
  137. package/package/components/scriptEditor/LogPanel.svelte +3 -2
  138. package/package/components/script_builder.d.ts +2 -2
  139. package/package/components/settings/CreateToken.svelte +76 -41
  140. package/package/components/settings/CreateToken.svelte.d.ts +1 -1
  141. package/package/components/settings/ScopeSelector.svelte +613 -0
  142. package/package/components/settings/ScopeSelector.svelte.d.ts +8 -0
  143. package/package/components/settings/TokenDisplay.svelte +103 -0
  144. package/package/components/settings/TokenDisplay.svelte.d.ts +10 -0
  145. package/package/components/settings/TokensTable.svelte +70 -349
  146. package/package/components/sidebar/CriticalAlertModal.svelte +3 -0
  147. package/package/components/triggers/DeleteTriggerButton.svelte +1 -1
  148. package/package/components/triggers/TriggerEditorToolbar.svelte +3 -3
  149. package/package/components/triggers/TriggerRetriesAndErrorHandler.svelte +55 -0
  150. package/package/components/triggers/TriggerRetriesAndErrorHandler.svelte.d.ts +13 -0
  151. package/package/components/triggers/TriggersEditor.svelte +45 -3
  152. package/package/components/triggers/TriggersWrapper.svelte +2 -2
  153. package/package/components/triggers/gcp/GcpTriggerEditorInner.svelte +43 -2
  154. package/package/components/triggers/gcp/utils.js +9 -1
  155. package/package/components/triggers/http/OpenAPISpecGenerator.svelte +1 -0
  156. package/package/components/triggers/http/RouteEditorInner.svelte +208 -164
  157. package/package/components/triggers/http/RouteEditorInner.svelte.d.ts +6 -2
  158. package/package/components/triggers/http/utils.js +9 -3
  159. package/package/components/triggers/kafka/KafkaTriggerEditorInner.svelte +43 -2
  160. package/package/components/triggers/kafka/utils.js +9 -1
  161. package/package/components/triggers/mqtt/MqttEditorConfigSection.svelte +4 -132
  162. package/package/components/triggers/mqtt/MqttEditorConfigSection.svelte.d.ts +2 -5
  163. package/package/components/triggers/mqtt/MqttTriggerEditorInner.svelte +178 -9
  164. package/package/components/triggers/mqtt/utils.js +9 -1
  165. package/package/components/triggers/nats/NatsTriggerEditorInner.svelte +43 -2
  166. package/package/components/triggers/nats/utils.js +9 -1
  167. package/package/components/triggers/postgres/PostgresTriggerEditorInner.svelte +41 -2
  168. package/package/components/triggers/postgres/utils.js +9 -1
  169. package/package/components/triggers/schedules/ScheduleEditorInner.svelte +34 -88
  170. package/package/components/triggers/sqs/SqsTriggerEditorInner.svelte +43 -2
  171. package/package/components/triggers/sqs/utils.js +9 -1
  172. package/package/components/triggers/utils.js +12 -0
  173. package/package/components/triggers/websocket/WebsocketTriggerEditorInner.svelte +43 -2
  174. package/package/components/triggers/websocket/utils.js +11 -1
  175. package/package/components/workspaceSettings/AISettings.svelte +0 -2
  176. package/package/components/workspaceSettings/FilterList.svelte +56 -0
  177. package/package/components/workspaceSettings/FilterList.svelte.d.ts +8 -0
  178. package/package/components/workspaceSettings/GitSyncFilterSettings.svelte +785 -0
  179. package/package/components/workspaceSettings/GitSyncFilterSettings.svelte.d.ts +18 -0
  180. package/package/gen/core/OpenAPI.js +1 -1
  181. package/package/gen/schemas.gen.d.ts +305 -23
  182. package/package/gen/schemas.gen.js +305 -23
  183. package/package/gen/services.gen.d.ts +33 -1
  184. package/package/gen/services.gen.js +66 -2
  185. package/package/gen/types.gen.d.ts +216 -11
  186. package/package/history.svelte.js +0 -2
  187. package/package/hub.d.ts +1 -0
  188. package/package/hubPaths.json +5 -2
  189. package/package/infer.js +16 -10
  190. package/package/svelte5Utils.svelte.d.ts +1 -0
  191. package/package/svelte5Utils.svelte.js +25 -18
  192. package/package/toast.js +10 -0
  193. package/package/utils.d.ts +3 -2
  194. package/package/utils.js +20 -5
  195. package/package.json +11 -11
  196. package/package/components/ResultJobLoader.svelte +0 -219
  197. package/package/components/ResultJobLoader.svelte.d.ts +0 -52
  198. package/package/components/TestJobLoader.svelte +0 -274
  199. package/package/components/TestJobLoader.svelte.d.ts +0 -43
  200. package/package/components/icons/AssetVarIcon.svelte +0 -31
  201. package/package/components/icons/AssetVarIcon.svelte.d.ts +0 -9
  202. /package/package/components/runs/{JobLoader.svelte → JobsLoader.svelte} +0 -0
@@ -0,0 +1,785 @@
1
+ <script lang="ts">import Toggle from '../Toggle.svelte';
2
+ import { Filter, Save, Eye, Loader2, CheckCircle2, XCircle, Check } from 'lucide-svelte';
3
+ import Tooltip from '../Tooltip.svelte';
4
+ import yaml from 'js-yaml';
5
+ import hubPaths from '../../hubPaths.json';
6
+ import { JobService } from '../../gen';
7
+ import { workspaceStore } from '../../stores';
8
+ import { Button } from '../common';
9
+ import { sendUserToast } from '../../toast';
10
+ import FilterList from './FilterList.svelte';
11
+ import { Tabs, Tab } from '../common';
12
+ let { git_repo_resource_path = $bindable(''), include_path = $bindable(['f/**']), include_type = $bindable(['script', 'flow', 'app', 'folder']), exclude_types_override = $bindable([]), isLegacyRepo = false, yamlText = $bindable(''), onSettingsChange = (settings) => { }, excludes = $bindable([]), extraIncludes = $bindable([]) } = $props();
13
+ // Component state
14
+ let collapsed = $state(false);
15
+ let editAsYaml = $state(false);
16
+ let yamlError = $state('');
17
+ let isPullMode = $state(false);
18
+ // Preview/Push state
19
+ let previewResult = $state(null);
20
+ let previewJobId = $state(null);
21
+ let previewJobStatus = $state(undefined);
22
+ let pushJobId = $state(null);
23
+ let pushJobStatus = $state(undefined);
24
+ let isPreviewLoading = $state(false);
25
+ let isPushing = $state(false);
26
+ let previewError = $state('');
27
+ let previewSettingsSnapshot = $state(null);
28
+ // Compute effective include types (include_type minus exclude_types_override for legacy repos only)
29
+ const effectiveIncludeTypes = $derived(isLegacyRepo
30
+ ? include_type.filter((type) => !exclude_types_override.includes(type))
31
+ : include_type);
32
+ // Compute type toggles from effective include types
33
+ const typeToggles = $derived({
34
+ scripts: effectiveIncludeTypes.includes('script'),
35
+ flows: effectiveIncludeTypes.includes('flow'),
36
+ apps: effectiveIncludeTypes.includes('app'),
37
+ folders: effectiveIncludeTypes.includes('folder'),
38
+ resourceTypes: effectiveIncludeTypes.includes('resourcetype'),
39
+ resources: effectiveIncludeTypes.includes('resource'),
40
+ variables: effectiveIncludeTypes.includes('variable'),
41
+ secrets: effectiveIncludeTypes.includes('secret'),
42
+ schedules: effectiveIncludeTypes.includes('schedule'),
43
+ users: effectiveIncludeTypes.includes('user'),
44
+ groups: effectiveIncludeTypes.includes('group'),
45
+ triggers: effectiveIncludeTypes.includes('trigger'),
46
+ settings: effectiveIncludeTypes.includes('settings'),
47
+ key: effectiveIncludeTypes.includes('key')
48
+ });
49
+ // Tab selection for filter kinds
50
+ let filtersTab = $state('includes');
51
+ function updateIncludeType(key, value) {
52
+ const newTypes = new Set(include_type);
53
+ const typeMap = {
54
+ scripts: 'script',
55
+ flows: 'flow',
56
+ apps: 'app',
57
+ folders: 'folder',
58
+ resourceTypes: 'resourcetype',
59
+ resources: 'resource',
60
+ variables: 'variable',
61
+ secrets: 'secret',
62
+ schedules: 'schedule',
63
+ users: 'user',
64
+ groups: 'group',
65
+ triggers: 'trigger',
66
+ settings: 'settings',
67
+ key: 'key'
68
+ };
69
+ if (value) {
70
+ newTypes.add(typeMap[key]);
71
+ }
72
+ else {
73
+ newTypes.delete(typeMap[key]);
74
+ if (key === 'variables') {
75
+ newTypes.delete('secret');
76
+ }
77
+ }
78
+ include_type = Array.from(newTypes);
79
+ }
80
+ function capitalize(str) {
81
+ return str.charAt(0).toUpperCase() + str.slice(1);
82
+ }
83
+ // Simple JSON-based UI state helper
84
+ function getUIState() {
85
+ return {
86
+ include_path,
87
+ exclude_path: excludes,
88
+ extra_include_path: extraIncludes,
89
+ include_type
90
+ };
91
+ }
92
+ // Apply settings from backend format (used by both local git repo and backend settings)
93
+ function fromBackendFormat(settings) {
94
+ include_path = settings.include_path || [];
95
+ excludes = settings.exclude_path || [];
96
+ extraIncludes = settings.extra_include_path || [];
97
+ include_type = settings.include_type || [];
98
+ }
99
+ // Simplified YAML parsing for manual editing
100
+ function fromYaml(yamlStr) {
101
+ yamlError = '';
102
+ try {
103
+ const parsed = yaml.load(yamlStr);
104
+ if (!parsed || typeof parsed !== 'object') {
105
+ throw new Error('Invalid YAML structure');
106
+ }
107
+ const obj = parsed;
108
+ yamlText = yamlStr;
109
+ // Extract includes - reset to default if not present
110
+ if (obj.includes && Array.isArray(obj.includes)) {
111
+ include_path = obj.includes.map((p) => {
112
+ if (typeof p !== 'string') {
113
+ throw new Error('includes must contain only strings');
114
+ }
115
+ // Handle quoted strings
116
+ if (/^['"].*['"]$/.test(p)) {
117
+ return p.slice(1, -1).replace(/''/g, "'");
118
+ }
119
+ return p;
120
+ });
121
+ }
122
+ else {
123
+ // Reset to default if includes is not present
124
+ include_path = ['f/**'];
125
+ }
126
+ // Build the type set based on the YAML flags
127
+ const newTypes = new Set();
128
+ // Always include core types (these are fundamental and not controlled by flags)
129
+ newTypes.add('script');
130
+ newTypes.add('flow');
131
+ newTypes.add('app');
132
+ newTypes.add('folder');
133
+ // Handle skip flags (if skipX is false or undefined, include the type)
134
+ if (obj.skipResourceTypes !== true)
135
+ newTypes.add('resourcetype');
136
+ if (obj.skipResources !== true)
137
+ newTypes.add('resource');
138
+ if (obj.skipVariables !== true)
139
+ newTypes.add('variable');
140
+ if (obj.skipSecrets !== true)
141
+ newTypes.add('secret');
142
+ // Handle include flags (if includeX is true, include the type)
143
+ if (obj.includeSchedules === true)
144
+ newTypes.add('schedule');
145
+ if (obj.includeTriggers === true)
146
+ newTypes.add('trigger');
147
+ if (obj.includeUsers === true)
148
+ newTypes.add('user');
149
+ if (obj.includeGroups === true)
150
+ newTypes.add('group');
151
+ if (obj.includeSettings === true)
152
+ newTypes.add('settings');
153
+ if (obj.includeKey === true)
154
+ newTypes.add('key');
155
+ // Apply business rule: secrets can only be included if variables are included
156
+ // This matches the UI behavior where turning off variables also turns off secrets
157
+ if (!newTypes.has('variable')) {
158
+ newTypes.delete('secret');
159
+ }
160
+ include_type = Array.from(newTypes);
161
+ }
162
+ catch (e) {
163
+ yamlError = e.message || 'Invalid YAML';
164
+ console.error('Error parsing YAML:', e);
165
+ }
166
+ }
167
+ // Simple YAML generation for manual editing mode
168
+ function generateYamlFromUI() {
169
+ try {
170
+ const validIncludePath = include_path;
171
+ const validExcludePath = excludes;
172
+ const validExtraInclude = extraIncludes;
173
+ // Basic YAML structure - let the CLI handle the proper normalization
174
+ let config = {
175
+ includes: validIncludePath,
176
+ excludes: validExcludePath,
177
+ extraIncludes: validExtraInclude,
178
+ codebases: []
179
+ };
180
+ // Let the CLI handle the optimization of skip/include flags
181
+ // Just convert the UI state directly
182
+ if (!include_type.includes('variable'))
183
+ config.skipVariables = true;
184
+ if (!include_type.includes('resource'))
185
+ config.skipResources = true;
186
+ if (!include_type.includes('secret'))
187
+ config.skipSecrets = true;
188
+ if (!include_type.includes('resourcetype'))
189
+ config.skipResourceTypes = true;
190
+ if (include_type.includes('schedule'))
191
+ config.includeSchedules = true;
192
+ if (include_type.includes('trigger'))
193
+ config.includeTriggers = true;
194
+ if (include_type.includes('user'))
195
+ config.includeUsers = true;
196
+ if (include_type.includes('group'))
197
+ config.includeGroups = true;
198
+ if (include_type.includes('settings'))
199
+ config.includeSettings = true;
200
+ if (include_type.includes('key'))
201
+ config.includeKey = true;
202
+ return yaml.dump(config, {
203
+ indent: 2,
204
+ lineWidth: -1,
205
+ quotingType: '"',
206
+ forceQuotes: false,
207
+ noRefs: true
208
+ });
209
+ }
210
+ catch (e) {
211
+ console.warn('Failed to generate YAML:', e);
212
+ yamlError = e.message || 'Failed to generate YAML';
213
+ return `includes:
214
+ - f/**
215
+ excludes: []
216
+ extraIncludes: []
217
+ codebases: []`;
218
+ }
219
+ }
220
+ function switchToYaml() {
221
+ yamlText = generateYamlFromUI();
222
+ yamlError = '';
223
+ editAsYaml = true;
224
+ }
225
+ function switchToUI() {
226
+ fromYaml(yamlText);
227
+ if (!yamlError) {
228
+ editAsYaml = false;
229
+ }
230
+ }
231
+ // Simplified preview function - always uses JSON approach
232
+ async function previewFiltersToGitRepo() {
233
+ isPreviewLoading = true;
234
+ previewError = '';
235
+ previewResult = null;
236
+ previewJobId = null;
237
+ previewJobStatus = undefined;
238
+ // Take a snapshot of current settings
239
+ previewSettingsSnapshot = JSON.stringify({
240
+ include_path,
241
+ excludes,
242
+ extraIncludes,
243
+ include_type
244
+ });
245
+ try {
246
+ const workspace = $workspaceStore;
247
+ if (!workspace)
248
+ return;
249
+ // Always pass UI state as JSON - the backend now handles this uniformly
250
+ const payloadObj = {
251
+ workspace_id: workspace,
252
+ repo_url_resource_path: git_repo_resource_path,
253
+ only_wmill_yaml: true,
254
+ dry_run: true,
255
+ pull: isPullMode,
256
+ settings_json: JSON.stringify(getUIState())
257
+ };
258
+ const jobId = await JobService.runScriptByPath({
259
+ workspace,
260
+ path: hubPaths.gitInitRepo,
261
+ requestBody: payloadObj,
262
+ skipPreprocessor: true
263
+ });
264
+ previewJobId = jobId;
265
+ previewJobStatus = 'running';
266
+ let jobSuccess = false;
267
+ let result = {};
268
+ await (await import('../../utils')).tryEvery({
269
+ tryCode: async () => {
270
+ const testResult = await JobService.getCompletedJob({ workspace, id: jobId });
271
+ jobSuccess = !!testResult.success;
272
+ if (jobSuccess) {
273
+ const jobResult = await JobService.getCompletedJobResult({ workspace, id: jobId });
274
+ result = jobResult;
275
+ }
276
+ },
277
+ timeoutCode: async () => {
278
+ try {
279
+ await JobService.cancelQueuedJob({
280
+ workspace,
281
+ id: jobId,
282
+ requestBody: { reason: 'Preview job timed out after 5s' }
283
+ });
284
+ }
285
+ catch (err) { }
286
+ },
287
+ interval: 500,
288
+ timeout: 10000
289
+ });
290
+ previewJobStatus = jobSuccess ? 'success' : 'failure';
291
+ if (jobSuccess) {
292
+ previewResult = result;
293
+ }
294
+ else {
295
+ previewError = 'Preview failed';
296
+ }
297
+ }
298
+ catch (e) {
299
+ previewJobStatus = 'failure';
300
+ previewError = e?.message || 'Preview failed';
301
+ previewResult = null;
302
+ }
303
+ finally {
304
+ isPreviewLoading = false;
305
+ }
306
+ }
307
+ // Simplified push function - always uses JSON approach
308
+ async function pushFiltersToGitRepo() {
309
+ if (isPullMode) {
310
+ // In pull mode, apply the local settings (from git repo) to UI
311
+ if (previewResult?.local) {
312
+ try {
313
+ fromBackendFormat(previewResult.local);
314
+ yamlText = generateYamlFromUI();
315
+ onSettingsChange({ yaml: yamlText });
316
+ sendUserToast('Changes applied - remember to save repository settings to persist changes');
317
+ // Clear the preview state after applying settings
318
+ previewResult = null;
319
+ previewJobId = null;
320
+ previewJobStatus = undefined;
321
+ previewError = '';
322
+ }
323
+ catch (e) {
324
+ previewError = 'Failed to apply pulled settings: ' + e.message;
325
+ }
326
+ }
327
+ return;
328
+ }
329
+ // Push mode - send current UI state as JSON
330
+ isPushing = true;
331
+ pushJobId = null;
332
+ pushJobStatus = undefined;
333
+ try {
334
+ const workspace = $workspaceStore;
335
+ if (!workspace)
336
+ return;
337
+ const payloadObj = {
338
+ workspace_id: workspace,
339
+ repo_url_resource_path: git_repo_resource_path,
340
+ dry_run: false,
341
+ pull: isPullMode,
342
+ only_wmill_yaml: true,
343
+ settings_json: JSON.stringify(getUIState())
344
+ };
345
+ const jobId = await JobService.runScriptByPath({
346
+ workspace,
347
+ path: hubPaths.gitInitRepo,
348
+ requestBody: payloadObj,
349
+ skipPreprocessor: true
350
+ });
351
+ pushJobId = jobId;
352
+ pushJobStatus = 'running';
353
+ let jobSuccess = false;
354
+ await (await import('../../utils')).tryEvery({
355
+ tryCode: async () => {
356
+ const testResult = await JobService.getCompletedJob({ workspace, id: jobId });
357
+ jobSuccess = !!testResult.success;
358
+ },
359
+ timeoutCode: async () => {
360
+ try {
361
+ await JobService.cancelQueuedJob({
362
+ workspace,
363
+ id: jobId,
364
+ requestBody: { reason: 'Push job timed out after 5s' }
365
+ });
366
+ }
367
+ catch (err) { }
368
+ },
369
+ interval: 500,
370
+ timeout: 10000
371
+ });
372
+ pushJobStatus = jobSuccess ? 'success' : 'failure';
373
+ if (jobSuccess) {
374
+ // Reset preview state after successful push
375
+ previewResult = null;
376
+ previewJobId = null;
377
+ previewJobStatus = undefined;
378
+ previewError = '';
379
+ }
380
+ }
381
+ catch (e) {
382
+ pushJobStatus = 'failure';
383
+ }
384
+ finally {
385
+ isPushing = false;
386
+ }
387
+ }
388
+ // Simplified export function for backward compatibility
389
+ export function toYaml() {
390
+ return generateYamlFromUI();
391
+ }
392
+ export function setSettings(settings) {
393
+ yamlText = settings.yaml;
394
+ fromYaml(settings.yaml);
395
+ }
396
+ $effect(() => {
397
+ // Reset preview state when switching modes
398
+ if (isPullMode !== undefined) {
399
+ previewResult = null;
400
+ previewJobId = null;
401
+ previewJobStatus = undefined;
402
+ pushJobId = null;
403
+ pushJobStatus = undefined;
404
+ isPreviewLoading = false;
405
+ isPushing = false;
406
+ previewError = '';
407
+ }
408
+ });
409
+ // Reset preview state when settings change (making preview stale)
410
+ $effect(() => {
411
+ // Track all the settings that affect the preview
412
+ const currentSettings = JSON.stringify({
413
+ include_path,
414
+ excludes,
415
+ extraIncludes,
416
+ include_type
417
+ });
418
+ // If we have an existing preview result and settings have changed from snapshot, clear it
419
+ if (previewResult !== null &&
420
+ previewSettingsSnapshot !== null &&
421
+ currentSettings !== previewSettingsSnapshot) {
422
+ previewResult = null;
423
+ previewJobId = null;
424
+ previewJobStatus = undefined;
425
+ previewError = '';
426
+ previewSettingsSnapshot = null;
427
+ }
428
+ });
429
+ </script>
430
+
431
+ <div class="rounded-lg shadow-sm border p-0 w-full">
432
+ <!-- Card Header -->
433
+ <div class="flex items-center justify-between min-h-10 px-4 py-1 border-b">
434
+ <div class="flex items-center gap-2">
435
+ <Filter size={18} class="text-primary" />
436
+ <span class="font-semibold text-sm">Git Sync filter settings</span>
437
+ </div>
438
+ <div class="flex items-center gap-2">
439
+ {#if !collapsed}
440
+ <button
441
+ class="text-xs px-2 py-1 rounded border border-gray-300 bg-surface-primary hover:bg-surface-secondary"
442
+ onclick={editAsYaml ? switchToUI : switchToYaml}
443
+ >
444
+ {editAsYaml ? 'Edit in UI' : 'Edit as YAML'}
445
+ </button>
446
+ {/if}
447
+ <button
448
+ class="text-gray-500 hover:text-primary focus:outline-none"
449
+ onclick={() => (collapsed = !collapsed)}
450
+ aria-label="Toggle collapse"
451
+ >
452
+ {#if collapsed}
453
+ <svg
454
+ xmlns="http://www.w3.org/2000/svg"
455
+ class="h-5 w-5"
456
+ fill="none"
457
+ viewBox="0 0 24 24"
458
+ stroke="currentColor"
459
+ >
460
+ <path
461
+ stroke-linecap="round"
462
+ stroke-linejoin="round"
463
+ stroke-width="2"
464
+ d="M19 9l-7 7-7-7"
465
+ />
466
+ </svg>
467
+ {:else}
468
+ <svg
469
+ xmlns="http://www.w3.org/2000/svg"
470
+ class="h-5 w-5"
471
+ fill="none"
472
+ viewBox="0 0 24 24"
473
+ stroke="currentColor"
474
+ >
475
+ <path
476
+ stroke-linecap="round"
477
+ stroke-linejoin="round"
478
+ stroke-width="2"
479
+ d="M5 15l7-7 7 7"
480
+ />
481
+ </svg>
482
+ {/if}
483
+ </button>
484
+ </div>
485
+ </div>
486
+ {#if !collapsed}
487
+ {#if editAsYaml}
488
+ <div class="px-4 py-4">
489
+ <textarea
490
+ class="w-full h-64 font-mono text-xs border rounded p-2 bg-gray-50 focus:outline-none focus:ring-2 focus:ring-primary"
491
+ spellcheck="false"
492
+ bind:value={yamlText}
493
+ ></textarea>
494
+ {#if yamlError}
495
+ <div class="text-xs text-red-600 mt-2">{yamlError}</div>
496
+ {/if}
497
+ </div>
498
+ {:else}
499
+ <div class="px-4 py-2">
500
+ <div class="grid grid-cols-1 md:grid-cols-2 md:gap-32">
501
+ <div class="flex flex-col gap-2">
502
+ <Tabs bind:selected={filtersTab}>
503
+ <Tab value="includes">Includes</Tab>
504
+ <Tab value="excludes">Excludes</Tab>
505
+ </Tabs>
506
+
507
+ {#if filtersTab === 'includes'}
508
+ <FilterList
509
+ title="Include path filters"
510
+ bind:items={include_path}
511
+ placeholder="Add filter (e.g. f/**)"
512
+ >
513
+ {#snippet tooltip()}
514
+ <Tooltip>
515
+ Only scripts, flows and apps with their path matching one of those filters will
516
+ be synced to the Git repositories below. The filters allow '*' and '**'
517
+ characters, with '*' matching any character allowed in paths until the next
518
+ slash (/) and '**' matching anything including slashes. By default everything in
519
+ folders will be synced.
520
+ </Tooltip>
521
+ {/snippet}
522
+ </FilterList>
523
+ {:else if filtersTab === 'excludes'}
524
+ <FilterList
525
+ title="Exclude path filters"
526
+ bind:items={excludes}
527
+ placeholder="Add filter (e.g. f/**)"
528
+ >
529
+ {#snippet tooltip()}
530
+ <Tooltip>
531
+ After the include / extra include checks, if a file matches any of these
532
+ patterns it will be skipped.
533
+ </Tooltip>
534
+ {/snippet}
535
+ </FilterList>
536
+ {/if}
537
+ </div>
538
+ <!-- Type Filters Section (Right) -->
539
+ <div>
540
+ <div class="flex items-center gap-2 mb-3">
541
+ <h4 class="font-semibold text-sm">Type filters</h4>
542
+ <Tooltip>
543
+ On top of the filter path above, you can include only certain type of object to be
544
+ synced with the Git repository. By default everything is synced.
545
+ </Tooltip>
546
+ </div>
547
+ <div class="grid grid-cols-2 gap-x-4 gap-y-2">
548
+ <div class="flex items-center gap-2">
549
+ <Toggle
550
+ size="xs"
551
+ checked={typeToggles.scripts}
552
+ on:change={(e) => updateIncludeType('scripts', e.detail)}
553
+ options={{ right: capitalize('scripts') }}
554
+ />
555
+ </div>
556
+ <div class="flex items-center gap-2">
557
+ <Toggle
558
+ size="xs"
559
+ checked={typeToggles.flows}
560
+ on:change={(e) => updateIncludeType('flows', e.detail)}
561
+ options={{ right: capitalize('flows') }}
562
+ />
563
+ </div>
564
+ <div class="flex items-center gap-2">
565
+ <Toggle
566
+ size="xs"
567
+ checked={typeToggles.apps}
568
+ on:change={(e) => updateIncludeType('apps', e.detail)}
569
+ options={{ right: capitalize('apps') }}
570
+ />
571
+ </div>
572
+ <div class="flex items-center gap-2">
573
+ <Toggle
574
+ size="xs"
575
+ checked={typeToggles.folders}
576
+ on:change={(e) => updateIncludeType('folders', e.detail)}
577
+ options={{ right: capitalize('folders') }}
578
+ />
579
+ </div>
580
+ <div class="flex items-center gap-2">
581
+ <Toggle
582
+ size="xs"
583
+ checked={typeToggles.resourceTypes}
584
+ on:change={(e) => updateIncludeType('resourceTypes', e.detail)}
585
+ options={{ right: capitalize('resourceTypes') }}
586
+ />
587
+ </div>
588
+ <div class="flex items-center gap-2">
589
+ <Toggle
590
+ size="xs"
591
+ checked={typeToggles.resources}
592
+ on:change={(e) => updateIncludeType('resources', e.detail)}
593
+ options={{ right: capitalize('resources') }}
594
+ />
595
+ </div>
596
+ <div class="col-span-2 flex items-center gap-2">
597
+ <Toggle
598
+ size="xs"
599
+ checked={typeToggles.variables}
600
+ on:change={(e) => updateIncludeType('variables', e.detail)}
601
+ options={{ right: 'Variables' }}
602
+ />
603
+ <span class="text-gray-400">-</span>
604
+ <Toggle
605
+ size="xs"
606
+ disabled={!typeToggles.variables}
607
+ checked={typeToggles.secrets}
608
+ on:change={(e) => updateIncludeType('secrets', e.detail)}
609
+ options={{ left: 'Include secrets' }}
610
+ />
611
+ </div>
612
+ <div class="flex items-center gap-2">
613
+ <Toggle
614
+ size="xs"
615
+ checked={typeToggles.schedules}
616
+ on:change={(e) => updateIncludeType('schedules', e.detail)}
617
+ options={{ right: capitalize('schedules') }}
618
+ />
619
+ </div>
620
+ <div class="flex items-center gap-2">
621
+ <Toggle
622
+ size="xs"
623
+ checked={typeToggles.users}
624
+ on:change={(e) => updateIncludeType('users', e.detail)}
625
+ options={{ right: capitalize('users') }}
626
+ />
627
+ </div>
628
+ <div class="flex items-center gap-2">
629
+ <Toggle
630
+ size="xs"
631
+ checked={typeToggles.groups}
632
+ on:change={(e) => updateIncludeType('groups', e.detail)}
633
+ options={{ right: capitalize('groups') }}
634
+ />
635
+ </div>
636
+ <div class="flex items-center gap-2">
637
+ <Toggle
638
+ size="xs"
639
+ checked={typeToggles.triggers}
640
+ on:change={(e) => updateIncludeType('triggers', e.detail)}
641
+ options={{ right: capitalize('triggers') }}
642
+ />
643
+ </div>
644
+ <div class="flex items-center gap-2">
645
+ <Toggle
646
+ size="xs"
647
+ checked={typeToggles.settings}
648
+ on:change={(e) => updateIncludeType('settings', e.detail)}
649
+ options={{ right: 'Workspace settings' }}
650
+ />
651
+ </div>
652
+ <div class="flex items-center gap-2">
653
+ <Toggle
654
+ size="xs"
655
+ checked={typeToggles.key}
656
+ on:change={(e) => updateIncludeType('key', e.detail)}
657
+ options={{ right: 'Encryption key' }}
658
+ />
659
+ </div>
660
+ </div>
661
+ </div>
662
+ </div>
663
+ </div>
664
+ <div class="mt-6 flex flex-col gap-2 p-2">
665
+ <div class="flex flex-col gap-2 mb-2">
666
+ <Toggle
667
+ size="sm"
668
+ bind:checked={isPullMode}
669
+ options={{
670
+ left: 'Push',
671
+ right: 'Pull'
672
+ }}
673
+ />
674
+ <span class="text-xs text-tertiary">
675
+ {isPullMode ? 'Pull settings from Git repository' : 'Push settings to Git repository'}
676
+ </span>
677
+ </div>
678
+ <div class="flex gap-2 items-center">
679
+ <Button
680
+ size="sm"
681
+ on:click={previewFiltersToGitRepo}
682
+ disabled={isPreviewLoading || isPushing}
683
+ startIcon={{
684
+ icon: isPreviewLoading ? Loader2 : Eye,
685
+ classes: isPreviewLoading ? 'animate-spin' : ''
686
+ }}
687
+ >
688
+ {isPreviewLoading ? 'Previewing...' : 'Preview'}
689
+ </Button>
690
+ {#if previewResult?.hasChanges && (previewResult?.isInitialSetup || (previewResult?.diff && Object.keys(previewResult.diff).length > 0))}
691
+ <Button
692
+ size="sm"
693
+ on:click={pushFiltersToGitRepo}
694
+ disabled={isPushing || isPreviewLoading}
695
+ color={isPullMode ? 'dark' : 'red'}
696
+ startIcon={{
697
+ icon: isPushing ? Loader2 : isPullMode ? Check : Save,
698
+ classes: isPushing ? 'animate-spin' : ''
699
+ }}
700
+ >
701
+ {isPushing
702
+ ? isPullMode
703
+ ? 'Applying...'
704
+ : 'Pushing...'
705
+ : isPullMode
706
+ ? 'Apply'
707
+ : 'Push Settings to Git'}
708
+ </Button>
709
+ {/if}
710
+ </div>
711
+ {#if previewError}
712
+ <div class="text-xs text-red-600 mt-2">{previewError}</div>
713
+ {/if}
714
+ {#if previewJobId}
715
+ <div class="flex items-center gap-2 text-xs text-tertiary mt-1">
716
+ {#if previewJobStatus === 'running'}
717
+ <Loader2 class="animate-spin" size={14} />
718
+ {:else if previewJobStatus === 'success'}
719
+ <CheckCircle2 size={14} class="text-green-600" />
720
+ {:else if previewJobStatus === 'failure'}
721
+ <XCircle size={14} class="text-red-700" />
722
+ {/if}
723
+ Preview job:
724
+ <a
725
+ target="_blank"
726
+ class="underline"
727
+ href={`/run/${previewJobId}?workspace=${$workspaceStore}`}>{previewJobId}</a
728
+ >
729
+ </div>
730
+ {/if}
731
+ {#if previewResult}
732
+ <div
733
+ class="border rounded p-2 text-xs max-h-40 overflow-y-auto bg-surface-secondary mt-2"
734
+ >
735
+ <div class="font-semibold text-[11px] mb-1 text-tertiary">Preview of changes:</div>
736
+ {#if previewResult.isInitialSetup}
737
+ <div class="mt-2 text-green-600">
738
+ {previewResult.message || 'wmill.yaml will be created with repository settings'}
739
+ </div>
740
+ {:else if previewResult.hasChanges && previewResult.diff && Object.keys(previewResult.diff).length > 0}
741
+ <div class="mt-2 space-y-1">
742
+ {#each Object.entries(previewResult.diff) as [field, change]}
743
+ <div class="flex items-start gap-2 text-2xs">
744
+ <span class="font-mono text-tertiary min-w-0 flex-shrink-0">{field}:</span>
745
+ <div class="min-w-0 flex-1">
746
+ {#if Array.isArray(change.from) || Array.isArray(change.to)}
747
+ <div class="space-y-0.5">
748
+ <div class="text-red-600">- {JSON.stringify(change.from)}</div>
749
+ <div class="text-green-600">+ {JSON.stringify(change.to)}</div>
750
+ </div>
751
+ {:else}
752
+ <span class="text-red-600">{JSON.stringify(change.from)}</span>
753
+ <span class="text-tertiary"> → </span>
754
+ <span class="text-green-600">{JSON.stringify(change.to)}</span>
755
+ {/if}
756
+ </div>
757
+ </div>
758
+ {/each}
759
+ </div>
760
+ {:else}
761
+ <div class="mt-2 text-tertiary">No changes found! The file is up to date.</div>
762
+ {/if}
763
+ </div>
764
+ {/if}
765
+ {#if pushJobId}
766
+ <div class="flex items-center gap-2 text-xs text-tertiary mt-1">
767
+ {#if pushJobStatus === 'running'}
768
+ <Loader2 class="animate-spin" size={14} />
769
+ {:else if pushJobStatus === 'success'}
770
+ <CheckCircle2 size={14} class="text-green-600" />
771
+ {:else if pushJobStatus === 'failure'}
772
+ <XCircle size={14} class="text-red-700" />
773
+ {/if}
774
+ Push job:
775
+ <a
776
+ target="_blank"
777
+ class="underline"
778
+ href={`/run/${pushJobId}?workspace=${$workspaceStore}`}>{pushJobId}</a
779
+ >
780
+ </div>
781
+ {/if}
782
+ </div>
783
+ {/if}
784
+ {/if}
785
+ </div>