windmill-components 1.138.7 → 1.139.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 (39) hide show
  1. package/package/components/DeployWorkspace.svelte +0 -1
  2. package/package/components/DisplayResult.svelte +3 -1
  3. package/package/components/EditorBar.svelte +0 -1
  4. package/package/components/GroupEditor.svelte +6 -1
  5. package/package/components/ResultJobLoader.svelte +9 -1
  6. package/package/components/ResultJobLoader.svelte.d.ts +1 -1
  7. package/package/components/ScheduleEditor.svelte +0 -1
  8. package/package/components/SchemaEditor.svelte +0 -1
  9. package/package/components/SupabaseConnect.svelte +2 -1
  10. package/package/components/apps/components/display/AppCarouselList.svelte +161 -0
  11. package/package/components/apps/components/display/AppCarouselList.svelte.d.ts +24 -0
  12. package/package/components/apps/components/display/AppMarkdown.svelte +66 -0
  13. package/package/components/apps/components/display/AppMarkdown.svelte.d.ts +23 -0
  14. package/package/components/apps/components/display/index.d.ts +1 -0
  15. package/package/components/apps/components/display/index.js +1 -0
  16. package/package/components/apps/components/helpers/RunnableComponent.svelte +77 -53
  17. package/package/components/apps/components/helpers/eval.js +0 -1
  18. package/package/components/apps/components/icon.js +7 -1
  19. package/package/components/apps/components/inputs/AppFileInput.svelte +8 -0
  20. package/package/components/apps/components/inputs/AppSelect.svelte +54 -28
  21. package/package/components/apps/editor/AppEditorHeader.svelte +23 -0
  22. package/package/components/apps/editor/component/Component.svelte +20 -1
  23. package/package/components/apps/editor/component/components.d.ts +73 -2
  24. package/package/components/apps/editor/component/components.js +70 -2
  25. package/package/components/apps/editor/component/sets.js +3 -1
  26. package/package/components/apps/editor/componentsPanel/quickStyleProperties.js +6 -0
  27. package/package/components/apps/editor/settingsPanel/GridTab.svelte +1 -1
  28. package/package/components/apps/editor/settingsPanel/script/shared/ScriptSettingHeader.svelte +1 -1
  29. package/package/components/apps/types.d.ts +4 -0
  30. package/package/components/apps/utils.js +0 -1
  31. package/package/components/codeGen/ScriptGen.svelte +84 -80
  32. package/package/components/common/button/Button.svelte +6 -2
  33. package/package/components/common/button/ButtonDropdown.svelte +1 -1
  34. package/package/components/flows/content/FlowModuleMock.svelte +0 -1
  35. package/package/components/graph/svelvet/edges/views/Edges/BaseEdge.svelte +0 -1
  36. package/package/logout.js +0 -1
  37. package/package.json +11 -1
  38. package/package/components/flows/content/FlowModuleConcurrencyLimit.svelte +0 -51
  39. package/package/components/flows/content/FlowModuleConcurrencyLimit.svelte.d.ts +0 -17
@@ -113,7 +113,6 @@ async function getDependencies(kind, path) {
113
113
  let processed = [];
114
114
  while (toProcess.length > 0) {
115
115
  const { kind, path } = toProcess.pop();
116
- console.log('BAR', kind, path);
117
116
  toProcess.push(...(await rec(kind, path)));
118
117
  processed.push({ kind, path });
119
118
  }
@@ -197,7 +197,9 @@ $: jsonStr = JSON.stringify(result, null, 4);
197
197
  href="data:application/octet-stream;base64,{result.file}">Download</a
198
198
  >
199
199
  </div>
200
- {:else if !forceJson && resultKind == 'error'}<div class="flex flex-col items-start">
200
+ {:else if !forceJson && resultKind == 'error' && result?.error}<div
201
+ class="flex flex-col items-start"
202
+ >
201
203
  <span class="text-red-500 font-semibold text-sm whitespace-pre-wrap"
202
204
  >{#if result.error.name || result.error.message}{result.error.name}: {result.error
203
205
  .message}{:else}{JSON.stringify(result.error, null, 4)}{/if}</span
@@ -361,7 +361,6 @@ let historyBrowserDrawerOpen = false;
361
361
  }
