windmill-components 1.695.0 → 1.698.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 (157) hide show
  1. package/dist/sharedUtils/assets/tokens/colorTokensConfig.d.ts +2 -0
  2. package/dist/sharedUtils/base.d.ts +1 -0
  3. package/dist/sharedUtils/cloud.d.ts +1 -0
  4. package/dist/sharedUtils/common.d.ts +111 -0
  5. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/count.d.ts +5 -0
  6. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/delete.d.ts +5 -0
  7. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/insert.d.ts +5 -0
  8. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/select.d.ts +13 -0
  9. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/update.d.ts +11 -0
  10. package/dist/sharedUtils/components/apps/components/display/dbtable/utils.d.ts +95 -0
  11. package/dist/sharedUtils/components/apps/editor/appPolicy.d.ts +6 -0
  12. package/dist/sharedUtils/components/apps/editor/appUtilsCore.d.ts +7 -0
  13. package/dist/sharedUtils/components/apps/editor/appUtilsS3.d.ts +33 -0
  14. package/dist/sharedUtils/components/apps/editor/commonAppUtils.d.ts +10 -0
  15. package/dist/sharedUtils/components/apps/editor/component/components.d.ts +5371 -0
  16. package/dist/sharedUtils/components/apps/editor/component/default-codes.d.ts +3 -0
  17. package/dist/sharedUtils/components/apps/editor/component/index.d.ts +3 -0
  18. package/dist/sharedUtils/components/apps/editor/component/sets.d.ts +7 -0
  19. package/dist/sharedUtils/components/apps/editor/componentsPanel/componentDefaultProps.d.ts +3 -0
  20. package/dist/sharedUtils/components/apps/gridUtils.d.ts +14 -0
  21. package/dist/sharedUtils/components/apps/inputType.d.ts +178 -0
  22. package/dist/sharedUtils/components/apps/rx.d.ts +29 -0
  23. package/dist/sharedUtils/components/apps/sharedTypes.d.ts +21 -0
  24. package/dist/sharedUtils/components/apps/types.d.ts +274 -0
  25. package/dist/sharedUtils/components/assets/lib.d.ts +25 -0
  26. package/dist/sharedUtils/components/common/alert/model.d.ts +2 -0
  27. package/dist/sharedUtils/components/common/badge/model.d.ts +8 -0
  28. package/dist/sharedUtils/components/common/button/model.d.ts +45 -0
  29. package/dist/sharedUtils/components/common/fileInput/model.d.ts +1 -0
  30. package/dist/sharedUtils/components/common/index.d.ts +24 -0
  31. package/dist/sharedUtils/components/common/skeleton/model.d.ts +21 -0
  32. package/dist/sharedUtils/components/dbTypes.d.ts +14 -0
  33. package/dist/sharedUtils/components/diff_drawer.d.ts +26 -0
  34. package/dist/sharedUtils/components/ducklake.d.ts +1 -0
  35. package/dist/sharedUtils/components/flows/scheduleUtils.d.ts +7 -0
  36. package/dist/sharedUtils/components/icons/index.d.ts +101 -0
  37. package/dist/sharedUtils/components/random_positive_adjetive.d.ts +1 -0
  38. package/dist/sharedUtils/components/raw_apps/rawAppPolicy.d.ts +10 -0
  39. package/dist/sharedUtils/components/raw_apps/utils.d.ts +15 -0
  40. package/dist/sharedUtils/components/triggers/email/utils.d.ts +4 -0
  41. package/dist/sharedUtils/components/triggers/gcp/utils.d.ts +2 -0
  42. package/dist/sharedUtils/components/triggers/http/utils.d.ts +11 -0
  43. package/dist/sharedUtils/components/triggers/kafka/utils.d.ts +2 -0
  44. package/dist/sharedUtils/components/triggers/mqtt/utils.d.ts +2 -0
  45. package/dist/sharedUtils/components/triggers/nats/utils.d.ts +2 -0
  46. package/dist/sharedUtils/components/triggers/postgres/utils.d.ts +8 -0
  47. package/dist/sharedUtils/components/triggers/sqs/utils.d.ts +2 -0
  48. package/dist/sharedUtils/components/triggers/triggers.svelte.d.ts +32 -0
  49. package/dist/sharedUtils/components/triggers/utils.d.ts +80 -0
  50. package/dist/sharedUtils/components/triggers/websocket/utils.d.ts +2 -0
  51. package/dist/sharedUtils/components/triggers.d.ts +20 -0
  52. package/dist/sharedUtils/gen/core/ApiError.d.ts +10 -0
  53. package/dist/sharedUtils/gen/core/ApiRequestOptions.d.ts +13 -0
  54. package/dist/sharedUtils/gen/core/ApiResult.d.ts +7 -0
  55. package/dist/sharedUtils/gen/core/CancelablePromise.d.ts +26 -0
  56. package/dist/sharedUtils/gen/core/OpenAPI.d.ts +27 -0
  57. package/dist/sharedUtils/gen/core/request.d.ts +29 -0
  58. package/dist/sharedUtils/gen/index.d.ts +6 -0
  59. package/dist/sharedUtils/gen/schemas.gen.d.ts +7036 -0
  60. package/dist/sharedUtils/gen/services.gen.d.ts +6047 -0
  61. package/dist/sharedUtils/gen/types.gen.d.ts +21881 -0
  62. package/dist/sharedUtils/history.svelte.d.ts +9 -0
  63. package/dist/sharedUtils/hub.d.ts +49 -0
  64. package/dist/sharedUtils/jsr.json +6 -0
  65. package/dist/sharedUtils/lib.d.ts +5 -0
  66. package/dist/sharedUtils/lib.es.js +1588 -0
  67. package/dist/sharedUtils/package.json +12 -0
  68. package/dist/sharedUtils/schema.d.ts +3 -0
  69. package/dist/sharedUtils/stores.d.ts +97 -0
  70. package/dist/sharedUtils/svelte5Utils.svelte.d.ts +80 -0
  71. package/dist/sharedUtils/toast.d.ts +8 -0
  72. package/dist/sharedUtils/utils.d.ts +265 -0
  73. package/package/components/AppConnectInner.svelte +38 -5
  74. package/package/components/CompareWorkspaces.svelte +142 -486
  75. package/package/components/Editor.svelte +5 -4
  76. package/package/components/Editor.svelte.d.ts +1 -0
  77. package/package/components/FilterSearchbar.svelte +3 -1
  78. package/package/components/FilterSearchbar.svelte.d.ts +1 -0
  79. package/package/components/ForkWorkspaceBanner.svelte +16 -0
  80. package/package/components/LogViewer.svelte +51 -60
  81. package/package/components/OnBehalfOfSelector.svelte +10 -7
  82. package/package/components/ResourceEditor.svelte +198 -311
  83. package/package/components/ResourceEditor.svelte.d.ts +3 -3
  84. package/package/components/ResourceEditorDrawer.svelte +17 -6
  85. package/package/components/ResourceForm.svelte +235 -0
  86. package/package/components/ResourceForm.svelte.d.ts +25 -0
  87. package/package/components/RunsPage.svelte +1 -0
  88. package/package/components/ScriptBuilder.svelte +1 -0
  89. package/package/components/ScriptEditor.svelte +10 -3
  90. package/package/components/ScriptEditor.svelte.d.ts +1 -0
  91. package/package/components/TaggedTextInput.svelte +4 -1
  92. package/package/components/TaggedTextInput.svelte.d.ts +2 -0
  93. package/package/components/VariableEditor.svelte +177 -199
  94. package/package/components/VariableEditor.svelte.d.ts +1 -2
  95. package/package/components/VariableForm.svelte +133 -0
  96. package/package/components/VariableForm.svelte.d.ts +22 -0
  97. package/package/components/WsSpecificVersions.svelte +39 -0
  98. package/package/components/WsSpecificVersions.svelte.d.ts +9 -0
  99. package/package/components/apps/components/helpers/RunnableComponent.svelte.d.ts +0 -1
  100. package/package/components/apps/editor/AppEditorHeaderDeploy.svelte.d.ts +1 -1
  101. package/package/components/common/table/AppRow.svelte +2 -1
  102. package/package/components/common/table/AppRow.svelte.d.ts +1 -0
  103. package/package/components/common/table/FlowRow.svelte +2 -1
  104. package/package/components/common/table/FlowRow.svelte.d.ts +1 -0
  105. package/package/components/common/table/RawAppRow.svelte +2 -1
  106. package/package/components/common/table/RawAppRow.svelte.d.ts +1 -0
  107. package/package/components/common/table/Row.svelte +11 -3
  108. package/package/components/common/table/Row.svelte.d.ts +2 -1
  109. package/package/components/common/table/RowIcon.svelte +18 -2
  110. package/package/components/common/table/RowIcon.svelte.d.ts +1 -1
  111. package/package/components/common/table/ScriptRow.svelte +2 -1
  112. package/package/components/common/table/ScriptRow.svelte.d.ts +1 -0
  113. package/package/components/copilot/autocomplete/Autocompletor.d.ts +3 -1
  114. package/package/components/copilot/autocomplete/Autocompletor.js +5 -2
  115. package/package/components/copilot/autocomplete/request.d.ts +1 -0
  116. package/package/components/copilot/autocomplete/request.js +1 -1
  117. package/package/components/copilot/chat/AIChatManager.svelte.js +14 -4
  118. package/package/components/copilot/chat/AiChatLayout.svelte +2 -0
  119. package/package/components/copilot/chat/ContextManager.svelte.d.ts +1 -0
  120. package/package/components/copilot/chat/CreatedResourceActionDrawers.svelte +129 -0
  121. package/package/components/copilot/chat/CreatedResourceActionDrawers.svelte.d.ts +4 -0
  122. package/package/components/copilot/chat/ToolExecutionDisplay.svelte +14 -6
  123. package/package/components/copilot/chat/ToolMessageActions.svelte +73 -0
  124. package/package/components/copilot/chat/ToolMessageActions.svelte.d.ts +7 -0
  125. package/package/components/copilot/chat/createdResourceActions.svelte.d.ts +6 -0
  126. package/package/components/copilot/chat/createdResourceActions.svelte.js +29 -0
  127. package/package/components/copilot/chat/script/core.d.ts +6 -2
  128. package/package/components/copilot/chat/script/core.js +13 -7
  129. package/package/components/copilot/chat/script/wacPrompt.test.d.ts +1 -0
  130. package/package/components/copilot/chat/script/wacPrompt.test.js +25 -0
  131. package/package/components/copilot/chat/shared.d.ts +12 -0
  132. package/package/components/copilot/chat/shared.test.js +23 -2
  133. package/package/components/copilot/chat/workspaceTools.js +34 -4
  134. package/package/components/flows/content/ScriptEditorDrawer.svelte +1 -0
  135. package/package/components/graph/wacToFlow.js +1 -1
  136. package/package/components/graph/wacToFlow.test.d.ts +1 -0
  137. package/package/components/graph/wacToFlow.test.js +17 -0
  138. package/package/components/home/Item.svelte +5 -1
  139. package/package/components/home/Item.svelte.d.ts +1 -0
  140. package/package/components/home/ItemsList.svelte +260 -3
  141. package/package/components/instanceSettings/SecretBackendConfig.svelte +457 -88
  142. package/package/components/runs/useJobsLoader.svelte.js +5 -11
  143. package/package/components/sidebar/WorkspaceMenu.svelte +19 -5
  144. package/package/externalDomain.d.ts +2 -0
  145. package/package/externalDomain.js +16 -0
  146. package/package/gen/core/OpenAPI.js +1 -1
  147. package/package/gen/types.gen.d.ts +0 -112
  148. package/package/hubPaths.json +2 -2
  149. package/package/system_prompts/index.d.ts +1 -1
  150. package/package/system_prompts/index.js +22 -3
  151. package/package/system_prompts/prompts.d.ts +2 -2
  152. package/package/system_prompts/prompts.js +6 -3
  153. package/package/utils_deployable.d.ts +162 -638
  154. package/package/utils_deployable.js +75 -143
  155. package/package/utils_workspace_deploy.d.ts +10 -4
  156. package/package/utils_workspace_deploy.js +167 -42
  157. package/package.json +7 -3
