@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.
- package/esm2022/lib/group-by-manager/group-by-manager.mjs +3 -1
- package/esm2022/lib/models/organizer-chart-adapter.mjs +1 -17
- package/esm2022/lib/organizer-button/organizer-button.component.mjs +18 -25
- package/esm2022/lib/organizer-facade/organizer-facade.mjs +31 -21
- package/esm2022/lib/organizer-facade/organizer-facade.types.mjs +1 -1
- package/esm2022/lib/slice-panel/slice-panel.component.mjs +67 -51
- package/esm2022/lib/slice-panel/slice-panel.model.mjs +1 -1
- package/esm2022/public-api.mjs +1 -2
- package/fesm2022/oneteme-jquery-organizer.mjs +117 -202
- package/fesm2022/oneteme-jquery-organizer.mjs.map +1 -1
- package/lib/organizer-button/organizer-button.component.d.ts +4 -3
- package/lib/organizer-facade/organizer-facade.d.ts +8 -3
- package/lib/organizer-facade/organizer-facade.types.d.ts +2 -2
- package/lib/slice-panel/slice-panel.component.d.ts +7 -2
- package/lib/slice-panel/slice-panel.model.d.ts +4 -4
- package/package.json +2 -2
- package/public-api.d.ts +0 -1
- package/esm2022/lib/lazy-field-manager/lazy-field-manager.mjs +0 -91
- package/lib/lazy-field-manager/lazy-field-manager.d.ts +0 -25
|
@@ -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
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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['
|
|
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['
|
|
584
|
-
|
|
585
|
-
if (
|
|
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
|
|
773
|
+
const distinct = this._computeDistinctValues(column.key);
|
|
775
774
|
const newSlice = {
|
|
776
775
|
title: column.header,
|
|
777
776
|
columnKey: column.key,
|
|
778
|
-
categories:
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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:
|
|
864
|
-
key: v, label: v,
|
|
865
|
-
filter: (row) =>
|
|
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:
|
|
865
|
+
categories: this._buildCategories(slice.columnKey, this._computeDistinctValues(slice.columnKey)),
|
|
873
866
|
};
|
|
874
867
|
}
|
|
875
|
-
|
|
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
|
|
890
|
+
const counts = new Map();
|
|
891
|
+
let empty = 0;
|
|
892
|
+
(this.data || []).forEach((row) => {
|
|
893
893
|
const val = this._getLazyAwareValue(columnKey, row);
|
|
894
|
-
|
|
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
|
|
897
|
-
if (
|
|
898
|
-
|
|
899
|
-
|
|
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 =
|
|
903
|
-
if (colDef?.lazy) {
|
|
904
|
-
return
|
|
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
|
-
|
|
939
|
-
|
|
940
|
-
|
|
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
|
-
|
|
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
|
|
1502
|
-
this.fields.activeFields = this.fields.activeFields
|
|
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
|
-
|
|
1506
|
-
|
|
1507
|
-
const
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
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
|
-
|
|
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,
|
|
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
|