windmill-components 1.305.6 → 1.306.8

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 (42) hide show
  1. package/package/assets/app.css +21 -0
  2. package/package/components/apps/components/buttons/AppButton.svelte +7 -3
  3. package/package/components/apps/components/display/AppDownload.svelte +12 -8
  4. package/package/components/apps/components/display/AppHtml.svelte +6 -23
  5. package/package/components/apps/components/display/AppHtml.svelte.d.ts +0 -2
  6. package/package/components/apps/components/display/AppMap.svelte +62 -70
  7. package/package/components/apps/components/display/AppMap.svelte.d.ts +1 -0
  8. package/package/components/apps/components/display/AppMenu.svelte +13 -9
  9. package/package/components/apps/components/display/AppStatCard.svelte +6 -4
  10. package/package/components/apps/components/display/table/AppAggridTable.svelte +110 -9
  11. package/package/components/apps/components/display/table/AppAggridTable.svelte.d.ts +2 -0
  12. package/package/components/apps/components/display/table/AppAggridTableActions.svelte +232 -0
  13. package/package/components/apps/components/display/table/AppAggridTableActions.svelte.d.ts +30 -0
  14. package/package/components/apps/components/display/table/AppAggridTableEe.svelte +10 -1
  15. package/package/components/apps/components/display/table/AppAggridTableEe.svelte.d.ts +2 -0
  16. package/package/components/apps/components/display/table/AppTable.svelte +0 -1
  17. package/package/components/apps/components/helpers/eval.js +1 -1
  18. package/package/components/apps/components/icon.js +0 -2
  19. package/package/components/apps/components/inputs/AppCheckbox.svelte +1 -0
  20. package/package/components/apps/components/inputs/AppTextInput.svelte +27 -11
  21. package/package/components/apps/editor/AppEditorHeader.svelte +4 -0
  22. package/package/components/apps/editor/AppInputs.svelte +11 -0
  23. package/package/components/apps/editor/SettingsPanel.svelte +22 -3
  24. package/package/components/apps/editor/appUtils.js +30 -0
  25. package/package/components/apps/editor/component/Component.svelte +2 -0
  26. package/package/components/apps/editor/component/ComponentCallbacks.svelte +4 -0
  27. package/package/components/apps/editor/component/components.d.ts +25 -2
  28. package/package/components/apps/editor/component/components.js +12 -0
  29. package/package/components/apps/editor/contextPanel/components/OutputHeader.svelte +13 -0
  30. package/package/components/apps/editor/contextPanel/components/TableActionsOutput.svelte +7 -0
  31. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptsPanelWithTable.svelte +14 -0
  32. package/package/components/apps/editor/inlineScriptsPanel/utils.js +8 -0
  33. package/package/components/apps/editor/settingsPanel/ComponentPanel.svelte +3 -0
  34. package/package/components/apps/editor/settingsPanel/TableActions.svelte +86 -72
  35. package/package/components/apps/editor/settingsPanel/TableActions.svelte.d.ts +1 -1
  36. package/package/components/apps/editor/settingsPanel/inputEditor/IconSelectInput.svelte +1 -0
  37. package/package/components/apps/utils.js +9 -0
  38. package/package/components/common/fileInput/FileInput.svelte +16 -0
  39. package/package/components/common/fileUpload/FileUpload.svelte +19 -19
  40. package/package/user.js +1 -1
  41. package/package/utils.js +1 -1
  42. package/package.json +8 -1
@@ -117,3 +117,24 @@
117
117
  }
118
118
  }
119
119
  }
120
+
121
+ .grid-cell-centered {
122
+ display: flex;
123
+ align-items: center;
124
+ justify-content: center;
125
+ }
126
+ .grid-cell-centered .svelte-select {
127
+ height: 32px !important;
128
+ }
129
+
130
+ .grid-cell-centered .selected-item {
131
+ margin-top: -4px;
132
+ }
133
+
134
+ .ol-overlaycontainer-stopevent {
135
+ @apply flex flex-col justify-start items-end;
136
+ }
137
+ .ol-control button {
138
+ @apply w-7 h-7 center-center bg-surface border text-secondary
139
+ rounded mt-1 mr-1 shadow duration-200 hover:bg-surface-hover focus:bg-surface-hover;
140
+ }
@@ -43,11 +43,11 @@ if (controls) {
43
43
  $componentControl[id] = controls;
44
44
  }