@@ -1,340 +1,227 @@
1
- <script lang="ts">import { run } from 'svelte/legacy';
2
- import { ResourceService } from '../gen';
3
- import { canWrite, emptyString, isOwner, urlize } from '../utils';
1
+ <script lang="ts">import { ResourceService, WorkspaceService } from '../gen';
2
+ import { canWrite } from '../utils';
4
3
  import { createEventDispatcher, untrack } from 'svelte';
5
- import { Alert, Skeleton } from './common';
6
- import Path from './Path.svelte';
7
- import LabelsInput from './LabelsInput.svelte';
8
- import Required from './Required.svelte';
9
4
  import { userStore, workspaceStore } from '../stores';
10
- import SchemaForm from './SchemaForm.svelte';
11
- import SimpleEditor from './SimpleEditor.svelte';
12
- import FilesetEditor from './FilesetEditor.svelte';
13
- import Toggle from './Toggle.svelte';
14
5
  import { sendUserToast } from '../toast';
15
- import TestConnection from './TestConnection.svelte';
16
- import { Pen } from 'lucide-svelte';
17
- import Markdown from 'svelte-exmarkdown';
18
- import autosize from '../autosize';
19
- import GfmMarkdown from './GfmMarkdown.svelte';
20
- import TestTriggerConnection from './triggers/TestTriggerConnection.svelte';
21
- import GitHubAppIntegration from './GitHubAppIntegration.svelte';
22
- import Button from './common/button/Button.svelte';
23
6
  import { clearJsonSchemaResourceCache } from './schema/jsonSchemaResource.svelte';
