@industream/flowmaker-flowbox-ui-components 0.0.12 → 0.0.13

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.
@@ -2,11 +2,6 @@
2
2
  import { DataCatalogClient } from '@industream/datacatalog-client';
3
3
  import type { CatalogEntry, DataType, SourceType } from '@industream/datacatalog-client/dto';
4
4
 
5
- interface FilterOptions {
6
- searchtext?: string | null; // Case-insensitive LIKE %text% filter on entry name
7
- datasetfilter?: string | null; // Filter entries by sourceParams.dataset
8
- }
9
-
10
5
  interface Props {
11
6
  id?: string;
12
7
  dcapiurl?: string;
@@ -14,9 +9,8 @@
14
9
  datatypefilter?: DataType | DataType[] | null;
15
10
  namefilter?: string | string[] | null;
16
11
  initialselection?: string | null;
17
- onentryselect?: (entry: CatalogEntry | null) => void;
18
- onitemsloaded?: (filtered: CatalogEntry[], all: CatalogEntry[]) => void;
19
- onsearchmiss?: (text: string) => void; // Called when searchtext matches nothing
12
+ onentryselect?: (entry: CatalogEntry) => void;
13
+ onitemsloaded?: (entries: CatalogEntry[]) => void;
20
14
  }
21
15
 
22
16
  let {
@@ -27,8 +21,7 @@
27
21
  namefilter = null,
28
22
  initialselection = null,
29
23
  onentryselect = null,
30
- onitemsloaded = null,
31
- onsearchmiss = null
24
+ onitemsloaded = null
32
25
  }: Props = $props();
33
26
 
34
27
  let catalogEntries = $state<CatalogEntry[]>([]);
@@ -38,13 +31,6 @@
38
31
  let error = $state<string | null>(null);
39
32
  let dropdownRef = $state<HTMLElement | null>(null);
40
33
 
41
- // Active dynamic filters (set via setFilters method)
42
- let activeSearchtext: string | null = null;
43
- let activeDatasetfilter: string | null = null;
44
- let autoSelectedId: string | null = null;
45
- let searchMissText = $state<string | null>(null);
46
- let multipleMatchText = $state<string | null>(null);
47
-
48
34
  // Load catalog entries when component mounts or dcapiurl/sourcetypefilter changes
49
35
  $effect(() => {
50
36
  // Read sourcetypefilter to establish dependency tracking
@@ -54,6 +40,11 @@
54
40
  }
55
41
  });
56
42
 
43
+ // Apply client-side filters when entries or filters change
44
+ $effect(() => {
45
+ filteredEntries = applyFilters(catalogEntries);
46
+ });
47
+
57
48
  // Inject styles into shadow DOM to fix trigger-label width
58
49
  $effect(() => {
59
50
  if (dropdownRef) {
@@ -69,10 +60,11 @@
69
60
  }
70
61
  });
71
62
 