45
45
  let runnableComponent;
46
+ let confirmedCallback = undefined;
46
47
  let beforeIconComponent;
47
48
  let afterIconComponent;
48
49
  $: resolvedConfig.beforeIcon && beforeIconComponent && handleBeforeIcon();
49
50
  $: resolvedConfig.afterIcon && afterIconComponent && handleAfterIcon();
50
- let confirmedCallback = undefined;
51
51
  async function handleBeforeIcon() {
52
52
  if (resolvedConfig.beforeIcon) {
53
53
  beforeIconComponent = await loadIcon(resolvedConfig.beforeIcon, beforeIconComponent, 14, undefined, undefined);
@@ -180,13 +180,17 @@ let css = initCss($app.css?.buttoncomponent, customCss);
180
180
  {loading}
181
181
  >
182
182
  {#if resolvedConfig.beforeIcon}
183
- <div class="min-w-4" bind:this={beforeIconComponent} />
183
+ {#key resolvedConfig.beforeIcon}
184
+ <div class="min-w-4" bind:this={beforeIconComponent} />
185
+ {/key}
184
186
  {/if}
185
187
  {#if resolvedConfig.label?.toString() && resolvedConfig.label?.toString()?.length > 0}
186
188
  <div>{resolvedConfig.label.toString()}</div>
187
189
  {/if}
188
190
  {#if resolvedConfig.afterIcon}
189
- <div class="min-w-4" bind:this={afterIconComponent} />
191
+ {#key resolvedConfig.afterIcon}
192
+ <div class="min-w-4" bind:this={afterIconComponent} />
193
+ {/key}
190
194
  {/if}
191
195
  </Button>
192
196
  {/key}
@@ -23,16 +23,16 @@ const { app, worldStore } = getContext('AppViewerContext');
23
23
  initOutput($worldStore, id, {});
24
24
  let beforeIconComponent;
25
25
  let afterIconComponent;
26
- $: resolvedConfig.beforeIcon && handleBeforeIcon();
27
- $: resolvedConfig.afterIcon && handleAfterIcon();
26
+ $: resolvedConfig.beforeIcon && beforeIconComponent && handleBeforeIcon();
27
+ $: resolvedConfig.afterIcon && afterIconComponent && handleAfterIcon();
28
28
  async function handleBeforeIcon() {
29
29
  if (resolvedConfig.beforeIcon) {
30
- beforeIconComponent = await loadIcon(resolvedConfig.beforeIcon);
30
+ beforeIconComponent = await loadIcon(resolvedConfig.beforeIcon, beforeIconComponent, 14, undefined, undefined);
31
31
  }
32
32
  }
33
33
  async function handleAfterIcon() {
34
34
  if (resolvedConfig.afterIcon) {
35
- afterIconComponent = await loadIcon(resolvedConfig.afterIcon);
35
+ afterIconComponent = await loadIcon(resolvedConfig.afterIcon, afterIconComponent, 14, undefined, undefined);
36
36
  }
37
37
  }
38
38
  let css = initCss($app.css?.downloadcomponent, customCss);
@@ -87,14 +87,18 @@ let css = initCss($app.css?.downloadcomponent, customCss);
87
87
  nonCaptureEvent
88
88
  >
89
89
  <span class="truncate inline-flex gap-2 items-center">
90
- {#if resolvedConfig.beforeIcon && beforeIconComponent}
91
- <svelte:component this={beforeIconComponent} size={14} />
90
+ {#if resolvedConfig.beforeIcon}
91
+ {#key resolvedConfig.beforeIcon}
92
+ <div class="min-w-4" bind:this={beforeIconComponent} />
93
+ {/key}
92
94
  {/if}
93
95
  {#if resolvedConfig.label && resolvedConfig.label?.length > 0}
94
96
  <div>{resolvedConfig.label}</div>
95
97
  {/if}
96
- {#if resolvedConfig.afterIcon && afterIconComponent}
97
- <svelte:component this={afterIconComponent} size={14} />
98
+ {#if resolvedConfig.afterIcon}
99
+ {#key resolvedConfig.afterIcon}
100
+ <div class="min-w-4" bind:this={afterIconComponent} />
101
+ {/key}
98
102
  {/if}
99
103
  </span>
100
104
  </Button>
@@ -2,21 +2,18 @@
2
2
  import { initOutput } from '../../editor/appUtils';
3
3
  import { initCss } from '../../utils';
4
4
  import RunnableWrapper from '../helpers/RunnableWrapper.svelte';
5
- import { twMerge } from 'tailwind-merge';
6
5
  import ResolveStyle from '../helpers/ResolveStyle.svelte';
7
6
  export let id;
8
7
  export let componentInput;
9
8
  export let initializing = undefined;
10
9
  export let customCss = undefined;
11
10
  export let render;
12
- const { app, worldStore, mode } = getContext('AppViewerContext');
11
+ const { app, worldStore } = getContext('AppViewerContext');
13
12
  const outputs = initOutput($worldStore, id, {
14
13
  result: undefined,
15
14
  loading: false
16
15
  });
17
16
  let result = undefined;
18
- let h = undefined;
19
- let w = undefined;
20
17
  let css = initCss($app.css?.htmlcomponent, customCss);
21
18
  </script>
22
19
 
@@ -35,8 +32,6 @@ let css = initCss($app.css?.htmlcomponent, customCss);
35
32
  e?.preventDefault()
36
33
  }}
37
34
  class="h-full w-full"
38
- bind:clientHeight={h}
39
- bind:clientWidth={w}
40
35
  >
41
36
  <RunnableWrapper
42
37
  {outputs}
@@ -47,22 +42,10 @@ let css = initCss($app.css?.htmlcomponent, customCss);
47
42
  bind:initializing
48
43
  bind:result
49
44
  >
50
- {#key result}
51
- <iframe
52
- frameborder="0"
53
- style="height: {h}px; width: {w}px; {css?.container?.style ?? ''}"
54
- class={twMerge('p-0', css?.container?.class, 'wm-html')}
55
- title="sandbox"
56
- srcdoc={result
57
- ? '<base target="_parent" /><scr' +
58
- `ipt type="application/javascript" src="/tailwind.js"></script>` +
59
- result
60
- : ''}
61
- />
62
- {/key}
63
- <!-- svelte-ignore a11y-click-events-have-key-events -->
64
- {#if $mode == 'dnd'}
65
- <div on:click|stopPropagation class="absolute top-0 h-full w-full" />
66
- {/if}
45
+ <div class="w-full h-full overflow-auto">
46
+ {#key result}
47
+ {@html result}
48
+ {/key}
49
+ </div>
67
50
  </RunnableWrapper>
68
51
  </div>
@@ -10,8 +10,6 @@ declare const __propDef: {
10
10
  render: boolean;
11
11
  };
12
12
  events: {
13
- click: MouseEvent;
14
- } & {
15
13
  [evt: string]: CustomEvent<any>;
16
14
  };
17
15
  slots: {};
@@ -1,6 +1,5 @@
1
1
  <script>import { getContext } from 'svelte';
2
2
  import { initCss } from '../../utils';
3
- import { InputValue } from '../helpers';
4
3
  import { twMerge } from 'tailwind-merge';
5
4
  import { Map, View, Feature } from 'ol';
6
5
  import { useGeographic } from 'ol/proj';
@@ -8,9 +7,12 @@ import { OSM, Vector as VectorSource } from 'ol/source';
8
7
  import { Vector as VectorLayer, Tile as TileLayer } from 'ol/layer';
9
8
  import { Point } from 'ol/geom';
10
9
  import { defaults as defaultControls } from 'ol/control';
11
- import { findGridItem, initOutput } from '../../editor/appUtils';
10
+ import { findGridItem, initConfig, initOutput } from '../../editor/appUtils';
12
11
  import InitializeComponent from '../helpers/InitializeComponent.svelte';
13
12
  import ResolveStyle from '../helpers/ResolveStyle.svelte';
13
+ import { components } from '../../editor/component';
14
+ import ResolveConfig from '../helpers/ResolveConfig.svelte';
15
+ import { Style, Circle, Fill, Stroke, Text } from 'ol/style';
14
16
  const LAYER_NAME = {
15
17
  MARKER: 'Marker'
16
18
  };
@@ -18,7 +20,9 @@ export let id;
18
20
  export let configuration;
19
21
  export let customCss = undefined;
20
22
  export let render;
23
+ export let extraKey = undefined;
21
24
  const { app, worldStore, selectedComponent, connectingInput, focusedGrid, mode } = getContext('AppViewerContext');
25
+ const resolvedConfig = initConfig(components['mapcomponent'].initialData.configuration, configuration);
22
26
  let outputs = initOutput($worldStore, id, {
23
27
  mapRegion: {
24
28
  topLeft: { lat: 0, lon: 0 },
@@ -27,18 +31,13 @@ let outputs = initOutput($worldStore, id, {
27
31
  });
28
32
  let map = undefined;
29
33
  let mapElement = undefined;
30
- let longitude = undefined;
31
- let latitude = undefined;
32
- let zoom = undefined;
33
- // If string, it's a JSON file read as text
34
- let markers = undefined;
35
- $: if (map && longitude && latitude) {
36
- map.getView().setCenter([longitude, latitude]);
34
+ $: if (map && resolvedConfig.longitude && resolvedConfig.latitude) {
35
+ map.getView().setCenter([resolvedConfig.longitude, resolvedConfig.latitude]);
37
36
  }
38
- $: if (map && zoom) {
39
- map.getView().setZoom(zoom);
37
+ $: if (map && resolvedConfig.zoom) {
38
+ map.getView().setZoom(resolvedConfig.zoom);
40
39
  }
41
- $: if (map && markers) {
40
+ $: if (map && resolvedConfig.markers) {
42
41
  updateMarkers();
43
42
  }
44
43
  function selectComponent() {
@@ -56,12 +55,12 @@ function getLayersByName(name) {
56
55
  function getMarkerArray() {
57
56
  let array = undefined;
58
57
  try {
59
- if (typeof markers === 'string') {
60
- const json = JSON.parse(markers);
58
+ if (typeof resolvedConfig.markers === 'string') {
59
+ const json = JSON.parse(resolvedConfig.markers);
61
60
  array = Array.isArray(json) ? json : [json];
62
61
  }
63
62
  else {
64
- array = markers;
63
+ array = resolvedConfig.markers;
65
64
  }
66
65
  return array?.filter((m) => !isNaN(+m.lat) && !isNaN(+m.lon));
67
66
  }
@@ -73,24 +72,34 @@ function getMarkerArray() {
73
72
  function createMarkerLayers() {
74
73
  const markerArray = getMarkerArray();
75
74
  return markerArray?.map((m) => {
75
+ const feature = new Feature({
76
+ geometry: new Point([+m.lon, +m.lat]),
77
+ name: m.title
78
+ });
79
+ feature.setStyle(new Style({
80
+ image: new Circle({
81
+ radius: m.radius ?? 7,
82
+ fill: new Fill({ color: m.color ?? '#dc2626' }),
83
+ stroke: new Stroke({ width: m.strokeWidth ?? 3, color: m.strokeColor ?? '#fca5a5' })
84
+ }),
85
+ text: new Text({
86
+ text: m.title,
87
+ font: '12px Calibri,sans-serif',
88
+ fill: new Fill({ color: '#000' }),
89
+ stroke: new Stroke({
90
+ color: '#fff',
91
+ width: 2
92
+ }),
93
+ offsetY: -15
94
+ })
95
+ }));
76
96
  return new VectorLayer({
77
97
  properties: {
78
98
  name: LAYER_NAME.MARKER
79
99
  },
80
100
  source: new VectorSource({
81
- features: [
82
- new Feature({
83
- geometry: new Point([+m.lon, +m.lat]),
84
- name: m.title
85
- })
86
- ]
87
- }),
88
- style: {
89
- 'circle-radius': m.radius ?? 7,
90
- 'circle-fill-color': m.color ?? '#dc2626',
91
- 'circle-stroke-width': m.strokeWidth ?? 3,
92
- 'circle-stroke-color': m.strokeColor ?? '#fca5a5'
93
- }
101
+ features: [feature]
102
+ })
94
103
  });
95
104
  });
96
105
  }
@@ -116,8 +125,8 @@ $: if (!map && mapElement) {
116
125
  ...(createMarkerLayers() || [])
117
126
  ],
118
127
  view: new View({
119
- center: [longitude ?? 0, latitude ?? 0],
120
- zoom: zoom ?? 2
128
+ center: [resolvedConfig.longitude ?? 0, resolvedConfig.latitude ?? 0],
129
+ zoom: resolvedConfig.zoom ?? 2
121
130
  }),
122
131
  controls: defaultControls({
123
132
  attribution: false
@@ -125,9 +134,21 @@ $: if (!map && mapElement) {
125
134
  });
126
135
  updateRegionOutput();
127
136
  }
137
+ let previousLock = undefined;
138
+ function updateInteractions(map) {
139
+ if (previousLock === resolvedConfig.lock) {
140
+ return;
141
+ }
142
+ previousLock = resolvedConfig.lock;
143
+ map.getInteractions().forEach((i) => {
144
+ i.setActive(!resolvedConfig.lock);
145
+ });
146
+ map.changed();
147
+ }
148
+ $: map && resolvedConfig && updateInteractions(map);
128
149
  let css = initCss($app.css?.mapcomponent, customCss);
129
150
  function updateRegionOutput() {
130
- if (map) {
151
+ if (map && !resolvedConfig.lock) {
131
152
  let extent = map.getView().calculateExtent(map.getSize());
132
153
  const [left, bottom, right, top] = extent;
133
154
  if (outputs?.mapRegion) {
@@ -162,10 +183,16 @@ function handleSyncRegion() {
162
183
  }
163
184
  </script>
164
185
 
165
- <InputValue key="longitude" {id} input={configuration.longitude} bind:value={longitude} />
166
- <InputValue key="latitude" {id} input={configuration.latitude} bind:value={latitude} />
167
- <InputValue key="zoom" {id} input={configuration.zoom} bind:value={zoom} />
168
- <InputValue key="markers" {id} input={configuration.markers} bind:value={markers} />
186
+ {#each Object.entries(components['mapcomponent'].initialData.configuration) as [key, initialConfig] (key)}
187
+ <ResolveConfig
188
+ {id}
189
+ {extraKey}
190
+ {key}
191
+ bind:resolvedConfig={resolvedConfig[key]}
192
+ configuration={configuration[key]}
193
+ {initialConfig}
194
+ />
195
+ {/each}
169
196
 
170
197
  <InitializeComponent {id} />
171
198
 
@@ -201,38 +228,3 @@ function handleSyncRegion() {
201
228
  {/if}
202
229
  </div>
203
230
  {/if}
204
-
205
- <style global>
206
- :global(.ol-overlaycontainer-stopevent) {
207
- display: flex;
208
- flex-direction: column;
209
- align-items: flex-end;
210
- justify-content: flex-start
211
- }
212
- :global(.ol-control) :global(button) {
213
- margin-top: 0.25rem;
214
- margin-right: 0.25rem;
215
- height: 1.75rem;
216
- width: 1.75rem;
217
- border-radius: 0.25rem;
218
- border-width: 1px;
219
- --tw-bg-opacity: 1;
220
- background-color: rgb(var(--color-surface) / var(--tw-bg-opacity));
221
- --tw-text-opacity: 1;
222
- color: rgb(var(--color-text-secondary) / var(--tw-text-opacity));
223
- --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
224
- --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
225
- box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
226
- transition-duration: 200ms;
227
- display: flex;
228
- justify-content: center;
229
- align-items: center
230
- }
231
- :global(.ol-control) :global(button:hover) {
232
- --tw-bg-opacity: 1;
233
- background-color: rgb(var(--color-surface-hover) / var(--tw-bg-opacity))
234
- }
235
- :global(.ol-control) :global(button:focus) {
236
- --tw-bg-opacity: 1;
237
- background-color: rgb(var(--color-surface-hover) / var(--tw-bg-opacity))
238
- }</style>
@@ -6,6 +6,7 @@ declare const __propDef: {
6
6
  configuration: RichConfigurations;
7
7
  customCss?: ComponentCustomCSS<'mapcomponent'> | undefined;
8
8
  render: boolean;
9
+ extraKey?: string | undefined;
9
10
  };
10
11
  events: {
11
12
  [evt: string]: CustomEvent<any>;
@@ -25,19 +25,19 @@ let outputs = initOutput($worldStore, id, {
25
25
  }
26
26
  });
27
27
  const resolvedConfig = initConfig(components['menucomponent'].initialData.configuration, configuration);
28
+ let css = initCss($app.css?.menucomponent, customCss);
28
29
  let beforeIconComponent;
29
30
  let afterIconComponent;
30
- let css = initCss($app.css?.menucomponent, customCss);
31
- $: resolvedConfig.beforeIcon && handleBeforeIcon();
32
- $: resolvedConfig.afterIcon && handleAfterIcon();
31
+ $: resolvedConfig.beforeIcon && beforeIconComponent && handleBeforeIcon();
32
+ $: resolvedConfig.afterIcon && afterIconComponent && handleAfterIcon();
33
33
  async function handleBeforeIcon() {
34
34
  if (resolvedConfig.beforeIcon) {
35
- beforeIconComponent = await loadIcon(resolvedConfig.beforeIcon);
35
+ beforeIconComponent = await loadIcon(resolvedConfig.beforeIcon, beforeIconComponent, 14, undefined, undefined);
36
36
  }
37
37
  }
38
38
  async function handleAfterIcon() {
39
39
  if (resolvedConfig.afterIcon) {
40
- afterIconComponent = await loadIcon(resolvedConfig.afterIcon);
40
+ afterIconComponent = await loadIcon(resolvedConfig.afterIcon, afterIconComponent, 14, undefined, undefined);
41
41
  }
42
42
  }
43
43
  </script>
@@ -86,14 +86,18 @@ async function handleAfterIcon() {
86
86
  nonCaptureEvent
87
87
  >
88
88
  <span class="truncate inline-flex gap-2 items-center">
89
- {#if resolvedConfig.beforeIcon && beforeIconComponent}
90
- <svelte:component this={beforeIconComponent} size={14} />
89
+ {#if resolvedConfig.beforeIcon}
90
+ {#key resolvedConfig.beforeIcon}
91
+ <div class="min-w-4" bind:this={beforeIconComponent} />
92
+ {/key}
91
93
  {/if}
92
94
  {#if resolvedConfig.label && resolvedConfig.label?.length > 0}
93
95
  <div>{resolvedConfig.label}</div>
94
96
  {/if}
95
- {#if resolvedConfig.afterIcon && afterIconComponent}
96
- <svelte:component this={afterIconComponent} size={14} />
97
+ {#if resolvedConfig.afterIcon}
98
+ {#key resolvedConfig.afterIcon}
99
+ <div class="min-w-4" bind:this={afterIconComponent} />
100
+ {/key}
97
101
  {/if}
98
102
  </span>
99
103
  </Button>
@@ -18,10 +18,10 @@ let resolvedConfig = initConfig(components['statcomponent'].initialData.configur
18
18
  initOutput($worldStore, id, {});
19
19
  let css = initCss($app.css?.statcomponent, customCss);
20
20
  let iconComponent;
21
- $: isIcon && resolvedConfig?.media?.configuration?.icon?.icon && handleIcon();
21
+ $: isIcon && resolvedConfig?.media?.configuration?.icon?.icon && iconComponent && handleIcon();
22
22
  async function handleIcon() {
23
23
  if (resolvedConfig?.media?.configuration?.icon?.icon) {
24
- iconComponent = await loadIcon(resolvedConfig.media.configuration.icon.icon);
24
+ iconComponent = await loadIcon(resolvedConfig?.media?.configuration?.icon?.icon, iconComponent, 34, undefined, undefined);
25
25
  }
26
26
  }
27
27
  $: isIcon = resolvedConfig.media?.selected == 'icon';
@@ -66,8 +66,10 @@ $: isIcon = resolvedConfig.media?.selected == 'icon';
66
66
  style={css?.media?.style}
67
67
  >
68
68
  {#if isIcon}
69
- {#if resolvedConfig?.media && iconComponent}
70
- <svelte:component this={iconComponent} size={24} />
69
+ {#if resolvedConfig?.media}
70
+ {#key resolvedConfig.media}
71
+ <div class="min-w-4 text-primary" bind:this={iconComponent} />
72
+ {/key}
71
73
  {/if}
72
74
  {:else}
73
75
  <Loader loading={resolvedConfig?.media?.configuration?.image?.source == undefined}>
@@ -1,6 +1,6 @@
1
1
  <script>import { GridApi, createGrid } from 'ag-grid-community';
2
2
  import { isObject, sendUserToast } from '../../../../../utils';
3
- import { getContext } from 'svelte';
3
+ import { SvelteComponent, getContext, onDestroy } from 'svelte';
4
4
  import RunnableWrapper from '../../helpers/RunnableWrapper.svelte';
5
5
  import { initConfig, initOutput } from '../../../editor/appUtils';
6
6
  import { components } from '../../../editor/component';
@@ -13,6 +13,7 @@ import { Loader2 } from 'lucide-svelte';
13
13
  import { twMerge } from 'tailwind-merge';
14
14
  import { initCss } from '../../../utils';
15
15
  import ResolveStyle from '../../helpers/ResolveStyle.svelte';
16
+ import AppAggridTableActions from './AppAggridTableActions.svelte';
16
17
  // import 'ag-grid-community/dist/styles/ag-theme-alpine-dark.css'
17
18
  export let id;
18
19
  export let componentInput;
@@ -20,7 +21,11 @@ export let configuration;
20
21
  export let initializing = undefined;
21
22
  export let render;
22
23
  export let customCss = undefined;
23
- const { app, worldStore, selectedComponent, componentControl, darkMode } = getContext('AppViewerContext');
24
+ export let actions = undefined;
25
+ const context = getContext('AppViewerContext');
26
+ const iterContext = getContext('ListWrapperContext');
27
+ const listInputs = getContext('ListInputs');
28
+ const { app, worldStore, selectedComponent, componentControl, darkMode } = context;
24
29
  const rowHeights = {
25
30
  normal: 40,
26
31
  compact: 30,
@@ -59,6 +64,7 @@ let outputs = initOutput($worldStore, id, {
59
64
  page: 0,
60
65
  newChange: { row: 0, column: '', value: undefined },
61
66
  ready: undefined,
67
+ inputs: {},
62
68
  filters: {},
63
69
  displayedRowCount: 0
64
70
  });
@@ -75,8 +81,14 @@ function toggleRow(row) {
75
81
  if (!deepEqual(outputs?.selectedRow?.peak(), data)) {
76
82
  outputs?.selectedRow.set(data);
77
83
  }
84
+ if (iterContext && listInputs) {
85
+ listInputs.set(id, { selectedRow: data, selectedRowIndex: selectedRowIndex });
86
+ }
78
87
  }
79
88
  }
89
+ onDestroy(() => {
90
+ listInputs?.remove(id);
91
+ });
80
92
  function toggleRows(rows) {
81
93
  if (rows.length === 0) {
82
94
  outputs?.selectedRows.set([]);
@@ -111,16 +123,93 @@ function onCellValueChanged(event) {
111
123
  let extraConfig = resolvedConfig.extraConfig;
112
124
  let api = undefined;
113
125
  let eGui;
114
- $: loaded && eGui && mountGrid();
115
126
  let state = undefined;
127
+ $: loaded && eGui && mountGrid();
128
+ const cachedDivs = new Map();
129
+ function refreshActions(actions) {
130
+ if (!deepEqual(actions, lastActions)) {
131
+ lastActions = [...actions];
132
+ cachedDivs.forEach((cachedDiv) => {
133
+ cachedDiv.svelteComponent.$destroy();
134
+ cachedDiv.div.remove();
135
+ });
136
+ cachedDivs.clear();
137
+ updateOptions();
138
+ }
139
+ }
140
+ let lastActions = undefined;
141
+ $: actions && refreshActions(actions);
142
+ let inputs = {};
143
+ function actionRenderer(params) {
144
+ const { rowIndex, data: row } = params;
145
+ if (rowIndex === -1 || actions == undefined || actions?.length == 0) {
146
+ return null;
147
+ }
148
+ if (cachedDivs.has(rowIndex)) {
149
+ return cachedDivs.get(rowIndex)?.div;
150
+ }
151
+ const div = document.createElement('div');
152
+ div.classList.add('flex', 'flex-row', 'items-center', 'w-full', 'h-full');
153
+ const svelteComponent = new AppAggridTableActions({
154
+ target: div,
155
+ props: {
156
+ id: id,
157
+ actions,
158
+ rowIndex,
159
+ row,
160
+ render,
161
+ wrapActions: resolvedConfig.wrapActions,
162
+ onSet: (id, value) => {
163
+ if (!inputs[id]) {
164
+ inputs[id] = { [rowIndex]: value };
165
+ }
166
+ else {
167
+ inputs[id] = { ...inputs[id], [rowIndex]: value };
168
+ }
169
+ outputs?.inputs.set(inputs, true);
170
+ },
171
+ onRemove: (id) => {
172
+ if (inputs?.[id] == undefined) {
173
+ return;
174
+ }
175
+ delete inputs[id][rowIndex];
176
+ inputs[id] = { ...inputs[id] };
177
+ if (Object.keys(inputs?.[id] ?? {}).length == 0) {
178
+ delete inputs[id];
179
+ inputs = { ...inputs };
180
+ }
181
+ outputs?.inputs.set(inputs, true);
182
+ }
183
+ },
184
+ context: new Map([['AppViewerContext', context]])
185
+ });
186
+ cachedDivs.set(rowIndex, {
187
+ div,
188
+ actions,
189
+ svelteComponent
190
+ });
191
+ return div;
192
+ }
116
193
  function mountGrid() {
117
194
  if (eGui) {
118
195
  try {
196
+ let columnDefs = Array.isArray(resolvedConfig?.columnDefs) && resolvedConfig.columnDefs.every(isObject)
197
+ ? [...resolvedConfig?.columnDefs] // Clone to avoid direct mutation
198
+ : [];
199
+ // Add the action column if actions are defined
200
+ if (actions && actions.length > 0) {
201
+ columnDefs.push({
202
+ headerName: 'Actions',
203
+ cellRenderer: actionRenderer,
204
+ autoHeight: true,
205
+ cellStyle: { textAlign: 'center' },
206
+ cellClass: 'grid-cell-centered',
207
+ ...(!resolvedConfig?.wrapActions ? { minWidth: 130 * actions?.length } : {})
208
+ });
209
+ }
119
210
  createGrid(eGui, {
120
211
  rowData: value,
121
- columnDefs: Array.isArray(resolvedConfig?.columnDefs) && resolvedConfig.columnDefs.every(isObject)
122
- ? resolvedConfig?.columnDefs
123
- : [],
212
+ columnDefs: columnDefs,
124
213
  pagination: resolvedConfig?.pagination,
125
214
  paginationAutoPageSize: resolvedConfig?.pagination,
126
215
  defaultColDef: {
@@ -215,11 +304,23 @@ function updateValue() {
215
304
  }
216
305
  function updateOptions() {
217
306
  try {
307
+ const columnDefs = Array.isArray(resolvedConfig?.columnDefs) && resolvedConfig.columnDefs.every(isObject)
308
+ ? [...resolvedConfig?.columnDefs] // Clone to avoid direct mutation
309
+ : [];
310
+ // Add the action column if actions are defined
311
+ if (actions && actions.length > 0) {
312
+ columnDefs.push({
313
+ headerName: 'Actions',
314
+ cellRenderer: actionRenderer,
315
+ autoHeight: true,
316
+ cellStyle: { textAlign: 'center' },
317
+ cellClass: 'grid-cell-centered',
318
+ ...(!resolvedConfig?.wrapActions ? { minWidth: 130 * actions?.length } : {})
319
+ });
320
+ }
218
321
  api?.updateGridOptions({
219
322
  rowData: value,
220
- columnDefs: Array.isArray(resolvedConfig?.columnDefs) && resolvedConfig.columnDefs.every(isObject)
221
- ? resolvedConfig?.columnDefs
222
- : undefined,
323
+ columnDefs: columnDefs,
223
324
  pagination: resolvedConfig?.pagination,
224
325
  paginationAutoPageSize: resolvedConfig?.pagination,
225
326
  defaultColDef: {
@@ -1,6 +1,7 @@
1
1
  import { SvelteComponent } from "svelte";
2
2
  import type { AppInput } from '../../../inputType';
3
3
  import type { ComponentCustomCSS, RichConfigurations } from '../../../types';
4
+ import { type TableAction } from '../../../editor/component';
4
5
  import 'ag-grid-community/styles/ag-grid.css';
5
6
  import 'ag-grid-community/styles/ag-theme-alpine.css';
6
7
  declare const __propDef: {
@@ -11,6 +12,7 @@ declare const __propDef: {
11
12
  initializing?: boolean | undefined;
12
13
  render: boolean;
13
14
  customCss?: ComponentCustomCSS<'aggridcomponent'> | undefined;
15
+ actions?: TableAction[] | undefined;
14
16
  };
15
17
  events: {
16
18
  [evt: string]: CustomEvent<any>;