24
- import ResourceGen from './copilot/ResourceGen.svelte';
25
- import SyncResourceTypes from './SyncResourceTypes.svelte';
26
- let { canSave = $bindable(true), resource_type = $bindable(undefined), path = $bindable(''), hidePath = false, onChange, defaultValues = undefined, workspace = undefined } = $props();
7
+ import ResourceForm from './ResourceForm.svelte';
8
+ import Alert from './common/alert/Alert.svelte';
9
+ import { resource } from 'runed';
10
+ import { deepEqual } from 'fast-equals';
11
+ import { getUserExt } from '../user';
12
+ let { canSave = $bindable(true), resource_type = $bindable(undefined), path = $bindable(''), hidePath = false, onChange, defaultValues = undefined, workspace = undefined, selected = $bindable() } = $props();
13
+ const dispatch = createEventDispatcher();
27
14
  let effectiveWorkspace = $derived(workspace ?? $workspaceStore);
15
+ let initialPath = path;
16
+ let states = $state({});
17
+ let initialStates = $state({});
18
+ let existedInitially = $state({});
19
+ let fetchedResources = $state({});
20
+ let perWsUser = $state({});
28
21
  let isValid = $state(true);
29
22
  let jsonError = $state('');
30
- let can_write = $state(true);
31
- let initialPath = path;
32
- let resourceToEdit = $state(undefined);
33
- let description = $state('');
34
- let labels = $state(undefined);
35
- let DESCRIPTION_PLACEHOLDER = `Describe what this resource is for`;
36
- let resourceSchema = $state(undefined);
37
- let args = $state({});
38
- let loadingSchema = $state(true);
39
- let linkedVars = $state([]);
40
- let resourceTypeInfo = $state(undefined);
41
- let editDescription = $state(false);
42
23
  let viewJsonSchema = $state(false);