72
- function applyBaseFilters(entries: CatalogEntry[]): CatalogEntry[] {
63
+ function applyFilters(entries: CatalogEntry[]): CatalogEntry[] {
73
64
  let result = entries;
74
65
 
75
66
  // Filter by source type name (from sourceConnection.sourceType.name)
67
+ // Note: Server-side filtering is now done via API, this is just for additional client-side filtering if needed
76
68
  if (sourcetypefilter && sourcetypefilter.length > 0) {
77
69
  const sourceTypeNames = Array.isArray(sourcetypefilter) ? sourcetypefilter : [sourcetypefilter];
78
70
  result = result.filter(entry =>
@@ -92,54 +84,6 @@
92
84
  return result;
93
85
  }
94
86
 
95
- function applyDynamicFilters(entries: CatalogEntry[], { skipSearch = false } = {}): CatalogEntry[] {
96
- let result = entries;
97
-
98
- if (activeDatasetfilter) {
99
- result = result.filter(entry =>
100
- entry.sourceParams?.dataset === activeDatasetfilter
101
- );
102
- }
103
-
104
- if (!skipSearch && activeSearchtext?.trim()) {
105
- const needle = activeSearchtext.trim().toLowerCase();
106
- result = result.filter(entry =>
107
- entry.name?.toLowerCase().includes(needle)
108
- );
109
- }
110
-
111
- return result;
112
- }
113
-
114
- function runFilters() {
115
- const base = applyBaseFilters(catalogEntries);
116
- let result = applyDynamicFilters(base);
117
-
118
- // Search-miss fallback: drop search filter and notify consumer
119
- if (result.length === 0 && activeSearchtext?.trim()) {
120
- searchMissText = activeSearchtext.trim();
121
- multipleMatchText = null;
122
- result = applyDynamicFilters(base, { skipSearch: true });
123
- onsearchmiss?.(activeSearchtext.trim());
124
- } else {
125
- searchMissText = null;
126
- multipleMatchText = (result.length > 1 && activeSearchtext?.trim()) ? activeSearchtext.trim() : null;
127
- }
128
-
129
- filteredEntries = result;
130
-
131
- // Auto-select / auto-clear only when dynamic filters are active
132
- if (activeSearchtext?.trim() || activeDatasetfilter) {
133
- if (result.length === 1 && result[0].id !== autoSelectedId) {
134
- autoSelectedId = result[0].id;
135
- select(result[0]);
136
- } else if (result.length !== 1) {
137
- autoSelectedId = null;
138
- select(null);
139
- }
140
- }
141
- }
142
-
143
87
  async function loadCatalogEntries() {
144
88
  loading = true;
145
89
  error = null;
@@ -160,13 +104,8 @@
160
104
 
161
105
  const result = await client.catalogEntries.get(filters);
162
106
  catalogEntries = result.items || [];
163
- // Apply base filters synchronously so initialselection works
164
- filteredEntries = applyBaseFilters(catalogEntries);
165
-
166
- // Re-apply dynamic filters if any are active
167
- if (activeSearchtext || activeDatasetfilter) {
168
- runFilters();
169
- }
107
+ // Apply filters synchronously so initialselection works
108
+ filteredEntries = applyFilters(catalogEntries);
170
109
 
171
110
  // Auto-select initial selection if provided
172
111
  if (initialselection) {
@@ -177,7 +116,7 @@
177
116
  }
178
117
  }
179
118
 
180
- onitemsloaded?.(filteredEntries, catalogEntries);
119
+ onitemsloaded?.(filteredEntries);
181
120
  } catch (e) {
182
121
  console.error('Failed to load catalog entries:', e);
183
122
  error = e.message || 'Failed to load catalog entries';
@@ -199,29 +138,20 @@
199
138
  }
200
139
  }
201
140
 
202
- // Set dynamic filters and re-run filter logic. Call with {} to clear all dynamic filters.
203
- export function setFilters(opts: FilterOptions) {
204
- activeSearchtext = opts.searchtext ?? null;
205
- activeDatasetfilter = opts.datasetfilter ?? null;
206
- runFilters();
207
- }
208
-
209
- // Programmatically select a catalog entry (pass null to clear)
210
- export function select(idOrEntry: string | CatalogEntry | null) {
211
- if (!idOrEntry) {
212
- selectedValue = '';
213
- if (dropdownRef) dropdownRef.value = '';
214
- onentryselect?.(null);
215
- return;
216
- }
141
+ // Exposed method to programmatically select a catalog entry
142
+ export function select(idOrEntry: string | CatalogEntry) {
217
143
  const id = typeof idOrEntry === 'string' ? idOrEntry : idOrEntry?.id;
218
144
  if (!id) return;
219
145
 
220
146
  const entry = filteredEntries.find(ce => ce.id === id);
221
147
  if (entry) {
222
148
  selectedValue = id;
223
- if (dropdownRef) dropdownRef.value = id;
224
- onentryselect?.(entry);
149
+ if (dropdownRef) {
150
+ dropdownRef.value = id;
151
+ }
152
+ if (onentryselect) {
153
+ onentryselect(entry);
154
+ }
225
155
  }
226
156
  }
227
157
 
@@ -239,13 +169,6 @@
239
169
  export function getAllEntries(): CatalogEntry[] {
240
170
  return catalogEntries;
241
171
  }
242
-
243
- // Reload entries from the API, optionally auto-selecting an entry by ID after reload
244
- export function reload(selectAfterReload?: string) {
245
- loadCatalogEntries().then(() => {
246
- if (selectAfterReload) select(selectAfterReload);
247
- });
248
- }
249
172
  </script>
250
173
 
251
174
  {#if loading}
@@ -285,42 +208,8 @@
285
208
  </cds-dropdown-item>
286
209
  {/each}
287
210
  </cds-dropdown>
288
- {#if searchMissText}
289
- <div class="search-miss search-miss-muted">
290
- <svg viewBox="0 0 32 32" fill="currentColor" width="14" height="14">
291
- <path d="M16 2a14 14 0 1014 14A14 14 0 0016 2zm-1.13 5h2.25v12h-2.25zm1.13 17a1.5 1.5 0 111.5-1.5A1.5 1.5 0 0116 24z"/>
292
- </svg>
293
- <span>No match for "{searchMissText}" — showing all entries</span>
294
- </div>
295
- {/if}
296
- {#if multipleMatchText}
297
- <div class="search-miss search-miss-muted">
298
- <svg viewBox="0 0 32 32" fill="currentColor" width="14" height="14">
299
- <path d="M16 2a14 14 0 1014 14A14 14 0 0016 2zm-1.13 5h2.25v12h-2.25zm1.13 17a1.5 1.5 0 111.5-1.5A1.5 1.5 0 0116 24z"/>
300
- </svg>
301
- <span>Multiple entries found for "{multipleMatchText}" — please make a selection</span>
302
- </div>
303
- {/if}
304
211
  {/if}
305
212
 
306
213
  <style>
307
- .search-miss {
308
- display: flex;
309
- align-items: center;
310
- gap: 0.5rem;
311
- padding: 0.5rem 0.75rem;
312
- margin-top: 0.25rem;
313
- font-size: 0.875rem;
314
- background: var(--cds-support-warning, #f1c21b);
315
- color: #161616;
316
- }
317
-
318
- .search-miss-muted {
319
- background: var(--cds-layer-02, #e0e0e0);
320
- color: var(--cds-text-secondary, #525252);
321
- }
322
-
323
- .search-miss svg {
324
- flex-shrink: 0;
325
- }
214
+ /* Styles moved to inline for shadow DOM compatibility */
326
215
  </style>
@@ -1,8 +1,4 @@
1
1
  import type { CatalogEntry, DataType } from '@industream/datacatalog-client/dto';
2
- interface FilterOptions {
3
- searchtext?: string | null;
4
- datasetfilter?: string | null;
5
- }
6
2
  interface Props {
7
3
  id?: string;
8
4
  dcapiurl?: string;
@@ -10,17 +6,14 @@ interface Props {
10
6
  datatypefilter?: DataType | DataType[] | null;
11
7
  namefilter?: string | string[] | null;
12
8
  initialselection?: string | null;
13
- onentryselect?: (entry: CatalogEntry | null) => void;
14
- onitemsloaded?: (filtered: CatalogEntry[], all: CatalogEntry[]) => void;
15
- onsearchmiss?: (text: string) => void;
9
+ onentryselect?: (entry: CatalogEntry) => void;
10
+ onitemsloaded?: (entries: CatalogEntry[]) => void;
16
11
  }
17
12
  declare const DCCatalogEntry: import("svelte").Component<Props, {
18
- setFilters: (opts: FilterOptions) => void;
19
- select: (idOrEntry: string | CatalogEntry | null) => void;
13
+ select: (idOrEntry: string | CatalogEntry) => void;
20
14
  getSelection: () => CatalogEntry | null;
21
15
  getEntries: () => CatalogEntry[];
22
16
  getAllEntries: () => CatalogEntry[];
23
- reload: (selectAfterReload?: string) => void;
24
17
  }, "">;
25
18
  type DCCatalogEntry = ReturnType<typeof DCCatalogEntry>;
26
19
  export default DCCatalogEntry;
@@ -0,0 +1,113 @@
1
+ <script lang="ts">
2
+ /**
3
+ * DCCatalogEntryPicker — DataCatalog entry picker with configurable columns.
4
+ *
5
+ * Composes TagBrowser (searchable table with multi-select) and SelectedTags
6
+ * (collapsible summary with remove). Owns the DataCatalog fetch lifecycle.
7
+ *
8
+ * Column keys reference the COLUMN_DEFS registry in columns.ts:
9
+ * 'name' → CatalogEntry.name (text)
10
+ * 'dataType' → CatalogEntry.dataType (pill)
11
+ * 'nodeId' → CatalogEntry.sourceParams.nodeId (code)
12
+ * 'unit' → CatalogEntry.metadata.unit (pill)
13
+ * 'labels' → CatalogEntry.labels[] (label pills)
14
+ *
15
+ * @prop dcApiUrl — DataCatalog API base URL
16
+ * @prop sourceConnectionId — Filters catalog entries by source connection
17
+ * @prop selectedIds — (bindable) Array of selected CatalogEntry IDs
18
+ * @prop entries — (bindable) Loaded catalog entries (exposed for parent access)
19
+ * @prop columns — Column keys for the browse table (default: name, dataType, labels)
20
+ * @prop selectedColumnsDisplay — Column keys for the selected tags panel (default: name, dataType, labels)
21
+ * @prop emptyMessage — Message when no entries match the source connection
22
+ * @prop onSelectionChange — Called when selection changes (receives full selectedIds array)
23
+ * @prop onRemove — Called when a single entry is removed from the selection
24
+ */
25
+ import { DataCatalogClient } from '@industream/datacatalog-client';
26
+ import type { CatalogEntry } from '@industream/datacatalog-client/dto';
27
+ import { DEFAULT_COLUMNS, DEFAULT_SELECTED_COLUMNS_DISPLAY } from './picker-column-helpers';
28
+ import TagBrowser from './TagBrowser.svelte';
29
+ import SelectedTags from './SelectedTags.svelte';
30
+
31
+ interface Props {
32
+ dcApiUrl?: string;
33
+ sourceConnectionId?: string;
34
+ selectedIds?: string[];
35
+ entries?: CatalogEntry[];
36
+ columns?: string[];
37
+ selectedColumnsDisplay?: string[];
38
+ emptyMessage?: string;
39
+ onSelectionChange?: (ids: string[]) => void;
40
+ onRemove?: (id: string) => void;
41
+ }
42
+
43
+ let {
44
+ dcApiUrl = '',
45
+ sourceConnectionId = '',
46
+ selectedIds = $bindable([]),
47
+ entries = $bindable([]),
48
+ columns = DEFAULT_COLUMNS,
49
+ selectedColumnsDisplay = DEFAULT_SELECTED_COLUMNS_DISPLAY,
50
+ emptyMessage = 'No entries found for this source connection.',
51
+ onSelectionChange = null,
52
+ onRemove = null
53
+ }: Props = $props();
54
+
55
+ let loading = $state(false);
56
+ let error = $state('');
57
+
58
+ $effect(() => {
59
+ if (dcApiUrl && sourceConnectionId) {
60
+ loadEntries(dcApiUrl, sourceConnectionId);
61
+ } else {
62
+ entries = [];
63
+ error = '';
64
+ }
65
+ });
66
+
67
+ async function loadEntries(apiUrl: string, connId: string) {
68
+ loading = true;
69
+ error = '';
70
+ try {
71
+ const client = new DataCatalogClient({ baseUrl: apiUrl });
72
+ const result = await client.catalogEntries.get({ sourceConnectionIds: [connId] });
73
+ entries = result.items ?? [];
74
+ } catch (err: any) {
75
+ error = err.message ?? 'Failed to load catalog entries';
76
+ entries = [];
77
+ } finally {
78
+ loading = false;
79
+ }
80
+ }
81
+ </script>
82
+
83
+ <TagBrowser
84
+ {entries}
85
+ bind:selectedIds
86
+ {columns}
87
+ {loading}
88
+ {error}
89
+ {emptyMessage}
90
+ {onSelectionChange}
91
+ />
92
+
93
+ {#if selectedIds.length > 0}
94
+ <SelectedTags
95
+ {entries}
96
+ bind:selectedIds
97
+ columns={selectedColumnsDisplay}
98
+ {onRemove}
99
+ />
100
+ {:else}
101
+ <small class="helper-text warning">Select at least one tag to monitor</small>
102
+ {/if}
103
+
104
+ <style>
105
+ .helper-text {
106
+ color: var(--cds-text-secondary, #525252);
107
+ font-size: 0.75rem;
108
+ margin-top: 0.25rem;
109
+ }
110
+ .helper-text.warning {
111
+ color: var(--cds-support-warning, #f1c21b);
112
+ }
113
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { CatalogEntry } from '@industream/datacatalog-client/dto';
2
+ interface Props {
3
+ dcApiUrl?: string;
4
+ sourceConnectionId?: string;
5
+ selectedIds?: string[];
6
+ entries?: CatalogEntry[];
7
+ columns?: string[];
8
+ selectedColumnsDisplay?: string[];
9
+ emptyMessage?: string;
10
+ onSelectionChange?: (ids: string[]) => void;
11
+ onRemove?: (id: string) => void;
12
+ }
13
+ declare const DCCatalogEntryPicker: import("svelte").Component<Props, {}, "entries" | "selectedIds">;
14
+ type DCCatalogEntryPicker = ReturnType<typeof DCCatalogEntryPicker>;
15
+ export default DCCatalogEntryPicker;
@@ -0,0 +1,150 @@
1
+ <script>
2
+ import { DEFAULT_SELECTED_COLUMNS_DISPLAY, resolveColumn, resolveValue } from './picker-column-helpers';
3
+
4
+ let {
5
+ entries = [],
6
+ selectedIds = $bindable([]),
7
+ columns = DEFAULT_SELECTED_COLUMNS_DISPLAY,
8
+ onRemove = null
9
+ } = $props();
10
+
11
+ let expanded = $state(true);
12
+
13
+ /** Resolved column descriptors — maps each column key to its label, resolver and render type */
14
+ const columnDescriptors = $derived(
15
+ columns
16
+ .map(k => { const resolved = resolveColumn(k); return resolved ? { key: k, ...resolved } : null; })
17
+ .filter(Boolean)
18
+ );
19
+
20
+ const selectedEntries = $derived(() => {
21
+ const idSet = new Set(selectedIds);
22
+ return entries.filter(e => idSet.has(e.id));
23
+ });
24
+
25
+ const selectedCount = $derived(selectedIds.length);
26
+
27
+ $effect(() => {
28
+ if (selectedCount === 0) {
29
+ expanded = false;
30
+ } else if (selectedCount > 0 && !expanded) {
31
+ expanded = true;
32
+ }
33
+ });
34
+
35
+ function handleRemove(id) {
36
+ onRemove?.(id);
37
+ }
38
+ </script>
39
+
40
+ <div class="selected-tags">
41
+ <button class="panel-header" aria-expanded={expanded} onclick={() => expanded = !expanded}>
42
+ <svg class="chevron" class:chevron-expanded={expanded} viewBox="0 0 16 16" width="16" height="16">
43
+ <path d="M11 8L6 13V3z" fill="currentColor"></path>
44
+ </svg>
45
+ <span class="panel-title">Selected Tags ({selectedCount})</span>
46
+ </button>
47
+
48
+ {#if expanded}
49
+ <div class="panel-body">
50
+ {#if selectedEntries().length === 0}
51
+ <div class="empty-message">No tags selected</div>
52
+ {:else}
53
+ <div class="tag-list">
54
+ {#each selectedEntries() as entry (entry.id)}
55
+ <div class="tag-row">
56
+ <div class="tag-info">
57
+ {#each columnDescriptors as columnDescriptor, index (columnDescriptor.key)}
58
+ {@const val = resolveValue(entry, columnDescriptor.key)}
59
+ {#if index === 0}
60
+ <!-- First column: bold primary label -->
61
+ <span class="tag-primary">{val ?? '-'}</span>
62
+ {:else if columnDescriptor.type === 'labels' && Array.isArray(val)}
63
+ {#each val as label (label.id)}
64
+ <span class="meta-item">{label.name}</span>
65
+ {/each}
66
+ {:else if columnDescriptor.type === 'code'}
67
+ {#if val}<code class="tag-code">{val}</code>{/if}
68
+ {:else}
69
+ {#if val}<span class="meta-item">{val}</span>{/if}
70
+ {/if}
71
+ {/each}
72
+ </div>
73
+ <button
74
+ class="remove-button"
75
+ title="Remove {entry.name}"
76
+ aria-label="Remove {entry.name}"
77
+ onclick={() => handleRemove(entry.id)}
78
+ >
79
+ <svg viewBox="0 0 16 16" width="14" height="14"><path d="M12 4.7L11.3 4 8 7.3 4.7 4 4 4.7 7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8z" fill="currentColor"></path></svg>
80
+ </button>
81
+ </div>
82
+ {/each}
83
+ </div>
84
+ {/if}
85
+ </div>
86
+ {/if}
87
+ </div>
88
+
89
+ <style>
90
+ .selected-tags {
91
+ border: 1px solid var(--cds-border-subtle-01, #393939);
92
+ background: var(--cds-layer-01, #262626);
93
+ }
94
+ .panel-header {
95
+ display: flex; align-items: center; gap: 0.5rem;
96
+ width: 100%; padding: 0.5rem 0.75rem;
97
+ background: var(--cds-layer-02, #2e2e2e); border: none;
98
+ color: var(--cds-text-primary, #f4f4f4);
99
+ font-size: 0.8125rem; font-weight: 600;
100
+ cursor: pointer; text-align: left; transition: background-color 0.15s;
101
+ }
102
+ .panel-header:hover { background: var(--cds-layer-hover-01, #4c4c4c); }
103
+ .chevron {
104
+ color: var(--cds-text-secondary, #c6c6c6);
105
+ transition: transform 0.15s ease; flex-shrink: 0;
106
+ }
107
+ .chevron-expanded { transform: rotate(90deg); }
108
+ .panel-title { flex: 1; }
109
+ .panel-body { max-height: 200px; overflow-y: auto; }
110
+ .empty-message {
111
+ padding: 1rem; text-align: center;
112
+ color: var(--cds-text-helper, #8d8d8d); font-size: 0.8125rem;
113
+ }
114
+ .tag-row {
115
+ display: flex; align-items: center; gap: 0.5rem;
116
+ padding: 0.375rem 0.75rem;
117
+ border-bottom: 1px solid var(--cds-border-subtle-01, #393939);
118
+ transition: background-color 0.1s;
119
+ }
120
+ .tag-row:last-child { border-bottom: none; }
121
+ .tag-row:hover { background: var(--cds-layer-hover-01, #4c4c4c); }
122
+ .tag-info {
123
+ flex: 1; display: flex; align-items: center; gap: 0.75rem;
124
+ min-width: 0; overflow: hidden;
125
+ }
126
+ .tag-primary {
127
+ font-weight: 600; font-size: 0.8125rem;
128
+ color: var(--cds-text-primary, #f4f4f4);
129
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
130
+ flex-shrink: 0; max-width: 12rem;
131
+ }
132
+ .tag-code {
133
+ font-family: 'IBM Plex Mono', monospace; font-size: 0.6875rem;
134
+ color: var(--cds-text-secondary, #c6c6c6);
135
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
136
+ }
137
+ .meta-item {
138
+ padding: 0.0625rem 0.375rem;
139
+ background: var(--cds-tag-background-gray, #393939);
140
+ color: var(--cds-tag-color-gray, #c6c6c6);
141
+ font-size: 0.6875rem; border-radius: 1rem;
142
+ }
143
+ .remove-button {
144
+ background: transparent; border: none;
145
+ color: var(--cds-text-secondary, #c6c6c6);
146
+ cursor: pointer; padding: 0.25rem;
147
+ transition: color 0.15s; flex-shrink: 0;
148
+ }
149
+ .remove-button:hover { color: var(--cds-support-error, #fa4d56); }
150
+ </style>
@@ -0,0 +1,18 @@
1
+ export default SelectedTags;
2
+ type SelectedTags = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const SelectedTags: import("svelte").Component<{
7
+ entries?: any[];
8
+ selectedIds?: any[];
9
+ columns?: typeof DEFAULT_SELECTED_COLUMNS_DISPLAY;
10
+ onRemove?: any;
11
+ }, {}, "selectedIds">;
12
+ type $$ComponentProps = {
13
+ entries?: any[];
14
+ selectedIds?: any[];
15
+ columns?: typeof DEFAULT_SELECTED_COLUMNS_DISPLAY;
16
+ onRemove?: any;
17
+ };
18
+ import { DEFAULT_SELECTED_COLUMNS_DISPLAY } from './picker-column-helpers';