362
362
  } else {
363
363
  const tsSchema = compile(resourceType.schema)
364
- console.log(tsSchema)
365
364
  editor.insertAtCursor(`type ${toCamel(capitalize(name))} = ${tsSchema}\n`)
366
365
  }
367
366
  sendUserToast(`${name} inserted at cursor`)
@@ -37,7 +37,12 @@ async function addToGroup() {
37
37
  loadGroup();
38
38
  }
39
39
  async function loadInstanceGroup() {
40
- instance_group = await GroupService.getInstanceGroup({ name });
40
+ try {
41
+ instance_group = await GroupService.getInstanceGroup({ name });
42
+ }
43
+ catch (e) {
44
+ instance_group = undefined;
45
+ }
41
46
  }
42
47
  async function loadGroup() {
43
48
  try {
@@ -118,7 +118,15 @@ async function loadTestJob(id) {
118
118
  if (currentId === id) {
119
119
  job = { ...maybe_job, id };
120
120
  await tick();
121
- dispatch('done', job);
121
+ if ('error' in job ?? {}) {
122
+ dispatch('doneError', {
123
+ id,
124
+ error: job.result.error
125
+ });
126
+ }
127
+ else {
128
+ dispatch('done', job);
129
+ }
122
130
  currentId = undefined;
123
131
  }
124
132
  }
@@ -19,8 +19,8 @@ declare const __propDef: {
19
19
  };
20
20
  events: {
21
21
  started: CustomEvent<any>;
22
- done: CustomEvent<any>;
23
22
  doneError: CustomEvent<any>;
23
+ done: CustomEvent<any>;
24
24
  } & {
25
25
  [evt: string]: CustomEvent<any>;
26
26
  };
@@ -89,7 +89,6 @@ async function loadSchedule() {
89
89
  script_path = s.script_path ?? '';
90
90
  is_flow = s.is_flow;
91
91
  if (s.on_failure) {
92
- console.log(s.on_failure);
93
92
  let splitted = s.on_failure.split('/');
94
93
  errorHandleritemKind = splitted[0];
95
94
  errorHandlerPath = splitted.slice(1)?.join('/');
@@ -101,7 +101,6 @@ function startEditArgument(argName) {
101
101
  if (Object.keys(schema.properties).includes(argName)) {
102
102
  editing = true;
103
103
  const modalProperty = schemaToModal(schema.properties[argName], argName, schema.required.includes(argName));
104
- console.log(modalProperty.format);
105
104
  oldArgName = argName;
106
105
  schemaModal.openDrawer(modalProperty);
107
106
  }
@@ -126,7 +126,8 @@ async function save() {
126
126
  bind:error={pathError}
127
127
  bind:path
128
128
  initialPath=""
129
- fullNamePlaceholder={'supabase_' + selectedDatabase?.name}
129
+ fullNamePlaceholder={'supabase_' +
130
+ selectedDatabase?.name?.replace(/\s+/g, '').replace(/[^\w\s]/gi, '')}
130
131
  kind="resource"
131
132
  />
132
133
 
@@ -0,0 +1,161 @@
1
+ <script>import { getContext } from 'svelte';
2
+ import { initConfig, initOutput } from '../../editor/appUtils';
3
+ import SubGridEditor from '../../editor/SubGridEditor.svelte';
4
+ import { concatCustomCss } from '../../utils';
5
+ import InitializeComponent from '../helpers/InitializeComponent.svelte';
6
+ import ResolveConfig from '../helpers/ResolveConfig.svelte';
7
+ import { components } from '../../editor/component';
8
+ import RunnableWrapper from '../helpers/RunnableWrapper.svelte';
9
+ import ListWrapper from '../layout/ListWrapper.svelte';
10
+ import Carousel from 'svelte-carousel';
11
+ import { ArrowLeftCircle, ArrowRightCircle } from 'lucide-svelte';
12
+ import { Button } from '../../../common';
13
+ export let id;
14
+ export let componentInput;
15
+ export let configuration;
16
+ export let customCss = undefined;
17
+ export let render;
18
+ export let initializing;
19
+ export let componentContainerHeight;
20
+ const { app, focusedGrid, selectedComponent, worldStore, connectingInput } = getContext('AppViewerContext');
21
+ const outputs = initOutput($worldStore, id, {
22
+ result: undefined,
23
+ loading: false,
24
+ inputs: {}
25
+ });
26
+ const resolvedConfig = initConfig(components['carousellistcomponent'].initialData.configuration, configuration);
27
+ function onFocus() {
28
+ $focusedGrid = {
29
+ parentComponentId: id,
30
+ subGridIndex: 0
31
+ };
32
+ }
33
+ $: css = concatCustomCss($app.css?.containercomponent, customCss);
34
+ let result = undefined;
35
+ let inputs = {};
36
+ let carousel;
37
+ $: $selectedComponent?.includes(id) &&
38
+ $focusedGrid === undefined &&
39
+ ($focusedGrid = {
40
+ parentComponentId: id,
41
+ subGridIndex: 0
42
+ });
43
+ </script>
44
+
45
+ {#each Object.keys(components['carousellistcomponent'].initialData.configuration) as key (key)}
46
+ <ResolveConfig
47
+ {id}
48
+ {key}
49
+ bind:resolvedConfig={resolvedConfig[key]}
50
+ configuration={configuration[key]}
51
+ />
52
+ {/each}
53
+
54
+ <InitializeComponent {id} />
55
+
56
+ <RunnableWrapper
57
+ render={true}
58
+ {outputs}
59
+ autoRefresh
60
+ {componentInput}
61
+ {id}
62
+ bind:initializing
63
+ bind:result
64
+ >
65
+ <div class="w-full flex flex-wrap overflow-auto divide-y max-h-full">
66
+ {#if $app.subgrids?.[`${id}-0`]}
67
+ {#if Array.isArray(result) && result.length > 0}
68
+ {#key result}
69
+ <Carousel
70
+ particlesToShow={1}
71
+ particlesToScroll={1}
72
+ autoplay={false}
73
+ autoplayProgressVisible={false}
74
+ timingFunction={resolvedConfig.timingFunction}
75
+ dots={true}
76
+ arrows={true}
77
+ swiping={false}
78
+ bind:this={carousel}
79
+ let:currentPageIndex
80
+ on:pageChange={(event) => {
81
+ $focusedGrid = {
82
+ parentComponentId: id,
83
+ subGridIndex: event.detail
84
+ }
85
+ }}
86
+ >
87
+ <div slot="prev" class="h-full flex justify-center flex-col p-2">
88
+ <div>
89
+ <Button
90
+ color="light"
91
+ on:click={() => {
92
+ const pagesCount = result?.length ?? 0
93
+
94
+ if (currentPageIndex > 0) {
95
+ carousel.goTo(currentPageIndex - 1)
96
+ } else {
97
+ carousel.goTo(pagesCount - 1)
98
+ }
99
+ }}
100
+ >
101
+ <ArrowLeftCircle size={16} />
102
+ </Button>
103
+ </div>
104
+ </div>
105
+ <div slot="next" class="h-full flex justify-center flex-col p-2">
106
+ <div>
107
+ <Button
108
+ color="light"
109
+ on:click={() => {
110
+ const pagesCount = result?.length ?? 0
111
+ if (currentPageIndex < pagesCount - 1) {
112
+ carousel.goTo(currentPageIndex + 1)
113
+ } else {
114
+ carousel.goTo(0)
115
+ }
116
+ }}
117
+ >
118
+ <ArrowRightCircle size={16} />
119
+ </Button>
120
+ </div>
121
+ </div>
122
+ {#each result ?? [] as value, index}
123
+ <div class="overflow-auto w-full">
124
+ <ListWrapper
125
+ on:inputsChange={() => {
126
+ outputs?.inputs.set(inputs, true)
127
+ }}
128
+ bind:inputs
129
+ {value}
130
+ {index}
131
+ >
132
+ <SubGridEditor
133
+ {id}
134
+ visible={render}
135
+ class={css?.container?.class}
136
+ style={css?.container?.style}
137
+ subGridId={`${id}-0`}
138
+ containerHeight={componentContainerHeight - 40}
139
+ on:focus={() => {
140
+ if (!$connectingInput.opened) {
141
+ $selectedComponent = [id]
142
+ }
143
+ onFocus()
144
+ }}
145
+ />
146
+ </ListWrapper>
147
+ </div>
148
+ {/each}
149
+ </Carousel>
150
+ {/key}
151
+ {:else}
152
+ <ListWrapper disabled value={undefined} index={0}>
153
+ <SubGridEditor visible={false} {id} subGridId={`${id}-0`} />
154
+ </ListWrapper>
155
+ {#if !Array.isArray(result)}
156
+ <div class="text-center text-tertiary">Input data is not an array</div>
157
+ {/if}
158
+ {/if}
159
+ {/if}
160
+ </div>
161
+ </RunnableWrapper>
@@ -0,0 +1,24 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ import type { ComponentCustomCSS, RichConfigurations } from '../../types';
3
+ import type { AppInput } from '../../inputType';
4
+ declare const __propDef: {
5
+ props: {
6
+ id: string;
7
+ componentInput: AppInput | undefined;
8
+ configuration: RichConfigurations;
9
+ customCss?: ComponentCustomCSS<'containercomponent'> | undefined;
10
+ render: boolean;
11
+ initializing: boolean | undefined;
12
+ componentContainerHeight: number;
13
+ };
14
+ events: {
15
+ [evt: string]: CustomEvent<any>;
16
+ };
17
+ slots: {};
18
+ };
19
+ export type AppCarouselListProps = typeof __propDef.props;
20
+ export type AppCarouselListEvents = typeof __propDef.events;
21
+ export type AppCarouselListSlots = typeof __propDef.slots;
22
+ export default class AppCarouselList extends SvelteComponentTyped<AppCarouselListProps, AppCarouselListEvents, AppCarouselListSlots> {
23
+ }
24
+ export {};
@@ -0,0 +1,66 @@
1
+ <script>import { getContext } from 'svelte';
2
+ import { initConfig, initOutput } from '../../editor/appUtils';
3
+ import { concatCustomCss } from '../../utils';
4
+ import RunnableWrapper from '../helpers/RunnableWrapper.svelte';
5
+ import Markdown from 'svelte-exmarkdown';
6
+ import { classNames } from '../../../../utils';
7
+ import { components } from '../../editor/component';
8
+ import ResolveConfig from '../helpers/ResolveConfig.svelte';
9
+ export let id;
10
+ export let componentInput;
11
+ export let initializing = undefined;
12
+ export let customCss = undefined;
13
+ export let render;
14
+ export let configuration;
15
+ const { app, worldStore } = getContext('AppViewerContext');
16
+ const resolvedConfig = initConfig(components['mardowncomponent'].initialData.configuration, configuration);
17
+ const outputs = initOutput($worldStore, id, {
18
+ result: undefined,
19
+ loading: false
20
+ });
21
+ let result = undefined;
22
+ $: css = concatCustomCss($app.css?.mardowncomponent, customCss);
23
+ const proseMapping = {
24
+ sm: 'prose-sm',
25
+ Default: 'prose-base',
26
+ lg: 'prose-lg',
27
+ xl: 'prose-xl',
28
+ '2xl': 'prose-2xl'
29
+ };
30
+ </script>
31
+
32
+ {#each Object.keys(components['mardowncomponent'].initialData.configuration) as key (key)}
33
+ <ResolveConfig
34
+ {id}
35
+ {key}
36
+ bind:resolvedConfig={resolvedConfig[key]}
37
+ configuration={configuration[key]}
38
+ />
39
+ {/each}
40
+
41
+ <div
42
+ on:pointerdown={(e) => {
43
+ e?.preventDefault()
44
+ }}
45
+ class={classNames(
46
+ 'h-full w-full overflow-y-auto prose',
47
+ resolvedConfig?.size ? proseMapping[resolvedConfig.size] : '',
48
+ css?.container?.class
49
+ )}
50
+ >
51
+ <RunnableWrapper
52
+ {outputs}
53
+ {render}
54
+ autoRefresh
55
+ {componentInput}
56
+ {id}
57
+ bind:initializing
58
+ bind:result
59
+ >
60
+ {#if result}
61
+ {#key result}
62
+ <Markdown md={result} />
63
+ {/key}
64
+ {/if}
65
+ </RunnableWrapper>
66
+ </div>
@@ -0,0 +1,23 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ import type { AppInput } from '../../inputType';
3
+ import type { ComponentCustomCSS, RichConfigurations } from '../../types';
4
+ declare const __propDef: {
5
+ props: {
6
+ id: string;
7
+ componentInput: AppInput | undefined;
8
+ initializing?: boolean | undefined;
9
+ customCss?: ComponentCustomCSS<'mardowncomponent'> | undefined;
10
+ render: boolean;
11
+ configuration: RichConfigurations;
12
+ };
13
+ events: {
14
+ [evt: string]: CustomEvent<any>;
15
+ };
16
+ slots: {};
17
+ };
18
+ export type AppMarkdownProps = typeof __propDef.props;
19
+ export type AppMarkdownEvents = typeof __propDef.events;
20
+ export type AppMarkdownSlots = typeof __propDef.slots;
21
+ export default class AppMarkdown extends SvelteComponentTyped<AppMarkdownProps, AppMarkdownEvents, AppMarkdownSlots> {
22
+ }
23
+ export {};
@@ -13,3 +13,4 @@ export { default as AppText } from './AppText.svelte';
13
13
  export { default as AppTimeseries } from './AppTimeseries.svelte';
14
14
  export { default as PlotlyHtml } from './PlotlyHtml.svelte';
15
15
  export { default as VegaLiteHtml } from './VegaLiteHtml.svelte';
16
+ export { default as AppMarkdown } from './AppMarkdown.svelte';
@@ -13,3 +13,4 @@ export { default as AppText } from './AppText.svelte';
13
13
  export { default as AppTimeseries } from './AppTimeseries.svelte';
14
14
  export { default as PlotlyHtml } from './PlotlyHtml.svelte';
15
15
  export { default as VegaLiteHtml } from './VegaLiteHtml.svelte';
16
+ export { default as AppMarkdown } from './AppMarkdown.svelte';
@@ -125,22 +125,14 @@ async function executeComponent(noToast = false, inlineScriptOverride) {
125
125
  iter: iterContext ? $iterContext : undefined,
126
126
  row: rowContext ? $rowContext : undefined
127
127
  }), false, $state, $mode == 'dnd', $componentControl, $worldStore, $runnableComponents);
128
- await setResult(r, undefined);
129
- $state = $state;
130
128
  const job = generateNextFrontendJobId();
131
- const njobs = [{ job, component: id, result: r }, ...$jobs];
132
- $jobs = $jobs?.length > 100 ? njobs.slice(0, 100) : njobs;
129
+ await setResult(r, job);
130
+ $state = $state;
133
131
  }
134
132
  catch (e) {
135
133
  sendUserToast(`Error running frontend script ${id}: ` + e.message, true);
136
- // Manually add a fake job to the job list to show the error
137
134
  const job = generateNextFrontendJobId();
138
- const error = e.body ?? e.message;
139
- $errorByComponent[job] = {
140
- error,
141
- componentId: id
142
- };
143
- $jobs = [{ job, component: id, error }, ...$jobs];
135
+ await setResult({ error: { message: e.body ?? e.message } }, job);
144
136
  }
145
137
  loading = false;
146
138
  donePromise?.();
@@ -161,7 +153,7 @@ async function executeComponent(noToast = false, inlineScriptOverride) {
161
153
  return;
162
154
  }
163
155
  try {
164
- let njob = await resultJobLoader?.abstractRun(async () => {
156
+ await resultJobLoader?.abstractRun(async () => {
165
157
  const nonStaticRunnableInputs = {};
166
158
  const staticRunnableInputs = {};
167
159
  for (const k of Object.keys(fields ?? {})) {
@@ -206,13 +198,9 @@ async function executeComponent(noToast = false, inlineScriptOverride) {
206
198
  requestBody
207
199
  });
208
200
  });
209
- if (njob) {
210
- const njobs = [{ job: njob, component: id }, ...$jobs];
211
- $jobs = $jobs?.length > 100 ? njobs.slice(0, 100) : njobs;
212
- }
213
201
  }
214
202
  catch (e) {
215
- setResult({ error: e.body ?? e.message }, undefined);
203
+ updateResult({ error: e.body ?? e.message });
216
204
  loading = false;
217
205
  }
218
206
  }
@@ -226,7 +214,7 @@ export async function runComponent() {
226
214
  }
227
215
  }
228
216
  catch (e) {
229
- setResult({ error: e.body ?? e.message }, undefined);
217
+ updateResult({ error: e.body ?? e.message });
230
218
  }
231
219
  }
232
220
  function recordError(error, jobId) {
@@ -238,21 +226,49 @@ function recordError(error, jobId) {
238
226
  async function setJobId(jobId) {
239
227
  outputs.jobId?.set(jobId);
240
228
  }
241
- async function setResult(res, jobId) {
242
- dispatch('done');
243
- const hasRes = res !== undefined && res !== null;
229
+ function recordJob(jobId, result, error, transformer) {
230
+ const job = {
231
+ ...(result ? { result } : {}),
232
+ ...(error ? { error } : {}),
233
+ ...(transformer ? { transformer } : {}),
234
+ job: jobId,
235
+ component: id
236
+ };
237
+ if (error) {
238
+ recordError(error, jobId);
239
+ }
240
+ else if (job?.transformer?.error) {
241
+ recordError(job.transformer.error, jobId);
242
+ }
243
+ const njobs = [job, ...$jobs];
244
+ // Only keep the last 100 jobs
245
+ $jobs = $jobs?.length > 100 ? njobs.slice(0, 100) : njobs;
246
+ }
247
+ function getResultErrors(result) {
248
+ const errorAsArray = Array.isArray(result) ? result.flat() : [result];
249
+ const hasErrors = errorAsArray.some((r) => r?.error);
250
+ if (!hasErrors) {
251
+ return undefined;
252
+ }
253
+ return errorAsArray
254
+ .map((r) => r?.error?.message)
255
+ .filter(Boolean)
256
+ .join('\n');
257
+ }
258
+ async function runTransformer(res) {
244
259
  if (transformer) {
245
260
  try {
246
261
  let raw = $worldStore.newOutput(id, 'raw', res);
247
- res = await eval_like(transformer.content, computeGlobalContext($worldStore, {
262
+ const transformerResult = await eval_like(transformer.content, computeGlobalContext($worldStore, {
248
263
  iter: iterContext ? $iterContext : undefined,
249
264
  row: rowContext ? $rowContext : undefined,
250
265
  result: res
251
266
  }), false, $state, $mode == 'dnd', $componentControl, $worldStore, $runnableComponents);
252
- raw.set(res);
267
+ raw.set(transformerResult);
268
+ return transformerResult;
253
269
  }
254
270
  catch (err) {
255
- res = {
271
+ return {
256
272
  error: {
257
273
  name: 'TransformerError',
258
274
  message: 'An error occured in the transformer',
@@ -260,39 +276,40 @@ async function setResult(res, jobId) {
260
276
  }
261
277
  };
262
278
  }
263
- if (hasRes && res === undefined) {
264
- res = {
265
- error: {
266
- name: 'TransformerError',
267
- message: 'An error occured in the transformer',
268
- stack: 'Transformer returned undefined'
269
- }
270
- };
271
- }
272
279
  }
273
- // console.log('setr', id)
280
+ }
281
+ function updateResult(res) {
274
282
  outputs.result?.set(res);
275
283
  result = res;
276
- // Flows with loops can have multiple results
277
- const errorAsArray = Array.isArray(result) ? result.flat() : [result];
278
- // As soon as we have an error, we consider the component errored
279
- const hasErrors = errorAsArray.some((r) => r?.error);
280
- if (hasErrors) {
281
- const errorMessages = errorAsArray
282
- .map((r) => r?.error?.message)
283
- .filter(Boolean)
284
- .join('\n');
285
- jobId && recordError(errorMessages, jobId);
286
- dispatch('handleError', errorMessages);
284
+ }
285
+ async function setResult(res, jobId) {
286
+ dispatch('done');
287
+ const hasRes = res !== undefined && res !== null;
288
+ if (!jobId && !hasRes) {
289
+ return;
287
290
  }
288
- else {
289
- dispatch('success');
291
+ const errors = getResultErrors(res);
292
+ console.log('errors', errors);
293
+ if (errors) {
294
+ const transformerResult = transformer
295
+ ? { error: 'Transformer could not be run because of previous errors' }
296
+ : undefined;
297
+ recordJob(jobId, undefined, errors, transformerResult);
298
+ updateResult(res);
299
+ dispatch('handleError', errors);
300
+ return;
290
301
  }
291
- const previousJobId = Object.keys($errorByComponent).find((key) => $errorByComponent[key].componentId === id);
292
- if (previousJobId && !hasErrors) {
293
- delete $errorByComponent[previousJobId];
294
- $errorByComponent = $errorByComponent;
302
+ const transformerResult = await runTransformer(res);
303
+ if (transformerResult?.error) {
304
+ recordJob(jobId, res, undefined, transformerResult);
305
+ updateResult(transformerResult);
306
+ dispatch('handleError', transformerResult.error);
307
+ return;
295
308
  }
309
+ updateResult(transformerResult ?? res);
310
+ recordJob(jobId, result, undefined, transformerResult);
311
+ $errorByComponent = clearErrorByComponentId(id, $errorByComponent);
312
+ dispatch('success');
296
313
  donePromise?.();
297
314
  }
298
315
  function handleInputClick(e) {
@@ -377,7 +394,7 @@ let inputValues = {};
377
394
  loading = false
378
395
  }}
379
396
  on:doneError={(e) => {
380
- setResult({ error: e.detail }, e.detail.id)
397
+ setResult({ error: e.detail.error }, e.detail.id)
381
398
  loading = false
382
399
  }}
383
400
  bind:this={resultJobLoader}
@@ -414,10 +431,17 @@ let inputValues = {};
414
431
  <Alert type="error" title="Error during execution">
415
432
  <div class="flex flex-col gap-2">
416
433
  An error occured, please contact the app author.
434
+
435
+ {#if lastJobId && $errorByComponent[lastJobId]?.error}
436
+ <div class="font-bold">{$errorByComponent[lastJobId]?.error}</div>
437
+ {/if}
417
438
  <a
418
439
  href={`/run/${lastJobId}?workspace=${workspace}`}
419
- class="font-semibold text-red-800 underline">Job id: {lastJobId}</a
440
+ class="font-semibold text-red-800 underline"
441
+ target="_blank"
420
442
  >
443
+ Job id: {lastJobId}
444
+ </a>
421
445
  </div>
422
446
  </Alert>
423
447
  </div>
@@ -26,7 +26,6 @@ ${noReturn ? `return ${eval_string}` : eval_string}
26
26
  }
27
27
  function make_context_evaluator(eval_string, context, noReturn) {
28
28
  let template = create_context_function_template(eval_string, context, noReturn);
29
- console.debug(template);
30
29
  let functor = Function(template);
31
30
  return functor();
32
31
  }
@@ -1,4 +1,10 @@
1
- import { toKebabCase } from '../utils';
1
+ function toKebabCase(str) {
2
+ return str
3
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2') // Convert camel case to kebab case
4
+ .replace(/([A-Z0-9])([A-Z])/g, '$1-$2') // Separate consecutive uppercase letters
5
+ .replace(/([a-z])([0-9])/g, '$1-$2') // Separate letters from digits
6
+ .toLowerCase();
7
+ }
2
8
  export async function loadIcon(name) {
3
9
  let iconComponent;
4
10
  try {
@@ -13,11 +13,18 @@ const { app, worldStore } = getContext('AppViewerContext');
13
13
  let acceptedFileTypes = undefined;
14
14
  let allowMultiple = undefined;
15
15
  let text = undefined;
16
+ let includeMimeType = undefined;
16
17
  let outputs = initOutput($worldStore, id, {
17
18
  result: []
18
19
  });
19
20
  // Receives Base64 encoded strings from the input component
20
21
  async function handleChange(files) {
22
+ if (includeMimeType === false) {
23
+ files = files?.map((file) => {
24
+ const [_, data] = file.data.split('base64,');
25
+ return { name: file.name, data };
26
+ });
27
+ }
21
28
  outputs?.result.set(files);
22
29
  }
23
30
  $: css = concatCustomCss($app.css?.fileinputcomponent, customCss);
@@ -26,6 +33,7 @@ $: css = concatCustomCss($app.css?.fileinputcomponent, customCss);
26
33
  <InputValue {id} input={configuration.acceptedFileTypes} bind:value={acceptedFileTypes} />
27
34
  <InputValue {id} input={configuration.allowMultiple} bind:value={allowMultiple} />
28
35
  <InputValue {id} input={configuration.text} bind:value={text} />
36
+ <InputValue {id} input={configuration.includeMimeType} bind:value={includeMimeType} />
29
37
 
30
38
  <InitializeComponent {id} />
31
39