43
- let newResource = $derived(!path);
44
- const dispatch = createEventDispatcher();
45
- let rawCode = $state(undefined);
46
- async function initEdit() {
47
- resourceToEdit = await ResourceService.getResource({ workspace: effectiveWorkspace, path });
48
- description = resourceToEdit.description ?? '';
49
- labels = resourceToEdit.labels ?? undefined;
50
- resource_type = resourceToEdit.resource_type;
51
- args = resourceToEdit?.value ?? {};
52
- loadResourceType();
53
- can_write =
54
- resourceToEdit.workspace_id == effectiveWorkspace &&
55
- canWrite(path, resourceToEdit.extra_perms ?? {}, $userStore);
56
- linkedVars = Object.entries(args)
57
- .filter(([_, v]) => typeof v == 'string' && v == `$var:${initialPath}`)
58
- .map(([k, _]) => k);
59
- }
60
- if (!untrack(() => newResource)) {
61
- initEdit();
62
- }
63
- else if (resource_type) {
64
- loadResourceType();
65
- }
66
- else {
67
- sendUserToast('Resource type cannot be undefined for new resource creation', true);
68
- }
69
- export async function editResource() {
70
- if (resourceToEdit) {
71
- await ResourceService.updateResource({
72
- workspace: effectiveWorkspace,
73
- path: resourceToEdit.path,
74
- requestBody: { path, value: args, description, labels }
75
- });
76
- if (resourceToEdit.resource_type === 'json_schema') {
77
- clearJsonSchemaResourceCache(resourceToEdit.path, effectiveWorkspace);
24
+ let perWsValid = $state({});
25
+ const deployToResource = resource(() => selected, async (ws) => ws ? (await WorkspaceService.getDeployTo({ workspace: ws })).deploy_to : undefined);
26
+ const resourceTypeResource = resource([() => resource_type, () => effectiveWorkspace], async ([rt, ws]) => rt && ws ? ResourceService.getResourceType({ path: rt, workspace: ws }) : null);
27
+ let deployTo = $derived(deployToResource.current);
28
+ let resourceTypeInfo = $derived(resourceTypeResource.current ?? undefined);
29
+ let resourceSchema = $derived.by(() => {
30
+ const rt = resourceTypeResource.current;
31
+ if (!rt?.schema)
32
+ return undefined;
33
+ const schema = rt.schema;
34
+ return {
35
+ ...schema,
36
+ order: schema.order ?? Object.keys(schema.properties).sort()
37
+ };
38
+ });
39
+ let loadingSchema = $derived(resourceTypeResource.loading);
40
+ let current = $derived(selected ? states[selected] : undefined);
41
+ let resourceToEdit = $derived(selected ? fetchedResources[selected] : undefined);
42
+ let can_write = $derived.by(() => {
43
+ if (!selected)
44
+ return true;
45
+ const r = fetchedResources[selected];
46
+ if (!r)
47
+ return true;
48
+ return canWrite(current?.path ?? initialPath, r.extra_perms ?? {}, perWsUser[selected] ?? $userStore);
49
+ });
50
+ let linkedVars = $derived(Object.entries(current?.args ?? {})
51
+ .filter(([_, v]) => typeof v == 'string' && v == `$var:${initialPath}`)
52
+ .map(([k, _]) => k));
53
+ const dirtyWorkspaces = $derived(Object.keys(states).filter((ws) => !deepEqual(states[ws], initialStates[ws])));
54
+ const anyDirty = $derived(dirtyWorkspaces.length > 0);
55
+ const otherDirty = $derived(dirtyWorkspaces.length == 1
56
+ ? dirtyWorkspaces.filter((ws) => ws !== $workspaceStore)
57
+ : dirtyWorkspaces);
58
+ const dirtyValid = $derived(dirtyWorkspaces.every((ws) => perWsValid[ws] !== false));
59
+ const dirtyCanWrite = $derived(dirtyWorkspaces.every((ws) => {
60
+ const r = fetchedResources[ws];
61
+ return (!r ||
62
+ canWrite(states[ws]?.path ?? initialPath, r.extra_perms ?? {}, perWsUser[ws] ?? $userStore));
63
+ }));
64
+ // Bootstrap: ensure selected is set on mount (edit or new)
65
+ $effect(() => {
66
+ if (selected !== undefined)
67
+ return;
68
+ if (!effectiveWorkspace)
69
+ return;
70
+ untrack(() => {
71
+ selected = effectiveWorkspace;
72
+ if (!initialPath) {
73
+ // New resource
74
+ const s = {
75
+ path: '',
76
+ description: '',
77
+ args: (defaultValues && Object.keys(defaultValues).length > 0
78
+ ? defaultValues
79
+ : {}),
80
+ labels: undefined,
81
+ wsSpecific: false
82
+ };
83
+ states[effectiveWorkspace] = s;
84
+ initialStates[effectiveWorkspace] = structuredClone(s);
85
+ existedInitially[effectiveWorkspace] = false;
78
86
  }
79
- sendUserToast(`Updated resource at ${path}`);
80
- dispatch('refresh', path);
81
- }
82
- else {
83
- throw Error('Cannot edit undefined resource');
84
- }
85
- }
86
- export async function createResource() {
87
- await ResourceService.createResource({
88
- workspace: effectiveWorkspace,
89
- requestBody: { path, value: args, description, resource_type: resource_type, labels }
90
87
  });
91
- sendUserToast(`Updated resource at ${path}`);
92
- dispatch('refresh', path);
93
- }
94
- async function loadResourceType() {
95
- if (resource_type) {
96
- try {
97
- const resourceType = await ResourceService.getResourceType({
98
- workspace: effectiveWorkspace,
99
- path: resource_type
100
- });
101
- resourceTypeInfo = resourceType;
102
- if (resourceType.schema) {
103
- resourceSchema = resourceType.schema;
104
- resourceSchema.order =
105
- resourceSchema.order ?? Object.keys(resourceSchema.properties).sort();
106
- }
107
- if (resourceTypeInfo?.format_extension && !resourceTypeInfo?.is_fileset) {
108
- textFileContent = args.content;
88
+ });
89
+ // Lazy-fetch the resource for the selected workspace when not already cached
90
+ $effect(() => {
91
+ const ws = selected;
92
+ if (!ws || !initialPath)
93
+ return;
94
+ if (ws in states)
95
+ return;
96
+ untrack(() => {
97
+ Promise.all([
98
+ ResourceService.getResource({ workspace: ws, path: initialPath }),
99
+ getUserExt(ws)
100
+ ]).then(([r, user]) => {
101
+ fetchedResources[ws] = r;
102
+ const s = {
103
+ path: r.path,
104
+ description: r.description ?? '',
105
+ args: (r.value ?? {}),
106
+ labels: r.labels ?? undefined,
107
+ wsSpecific: r.ws_specific ?? false
108
+ };
109
+ states[ws] = s;
110
+ initialStates[ws] = structuredClone(s);
111
+ existedInitially[ws] = true;
112
+ perWsUser[ws] = user;
113
+ // Keep resource_type in sync for the base workspace (controls the schema)
114
+ if (ws === effectiveWorkspace) {
115
+ resource_type = r.resource_type;
109
116
  }
110
- }
111
- catch (err) {
112
- resourceSchema = undefined;
113
- loadingSchema = false;
114
- rawCode = JSON.stringify(args, null, 2);
115
- }
116
- }
117
- else {
118
- sendUserToast(`ResourceType cannot be undefined.`, true);
119
- }
120
- loadingSchema = false;
121
- }
122
- function parseJson() {
123
- try {
124
- args = JSON.parse(rawCode ?? '');
125
- jsonError = '';
126
- }
127
- catch (e) {
128
- jsonError = e.message;
129
- }
130
- }
131
- function updateArgsFromLinkedVars() {
132
- linkedVars.forEach((k) => {
133
- args[k] = `$var:${path}`;
117
+ });
134
118
  });
135
- }
136
- let textFileContent = $state('');
137
- function switchTab(asJson) {
138
- viewJsonSchema = asJson;
139
- if (asJson) {
140
- rawCode = JSON.stringify(args, null, 2);
141
- }
142
- else {
143
- parseJson();
144
- if (resourceTypeInfo?.format_extension && !resourceTypeInfo?.is_fileset) {
145
- textFileContent = args.content;
146
- }
147
- }
148
- }
149
- function parseTextFileContent() {
150
- args = {
151
- content: textFileContent
152
- };
153
- }
154
- run(() => {
155
- if (defaultValues && Object.keys(defaultValues).length > 0) {
156
- args = defaultValues;
157
- }
158
119
  });
159
- run(() => {
160
- canSave = (can_write && isValid && jsonError == '') || (viewJsonSchema && jsonError == '');
120
+ // Keep current.path bound to the outer `path` prop for consumers
121
+ $effect(() => {
122
+ if (current)
123
+ path = current.path;
161
124
  });
162
125
  $effect(() => {
163
- onChange && onChange({ path, args, description });
126
+ if (selected !== undefined) {
127
+ perWsValid[selected] = isValid && jsonError == '';
128
+ }
164
129
  });
165
- run(() => {
166
- rawCode && untrack(() => parseJson());
130
+ $effect(() => {
131
+ canSave = anyDirty && dirtyValid && dirtyCanWrite;
167
132
  });
168
- run(() => {
169
- linkedVars.length > 0 && path && untrack(() => updateArgsFromLinkedVars());
133
+ $effect(() => {
134
+ if (current)
135
+ onChange?.({ path: current.path, args: current.args, description: current.description });
170
136
  });
171
- run(() => {
172
- textFileContent && untrack(() => parseTextFileContent());
137
+ $effect(() => {
138
+ if (!current)
139
+ return;
140
+ if (linkedVars.length > 0 && current.path) {
141
+ untrack(() => {
142
+ linkedVars.forEach((k) => {
143
+ current.args[k] = `$var:${current.path}`;
144
+ });
145
+ });
146
+ }
173
147
  });
148
+ export async function save() {
149
+ const dirty = dirtyWorkspaces;
150
+ try {
151
+ for (const ws of dirty) {
152
+ const s = states[ws];
153
+ const ini = initialStates[ws];
154
+ if (existedInitially[ws]) {
155
+ await ResourceService.updateResource({
156
+ workspace: ws,
157
+ path: ini.path,
158
+ requestBody: {
159
+ path: s.path,
160
+ value: s.args,
161
+ description: s.description,
162
+ labels: s.labels,
163
+ ws_specific: s.wsSpecific
164
+ }
165
+ });
166
+ const fetched = fetchedResources[ws];
167
+ if (fetched?.resource_type === 'json_schema') {
168
+ clearJsonSchemaResourceCache(ini.path, ws);
169
+ }
170
+ }
171
+ else {
172
+ await ResourceService.createResource({
173
+ workspace: ws,
174
+ requestBody: {
175
+ path: s.path,
176
+ value: s.args,
177
+ description: s.description,
178
+ resource_type: resource_type,
179
+ labels: s.labels,
180
+ ws_specific: s.wsSpecific
181
+ }
182
+ });
183
+ }
184
+ }
185
+ sendUserToast(dirty.length > 1 ? `Saved resource in ${dirty.length} workspaces` : `Saved resource`);
186
+ dispatch('refresh', current?.path ?? path);
187
+ }
188
+ catch (err) {
189
+ sendUserToast(`Could not save resource: ${err.body ?? err.message}`, true);
190
+ }
191
+ }
174
192
  </script>
175
193
 
176
194
  <div>
177
195
  <div class="flex flex-col gap-6 py-2">
178
- {#if !hidePath}
179
- <div>
180
- {#if !can_write}
181
- <div class="m-2">
182
- <Alert type="warning" title="Only read access">
183
- You only have read access to this resource and cannot edit it
184
- </Alert>
185
- </div>
186
- {/if}
187
- <Path
188
- disabled={initialPath != '' && !isOwner(initialPath, $userStore, $workspaceStore)}
189
- bind:path
190
- {initialPath}
191
- namePlaceholder="resource"
192
- kind="resource"
193
- />
194
- </div>
196
+ {#if otherDirty.length > 0}
197
+ <Alert type="warning" title="Editing multiple workspaces">
198
+ You are going to edit the value in: {otherDirty.join(', ')}
199
+ </Alert>
195
200
  {/if}
196
- <LabelsInput bind:labels class="-mt-4" />
197
201
 
198
- {#if !emptyString(resourceTypeInfo?.description)}
199
- <div class="flex flex-col gap-1">
200
- <h4 class="text-xs text-emphasis font-semibold">{resourceTypeInfo?.name} description</h4>
201
- <div class="text-xs text-primary font-normal">
202
- <Markdown md={urlize(resourceTypeInfo?.description ?? '', 'md')} />
203
- </div>
204
- </div>
205
- {/if}
206
-
207
- <div class="flex flex-col gap-1">
208
- <h4 class="inline-flex items-center gap-2 text-xs text-emphasis font-semibold"
209
- >Resource description <Required required={false} />
210
- {#if can_write}
211
- <Button
212
- variant="subtle"
213
- unifiedSize="xs"
214
- btnClasses={editDescription ? 'bg-surface-hover' : ''}
215
- startIcon={{ icon: Pen }}
216
- on:click={() => (editDescription = !editDescription)}
217
- />
218
- {/if}
219
- </h4>
220
- {#if can_write && editDescription}
221
- <div class="relative">
222
- <div class="text-2xs text-primary absolute -top-4 right-0">GH Markdown</div>
223
- <textarea
224
- class="text-xs text-primary font-normal"
225
- disabled={!can_write}
226
- use:autosize
227
- bind:value={description}
228
- placeholder={DESCRIPTION_PLACEHOLDER}
229
- ></textarea>
230
- </div>
231
- {:else if description == undefined || description == ''}
232
- <div class="text-xs text-secondary font-normal">No description provided</div>
233
- {:else}
234
- <div class="text-xs text-primary font-normal">
235
- <GfmMarkdown md={description} noPadding />
236
- </div>
237
- {/if}
238
- </div>
239
-
240
- <div class="flex flex-col gap-1">
241
- <div class="w-full flex gap-4 flex-row-reverse items-center">
242
- <Toggle
243
- on:change={(e) => switchTab(e.detail)}
244
- options={{
245
- right: 'As JSON'
246
- }}
247
- />
248
- <ResourceGen
249
- bind:args
250
- resourceType={resource_type}
251
- resourceName={path}
252
- resourceDescription={description}
202
+ {#if current}
203
+ {#key current}
204
+ <ResourceForm
205
+ bind:path={current.path}
206
+ bind:labels={current.labels}
207
+ bind:description={current.description}
208
+ bind:args={current.args}
209
+ bind:wsSpecific={current.wsSpecific}
210
+ bind:isValid
211
+ bind:viewJsonSchema
212
+ bind:jsonError
213
+ {initialPath}
214
+ {hidePath}
215
+ {deployTo}
216
+ {can_write}
217
+ {resource_type}
218
+ {resourceTypeInfo}
253
219
  {resourceSchema}
220
+ {loadingSchema}
221
+ {resourceToEdit}
222
+ onLoadResourceType={() => resourceTypeResource.refetch()}
254
223
  />
255
- {#if resourceToEdit?.resource_type === 'nats' || resourceToEdit?.resource_type === 'kafka'}
256
- <TestTriggerConnection kind={resourceToEdit?.resource_type} args={{ connection: args }} />
257
- {:else}
258
- <TestConnection resourceType={resourceToEdit?.resource_type} {args} />
259
- {/if}
260
- {#if resource_type === 'git_repository' && $workspaceStore && ($userStore?.is_admin || $userStore?.is_super_admin)}
261
- <GitHubAppIntegration
262
- resourceType={resource_type}
263
- {args}
264
- {description}
265
- onArgsUpdate={(newArgs) => {
266
- args = newArgs
267
- // Update rawCode if in JSON view mode
268
- if (viewJsonSchema) {
269
- rawCode = JSON.stringify(args, null, 2)
270
- }
271
- }}
272
- onDescriptionUpdate={(newDescription) => (description = newDescription)}
273
- />
274
- {/if}
275
- </div>
276
-
277
- <div>
278
- {#if loadingSchema}
279
- <Skeleton layout={[[4]]} />
280
- {:else if !viewJsonSchema && resourceTypeInfo?.is_fileset}
281
- <div class="mt-1 flex items-center gap-2">
282
- <h5 class="inline-flex items-center gap-4">Fileset</h5>
283
- <ResourceGen
284
- bind:args
285
- resourceType={resource_type}
286
- resourceName={path}
287
- resourceDescription={description}
288
- {resourceSchema}
289
- isFileset
290
- />
291
- </div>
292
- <FilesetEditor bind:args />
293
- {:else if !viewJsonSchema && resourceSchema && resourceSchema?.properties}
294
- {#if resourceTypeInfo?.format_extension}
295
- <h5 class="mt-1 inline-flex items-center gap-4">
296
- File content ({resourceTypeInfo.format_extension})
297
- </h5>
298
- <div class="">
299
- <SimpleEditor
300
- autoHeight
301
- lang={resourceTypeInfo.format_extension}
302
- bind:code={textFileContent}
303
- fixedOverflowWidgets={false}
304
- />
305
- </div>
306
- {:else}
307
- <SchemaForm
308
- onlyMaskPassword
309
- noDelete
310
- disabled={!can_write}
311
- compact
312
- schema={resourceSchema}
313
- bind:args
314
- bind:isValid
315
- />
316
- {/if}
317
- {:else if !can_write}
318
- <input type="text" disabled value={rawCode} />
319
- {:else}
320
- {#if !viewJsonSchema}
321
- <div class="flex flex-col gap-2 mb-4">
322
- <p class="text-red-500 dark:text-red-400 text-xs">
323
- Resource type '{resource_type}' not found in your workspace
324
- </p>
325
- <SyncResourceTypes onSynced={loadResourceType} />
326
- <p class="italic text-secondary text-xs"> Define the value in JSON directly </p>
327
- </div>
328
- {/if}
329
-
330
- {#if !emptyString(jsonError)}<span class="text-red-400 text-xs mb-1 flex flex-row-reverse"
331
- >{jsonError}</span
332
- >{:else}<div class="py-2"></div>{/if}
333
- <div class="bg-surface-tertiary rounded-md border py-2.5">
334
- <SimpleEditor autoHeight lang="json" bind:code={rawCode} />
335
- </div>
336
- {/if}
337
- </div>
338
- </div>
224
+ {/key}
225
+ {/if}
339
226
  </div>
340
227
  </div>
@@ -10,6 +10,7 @@ interface Props {
10
10
  }) => void;
11
11
  defaultValues?: Record<string, any> | undefined;
12
12
  workspace?: string | undefined;
13
+ selected?: string | undefined;
13
14
  }
14
15
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
15
16
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
@@ -29,8 +30,7 @@ declare const ResourceEditor: $$__sveltets_2_IsomorphicComponent<Props, {
29
30
  } & {
30
31
  [evt: string]: CustomEvent<any>;
31
32
  }, {}, {
32
- editResource: () => Promise<void>;
33
- createResource: () => Promise<void>;
34
- }, "path" | "resource_type" | "canSave">;
33
+ save: () => Promise<void>;
34
+ }, "path" | "resource_type" | "selected" | "canSave">;
35
35
  type ResourceEditor = InstanceType<typeof ResourceEditor>;
36
36
  export default ResourceEditor;
@@ -1,6 +1,8 @@
1
1
  <script lang="ts">import { Button, Drawer } from './common';
2
2
  import DrawerContent from './common/drawer/DrawerContent.svelte';
3
3
  import { Loader2, Save } from 'lucide-svelte';
4
+ import WsSpecificVersions from './WsSpecificVersions.svelte';
5
+ import { workspaceStore } from '../stores';
4
6
  let { workspace = undefined, disableChatOffset = false } = $props();
5
7
  let drawer = $state();
6
8
  let canSave = $state(true);
@@ -8,21 +10,25 @@ let resource_type = $state(undefined);
8
10
  let defaultValues = $state(undefined);
9
11
  let resourceEditor = $state(undefined);
10
12
  let path = $state(undefined);
13
+ let selected = $state(undefined);
14
+ let effectiveWorkspace = $derived(workspace ?? $workspaceStore);
11
15
  export async function initEdit(p) {
12
16
  resource_type = undefined;
13
17
  path = p;
18
+ selected = effectiveWorkspace;
14
19
  drawer?.openDrawer?.();
15
20
  }
16
21
  export async function initNew(resourceType, nDefaultValues) {
17
22
  path = undefined;
18
23
  resource_type = resourceType;
19
24
  defaultValues = nDefaultValues;
25
+ selected = effectiveWorkspace;
20
26
  drawer?.openDrawer?.();
21
27
  }
22
28
  let mode = $derived(!path ? 'new' : 'edit');
23
29
  </script>
24
30
 
25
- <Drawer bind:this={drawer} size="800px" {disableChatOffset}>
31
+ <Drawer bind:this={drawer} size="50rem" {disableChatOffset}>
26
32
  <DrawerContent
27
33
  title={mode == 'edit' ? 'Edit ' + path : 'Add a resource'}
28
34
  on:close={drawer?.closeDrawer}
@@ -38,19 +44,24 @@ let mode = $derived(!path ? 'new' : 'edit');
38
44
  on:refresh
39
45
  bind:this={resourceEditor}
40
46
  bind:canSave
47
+ bind:selected
41
48
  />
42
49
  {/await}
43
50
  {#snippet actions()}
51
+ {#if mode == 'edit' && path && effectiveWorkspace}
52
+ <WsSpecificVersions
53
+ kind="resource"
54
+ workspaceId={effectiveWorkspace}
55
+ initialPath={path}
56
+ bind:selected
57
+ />
58
+ {/if}
44
59
  <Button
45
60
  variant="accent"
46
61
  unifiedSize="md"
47
62
  startIcon={{ icon: Save }}
48
63
  on:click={() => {
49
- if (mode == 'edit') {
50
- resourceEditor?.editResource()
51
- } else {
52
- resourceEditor?.createResource()
53
- }
64
+ resourceEditor?.save()
54
65
  drawer?.closeDrawer()
55
66
  }}
56
67
  disabled={!canSave}