@oneteme/jquery-organizer 0.0.6 → 0.0.7

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.
@@ -9,7 +9,7 @@ import * as i3 from '@angular/material/menu';
9
9
  import { MatMenuModule } from '@angular/material/menu';
10
10
  import * as i4 from '@angular/material/divider';
11
11
  import { MatDividerModule } from '@angular/material/divider';
12
- import { Subject, isObservable, take, takeUntil as takeUntil$1 } from 'rxjs';
12
+ import { Subject, isObservable } from 'rxjs';
13
13
  import { takeUntil } from 'rxjs/operators';
14
14
 
15
15
  function buildYFields(indicators) {
@@ -172,13 +172,7 @@ class OrganizerButtonComponent {
172
172
  this.fieldDataCache = new Map();
173
173
  this.destroy$ = new Subject();
174
174
  this.destroyed = false;
175
- }
176
- ngOnInit() {
177
- console.debug('[OrganizerButton] Initialized', {
178
- configFields: this.config?.fields?.length ?? 0,
179
- hasState: !!this.state,
180
- hideMenuValues: this.hideMenuValues
181
- });
175
+ this.sliceRequestId = 0;
182
176
  }
183
177
  ngOnDestroy() {
184
178
  this.destroyed = true;
@@ -198,27 +192,27 @@ class OrganizerButtonComponent {
198
192
  return `${visible}/${total}`;
199
193
  }
200
194
  onFieldToggle(fieldId, visible) {
201
- console.debug('[OrganizerButton] Field toggled', { fieldId, visible });
202
- const visibleFields = this.state?.visibleFields || [];
203
- const updated = visible
204
- ? [...visibleFields, fieldId]
205
- : visibleFields.filter(f => f !== fieldId);
195
+ const current = this.state?.visibleFields
196
+ ?? (this.config.fields ?? []).filter(f => f.visible !== false).map(f => f.id);
197
+ let updated;
198
+ if (visible) {
199
+ updated = current.includes(fieldId) ? current : [...current, fieldId];
200
+ }
201
+ else {
202
+ updated = current.filter(f => f !== fieldId);
203
+ }
206
204
  this.emitChange('fieldToggled', { visibleFields: updated });
207
205
  }
208
206
  onXFieldSelect(fieldId) {
209
- console.debug('[OrganizerButton] X field selected', { fieldId, current: this.state?.selectedX });
210
207
  // Évite une requête inutile si le X est déjà sélectionné
211
208
  if (this.state?.selectedX === fieldId) {
212
- console.debug('[OrganizerButton] X field already selected, skipping emit');
213
209
  return;
214
210
  }
215
211
  this.emitChange('xSelected', { selectedX: fieldId });
216
212
  }
217
213
  onYFieldSelect(fieldId) {
218
- console.debug('[OrganizerButton] Y field selected', { fieldId, current: this.state?.selectedY });
219
214
  // Évite une requête inutile si le Y est déjà sélectionné
220
215
  if (this.state?.selectedY === fieldId) {
221
- console.debug('[OrganizerButton] Y field already selected, skipping emit');
222
216
  return;
223
217
  }
224
218
  this.emitChange('ySelected', {
@@ -227,10 +221,8 @@ class OrganizerButtonComponent {
227
221
  });
228
222
  }
229
223
  onYAggregateSelect(yFieldId, aggregateId) {
230
- console.debug('[OrganizerButton] Y aggregate selected', { yFieldId, aggregateId, current: this.state?.selectedYAggregate });
231
224
  // Évite une requête inutile si l'aggregate est déjà sélectionné
232
225
  if (this.state?.selectedYAggregate === aggregateId && this.state?.selectedY === yFieldId) {
233
- console.debug('[OrganizerButton] Y aggregate already selected, skipping emit');
234
226
  return;
235
227
  }
236
228
  this.emitChange('ySelected', {
@@ -239,7 +231,6 @@ class OrganizerButtonComponent {
239
231
  });
240
232
  }
241
233
  onGroupBySelect(groupId) {
242
- console.debug('[OrganizerButton] Group by selected', { groupId });
243
234
  const current = this.state?.selectedGroupBy;
244
235
  this.emitChange('groupBySelected', { selectedGroupBy: current === groupId ? undefined : groupId });
245
236
  }
@@ -250,7 +241,6 @@ class OrganizerButtonComponent {
250
241
  this.emitChange('chartTypeSelected', { selectedChartType: chartType });
251
242
  }
252
243
  onTemplateSelect(templateId) {
253
- console.debug('[OrganizerButton] Template selected', { templateId });
254
244
  if (!this.config.templates?.length)
255
245
  return;
256
246
  const template = this.config.templates?.find(t => t.id === templateId);
@@ -261,7 +251,6 @@ class OrganizerButtonComponent {
261
251
  this.syncSliceState(newState.selectedSlices);
262
252
  }
263
253
  onSliceClick(sliceId) {
264
- console.debug('[OrganizerButton] Slice clicked', { sliceId });
265
254
  if (this.config.onSliceClick) {
266
255
  this.config.onSliceClick();
267
256
  }
@@ -285,6 +274,10 @@ class OrganizerButtonComponent {
285
274
  });
286
275
  }
287
276
  syncSliceState(selectedSlices, onLoaded) {
277
+ // Une nouvelle demande annule la précédente : seule la réponse la plus récente est prise en compte.
278
+ const requestId = ++this.sliceRequestId;
279
+ this.sliceSubscription?.unsubscribe();
280
+ this.sliceSubscription = undefined;
288
281
  const sliceId = selectedSlices?.[0];
289
282
  if (!sliceId || !this.config.onFetchSliceData) {
290
283
  this.sliceStateChange.emit(null);
@@ -299,7 +292,7 @@ class OrganizerButtonComponent {
299
292
  }
300
293
  const result = this.config.onFetchSliceData(sliceId);
301
294
  const handleData = (tasks) => {
302
- if (this.destroyed)
295
+ if (this.destroyed || requestId !== this.sliceRequestId)
303
296
  return;
304
297
  this.sliceStateChange.emit({
305
298
  sliceConfigs: [{ title: slice.label ?? sliceId, columnKey: sliceId }],
@@ -309,14 +302,14 @@ class OrganizerButtonComponent {
309
302
  onLoaded?.();
310
303
  };
311
304
  const handleError = (error) => {
312
- if (this.destroyed)
305
+ if (this.destroyed || requestId !== this.sliceRequestId)
313
306
  return;
314
307
  console.error('[OrganizerButton] Slice data loading failed', error);
315
308
  this.sliceStateChange.emit(null);
316
309
  onLoaded?.();
317
310
  };
318
311
  if (isObservable(result)) {
319
- result.pipe(takeUntil(this.destroy$)).subscribe({ next: handleData, error: handleError });
312
+ this.sliceSubscription = result.pipe(takeUntil(this.destroy$)).subscribe({ next: handleData, error: handleError });
320
313
  }
321
314
  else {
322
315
  void result.then(handleData, handleError);
@@ -551,7 +544,6 @@ class SlicePanelComponent {
551
544
  this.sliceConfigs = [];
552
545
  this.columns = [];
553
546
  this.data = [];
554
- this.lazyData = new Map();
555
547
  this.lazyStatus = new Map();
556
548
  this.showToggle = true;
557
549
  this.showCounts = true;
@@ -571,23 +563,28 @@ class SlicePanelComponent {
571
563
  this._countCache = new Map();
572
564
  this.trackBySliceIndex = (index, _) => index;
573
565
  this.trackByCategoryKey = (_, cat) => cat.key;
566
+ this._columnIndex = new Map();
574
567
  }
575
568
  get hostCollapsed() { return this.isCollapsed; }
576
569
  ngOnInit() {
577
570
  this.isCollapsed = this.collapsedByDefault;
578
571
  }
579
572
  ngOnChanges(changes) {
580
- if (changes['sliceConfigs'] || changes['data'] || changes['columns'] || changes['lazyData'] || changes['lazyStatus']) {
573
+ if (changes['sliceConfigs'] || changes['data'] || changes['columns'] || changes['lazyStatus']) {
574
+ const hadActiveFilters = this._hasActiveFilters();
581
575
  this._refreshDynamicSlices();
582
576
  this._rebuildCache();
583
- const shouldReemitFilter = !!(changes['data'] || changes['columns'] || changes['lazyData'] || changes['lazyStatus']);
584
- const hasActiveFilters = [...this.activeKeysBySlice.values()].some(s => s.size > 0);
585
- if (hasActiveFilters && shouldReemitFilter) {
577
+ const shouldReemitFilter = !!(changes['sliceConfigs'] || changes['data'] || changes['columns'] || changes['lazyStatus']);
578
+ // Un slice retiré de la config emporte sa sélection : le parent doit en être informé.
579
+ if (shouldReemitFilter && (hadActiveFilters || this._hasActiveFilters())) {
586
580
  this._emitFilter();
587
581
  }
588
582
  this._cdr.markForCheck();
589
583
  }
590
584
  }
585
+ _hasActiveFilters() {
586
+ return [...this.activeKeysBySlice.values()].some(s => s.size > 0);
587
+ }
591
588
  get showPanel() {
592
589
  const hasCfg = (this.sliceConfigs || []).length > 0 || this._dynamicSlices.length > 0;
593
590
  if (this.alwaysShow)
@@ -696,14 +693,16 @@ class SlicePanelComponent {
696
693
  return !this.activeKeysBySlice.has(sliceIndex) || this.activeKeysBySlice.get(sliceIndex).size === 0;
697
694
  }
698
695
  sliceCategoryCount(sliceIndex, categoryKey) {
699
- const cacheKey = `${sliceIndex}:${categoryKey}`;
700
- if (this._countCache.has(cacheKey)) {
701
- return this._countCache.get(cacheKey);
702
- }
703
696
  const slice = this._cachedSlices[sliceIndex];
704
697
  if (!slice)
705
698
  return 0;
706
699
  const category = (slice.categories || []).find((c) => c.key === categoryKey);
700
+ if (category?.count !== undefined)
701
+ return category.count;
702
+ const cacheKey = `${sliceIndex}:${categoryKey}`;
703
+ if (this._countCache.has(cacheKey)) {
704
+ return this._countCache.get(cacheKey);
705
+ }
707
706
  const count = category ? (this.data || []).filter((row) => category.filter ? category.filter(row) : true).length : 0;
708
707
  this._countCache.set(cacheKey, count);
709
708
  return count;
@@ -771,11 +770,11 @@ class SlicePanelComponent {
771
770
  addDynamicSlice(column) {
772
771
  if (this._dynamicSlices.some(slice => slice.key === column.key))
773
772
  return;
774
- const distinctValues = this._computeDistinctValues(column.key);
773
+ const distinct = this._computeDistinctValues(column.key);
775
774
  const newSlice = {
776
775
  title: column.header,
777
776
  columnKey: column.key,
778
- categories: distinctValues.map((v) => this._buildCategoryFromValue(column.key, v)),
777
+ categories: this._buildCategories(column.key, distinct),
779
778
  };
780
779
  this._dynamicSlices = [...this._dynamicSlices, { key: column.key, slice: newSlice }];
781
780
  this._rebuildCache();
@@ -787,14 +786,7 @@ class SlicePanelComponent {
787
786
  const dynamicIndex = sliceIndex - this.staticSliceCount;
788
787
  if (dynamicIndex < 0)
789
788
  return;
790
- const newActiveKeys = new Map();
791
- this.activeKeysBySlice.forEach((keys, idx) => {
792
- if (idx < sliceIndex)
793
- newActiveKeys.set(idx, keys);
794
- else if (idx > sliceIndex)
795
- newActiveKeys.set(idx - 1, keys);
796
- });
797
- this.activeKeysBySlice = newActiveKeys;
789
+ // Les sélections sont rapprochées des slices restants par identité dans _rebuildCache.
798
790
  this._dynamicSlices = this._dynamicSlices.filter((_, i) => i !== dynamicIndex);
799
791
  this._rebuildCache();
800
792
  this.dynamicSliceKeysChange.emit(this._dynamicSlices.map(d => d.key));
@@ -851,32 +843,37 @@ class SlicePanelComponent {
851
843
  if (!slice.columnKey || (slice.categories && slice.categories.length > 0)) {
852
844
  return slice;
853
845
  }
854
- const col = (this.columns || []).find(c => c.key === slice.columnKey);
846
+ const col = this._column(slice.columnKey);
855
847
  const isLazy = !!col?.lazy;
856
848
  if (isLazy && this.lazyStatus.get(slice.columnKey) !== 'loaded') {
857
849
  return { ...slice, categories: [] };
858
850
  }
859
851
  if (slice.bucket) {
860
- const distinctValues = [...new Set((this.data || []).map(slice.bucket))].sort();
852
+ const bucket = slice.bucket;
853
+ const counts = new Map();
854
+ (this.data || []).forEach(row => { const v = bucket(row); counts.set(v, (counts.get(v) ?? 0) + 1); });
861
855
  return {
862
856
  ...slice,
863
- categories: distinctValues.map((v) => ({
864
- key: v, label: v,
865
- filter: (row) => slice.bucket(row) === v,
857
+ categories: [...counts.keys()].sort().map((v) => ({
858
+ key: v, label: v, count: counts.get(v),
859
+ filter: (row) => bucket(row) === v,
866
860
  })),
867
861
  };
868
862
  }
869
- const distinctValues = this._computeDistinctValues(slice.columnKey);
870
863
  return {
871
864
  ...slice,
872
- categories: distinctValues.map((v) => this._buildCategoryFromValue(slice.columnKey, v)),
865
+ categories: this._buildCategories(slice.columnKey, this._computeDistinctValues(slice.columnKey)),
873
866
  };
874
867
  }
875
- _buildCategoryFromValue(columnKey, v) {
868
+ _buildCategories(columnKey, distinct) {
869
+ return distinct.values.map((v) => this._buildCategoryFromValue(columnKey, v, distinct.counts.get(v)));
870
+ }
871
+ _buildCategoryFromValue(columnKey, v, count) {
876
872
  if (v === EMPTY_CATEGORY_KEY) {
877
873
  return {
878
874
  key: EMPTY_CATEGORY_KEY,
879
875
  label: EMPTY_CATEGORY_LABEL,
876
+ count,
880
877
  filter: (row) => {
881
878
  const val = this._getLazyAwareValue(columnKey, row);
882
879
  return val == null || val === '';
@@ -884,24 +881,44 @@ class SlicePanelComponent {
884
881
  };
885
882
  }
886
883
  return {
887
- key: v, label: v,
884
+ key: v, label: v, count,
888
885
  filter: (row) => String(this._getLazyAwareValue(columnKey, row) ?? '') === v,
889
886
  };
890
887
  }
888
+ /** Valeurs distinctes (triées, « vide » en dernier) et effectifs, calculés en un seul passage. */
891
889
  _computeDistinctValues(columnKey) {
892
- const rawValues = (this.data || []).map((row) => {
890
+ const counts = new Map();
891
+ let empty = 0;
892
+ (this.data || []).forEach((row) => {
893
893
  const val = this._getLazyAwareValue(columnKey, row);
894
- return val != null && val !== '' ? String(val) : null;
894
+ if (val != null && val !== '') {
895
+ const text = String(val);
896
+ counts.set(text, (counts.get(text) ?? 0) + 1);
897
+ }
898
+ else {
899
+ empty++;
900
+ }
895
901
  });
896
- const distinct = [...new Set(rawValues.filter((v) => v !== null))].sort();
897
- if (rawValues.some(v => v === null))
898
- distinct.push(EMPTY_CATEGORY_KEY);
899
- return distinct;
902
+ const values = [...counts.keys()].sort();
903
+ if (empty > 0) {
904
+ values.push(EMPTY_CATEGORY_KEY);
905
+ counts.set(EMPTY_CATEGORY_KEY, empty);
906
+ }
907
+ return { values, counts };
908
+ }
909
+ _column(key) {
910
+ if (this._columnsRef !== this.columns) {
911
+ this._columnsRef = this.columns;
912
+ this._columnIndex = new Map();
913
+ (this.columns || []).forEach(c => { if (!this._columnIndex.has(c.key))
914
+ this._columnIndex.set(c.key, c); });
915
+ }
916
+ return key === undefined ? undefined : this._columnIndex.get(key);
900
917
  }
901
918
  _getLazyAwareValue(columnKey, row) {
902
- const colDef = (this.columns || []).find(c => c.key === columnKey);
903
- if (colDef?.lazy) {
904
- return this.lazyData.get(columnKey)?.get(row) ?? null;
919
+ const colDef = this._column(columnKey);
920
+ if (colDef?.lazy && this.lazyStatus.get(columnKey) !== 'loaded') {
921
+ return null;
905
922
  }
906
923
  if (colDef?.value) {
907
924
  return colDef.value(row, 0);
@@ -934,16 +951,10 @@ class SlicePanelComponent {
934
951
  this._countCache.clear();
935
952
  }
936
953
  _refreshDynamicSlices() {
937
- this._dynamicSlices = this._dynamicSlices.map(({ key, slice }) => {
938
- const distinctValues = this._computeDistinctValues(key);
939
- return {
940
- key,
941
- slice: {
942
- ...slice,
943
- categories: distinctValues.map((v) => this._buildCategoryFromValue(key, v)),
944
- },
945
- };
946
- });
954
+ this._dynamicSlices = this._dynamicSlices.map(({ key, slice }) => ({
955
+ key,
956
+ slice: { ...slice, categories: this._buildCategories(key, this._computeDistinctValues(key)) },
957
+ }));
947
958
  }
948
959
  _scrollSliceTitleIntoView(sliceIndex) {
949
960
  setTimeout(() => {
@@ -955,7 +966,7 @@ class SlicePanelComponent {
955
966
  }, 50);
956
967
  }
957
968
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SlicePanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
958
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SlicePanelComponent, isStandalone: true, selector: "slice-panel", inputs: { sliceConfigs: "sliceConfigs", columns: "columns", data: "data", lazyData: "lazyData", lazyStatus: "lazyStatus", showToggle: "showToggle", showCounts: "showCounts", collapsedByDefault: "collapsedByDefault", alwaysShow: "alwaysShow" }, outputs: { filterChange: "filterChange", activeKeysChange: "activeKeysChange", dynamicSliceKeysChange: "dynamicSliceKeysChange", collapsedChange: "collapsedChange" }, host: { properties: { "class.collapsed": "this.hostCollapsed" } }, viewQueries: [{ propertyName: "slicePanelBodyRef", first: true, predicate: ["slicePanelBody"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"slice-panel-wrapper\" [class.collapsed]=\"isCollapsed\">\n <aside class=\"slice-panel\" [class.collapsed]=\"isCollapsed\">\n <div class=\"slice-panel-header\">\n <span *ngIf=\"!isCollapsed\" class=\"slice-panel-title\">\n {{ i18n.filterPanelTitle(slices.length) }}\n </span>\n <button\n *ngIf=\"showToggle\"\n type=\"button\"\n class=\"slice-toggle\"\n [attr.aria-label]=\"isCollapsed ? i18n.expandFilterTitle : i18n.collapseFilterTitle\"\n (click)=\"togglePanel()\"\n >\n <mat-icon class=\"slice-toggle-mat-icon\">{{ isCollapsed ? 'filter_list' : 'filter_list_off' }}</mat-icon>\n </button>\n </div>\n\n <div class=\"slice-panel-body\" *ngIf=\"!isCollapsed\" #slicePanelBody>\n <ng-container *ngFor=\"let slice of slices; let si = index; trackBy: trackBySliceIndex\">\n <div class=\"slice-title-row\" [attr.data-slice-index]=\"si\">\n <button\n type=\"button\"\n class=\"slice-title-toggle\"\n [attr.aria-controls]=\"'slice-section-' + si\"\n [attr.aria-expanded]=\"!isSliceCollapsed(si)\"\n (click)=\"toggleSliceCollapse(si)\"\n >\n <span class=\"slice-title-chevron\" [class.expanded]=\"!isSliceCollapsed(si)\">\u203A</span>\n <mat-icon *ngIf=\"getSliceIcon(slice)\" class=\"slice-title-icon\">{{ getSliceIcon(slice) }}</mat-icon>\n <span class=\"slice-title\">{{ slice.title || i18n.filterBlockDefaultTitle }}</span>\n </button>\n <button\n *ngIf=\"isSliceDynamic(si)\"\n type=\"button\"\n class=\"slice-remove-btn\"\n [attr.aria-label]=\"'Supprimer le filtre ' + (slice.title || i18n.filterBlockDefaultTitle)\"\n (click)=\"removeDynamicSlice(si)\"\n >\u00D7</button>\n </div>\n\n <div [id]=\"'slice-section-' + si\" class=\"slice-section-items\" *ngIf=\"!isSliceCollapsed(si)\">\n <ng-container *ngIf=\"isSliceLoading(si); else sliceContent\">\n <div class=\"slice-lazy-loading\">\n <span class=\"lazy-skeleton\"></span>\n <span class=\"lazy-skeleton\"></span>\n <span class=\"lazy-skeleton\"></span>\n </div>\n </ng-container>\n <ng-template #sliceContent>\n <ng-container *ngFor=\"let category of slice.categories; trackBy: trackByCategoryKey\">\n <button\n *ngIf=\"sliceCategoryCount(si, category.key) > 0\"\n class=\"slice-item\"\n type=\"button\"\n [class.active]=\"isSliceCategoryActive(si, category.key)\"\n [attr.data-category-key]=\"category.key\"\n [title]=\"category.label\"\n (click)=\"onSliceCategorySelected(si, category.key)\"\n >\n <span>{{ category.label }}</span>\n <span *ngIf=\"showCounts\">{{ sliceCategoryCount(si, category.key) }}</span>\n </button>\n </ng-container>\n <div *ngIf=\"isSliceEmpty(si)\" class=\"slice-empty-state\">{{ i18n.filterEmptyState }}</div>\n </ng-template>\n </div>\n\n <hr *ngIf=\"si < slices.length - 1\" class=\"slice-divider\" />\n </ng-container>\n </div>\n </aside>\n</div>\n", styles: ["@keyframes slideInLeft{0%{opacity:0;transform:translate(-24px)}to{opacity:1;transform:translate(0)}}:host{display:block;height:100%;min-height:0;box-sizing:border-box;animation:slideInLeft .3s cubic-bezier(.34,1.56,.64,1) forwards}.slice-panel-wrapper{height:100%;max-height:100%;overflow-y:auto;box-sizing:border-box}.slice-panel{margin-top:0;border:1px solid var(--jqt-border-color);border-radius:10px;background:var(--jqt-surface-color);display:flex;flex-direction:column;min-width:0;height:100%;overflow:hidden;box-sizing:border-box}.slice-panel-header{flex-shrink:0;display:flex;justify-content:flex-end;align-items:center;height:var(--jqt-slice-header-height, 34px);padding:0 8px;margin-bottom:var(--jqt-slice-header-margin-bottom, 8px)}.slice-panel-header:has(.slice-panel-title){justify-content:space-between;padding-left:12px}.slice-panel-body{flex:1 1 0;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:4px;padding:var(--jqt-slice-body-padding, 4px 10px 10px);scrollbar-width:thin;scrollbar-color:var(--jqt-border-color) transparent}.slice-panel-body::-webkit-scrollbar{width:2px}.slice-panel-body::-webkit-scrollbar-thumb{background:var(--jqt-primary-color);border-radius:4px}.slice-panel-title{margin:0;padding-top:2px;font-size:11px;font-weight:700;line-height:1;text-transform:uppercase;letter-spacing:.08em;color:var(--jqt-text-color);-webkit-user-select:none;user-select:none;align-self:center;display:inline-flex;align-items:center;gap:5px}.slice-panel-title .slice-panel-title-icon{font-size:16px;width:16px;height:16px;line-height:1;flex-shrink:0}.slice-section-items{display:flex;flex-direction:column;gap:2px;flex:0 0 auto;scrollbar-width:thin;scrollbar-color:var(--jqt-border-color) transparent}.slice-section-items::-webkit-scrollbar{width:2px}.slice-section-items .slice-empty-state{padding:8px 10px;font-size:12px;color:var(--jqt-text-muted, #9ca3af);font-style:italic;text-align:center}.slice-section-items::-webkit-scrollbar-thumb{background:var(--jqt-border-color);border-radius:4px}.slice-toggle{border:0;background:var(--jqt-surface-color);color:var(--jqt-text-color);border-radius:6px;width:22px;height:22px;padding:0;font-size:14px;text-align:center;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;line-height:1}.slice-toggle-mat-icon{font-size:16px;width:16px;height:16px;line-height:1}.slice-panel.collapsed{border-color:transparent;background:transparent;overflow:visible}.slice-panel.collapsed .slice-panel-header{height:34px;padding:0;justify-content:center;align-items:center}.slice-panel.collapsed .slice-toggle{width:34px;height:34px;border:1px solid var(--jqt-border-color);background:var(--jqt-surface-color);border-radius:8px}.slice-panel.collapsed .slice-toggle:hover{border-color:var(--jqt-text-muted)}.slice-panel.collapsed .slice-toggle .slice-toggle-mat-icon{font-size:18px;width:18px;height:18px}.slice-title-row{display:flex;align-items:center;justify-content:space-between;gap:6px;margin:4px 0 6px;-webkit-user-select:none;user-select:none}.slice-title-row:first-of-type .slice-title{margin-top:0}.slice-title-toggle{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:6px;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;text-align:left}.slice-title-toggle:hover .slice-title{color:var(--jqt-text-color)}.slice-title-toggle:hover .slice-title-chevron{color:var(--jqt-text-secondary)}.slice-title-toggle:focus-visible{outline:2px solid var(--jqt-primary-color);outline-offset:2px;border-radius:4px}.slice-title-chevron{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;font-size:16px;line-height:1;color:var(--jqt-text-muted);transition:transform .15s ease;transform:rotate(0);position:relative;top:-1px}.slice-title-chevron.expanded{transform:rotate(90deg)}.slice-title{flex:1 1 auto;margin:0;font-size:var(--jqt-slice-section-title-font-size, 14px);font-weight:600;color:var(--jqt-title-color)}.slice-title-icon{flex-shrink:0;font-size:14px!important;width:14px!important;height:14px!important;color:var(--jqt-title-color)}.slice-remove-btn{background:none;border:none;cursor:pointer;color:var(--jqt-border-color);font-size:12px;padding:0 2px;line-height:1;flex-shrink:0;opacity:.5;transition:opacity .15s,color .15s}.slice-remove-btn:hover{color:var(--jqt-text-secondary);opacity:1}.slice-title-row:hover .slice-remove-btn{opacity:.8}.slice-item{display:flex;justify-content:space-between;align-items:center;text-align:left;width:100%;min-height:var(--jqt-slice-item-min-height, 30px);padding:var(--jqt-slice-item-padding, 5px 10px 5px 16px);background:transparent;border:0;cursor:pointer;border-radius:8px;color:var(--jqt-text-color);box-sizing:border-box;min-width:0;gap:8px;font-size:var(--jqt-slice-item-font-size, 13px)}.slice-item.active{background:var(--jqt-row-hover-bg);font-weight:600}.slice-item.slice-multi{padding-left:6px}.slice-item span:first-child{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.slice-item span:last-child{flex:0 0 auto;min-width:1.2em;text-align:right}.slice-check-box{flex:0 0 16px;width:16px;height:16px;border:1.5px solid var(--jqt-text-muted);border-radius:4px;background:var(--jqt-surface-color);display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;transition:background .15s,border-color .15s}.slice-check-box.checked{background:var(--jqt-text-secondary);border-color:var(--jqt-text-secondary)}.slice-check-box.checked:after{content:\"\";display:block;width:9px;height:5px;border-left:2px solid #fff;border-bottom:2px solid #fff;transform:rotate(-45deg) translateY(-1px)}.slice-divider{border:none;border-top:1px solid var(--jqt-border-color);margin:6px 0}.lazy-skeleton{display:block;height:12px;width:70%;border-radius:4px;background:linear-gradient(90deg,var(--jqt-border-color) 25%,var(--jqt-surface-alt-color) 50%,var(--jqt-border-color) 75%);background-size:200% 100%;animation:lazy-shimmer 1.4s ease-in-out infinite}.slice-lazy-loading{display:flex;flex-direction:column;gap:8px;padding:8px 10px}.slice-lazy-loading .lazy-skeleton{width:80%}.slice-lazy-loading .lazy-skeleton:nth-child(2){width:60%}.slice-lazy-loading .lazy-skeleton:nth-child(3){width:45%}@keyframes lazy-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
969
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SlicePanelComponent, isStandalone: true, selector: "slice-panel", inputs: { sliceConfigs: "sliceConfigs", columns: "columns", data: "data", lazyStatus: "lazyStatus", showToggle: "showToggle", showCounts: "showCounts", collapsedByDefault: "collapsedByDefault", alwaysShow: "alwaysShow" }, outputs: { filterChange: "filterChange", activeKeysChange: "activeKeysChange", dynamicSliceKeysChange: "dynamicSliceKeysChange", collapsedChange: "collapsedChange" }, host: { properties: { "class.collapsed": "this.hostCollapsed" } }, viewQueries: [{ propertyName: "slicePanelBodyRef", first: true, predicate: ["slicePanelBody"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"slice-panel-wrapper\" [class.collapsed]=\"isCollapsed\">\n <aside class=\"slice-panel\" [class.collapsed]=\"isCollapsed\">\n <div class=\"slice-panel-header\">\n <span *ngIf=\"!isCollapsed\" class=\"slice-panel-title\">\n {{ i18n.filterPanelTitle(slices.length) }}\n </span>\n <button\n *ngIf=\"showToggle\"\n type=\"button\"\n class=\"slice-toggle\"\n [attr.aria-label]=\"isCollapsed ? i18n.expandFilterTitle : i18n.collapseFilterTitle\"\n (click)=\"togglePanel()\"\n >\n <mat-icon class=\"slice-toggle-mat-icon\">{{ isCollapsed ? 'filter_list' : 'filter_list_off' }}</mat-icon>\n </button>\n </div>\n\n <div class=\"slice-panel-body\" *ngIf=\"!isCollapsed\" #slicePanelBody>\n <ng-container *ngFor=\"let slice of slices; let si = index; trackBy: trackBySliceIndex\">\n <div class=\"slice-title-row\" [attr.data-slice-index]=\"si\">\n <button\n type=\"button\"\n class=\"slice-title-toggle\"\n [attr.aria-controls]=\"'slice-section-' + si\"\n [attr.aria-expanded]=\"!isSliceCollapsed(si)\"\n (click)=\"toggleSliceCollapse(si)\"\n >\n <span class=\"slice-title-chevron\" [class.expanded]=\"!isSliceCollapsed(si)\">\u203A</span>\n <mat-icon *ngIf=\"getSliceIcon(slice)\" class=\"slice-title-icon\">{{ getSliceIcon(slice) }}</mat-icon>\n <span class=\"slice-title\">{{ slice.title || i18n.filterBlockDefaultTitle }}</span>\n </button>\n <button\n *ngIf=\"isSliceDynamic(si)\"\n type=\"button\"\n class=\"slice-remove-btn\"\n [attr.aria-label]=\"'Supprimer le filtre ' + (slice.title || i18n.filterBlockDefaultTitle)\"\n (click)=\"removeDynamicSlice(si)\"\n >\u00D7</button>\n </div>\n\n <div [id]=\"'slice-section-' + si\" class=\"slice-section-items\" *ngIf=\"!isSliceCollapsed(si)\">\n <ng-container *ngIf=\"isSliceLoading(si); else sliceContent\">\n <div class=\"slice-lazy-loading\">\n <span class=\"lazy-skeleton\"></span>\n <span class=\"lazy-skeleton\"></span>\n <span class=\"lazy-skeleton\"></span>\n </div>\n </ng-container>\n <ng-template #sliceContent>\n <ng-container *ngFor=\"let category of slice.categories; trackBy: trackByCategoryKey\">\n <button\n *ngIf=\"sliceCategoryCount(si, category.key) > 0\"\n class=\"slice-item\"\n type=\"button\"\n [class.active]=\"isSliceCategoryActive(si, category.key)\"\n [attr.data-category-key]=\"category.key\"\n [title]=\"category.label\"\n (click)=\"onSliceCategorySelected(si, category.key)\"\n >\n <span>{{ category.label }}</span>\n <span *ngIf=\"showCounts\">{{ sliceCategoryCount(si, category.key) }}</span>\n </button>\n </ng-container>\n <div *ngIf=\"isSliceEmpty(si)\" class=\"slice-empty-state\">{{ i18n.filterEmptyState }}</div>\n </ng-template>\n </div>\n\n <hr *ngIf=\"si < slices.length - 1\" class=\"slice-divider\" />\n </ng-container>\n </div>\n </aside>\n</div>\n", styles: ["@keyframes slideInLeft{0%{opacity:0;transform:translate(-24px)}to{opacity:1;transform:translate(0)}}:host{display:block;height:100%;min-height:0;box-sizing:border-box;animation:slideInLeft .3s cubic-bezier(.34,1.56,.64,1) forwards}.slice-panel-wrapper{height:100%;max-height:100%;overflow-y:auto;box-sizing:border-box}.slice-panel{margin-top:0;border:1px solid var(--jqt-border-color);border-radius:10px;background:var(--jqt-surface-color);display:flex;flex-direction:column;min-width:0;height:100%;overflow:hidden;box-sizing:border-box}.slice-panel-header{flex-shrink:0;display:flex;justify-content:flex-end;align-items:center;height:var(--jqt-slice-header-height, 34px);padding:0 8px;margin-bottom:var(--jqt-slice-header-margin-bottom, 8px)}.slice-panel-header:has(.slice-panel-title){justify-content:space-between;padding-left:12px}.slice-panel-body{flex:1 1 0;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:4px;padding:var(--jqt-slice-body-padding, 4px 10px 10px);scrollbar-width:thin;scrollbar-color:var(--jqt-border-color) transparent}.slice-panel-body::-webkit-scrollbar{width:2px}.slice-panel-body::-webkit-scrollbar-thumb{background:var(--jqt-primary-color);border-radius:4px}.slice-panel-title{margin:0;padding-top:2px;font-size:11px;font-weight:700;line-height:1;text-transform:uppercase;letter-spacing:.08em;color:var(--jqt-text-color);-webkit-user-select:none;user-select:none;align-self:center;display:inline-flex;align-items:center;gap:5px}.slice-panel-title .slice-panel-title-icon{font-size:16px;width:16px;height:16px;line-height:1;flex-shrink:0}.slice-section-items{display:flex;flex-direction:column;gap:2px;flex:0 0 auto;scrollbar-width:thin;scrollbar-color:var(--jqt-border-color) transparent}.slice-section-items::-webkit-scrollbar{width:2px}.slice-section-items .slice-empty-state{padding:8px 10px;font-size:12px;color:var(--jqt-text-muted, #9ca3af);font-style:italic;text-align:center}.slice-section-items::-webkit-scrollbar-thumb{background:var(--jqt-border-color);border-radius:4px}.slice-toggle{border:0;background:var(--jqt-surface-color);color:var(--jqt-text-color);border-radius:6px;width:22px;height:22px;padding:0;font-size:14px;text-align:center;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;line-height:1}.slice-toggle-mat-icon{font-size:16px;width:16px;height:16px;line-height:1}.slice-panel.collapsed{border-color:transparent;background:transparent;overflow:visible}.slice-panel.collapsed .slice-panel-header{height:34px;padding:0;justify-content:center;align-items:center}.slice-panel.collapsed .slice-toggle{width:34px;height:34px;border:1px solid var(--jqt-border-color);background:var(--jqt-surface-color);border-radius:8px}.slice-panel.collapsed .slice-toggle:hover{border-color:var(--jqt-text-muted)}.slice-panel.collapsed .slice-toggle .slice-toggle-mat-icon{font-size:18px;width:18px;height:18px}.slice-title-row{display:flex;align-items:center;justify-content:space-between;gap:6px;margin:4px 0 6px;-webkit-user-select:none;user-select:none}.slice-title-row:first-of-type .slice-title{margin-top:0}.slice-title-toggle{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:6px;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;text-align:left}.slice-title-toggle:hover .slice-title{color:var(--jqt-text-color)}.slice-title-toggle:hover .slice-title-chevron{color:var(--jqt-text-secondary)}.slice-title-toggle:focus-visible{outline:2px solid var(--jqt-primary-color);outline-offset:2px;border-radius:4px}.slice-title-chevron{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;font-size:16px;line-height:1;color:var(--jqt-text-muted);transition:transform .15s ease;transform:rotate(0);position:relative;top:-1px}.slice-title-chevron.expanded{transform:rotate(90deg)}.slice-title{flex:1 1 auto;margin:0;font-size:var(--jqt-slice-section-title-font-size, 14px);font-weight:600;color:var(--jqt-title-color)}.slice-title-icon{flex-shrink:0;font-size:14px!important;width:14px!important;height:14px!important;color:var(--jqt-title-color)}.slice-remove-btn{background:none;border:none;cursor:pointer;color:var(--jqt-border-color);font-size:12px;padding:0 2px;line-height:1;flex-shrink:0;opacity:.5;transition:opacity .15s,color .15s}.slice-remove-btn:hover{color:var(--jqt-text-secondary);opacity:1}.slice-title-row:hover .slice-remove-btn{opacity:.8}.slice-item{display:flex;justify-content:space-between;align-items:center;text-align:left;width:100%;min-height:var(--jqt-slice-item-min-height, 30px);padding:var(--jqt-slice-item-padding, 5px 10px 5px 16px);background:transparent;border:0;cursor:pointer;border-radius:8px;color:var(--jqt-text-color);box-sizing:border-box;min-width:0;gap:8px;font-size:var(--jqt-slice-item-font-size, 13px)}.slice-item.active{background:var(--jqt-row-hover-bg);font-weight:600}.slice-item.slice-multi{padding-left:6px}.slice-item span:first-child{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.slice-item span:last-child{flex:0 0 auto;min-width:1.2em;text-align:right}.slice-check-box{flex:0 0 16px;width:16px;height:16px;border:1.5px solid var(--jqt-text-muted);border-radius:4px;background:var(--jqt-surface-color);display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;transition:background .15s,border-color .15s}.slice-check-box.checked{background:var(--jqt-text-secondary);border-color:var(--jqt-text-secondary)}.slice-check-box.checked:after{content:\"\";display:block;width:9px;height:5px;border-left:2px solid #fff;border-bottom:2px solid #fff;transform:rotate(-45deg) translateY(-1px)}.slice-divider{border:none;border-top:1px solid var(--jqt-border-color);margin:6px 0}.lazy-skeleton{display:block;height:12px;width:70%;border-radius:4px;background:linear-gradient(90deg,var(--jqt-border-color) 25%,var(--jqt-surface-alt-color) 50%,var(--jqt-border-color) 75%);background-size:200% 100%;animation:lazy-shimmer 1.4s ease-in-out infinite}.slice-lazy-loading{display:flex;flex-direction:column;gap:8px;padding:8px 10px}.slice-lazy-loading .lazy-skeleton{width:80%}.slice-lazy-loading .lazy-skeleton:nth-child(2){width:60%}.slice-lazy-loading .lazy-skeleton:nth-child(3){width:45%}@keyframes lazy-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
959
970
  }
960
971
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SlicePanelComponent, decorators: [{
961
972
  type: Component,
@@ -966,8 +977,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
966
977
  type: Input
967
978
  }], data: [{
968
979
  type: Input
969
- }], lazyData: [{
970
- type: Input
971
980
  }], lazyStatus: [{
972
981
  type: Input
973
982
  }], showToggle: [{
@@ -1064,14 +1073,8 @@ function getStackItems(indicator) {
1064
1073
 
1065
1074
  function chartConfigToOrganizer(chartConfig, options = {}) {
1066
1075
  if (!chartConfig) {
1067
- console.debug('[OrganizerChartAdapter] Empty chart config, returning empty organizer config');
1068
1076
  return {};
1069
1077
  }
1070
- console.debug('[OrganizerChartAdapter] Converting chart config to organizer', {
1071
- hasGroups: !!chartConfig.groups,
1072
- indicatorCount: chartConfig.indicators?.items?.length ?? 0,
1073
- filterCount: chartConfig.filters?.items?.length ?? 0
1074
- });
1075
1078
  const { onFetchSliceData, onExportVisual, onExportData, switchView } = options;
1076
1079
  const indicators = getIndicatorItems(chartConfig);
1077
1080
  const activeIndicator = indicators.find(i => i.selected);
@@ -1105,7 +1108,6 @@ function chartConfigToOrganizer(chartConfig, options = {}) {
1105
1108
  }
1106
1109
  function chartConfigToState(chartConfig) {
1107
1110
  if (!chartConfig) {
1108
- console.debug('[OrganizerChartAdapter] Empty chart config for state conversion');
1109
1111
  return {};
1110
1112
  }
1111
1113
  const indicators = getIndicatorItems(chartConfig);
@@ -1114,12 +1116,6 @@ function chartConfigToState(chartConfig) {
1114
1116
  const activeGroup = getGroupItems(chartConfig).find(g => g.selected);
1115
1117
  const activeSlices = getFilterItems(chartConfig).filter(f => f.selected);
1116
1118
  const indicatorGroup = activeIndicator?.group;
1117
- console.debug('[OrganizerChartAdapter] Current chart state', {
1118
- activeGroup: activeGroup?.key,
1119
- activeIndicator: activeIndicator?.key,
1120
- activeStack: activeStack?.key,
1121
- sliceCount: activeSlices.length
1122
- });
1123
1119
  const state = {
1124
1120
  selectedX: activeGroup?.key,
1125
1121
  selectedY: indicatorGroup ?? activeIndicator?.key,
@@ -1149,10 +1145,8 @@ function chartConfigToUnifiedState(chartConfig, viewMode = 'chart') {
1149
1145
  }
1150
1146
  function applyOrganizerEventToChart(event, chartConfig) {
1151
1147
  if (!chartConfig) {
1152
- console.debug('[OrganizerChartAdapter] Cannot apply event to empty chart config');
1153
1148
  return;
1154
1149
  }
1155
- console.debug('[OrganizerChartAdapter] Applying organizer event', { eventType: event.type, state: event.state });
1156
1150
  const state = event.state;
1157
1151
  _cleanSynthetics(chartConfig);
1158
1152
  if (state.selectedX !== undefined)
@@ -1166,7 +1160,6 @@ function applyOrganizerEventToChart(event, chartConfig) {
1166
1160
  event.resolvedYUnit = resolveYUnit(chartConfig, event.state.selectedY, event.state.selectedYAggregate);
1167
1161
  }
1168
1162
  function handleOrganizerChartEvent(event, chartConfig, currentBinding, options = {}) {
1169
- console.debug('[OrganizerChartAdapter] Handling organizer event', { eventType: event.type });
1170
1163
  if (event.type === 'viewSwitched') {
1171
1164
  return {
1172
1165
  binding: {
@@ -1461,19 +1454,10 @@ class OrganizerFacade {
1461
1454
  }
1462
1455
  onDynamicSliceKeysChange(keys) {
1463
1456
  const allFields = this._panelConfig.fields ?? [];
1464
- const staticKeys = new Set((this._panelConfig.sliceConfigs ?? []).map(s => s.columnKey).filter((k) => !!k));
1465
- const dynamicKeySet = new Set(keys);
1466
- const existingKeys = new Set([...staticKeys, ...dynamicKeySet]);
1467
1457
  this.sliceBy.activeDynamicFields = keys
1468
1458
  .map(k => allFields.find(c => c.key === k))
1469
1459
  .filter((c) => !!c);
1470
- const seen = new Set();
1471
- this.sliceBy.availableForDynamic = allFields.filter(c => {
1472
- if (c.sliceable === false || existingKeys.has(c.key) || seen.has(c.key))
1473
- return false;
1474
- seen.add(c.key);
1475
- return true;
1476
- });
1460
+ this.sliceBy.availableForDynamic = this._availableForDynamic(new Set(keys));
1477
1461
  this._computeSliceLabel();
1478
1462
  this._events$.next({ type: 'dynamicSlicesChanged', keys });
1479
1463
  }
@@ -1498,23 +1482,42 @@ class OrganizerFacade {
1498
1482
  this.fields.activeFields = [...defaultFields];
1499
1483
  }
1500
1484
  else {
1501
- const allowedKeys = new Set((this._panelConfig.fields || []).map(c => c.key));
1502
- this.fields.activeFields = this.fields.activeFields.filter(c => allowedKeys.has(c.key));
1485
+ const current = this._definitionsByKey();
1486
+ this.fields.activeFields = this.fields.activeFields
1487
+ .filter(c => current.has(c.key))
1488
+ .map(c => current.get(c.key));
1503
1489
  }
1504
1490
  }
1505
- _refreshDynamicSliceMeta() {
1506
- const allFields = this._panelConfig.fields ?? [];
1507
- const staticKeys = new Set((this._panelConfig.sliceConfigs ?? []).map(s => s.columnKey).filter((k) => !!k));
1508
- const activeDynKeys = new Set(this.sliceBy.activeDynamicFields.map(c => c.key));
1509
- const seen1 = new Set();
1510
- this.sliceBy.availableForDynamic = allFields.filter(c => {
1511
- if (c.sliceable === false || staticKeys.has(c.key) || activeDynKeys.has(c.key) || seen1.has(c.key))
1491
+ /** Première définition de chaque clé dans la config courante. */
1492
+ _definitionsByKey() {
1493
+ const byKey = new Map();
1494
+ (this._panelConfig.fields || []).forEach(c => { if (!byKey.has(c.key))
1495
+ byKey.set(c.key, c); });
1496
+ return byKey;
1497
+ }
1498
+ _staticSliceKeys() {
1499
+ return new Set((this._panelConfig.sliceConfigs ?? []).map(s => s.columnKey).filter((k) => !!k));
1500
+ }
1501
+ /** Champs proposables en slice dynamique, hors slices statiques et slices déjà actifs. */
1502
+ _availableForDynamic(activeKeys) {
1503
+ const staticKeys = this._staticSliceKeys();
1504
+ const seen = new Set();
1505
+ return (this._panelConfig.fields ?? []).filter(c => {
1506
+ if (c.sliceable === false || staticKeys.has(c.key) || activeKeys.has(c.key) || seen.has(c.key))
1512
1507
  return false;
1513
1508
  if (!c.header && c.sliceable !== true)
1514
1509
  return false;
1515
- seen1.add(c.key);
1510
+ seen.add(c.key);
1516
1511
  return true;
1517
1512
  });
1513
+ }
1514
+ _refreshDynamicSliceMeta() {
1515
+ const allFields = this._panelConfig.fields ?? [];
1516
+ const staticKeys = this._staticSliceKeys();
1517
+ const current = this._definitionsByKey();
1518
+ this.sliceBy.activeDynamicFields = this.sliceBy.activeDynamicFields.map(c => current.get(c.key) ?? c);
1519
+ const activeDynKeys = new Set(this.sliceBy.activeDynamicFields.map(c => c.key));
1520
+ this.sliceBy.availableForDynamic = this._availableForDynamic(activeDynKeys);
1518
1521
  const seen2 = new Set();
1519
1522
  this.sliceBy.allDynamicFields = allFields.filter(c => {
1520
1523
  if (c.sliceable === false || staticKeys.has(c.key) || seen2.has(c.key))
@@ -1604,6 +1607,8 @@ class GroupByManager {
1604
1607
  }
1605
1608
  }
1606
1609
  groupPageForward(groupKey, totalCount) {
1610
+ if (this.groupPageSize <= 0)
1611
+ return;
1607
1612
  const maxPage = Math.ceil(totalCount / this.groupPageSize) - 1;
1608
1613
  const current = this._groupPages.get(groupKey) ?? 0;
1609
1614
  if (current < maxPage) {
@@ -1628,99 +1633,9 @@ class GroupByManager {
1628
1633
  }
1629
1634
  }
1630
1635
 
1631
- const LAZY_FIELD_LOADING_VALUE = '__lazy_loading__';
1632
- const LAZY_FIELD_ERROR_VALUE = '__lazy_error__';
1633
- class LazyFieldManager {
1634
- constructor() {
1635
- this._status = new Map();
1636
- this._data = new Map();
1637
- this._cancels = new Map();
1638
- }
1639
- get status() {
1640
- return this._status;
1641
- }
1642
- get data() {
1643
- return this._data;
1644
- }
1645
- getStatus(key) {
1646
- return this._status.get(key) ?? 'idle';
1647
- }
1648
- getRenderType(rowValue) {
1649
- if (rowValue === LAZY_FIELD_LOADING_VALUE)
1650
- return 'loading';
1651
- if (rowValue === LAZY_FIELD_ERROR_VALUE)
1652
- return 'error';
1653
- return 'value';
1654
- }
1655
- cancelAll() {
1656
- this._cancels.forEach(s => { s.next(); s.complete(); });
1657
- this._cancels.clear();
1658
- this._status = new Map();
1659
- this._data = new Map();
1660
- }
1661
- retry(field, resolvedData, callbacks) {
1662
- const k = field.key;
1663
- const prev = this._cancels.get(k);
1664
- if (prev) {
1665
- prev.next();
1666
- prev.complete();
1667
- }
1668
- this._cancels.delete(k);
1669
- const newStatus = new Map(this._status);
1670
- newStatus.delete(k);
1671
- this._status = newStatus;
1672
- const newData = new Map(this._data);
1673
- newData.delete(k);
1674
- this._data = newData;
1675
- this.fetch(field, resolvedData, callbacks);
1676
- }
1677
- fetch(field, resolvedData, callbacks) {
1678
- if (!field.lazy)
1679
- return;
1680
- const k = field.key;
1681
- if (this._status.get(k) === 'loading')
1682
- return;
1683
- const prev = this._cancels.get(k);
1684
- if (prev) {
1685
- prev.next();
1686
- prev.complete();
1687
- }
1688
- const cancel$ = new Subject();
1689
- this._cancels.set(k, cancel$);
1690
- const newStatus = new Map(this._status);
1691
- newStatus.set(k, 'loading');
1692
- this._status = newStatus;
1693
- callbacks.onRefresh();
1694
- field.lazy.fetchFn().pipe(take(1), takeUntil$1(cancel$)).subscribe({
1695
- next: (values) => {
1696
- const rowMap = new Map();
1697
- values.forEach((value, i) => {
1698
- if (i < resolvedData.length)
1699
- rowMap.set(resolvedData[i], value);
1700
- });
1701
- const newData = new Map(this._data);
1702
- newData.set(k, rowMap);
1703
- this._data = newData;
1704
- const newStatus2 = new Map(this._status);
1705
- newStatus2.set(k, 'loaded');
1706
- this._status = newStatus2;
1707
- callbacks.onRefresh();
1708
- callbacks.onMarkForCheck();
1709
- },
1710
- error: () => {
1711
- const newStatusErr = new Map(this._status);
1712
- newStatusErr.set(k, 'error');
1713
- this._status = newStatusErr;
1714
- callbacks.onRefresh();
1715
- callbacks.onMarkForCheck();
1716
- },
1717
- });
1718
- }
1719
- }
1720
-
1721
1636
  /**
1722
1637
  * Generated bundle index. Do not edit.
1723
1638
  */
1724
1639
 
1725
- export { DEFAULT_MENU_ICONS, DEFAULT_MENU_LABELS, GroupByManager, LAZY_FIELD_ERROR_VALUE, LAZY_FIELD_LOADING_VALUE, LazyFieldManager, OrganizerButtonComponent, OrganizerButtonEventType, OrganizerButtonModule, OrganizerFacade, SlicePanelComponent, applyOrganizerEventToChart, buildOrganizerChartBinding, buildYFields, chartConfigToOrganizer, chartConfigToState, chartConfigToUnifiedState, handleOrganizerChartEvent, humanizeKey, resolveYKey, resolveYUnit };
1640
+ export { DEFAULT_MENU_ICONS, DEFAULT_MENU_LABELS, GroupByManager, OrganizerButtonComponent, OrganizerButtonEventType, OrganizerButtonModule, OrganizerFacade, SlicePanelComponent, applyOrganizerEventToChart, buildOrganizerChartBinding, buildYFields, chartConfigToOrganizer, chartConfigToState, chartConfigToUnifiedState, handleOrganizerChartEvent, humanizeKey, resolveYKey, resolveYUnit };
1726
1641
  //# sourceMappingURL=oneteme-jquery-organizer.mjs.map