@fuentis/phoenix-ui 0.0.9-alpha.566 → 0.0.9-alpha.570
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/fesm2022/fuentis-phoenix-ui.mjs +142 -20
- package/fesm2022/fuentis-phoenix-ui.mjs.map +1 -1
- package/index.d.ts +114 -9
- package/package.json +1 -1
|
@@ -3243,8 +3243,9 @@ function buildFileName(baseKey, ext = 'xlsx') {
|
|
|
3243
3243
|
*/
|
|
3244
3244
|
const DEFAULT_MORE_ACTIONS = {
|
|
3245
3245
|
context: tableButtonContext.MORE,
|
|
3246
|
-
type:
|
|
3246
|
+
type: tableActionType.MENU,
|
|
3247
3247
|
buttonType: 'multiselect',
|
|
3248
|
+
label: '',
|
|
3248
3249
|
items: [
|
|
3249
3250
|
{ key: 'EXPORT_PDF', label: 'ACTION.EXPORT_PDF', icon: 'pi pi-file-pdf' },
|
|
3250
3251
|
{ key: 'EXPORT_EXCEL', label: 'ACTION.EXPORT_EXCEL', icon: 'pi pi-file-excel' },
|
|
@@ -3336,13 +3337,116 @@ class TableComponent {
|
|
|
3336
3337
|
skeletonRowCount = 8;
|
|
3337
3338
|
/** Array used by Angular @for (must be iterable) */
|
|
3338
3339
|
skeletonRows = Array.from({ length: this.skeletonRowCount });
|
|
3340
|
+
createSortWorkerInline() {
|
|
3341
|
+
const code = `
|
|
3342
|
+
const compareStringsNatural = (a,b) => a.localeCompare(b, undefined, { numeric:true, sensitivity:'base' });
|
|
3343
|
+
|
|
3344
|
+
const getNestedValue = (obj, path) => {
|
|
3345
|
+
try {
|
|
3346
|
+
if (!obj || !path) return undefined;
|
|
3347
|
+
if (Object.prototype.hasOwnProperty.call(obj, path)) {
|
|
3348
|
+
const v = obj[path];
|
|
3349
|
+
return (v && v.key !== undefined) ? v.key : v;
|
|
3350
|
+
}
|
|
3351
|
+
return path.split('.').reduce((acc, k) => (acc == null ? undefined : acc[k]), obj);
|
|
3352
|
+
} catch { return undefined; }
|
|
3353
|
+
};
|
|
3354
|
+
|
|
3355
|
+
const getComparableValue = (val, field, columnTypeMap, dateTypeKey='DATE') => {
|
|
3356
|
+
if (val === null || val === undefined) return '';
|
|
3357
|
+
const columnType = columnTypeMap?.[field];
|
|
3358
|
+
|
|
3359
|
+
if ((columnType || '').toString().toUpperCase() === 'BOOLEAN') {
|
|
3360
|
+
if (typeof val === 'boolean') return val ? 1 : 0;
|
|
3361
|
+
if (typeof val === 'number') return val ? 1 : 0;
|
|
3362
|
+
if (typeof val === 'string') {
|
|
3363
|
+
const s = val.trim().toLowerCase();
|
|
3364
|
+
if (['true','1','yes'].includes(s)) return 1;
|
|
3365
|
+
if (['false','0','no'].includes(s)) return 0;
|
|
3366
|
+
return '';
|
|
3367
|
+
}
|
|
3368
|
+
if (typeof val === 'object') {
|
|
3369
|
+
const v = val.value ?? val.key ?? val.enabled ?? val.checked;
|
|
3370
|
+
return getComparableValue(v, field, columnTypeMap, dateTypeKey);
|
|
3371
|
+
}
|
|
3372
|
+
return '';
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3375
|
+
if (typeof val === 'number') return val;
|
|
3376
|
+
|
|
3377
|
+
if (typeof val === 'string') {
|
|
3378
|
+
if (columnType === dateTypeKey) {
|
|
3379
|
+
const t = Date.parse(val);
|
|
3380
|
+
return Number.isNaN(t) ? val.toLowerCase() : t;
|
|
3381
|
+
}
|
|
3382
|
+
return val.toLowerCase();
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3385
|
+
if (val instanceof Date) return val.getTime();
|
|
3386
|
+
|
|
3387
|
+
if (typeof val === 'object') {
|
|
3388
|
+
if (val.from && val.to) {
|
|
3389
|
+
const from = Date.parse(val.from);
|
|
3390
|
+
const to = Date.parse(val.to);
|
|
3391
|
+
return (Number.isNaN(from) || Number.isNaN(to)) ? '' : (from + to);
|
|
3392
|
+
}
|
|
3393
|
+
if (Array.isArray(val) && val.length) return getComparableValue(val[0], field, columnTypeMap, dateTypeKey);
|
|
3394
|
+
|
|
3395
|
+
for (const k of ['name','value','label','key','date']) {
|
|
3396
|
+
if (val[k] !== undefined && val[k] !== null) return getComparableValue(val[k], field, columnTypeMap, dateTypeKey);
|
|
3397
|
+
}
|
|
3398
|
+
for (const v of Object.values(val)) {
|
|
3399
|
+
if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {
|
|
3400
|
+
return getComparableValue(v, field, columnTypeMap, dateTypeKey);
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3404
|
+
return '';
|
|
3405
|
+
};
|
|
3406
|
+
|
|
3407
|
+
const sortData = (data, meta, columnTypeMap, dateTypeKey='DATE') => {
|
|
3408
|
+
const sorted = (data || []).slice();
|
|
3409
|
+
if (!meta?.length) return sorted;
|
|
3410
|
+
|
|
3411
|
+
sorted.sort((a,b) => {
|
|
3412
|
+
for (const s of meta) {
|
|
3413
|
+
const field = s.field;
|
|
3414
|
+
const order = s.order ?? 1;
|
|
3415
|
+
|
|
3416
|
+
const A = getComparableValue(getNestedValue(a, field), field, columnTypeMap, dateTypeKey);
|
|
3417
|
+
const B = getComparableValue(getNestedValue(b, field), field, columnTypeMap, dateTypeKey);
|
|
3418
|
+
|
|
3419
|
+
if (typeof A === 'string' && typeof B === 'string') {
|
|
3420
|
+
const c = compareStringsNatural(A,B);
|
|
3421
|
+
if (c !== 0) return c * order;
|
|
3422
|
+
} else {
|
|
3423
|
+
if (A < B) return -1 * order;
|
|
3424
|
+
if (A > B) return 1 * order;
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
3427
|
+
return 0;
|
|
3428
|
+
});
|
|
3429
|
+
|
|
3430
|
+
return sorted;
|
|
3431
|
+
};
|
|
3432
|
+
|
|
3433
|
+
self.addEventListener('message', (ev) => {
|
|
3434
|
+
const data = ev.data || {};
|
|
3435
|
+
const sorted = sortData(data.data, data.multiSortMeta, data.columnTypeMap, data.dateTypeKey || 'DATE');
|
|
3436
|
+
self.postMessage({ reqId: data.reqId, sorted });
|
|
3437
|
+
});
|
|
3438
|
+
`;
|
|
3439
|
+
const blob = new Blob([code], { type: 'text/javascript' });
|
|
3440
|
+
const url = URL.createObjectURL(blob);
|
|
3441
|
+
return new Worker(url); // classic worker, nema module MIME problema
|
|
3442
|
+
}
|
|
3339
3443
|
constructor() {
|
|
3340
3444
|
/**
|
|
3341
3445
|
* Create sorting worker if supported.
|
|
3342
3446
|
* Fallback is synchronous sort (still works, but can freeze on huge arrays).
|
|
3343
3447
|
*/
|
|
3344
3448
|
if (typeof Worker !== 'undefined') {
|
|
3345
|
-
this.sortWorker =
|
|
3449
|
+
this.sortWorker = this.createSortWorkerInline();
|
|
3346
3450
|
this.sortWorker.onmessage = (e) => {
|
|
3347
3451
|
const { reqId, sorted } = e.data ?? {};
|
|
3348
3452
|
if (reqId !== this.latestWorkerReqId)
|
|
@@ -3495,6 +3599,22 @@ class TableComponent {
|
|
|
3495
3599
|
});
|
|
3496
3600
|
return sorted;
|
|
3497
3601
|
}
|
|
3602
|
+
normalizeInitialSort(cfg) {
|
|
3603
|
+
const s = cfg?.initialSort;
|
|
3604
|
+
// NEW style
|
|
3605
|
+
if (Array.isArray(s))
|
|
3606
|
+
return s.filter(x => !!x?.field);
|
|
3607
|
+
if (s && typeof s === 'object' && s.field)
|
|
3608
|
+
return [s];
|
|
3609
|
+
// LEGACY fallback
|
|
3610
|
+
if (cfg?.initialSortField) {
|
|
3611
|
+
return [{
|
|
3612
|
+
field: cfg.initialSortField,
|
|
3613
|
+
order: (cfg.initialSortOrder ?? 1),
|
|
3614
|
+
}];
|
|
3615
|
+
}
|
|
3616
|
+
return [];
|
|
3617
|
+
}
|
|
3498
3618
|
/**
|
|
3499
3619
|
* Applies initial sort once:
|
|
3500
3620
|
* - Uses tableConfiguration.initialSortField if provided
|
|
@@ -3509,7 +3629,6 @@ class TableComponent {
|
|
|
3509
3629
|
applyInitialSortIfNeeded() {
|
|
3510
3630
|
if (this.initialSortApplied)
|
|
3511
3631
|
return;
|
|
3512
|
-
// if no data, just render empty fast and stop loading
|
|
3513
3632
|
if (!this.allData?.length) {
|
|
3514
3633
|
this.tableData = [];
|
|
3515
3634
|
this.totalRecords = 0;
|
|
@@ -3519,33 +3638,32 @@ class TableComponent {
|
|
|
3519
3638
|
}
|
|
3520
3639
|
const cols = (this.selectedColumns?.length ? this.selectedColumns : this.columns) ?? [];
|
|
3521
3640
|
if (!cols.length)
|
|
3522
|
-
return;
|
|
3523
|
-
//
|
|
3524
|
-
const
|
|
3641
|
+
return;
|
|
3642
|
+
// 1) normalize config
|
|
3643
|
+
const cfgMeta = this.normalizeInitialSort(this.tableConfiguration);
|
|
3644
|
+
// 2) if nothing configured -> fallback first column ASC
|
|
3525
3645
|
const fallbackField = cols[0]?.field;
|
|
3526
|
-
const
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3646
|
+
const wantedMeta = (cfgMeta.length ? cfgMeta : [{ field: fallbackField, order: 1 }])
|
|
3647
|
+
.filter(m => !!m?.field);
|
|
3648
|
+
// 3) keep only fields that exist in columns
|
|
3649
|
+
const validMeta = wantedMeta.filter(m => cols.some((c) => c?.field === m.field));
|
|
3650
|
+
const finalMeta = validMeta.length ? validMeta : [{ field: fallbackField, order: 1 }];
|
|
3651
|
+
if (!finalMeta[0]?.field) {
|
|
3531
3652
|
this.tableData = this.allData;
|
|
3532
3653
|
this.totalRecords = this.tableData.length;
|
|
3533
3654
|
this.initialSortLoading = false;
|
|
3534
3655
|
this.initialSortApplied = true;
|
|
3535
|
-
this.cdr.markForCheck();
|
|
3536
3656
|
return;
|
|
3537
3657
|
}
|
|
3538
|
-
const meta = [{ field: finalField, order: 1 }];
|
|
3539
3658
|
try {
|
|
3540
3659
|
if (this.dt)
|
|
3541
|
-
this.dt.multiSortMeta =
|
|
3660
|
+
this.dt.multiSortMeta = finalMeta;
|
|
3542
3661
|
}
|
|
3543
3662
|
catch { }
|
|
3544
|
-
this.lastSortKey = JSON.stringify(
|
|
3663
|
+
this.lastSortKey = JSON.stringify(finalMeta);
|
|
3545
3664
|
this.initialSortApplied = true;
|
|
3546
|
-
this.initialSortFieldApplied =
|
|
3547
|
-
|
|
3548
|
-
this.runWorkerSort(meta);
|
|
3665
|
+
this.initialSortFieldApplied = finalMeta[0].field;
|
|
3666
|
+
this.runWorkerSort(finalMeta);
|
|
3549
3667
|
}
|
|
3550
3668
|
// ============================================================
|
|
3551
3669
|
// SEARCH / FILTER
|
|
@@ -3756,8 +3874,9 @@ class TableComponent {
|
|
|
3756
3874
|
* Some tables allow click on first N columns to open details.
|
|
3757
3875
|
*/
|
|
3758
3876
|
isColumnClickable(columnIndex) {
|
|
3759
|
-
|
|
3760
|
-
|
|
3877
|
+
const max = this.tableConfiguration?.clickableColumnCount ?? 1;
|
|
3878
|
+
const enabled = this.tableConfiguration?.hasCellClick ?? false;
|
|
3879
|
+
return columnIndex < max && enabled;
|
|
3761
3880
|
}
|
|
3762
3881
|
/**
|
|
3763
3882
|
* Utility for copy icons inside cells (prevents row-click).
|
|
@@ -4272,6 +4391,9 @@ class ObjectItemDialogComponent {
|
|
|
4272
4391
|
key: 'asd',
|
|
4273
4392
|
rows: 20,
|
|
4274
4393
|
selectionType: tableSelectionType.RADIO_BTN,
|
|
4394
|
+
actions: [],
|
|
4395
|
+
exportTable: false,
|
|
4396
|
+
filterConfiguration: []
|
|
4275
4397
|
};
|
|
4276
4398
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ObjectItemDialogComponent, deps: [{ token: i1$2.DynamicDialogRef }, { token: i1$2.DynamicDialogConfig }], target: i0.ɵɵFactoryTarget.Component });
|
|
4277
4399
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: ObjectItemDialogComponent, isStandalone: true, selector: "phoenix-object-item-dialog", viewQueries: [{ propertyName: "table", first: true, predicate: ["table"], descendants: true }], ngImport: i0, template: "<div style=\"overflow: hidden; padding-bottom: 50px\">\n <phoenix-table\n #table\n [data]=\"tableData\"\n [columns]=\"columns\"\n [tableConfiguration]=\"tableConfiguration\"\n (checkBoxSelection)=\"onSelectionChanged($event)\"\n >\n </phoenix-table>\n</div>\n<div class=\"absolute bottom-0 right-0 p-4\">\n <div class=\"flex gap-2\">\n <ng-container *ngFor=\"let action of actions\">\n <p-button\n [label]=\"action.label | translate\"\n [icon]=\"action.icon || ''\"\n [severity]=\"action.severity || 'primary'\"\n [disabled]=\"action.id === 'assign' && !hasSelection\"\n [id]=\"action.id\"\n (onClick)=\"actionClick(action.id)\"\n size=\"small\"\n ></p-button>\n </ng-container>\n</div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: TableModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: TableComponent, selector: "phoenix-table", inputs: ["columns", "selectedColumnsInput", "tableConfiguration", "filters", "data"], outputs: ["actionClick", "rowSelection", "checkBoxSelection", "saveColumns"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: i3$2.TranslatePipe, name: "translate" }] });
|