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,126 +1,176 @@
1
- <script lang="ts">import { VariableService } from '../gen';
2
- import Path from './Path.svelte';
3
- import LabelsInput from './LabelsInput.svelte';
4
- import { createEventDispatcher } from 'svelte';
1
+ <script lang="ts">import { VariableService, WorkspaceService } from '../gen';
2
+ import { createEventDispatcher, untrack } from 'svelte';
5
3
  import { userStore, workspaceStore } from '../stores';
6
- import Tooltip from './Tooltip.svelte';
7
4
  import { Button } from './common';
8
5
  import Drawer from './common/drawer/Drawer.svelte';
9
6
  import DrawerContent from './common/drawer/DrawerContent.svelte';
10
7
  import Alert from './common/alert/Alert.svelte';
11
- import Toggle from './Toggle.svelte';
12
8
  import { sendUserToast } from '../toast';
13
- import { canWrite, isOwner } from '../utils';
14
- import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte';
15
- import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte';
16
- import { Loader2, Save } from 'lucide-svelte';
17
- import autosize from '../autosize';
9
+ import { canWrite } from '../utils';
10
+ import { Save } from 'lucide-svelte';
11
+ import VariableForm from './VariableForm.svelte';
12
+ import WsSpecificVersions from './WsSpecificVersions.svelte';
13
+ import { resource } from 'runed';
14
+ import { deepEqual } from 'fast-equals';
15
+ import { getUserExt } from '../user';
18
16
  const dispatch = createEventDispatcher();
19
- let path = $state('');
20
- let variable = $state({
21
- value: '',
22
- is_secret: true,
23
- description: ''
24
- });
25
- let valid = $state(true);
26
- let labels = $state(undefined);
27
- let drawer = $state();
28
- let edit = $state(false);
29
- let initialPath = $state('');
17
+ let editPath = $state(undefined);
18
+ let states = $state({});
19
+ let initialStates = $state({});
20
+ let existedInitially = $state({});
21
+ let extraPerms = $state({});
22
+ let perWsUser = $state({});
23
+ let selected = $state(undefined);
30
24
  let pathError = $state('');
31
- let can_write = $state(true);
25
+ let drawer = $state();
26
+ let form = $state();
27
+ const deployTo = resource(() => selected, async (ws) => ws ? (await WorkspaceService.getDeployTo({ workspace: ws })).deploy_to : undefined);
28
+ const MAX_VARIABLE_LENGTH = 10000;
29
+ const edit = $derived(editPath !== undefined);
30
+ const initialPath = $derived(editPath ?? '');
31
+ const current = $derived(selected ? states[selected] : undefined);
32
+ const can_write = $derived.by(() => {
33
+ if (!selected || !edit)
34
+ return true;
35
+ const perms = extraPerms[selected];
36
+ if (!perms)
37
+ return true;
38
+ return canWrite(editPath ?? '', perms, perWsUser[selected] ?? $userStore);
39
+ });
40
+ const dirtyWorkspaces = $derived(Object.keys(states).filter((ws) => !deepEqual(states[ws], initialStates[ws])));
41
+ const anyDirty = $derived(dirtyWorkspaces.length > 0);
42
+ const otherDirty = $derived(dirtyWorkspaces.length == 1
43
+ ? dirtyWorkspaces.filter((ws) => ws !== $workspaceStore)
44
+ : dirtyWorkspaces);
45
+ const dirtyValid = $derived(dirtyWorkspaces.every((ws) => states[ws].variable.value.length <= MAX_VARIABLE_LENGTH));
46
+ const dirtyCanWrite = $derived(dirtyWorkspaces.every((ws) => {
47
+ const perms = extraPerms[ws];
48
+ return !perms || canWrite(editPath ?? '', perms, perWsUser[ws] ?? $userStore);
49
+ }));
50
+ // Lazy-fetch the variable for the selected workspace when not already cached
51
+ $effect(() => {
52
+ const ws = selected;
53
+ const p = editPath;
54
+ if (!ws || !p)
55
+ return;
56
+ if (ws in states)
57
+ return;
58
+ untrack(() => {
59
+ Promise.all([
60
+ VariableService.getVariable({ workspace: ws, path: p, decryptSecret: false }),
61
+ getUserExt(ws)
62
+ ]).then(([v, user]) => {
63
+ const s = {
64
+ path: v.path,
65
+ variable: {
66
+ value: v.value ?? '',
67
+ is_secret: v.is_secret,
68
+ description: v.description ?? ''
69
+ },
70
+ labels: v.labels ?? undefined,
71
+ wsSpecific: v.ws_specific ?? false
72
+ };
73
+ states[ws] = s;
74
+ initialStates[ws] = structuredClone(s);
75
+ existedInitially[ws] = true;
76
+ extraPerms[ws] = v.extra_perms ?? {};
77
+ perWsUser[ws] = user;
78
+ });
79
+ });
80
+ });
81
+ function reset() {
82
+ states = {};
83
+ initialStates = {};
84
+ existedInitially = {};
85
+ extraPerms = {};
86
+ perWsUser = {};
87
+ pathError = '';
88
+ }
32
89
  export function initNew() {
33
- variable = {
34
- value: '',
35
- is_secret: true,
36
- description: ''
90
+ reset();
91
+ editPath = undefined;
92
+ const ws = $workspaceStore;
93
+ const s = {
94
+ path: '',
95
+ variable: { value: '', is_secret: true, description: '' },
96
+ labels: undefined,
97
+ wsSpecific: false
37
98
  };
38
- edit = false;
39
- initialPath = '';
40
- path = '';
41
- labels = undefined;
42
- can_write = true;
99
+ states[ws] = s;
100
+ initialStates[ws] = structuredClone(s);
101
+ existedInitially[ws] = false;
102
+ selected = ws;
43
103
  drawer?.openDrawer();
44
104
  }
45
- export async function editVariable(edit_path) {
46
- edit = true;
47
- const getV = await VariableService.getVariable({
48
- workspace: $workspaceStore ?? '',
49
- path: edit_path,
50
- decryptSecret: false
51
- });
52
- can_write =
53
- getV.workspace_id == $workspaceStore &&
54
- canWrite(edit_path, getV.extra_perms ?? {}, $userStore);
55
- variable = {
56
- value: getV.value ?? '',
57
- is_secret: getV.is_secret,
58
- description: getV.description ?? ''
59
- };
60
- labels = getV.labels ?? undefined;
61
- initialPath = edit_path;
62
- path = edit_path;
105
+ export function editVariable(edit_path) {
106
+ reset();
107
+ editPath = edit_path;
108
+ selected = $workspaceStore;
63
109
  drawer?.openDrawer();
64
110
  }
65
- export async function loadVariable(path) {
111
+ async function loadSecret() {
112
+ if (!editPath || !selected)
113
+ return;
66
114
  const getV = await VariableService.getVariable({
67
- workspace: $workspaceStore ?? '',
68
- path,
115
+ workspace: selected,
116
+ path: editPath,
69
117
  decryptSecret: true
70
118
  });
71
- variable.value = getV.value ?? '';
72
- editor?.setCode(variable.value);
119
+ const s = states[selected];
120
+ const ini = initialStates[selected];
121
+ if (s)
122
+ s.variable.value = getV.value ?? '';
123
+ if (ini)
124
+ ini.variable.value = getV.value ?? '';
125
+ form?.setCode(getV.value ?? '');
73
126
  }
74
- const MAX_VARIABLE_LENGTH = 10000;
75
- $effect(() => {
76
- valid = variable.value.length <= MAX_VARIABLE_LENGTH;
77
- });
78
- async function createVariable() {
79
- await VariableService.createVariable({
80
- workspace: $workspaceStore,
81
- requestBody: {
82
- path,
83
- value: variable.value,
84
- is_secret: variable.is_secret,
85
- description: variable.description,
86
- labels
87
- }
88
- });
89
- sendUserToast(`Created variable ${path}`);
90
- dispatch('create');
91
- drawer?.closeDrawer();
92
- }
93
- async function updateVariable() {
127
+ async function save() {
128
+ const dirty = dirtyWorkspaces;
94
129
  try {
95
- const getV = await VariableService.getVariable({
96
- workspace: $workspaceStore ?? '',
97
- path: initialPath,
98
- decryptSecret: false
99
- });
100
- await VariableService.updateVariable({
101
- workspace: $workspaceStore,
102
- path: initialPath,
103
- requestBody: {
104
- path: getV.path != path ? path : undefined,
105
- value: variable.value == '' ? undefined : variable.value,
106
- is_secret: getV.is_secret != variable.is_secret ? variable.is_secret : undefined,
107
- description: getV.description != variable.description ? variable.description : undefined,
108
- labels
130
+ for (const ws of dirty) {
131
+ const s = states[ws];
132
+ const ini = initialStates[ws];
133
+ if (existedInitially[ws]) {
134
+ await VariableService.updateVariable({
135
+ workspace: ws,
136
+ path: ini.path,
137
+ requestBody: {
138
+ path: ini.path != s.path ? s.path : undefined,
139
+ value: s.variable.value == '' ? undefined : s.variable.value,
140
+ is_secret: ini.variable.is_secret != s.variable.is_secret ? s.variable.is_secret : undefined,
141
+ description: ini.variable.description != s.variable.description
142
+ ? s.variable.description
143
+ : undefined,
144
+ labels: s.labels,
145
+ ws_specific: s.wsSpecific
146
+ }
147
+ });
109
148
  }
110
- });
111
- sendUserToast(`Updated variable ${initialPath}`);
149
+ else {
150
+ await VariableService.createVariable({
151
+ workspace: ws,
152
+ requestBody: {
153
+ path: s.path,
154
+ value: s.variable.value,
155
+ is_secret: s.variable.is_secret,
156
+ description: s.variable.description,
157
+ labels: s.labels,
158
+ ws_specific: s.wsSpecific
159
+ }
160
+ });
161
+ }
162
+ }
163
+ sendUserToast(edit ? `Updated variable in ${dirty.length} workspace(s)` : `Created variable`);
112
164
  dispatch('create');
113
165
  drawer?.closeDrawer();
114
166
  }
115
167
  catch (err) {
116
- sendUserToast(`Could not update variable: ${err.body}`, true);
168
+ sendUserToast(`Could not save variable: ${err.body}`, true);
117
169
  }
118
170
  }
119
- let editorKind = $state('plain');
120
- let editor = $state(undefined);
121
171
  </script>
122
172
 
123
- <Drawer bind:this={drawer} size="900px">
173
+ <Drawer bind:this={drawer} size="50rem">
124
174
  <DrawerContent
125
175
  title={edit ? `Update variable at ${initialPath}` : 'Add a variable'}
126
176
  on:close={drawer?.closeDrawer}
@@ -132,114 +182,42 @@ let editor = $state(undefined);
132
182
  </Alert>
133
183
  {/if}
134
184
 
135
- <div class="flex flex-col gap-1">
136
- <label for="path" class="text-xs font-semibold text-emphasis">Path</label>
137
- <Path
138
- disabled={initialPath != '' && !isOwner(initialPath, $userStore, $workspaceStore)}
139
- bind:error={pathError}
140
- bind:path
141
- {initialPath}
142
- namePlaceholder="variable"
143
- kind="variable"
144
- />
145
- <LabelsInput bind:labels />
146
- </div>
147
- <label class="flex flex-col gap-1">
148
- <span class="text-xs font-semibold text-emphasis">Secret</span>
149
- <Toggle
150
- on:change={() => edit && loadVariable(initialPath)}
151
- bind:checked={variable.is_secret}
152
- disabled={edit && $userStore?.operator}
153
- />
154
- {#if variable.is_secret}
155
- <Alert type="warning" title="Audit log for each access">
156
- Every secret is encrypted at rest and in transit with a key specific to this workspace.
157
- In addition, any read of a secret variable generates an audit log whose operation name
158
- is: variables.decrypt_secret
159
- </Alert>
160
- {/if}
161
- </label>
162
-
163
- <div class="flex flex-col gap-1">
164
- <label for="variable-value" class="flex flex-row justify-left items-center">
165
- <span class="text-xs font-semibold text-emphasis">Variable value&nbsp;</span>
185
+ {#if otherDirty.length > 0}
186
+ <Alert type="warning" title="Editing multiple workspaces">
187
+ You are going to edit the value in: {otherDirty.join(', ')}
188
+ </Alert>
189
+ {/if}
166
190
 
167
- <span class="text-xs text-secondary font-normal">
168
- ({variable.value.length}/{MAX_VARIABLE_LENGTH} characters)
169
- </span>
170
- {#if edit && variable.is_secret}
171
- <div class="ml-3"></div>
172
- {#if $userStore?.operator}
173
- <div class="p-2 border">Operators cannot load secret value</div>
174
- {:else}
175
- <Button size="xs" variant="default" on:click={() => loadVariable(initialPath)}>
176
- Load secret value<Tooltip>Will generate an audit log</Tooltip>
177
- </Button>
178
- {/if}
179
- {/if}
180
- </label>
181
- <div>
182
- <div class="flex flex-col gap-2">
183
- <ToggleButtonGroup bind:selected={editorKind}>
184
- {#snippet children({ item })}
185
- <ToggleButton value="plain" label="Plain" {item} />
186
- <ToggleButton value="json" label="Json" {item} />
187
- <ToggleButton value="yaml" label="YAML" {item} />
188
- {/snippet}
189
- </ToggleButtonGroup>
190
- {#if editorKind == 'plain'}
191
- <textarea
192
- disabled={!can_write}
193
- rows="4"
194
- use:autosize
195
- bind:value={variable.value}
196
- placeholder="Update variable value"
197
- id="variable-value"
198
- ></textarea>
199
- {:else if editorKind == 'json'}
200
- <div class="border rounded mb-4 w-full">
201
- {#await import('./SimpleEditor.svelte')}
202
- <Loader2 class="animate-spin" />
203
- {:then Module}
204
- <Module.default
205
- bind:this={editor}
206
- autoHeight
207
- lang="json"
208
- bind:code={variable.value}
209
- fixedOverflowWidgets={false}
210
- class="bg-surface-tertiary"
211
- />
212
- {/await}
213
- </div>
214
- {:else if editorKind == 'yaml'}
215
- <div class="border rounded mb-4 w-full">
216
- {#await import('./SimpleEditor.svelte')}
217
- <Loader2 class="animate-spin" />
218
- {:then Module}
219
- <Module.default
220
- bind:this={editor}
221
- autoHeight
222
- lang="yaml"
223
- bind:code={variable.value}
224
- fixedOverflowWidgets={false}
225
- class="bg-surface-tertiary"
226
- />
227
- {/await}
228
- </div>
229
- {/if}
230
- </div>
231
- </div>
232
- </div>
233
- <label class="flex flex-col gap-1">
234
- <span class="text-xs font-semibold text-emphasis">Description</span>
235
- <textarea rows="4" use:autosize bind:value={variable.description} placeholder="Used for X"
236
- ></textarea>
237
- </label>
191
+ {#if current}
192
+ {#key current}
193
+ <VariableForm
194
+ bind:this={form}
195
+ bind:path={current.path}
196
+ bind:pathError
197
+ bind:variable={current.variable}
198
+ bind:labels={current.labels}
199
+ bind:wsSpecific={current.wsSpecific}
200
+ {initialPath}
201
+ deployTo={deployTo.current}
202
+ {can_write}
203
+ {edit}
204
+ onLoadSecret={loadSecret}
205
+ />
206
+ {/key}
207
+ {/if}
238
208
  </div>
239
209
  {#snippet actions()}
210
+ {#if edit && $workspaceStore}
211
+ <WsSpecificVersions
212
+ kind="variable"
213
+ workspaceId={$workspaceStore}
214
+ {initialPath}
215
+ bind:selected
216
+ />
217
+ {/if}
240
218
  <Button
241
- on:click={() => (edit ? updateVariable() : createVariable())}
242
- disabled={!can_write || !valid || pathError != ''}
219
+ on:click={save}
220
+ disabled={!anyDirty || !dirtyValid || !dirtyCanWrite || pathError != ''}
243
221
  startIcon={{ icon: Save }}
244
222
  variant="accent"
245
223
  size="sm"
@@ -17,8 +17,7 @@ declare const VariableEditor: $$__sveltets_2_IsomorphicComponent<Record<string,
17
17
  [evt: string]: CustomEvent<any>;
18
18
  }, {}, {
19
19
  initNew: () => void;
20
- editVariable: (edit_path: string) => Promise<void>;
21
- loadVariable: (path: string) => Promise<void>;
20
+ editVariable: (edit_path: string) => void;
22
21
  }, "">;
23
22
  type VariableEditor = InstanceType<typeof VariableEditor>;
24
23
  export default VariableEditor;
@@ -0,0 +1,133 @@
1
+ <script lang="ts">import Path from './Path.svelte';
2
+ import LabelsInput from './LabelsInput.svelte';
3
+ import Toggle from './Toggle.svelte';
4
+ import Alert from './common/alert/Alert.svelte';
5
+ import { Button } from './common';
6
+ import Tooltip from './Tooltip.svelte';
7
+ import Label from './Label.svelte';
8
+ import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte';
9
+ import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte';
10
+ import { Loader2 } from 'lucide-svelte';
11
+ import autosize from '../autosize';
12
+ import { userStore, workspaceStore } from '../stores';
13
+ import { isOwner } from '../utils';
14
+ let { path = $bindable(), initialPath, pathError = $bindable(), variable = $bindable(), labels = $bindable(), wsSpecific = $bindable(), deployTo, can_write, edit, onLoadSecret } = $props();
15
+ const MAX_VARIABLE_LENGTH = 10000;
16
+ let editorKind = $state('plain');
17
+ let editor = $state(undefined);
18
+ export function setCode(value) {
19
+ editor?.setCode(value);
20
+ }
21
+ </script>
22
+
23
+ <div class="flex flex-col gap-1">
24
+ <label for="path" class="text-xs font-semibold text-emphasis">Path</label>
25
+ <Path
26
+ disabled={initialPath != '' && !isOwner(initialPath, $userStore, $workspaceStore)}
27
+ bind:error={pathError}
28
+ bind:path
29
+ {initialPath}
30
+ namePlaceholder="variable"
31
+ kind="variable"
32
+ />
33
+ <LabelsInput bind:labels />
34
+ </div>
35
+ <label class="flex flex-col gap-1">
36
+ <span class="text-xs font-semibold text-emphasis">Secret</span>
37
+ <Toggle
38
+ on:change={() => edit && onLoadSecret?.()}
39
+ bind:checked={variable.is_secret}
40
+ disabled={edit && $userStore?.operator}
41
+ />
42
+ {#if variable.is_secret}
43
+ <Alert type="warning" title="Audit log for each access">
44
+ Every secret is encrypted at rest and in transit with a key specific to this workspace. In
45
+ addition, any read of a secret variable generates an audit log whose operation name is:
46
+ variables.decrypt_secret
47
+ </Alert>
48
+ {/if}
49
+ </label>
50
+
51
+ {#if deployTo}
52
+ <Label
53
+ label="Workspace specific"
54
+ tooltip="Prevents this variable from being deployed to prod/staging"
55
+ >
56
+ <Toggle bind:checked={wsSpecific} />
57
+ </Label>
58
+ {/if}
59
+
60
+ <div class="flex flex-col gap-1">
61
+ <label for="variable-value" class="flex flex-row justify-left items-center">
62
+ <span class="text-xs font-semibold text-emphasis">Variable value&nbsp;</span>
63
+ <span class="text-xs text-secondary font-normal">
64
+ ({variable.value.length}/{MAX_VARIABLE_LENGTH} characters)
65
+ </span>
66
+ {#if edit && variable.is_secret}
67
+ <div class="ml-3"></div>
68
+ {#if $userStore?.operator}
69
+ <div class="p-2 border">Operators cannot load secret value</div>
70
+ {:else}
71
+ <Button size="xs" variant="default" on:click={() => onLoadSecret?.()}>
72
+ Load secret value<Tooltip>Will generate an audit log</Tooltip>
73
+ </Button>
74
+ {/if}
75
+ {/if}
76
+ </label>
77
+ <div>
78
+ <div class="flex flex-col gap-2">
79
+ <ToggleButtonGroup bind:selected={editorKind}>
80
+ {#snippet children({ item })}
81
+ <ToggleButton value="plain" label="Plain" {item} />
82
+ <ToggleButton value="json" label="Json" {item} />
83
+ <ToggleButton value="yaml" label="YAML" {item} />
84
+ {/snippet}
85
+ </ToggleButtonGroup>
86
+ {#if editorKind == 'plain'}
87
+ <textarea
88
+ disabled={!can_write}
89
+ rows="4"
90
+ use:autosize
91
+ bind:value={variable.value}
92
+ placeholder="Update variable value"
93
+ id="variable-value"
94
+ ></textarea>
95
+ {:else if editorKind == 'json'}
96
+ <div class="border rounded mb-4 w-full">
97
+ {#await import('./SimpleEditor.svelte')}
98
+ <Loader2 class="animate-spin" />
99
+ {:then Module}
100
+ <Module.default
101
+ bind:this={editor}
102
+ autoHeight
103
+ lang="json"
104
+ bind:code={variable.value}
105
+ fixedOverflowWidgets={false}
106
+ class="bg-surface-tertiary"
107
+ />
108
+ {/await}
109
+ </div>
110
+ {:else if editorKind == 'yaml'}
111
+ <div class="border rounded mb-4 w-full">
112
+ {#await import('./SimpleEditor.svelte')}
113
+ <Loader2 class="animate-spin" />
114
+ {:then Module}
115
+ <Module.default
116
+ bind:this={editor}
117
+ autoHeight
118
+ lang="yaml"
119
+ bind:code={variable.value}
120
+ fixedOverflowWidgets={false}
121
+ class="bg-surface-tertiary"
122
+ />
123
+ {/await}
124
+ </div>
125
+ {/if}
126
+ </div>
127
+ </div>
128
+ </div>
129
+ <label class="flex flex-col gap-1">
130
+ <span class="text-xs font-semibold text-emphasis">Description</span>
131
+ <textarea rows="4" use:autosize bind:value={variable.description} placeholder="Used for X"
132
+ ></textarea>
133
+ </label>
@@ -0,0 +1,22 @@
1
+ interface Variable {
2
+ value: string;
3
+ is_secret: boolean;
4
+ description: string;
5
+ }
6
+ interface Props {
7
+ path: string;
8
+ initialPath: string;
9
+ pathError: string;
10
+ variable: Variable;
11
+ labels: string[] | undefined;
12
+ wsSpecific: boolean;
13
+ deployTo: string | undefined;
14
+ can_write: boolean;
15
+ edit: boolean;
16
+ onLoadSecret?: () => void;
17
+ }
18
+ declare const VariableForm: import("svelte").Component<Props, {
19
+ setCode: (value: string) => void;
20
+ }, "path" | "variable" | "labels" | "pathError" | "wsSpecific">;
21
+ type VariableForm = ReturnType<typeof VariableForm>;
22
+ export default VariableForm;
@@ -0,0 +1,39 @@
1
+ <script lang="ts">import { WorkspaceService } from '../gen';
2
+ import { resource } from 'runed';
3
+ import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte';
4
+ import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte';
5
+ import ToggleButtonMore from './common/toggleButton-v2/ToggleButtonMore.svelte';
6
+ let { kind, workspaceId, initialPath, selected = $bindable() } = $props();
7
+ let versionsResource = resource([() => ({ path: initialPath, ws: workspaceId, kind })], async ([{ path, ws, kind }]) => {
8
+ return await WorkspaceService.listWsSpecificVersions({ workspace: ws, kind, path });
9
+ });
10
+ const MAX_REGULAR = 3;
11
+ let versions = $derived([
12
+ workspaceId,
13
+ ...(versionsResource.current?.filter((v) => v != workspaceId) ?? [])
14
+ ]);
15
+ let nonForks = $derived(versions.filter((v) => !v.startsWith('wm-fork-')));
16
+ let forks = $derived(versions.filter((v) => v.startsWith('wm-fork-')));
17
+ // Cap the inline buttons at MAX_REGULAR. Overflow (non-fork) workspaces
18
+ // land in the dropdown above the forks so the visual ordering stays
19
+ // "regular workspaces first, forks last".
20
+ let regular = $derived(nonForks.slice(0, MAX_REGULAR));
21
+ let more = $derived([...nonForks.slice(MAX_REGULAR), ...forks]);
22
+ </script>
23
+
24
+ {#if versions.length > 1}
25
+ <ToggleButtonGroup bind:selected>
26
+ {#snippet children({ item })}
27
+ {#each regular as v (v)}
28
+ <ToggleButton value={v} label={v} {item} />
29
+ {/each}
30
+ {#if more.length > 0}
31
+ <ToggleButtonMore
32
+ togglableItems={more.map((v) => ({ label: v, value: v }))}
33
+ {item}
34
+ bind:selected
35
+ />
36
+ {/if}
37
+ {/snippet}
38
+ </ToggleButtonGroup>
39
+ {/if}
@@ -0,0 +1,9 @@
1
+ interface Props {
2
+ kind: 'resource' | 'variable';
3
+ workspaceId: string;
4
+ initialPath: string;
5
+ selected: string | undefined;
6
+ }
7
+ declare const WsSpecificVersions: import("svelte").Component<Props, {}, "selected">;
8
+ type WsSpecificVersions = ReturnType<typeof WsSpecificVersions>;
9
+ export default WsSpecificVersions;
@@ -84,7 +84,6 @@ declare const RunnableComponent: $$__sveltets_2_IsomorphicComponent<Props, {
84
84
  path?: string;
85
85
  lock?: string;
86
86
  cache_ttl?: number;
87
- tag?: string;
88
87
  };
89
88
  id?: number;
90
89
  force_viewer_static_fields?: {
@@ -14,6 +14,6 @@ type $$ComponentProps = {
14
14
  hideSecretUrl?: boolean;
15
15
  preserveOnBehalfOf?: boolean;
16
16
  };
17
- declare const AppEditorHeaderDeploy: import("svelte").Component<$$ComponentProps, {}, "summary" | "preserveOnBehalfOf" | "pathError" | "customPath" | "deploymentMsg" | "customPathError" | "newEditedPath">;
17
+ declare const AppEditorHeaderDeploy: import("svelte").Component<$$ComponentProps, {}, "summary" | "pathError" | "preserveOnBehalfOf" | "customPath" | "deploymentMsg" | "customPathError" | "newEditedPath">;
18
18
  type AppEditorHeaderDeploy = ReturnType<typeof AppEditorHeaderDeploy>;
19
19
  export default AppEditorHeaderDeploy;
@@ -18,7 +18,7 @@ import { getDeployUiSettings } from '../../home/deploy_ui';
18
18
  import { isRuleActive } from '../../../workspaceProtectionRules.svelte';
19
19
  import { buildForkEditUrl } from '../../../utils/editInFork';
20
20
  import { isCloudHosted } from '../../../cloud';
21
- let { app, marked, shareModal, moveDrawer, deploymentDrawer, deleteConfirmedCallback = $bindable(), depth = 0, menuOpen = $bindable(false), showEditButton = $bindable(true) } = $props();
21
+ let { app, marked, shareModal, moveDrawer, deploymentDrawer, deleteConfirmedCallback = $bindable(), depth = 0, menuOpen = $bindable(false), showEditButton = $bindable(true), keyboardSelected = false } = $props();
22
22
  const dispatch = createEventDispatcher();
23
23
  let appExport = $state(undefined);
24
24
  let appDeploymentHistory = $state(undefined);
@@ -43,6 +43,7 @@ async function loadAppJson() {
43
43
  workspaceId={app.workspace_id ?? $workspaceStore ?? ''}
44
44
  canFavorite={!app.draft_only}
45
45
  {depth}
46
+ {keyboardSelected}
46
47
  >
47
48
  {#snippet badges()}
48
49
  {#if app.execution_mode == 'anonymous'}