@c80/ui 1.0.64 → 1.1.2
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/README.md +1 -1
- package/esm2022/index.js +3 -0
- package/esm2022/index.js.map +1 -1
- package/esm2022/lib/header/header.component.js +4 -3
- package/esm2022/lib/header/header.component.js.map +1 -1
- package/esm2022/lib/icon/icon.definitions.js +3 -0
- package/esm2022/lib/icon/icon.definitions.js.map +1 -1
- package/esm2022/lib/icon/theme.service.js +19 -4
- package/esm2022/lib/icon/theme.service.js.map +1 -1
- package/esm2022/lib/info-message/index.js +3 -0
- package/esm2022/lib/info-message/index.js.map +1 -0
- package/esm2022/lib/info-message/info-message.component.js +25 -0
- package/esm2022/lib/info-message/info-message.component.js.map +1 -0
- package/esm2022/lib/info-message/info-message.types.js +2 -0
- package/esm2022/lib/info-message/info-message.types.js.map +1 -0
- package/esm2022/lib/legal-disclaimer/index.js +2 -0
- package/esm2022/lib/legal-disclaimer/index.js.map +1 -0
- package/esm2022/lib/legal-disclaimer/legal-disclaimer.component.js +21 -0
- package/esm2022/lib/legal-disclaimer/legal-disclaimer.component.js.map +1 -0
- package/esm2022/lib/modal/modal.component.js +9 -2
- package/esm2022/lib/modal/modal.component.js.map +1 -1
- package/esm2022/lib/modal/modal.service.js +17 -5
- package/esm2022/lib/modal/modal.service.js.map +1 -1
- package/esm2022/lib/modal/modal.types.js.map +1 -1
- package/esm2022/lib/navigation-card/index.js +3 -0
- package/esm2022/lib/navigation-card/index.js.map +1 -0
- package/esm2022/lib/navigation-card/navigation-card.component.js +18 -0
- package/esm2022/lib/navigation-card/navigation-card.component.js.map +1 -0
- package/esm2022/lib/navigation-card/navigation-card.types.js +2 -0
- package/esm2022/lib/navigation-card/navigation-card.types.js.map +1 -0
- package/esm2022/lib/table/table-dto-mapper.service.js +29 -32
- package/esm2022/lib/table/table-dto-mapper.service.js.map +1 -1
- package/esm2022/lib/table/table-selection.service.js +16 -16
- package/esm2022/lib/table/table-selection.service.js.map +1 -1
- package/esm2022/lib/table/table.component.js +22 -6
- package/esm2022/lib/table/table.component.js.map +1 -1
- package/esm2022/lib/table/table.utils.js +4 -3
- package/esm2022/lib/table/table.utils.js.map +1 -1
- package/index.d.ts +3 -0
- package/lib/header/header.component.d.ts +2 -1
- package/lib/icon/theme.service.d.ts +34 -0
- package/lib/info-message/index.d.ts +2 -0
- package/lib/info-message/info-message.component.d.ts +17 -0
- package/lib/info-message/info-message.types.d.ts +5 -0
- package/lib/legal-disclaimer/index.d.ts +1 -0
- package/lib/legal-disclaimer/legal-disclaimer.component.d.ts +15 -0
- package/lib/modal/modal.component.d.ts +5 -0
- package/lib/modal/modal.service.d.ts +11 -2
- package/lib/modal/modal.types.d.ts +1 -0
- package/lib/navigation-card/index.d.ts +2 -0
- package/lib/navigation-card/navigation-card.component.d.ts +10 -0
- package/lib/navigation-card/navigation-card.types.d.ts +7 -0
- package/lib/table/table-dto-mapper.service.d.ts +12 -5
- package/lib/table/table-selection.service.d.ts +1 -1
- package/lib/table/table.component.d.ts +2 -1
- package/lib/table/table.utils.d.ts +2 -1
- package/package.json +1 -1
|
@@ -33,16 +33,18 @@ export class ModalService {
|
|
|
33
33
|
* @param options.message
|
|
34
34
|
* @param options.confirmText
|
|
35
35
|
* @param options.cancelText
|
|
36
|
+
* @param options.allowHtml
|
|
36
37
|
* @returns Promise que resuelve true si se confirmó
|
|
37
38
|
*/
|
|
38
39
|
async confirm(options) {
|
|
39
|
-
const { title, message, confirmText = 'Confirmar', cancelText = 'Cancelar' } = options;
|
|
40
|
+
const { title, message, confirmText = 'Confirmar', cancelText = 'Cancelar', allowHtml } = options;
|
|
40
41
|
return this.showModal({
|
|
41
42
|
title,
|
|
42
43
|
message,
|
|
43
44
|
type: 'confirm',
|
|
44
45
|
confirmText,
|
|
45
46
|
cancelText,
|
|
47
|
+
allowHtml,
|
|
46
48
|
}).then((result) => result.confirmed);
|
|
47
49
|
}
|
|
48
50
|
/**
|
|
@@ -52,29 +54,35 @@ export class ModalService {
|
|
|
52
54
|
* @param options.message
|
|
53
55
|
* @param options.yesText
|
|
54
56
|
* @param options.noText
|
|
57
|
+
* @param options.allowHtml
|
|
55
58
|
* @returns Promise que resuelve true si se eligió Sí
|
|
56
59
|
*/
|
|
57
60
|
async yesNo(options) {
|
|
58
|
-
const { title, message, yesText = 'Sí', noText = 'No' } = options;
|
|
61
|
+
const { title, message, yesText = 'Sí', noText = 'No', allowHtml } = options;
|
|
59
62
|
return this.showModal({
|
|
60
63
|
title,
|
|
61
64
|
message,
|
|
62
65
|
type: 'yesNo',
|
|
63
66
|
yesText,
|
|
64
67
|
noText,
|
|
68
|
+
allowHtml,
|
|
65
69
|
}).then((result) => result.action === 'yes');
|
|
66
70
|
}
|
|
67
71
|
/**
|
|
68
72
|
*
|
|
69
73
|
* @param title
|
|
70
74
|
* @param message
|
|
75
|
+
* @param allowHtml
|
|
76
|
+
* @param confirmText
|
|
71
77
|
* @returns Promise que resuelve cuando se cierra el modal
|
|
72
78
|
*/
|
|
73
|
-
async info(title, message) {
|
|
79
|
+
async info(title, message, allowHtml, confirmText) {
|
|
74
80
|
return this.showModal({
|
|
75
81
|
title,
|
|
76
82
|
message,
|
|
77
83
|
type: 'info',
|
|
84
|
+
allowHtml,
|
|
85
|
+
confirmText,
|
|
78
86
|
}).then(() => void 0);
|
|
79
87
|
}
|
|
80
88
|
/**
|
|
@@ -84,16 +92,18 @@ export class ModalService {
|
|
|
84
92
|
* @param options.message
|
|
85
93
|
* @param options.confirmText
|
|
86
94
|
* @param options.cancelText
|
|
95
|
+
* @param options.allowHtml
|
|
87
96
|
* @returns Promise que resuelve true si se confirmó
|
|
88
97
|
*/
|
|
89
98
|
async warning(options) {
|
|
90
|
-
const { title, message, confirmText = 'Entendido', cancelText = 'Cancelar' } = options;
|
|
99
|
+
const { title, message, confirmText = 'Entendido', cancelText = 'Cancelar', allowHtml } = options;
|
|
91
100
|
return this.showModal({
|
|
92
101
|
title,
|
|
93
102
|
message,
|
|
94
103
|
type: 'warning',
|
|
95
104
|
confirmText,
|
|
96
105
|
cancelText,
|
|
106
|
+
allowHtml,
|
|
97
107
|
}).then((result) => result.confirmed);
|
|
98
108
|
}
|
|
99
109
|
/**
|
|
@@ -101,14 +111,16 @@ export class ModalService {
|
|
|
101
111
|
* @param title
|
|
102
112
|
* @param message
|
|
103
113
|
* @param confirmText
|
|
114
|
+
* @param allowHtml
|
|
104
115
|
* @returns Promise que resuelve true si se confirmó
|
|
105
116
|
*/
|
|
106
|
-
async error(title, message, confirmText = 'Entendido') {
|
|
117
|
+
async error(title, message, confirmText = 'Entendido', allowHtml) {
|
|
107
118
|
return this.showModal({
|
|
108
119
|
title,
|
|
109
120
|
message,
|
|
110
121
|
type: 'error',
|
|
111
122
|
confirmText,
|
|
123
|
+
allowHtml,
|
|
112
124
|
}).then(() => void 0);
|
|
113
125
|
}
|
|
114
126
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;;AAGnD;;GAEG;AAIH,MAAM,OAAO,YAAY;IACN,MAAM,GAAG,MAAM,CAAC,KAAK,kDAAC,CAAC;IACvB,MAAM,GAAG,MAAM,CAAc;QAC5C,KAAK,EAAE,EAAE;QACT,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,MAAM;KACb,kDAAC,CAAC;IAEK,cAAc,CAAiC;IAE9C,UAAU,GAAG;QACpB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;QAChC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;KACjC,CAAC;IAEF;;;OAGG;IACH,KAAK,CAAC,SAAS,CAAC,MAAmB;QACjC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACxB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEtB,OAAO,IAAI,OAAO,CAAc,CAAC,OAAO,EAAE,EAAE;YAC1C,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;QAChC,CAAC,CAAC,CAAC;IACL,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"modal.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, signal } from '@angular/core';\nimport type { ModalConfig, ModalResult } from './modal.types';\n\n/**\n *\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class ModalService {\n private readonly isOpen = signal(false);\n private readonly config = signal<ModalConfig>({\n title: '',\n message: '',\n type: 'info',\n });\n\n private resolvePromise?: (result: ModalResult) => void;\n\n readonly modalState = {\n isOpen: this.isOpen.asReadonly(),\n config: this.config.asReadonly(),\n };\n\n /**\n *\n * @param config\n */\n async showModal(config: ModalConfig): Promise<ModalResult> {\n this.config.set(config);\n this.isOpen.set(true);\n\n return new Promise<ModalResult>((resolve) => {\n this.resolvePromise = resolve;\n });\n }\n\n /**\n *\n * @param options\n * @param options.title\n * @param options.message\n * @param options.confirmText\n * @param options.cancelText\n * @param options.allowHtml\n * @returns Promise que resuelve true si se confirmó\n */\n async confirm(options: {\n title: string;\n message: string;\n confirmText?: string;\n cancelText?: string;\n allowHtml?: boolean;\n }): Promise<boolean> {\n const { title, message, confirmText = 'Confirmar', cancelText = 'Cancelar', allowHtml } = options;\n return this.showModal({\n title,\n message,\n type: 'confirm',\n confirmText,\n cancelText,\n allowHtml,\n }).then((result) => result.confirmed);\n }\n\n /**\n *\n * @param options\n * @param options.title\n * @param options.message\n * @param options.yesText\n * @param options.noText\n * @param options.allowHtml\n * @returns Promise que resuelve true si se eligió Sí\n */\n async yesNo(options: {\n title: string;\n message: string;\n yesText?: string;\n noText?: string;\n allowHtml?: boolean;\n }): Promise<boolean> {\n const { title, message, yesText = 'Sí', noText = 'No', allowHtml } = options;\n return this.showModal({\n title,\n message,\n type: 'yesNo',\n yesText,\n noText,\n allowHtml,\n }).then((result) => result.action === 'yes');\n }\n\n /**\n *\n * @param title\n * @param message\n * @param allowHtml\n * @param confirmText\n * @returns Promise que resuelve cuando se cierra el modal\n */\n async info(title: string, message: string, allowHtml?: boolean, confirmText?: string): Promise<void> {\n return this.showModal({\n title,\n message,\n type: 'info',\n allowHtml,\n confirmText,\n }).then(() => void 0);\n }\n\n /**\n *\n * @param options\n * @param options.title\n * @param options.message\n * @param options.confirmText\n * @param options.cancelText\n * @param options.allowHtml\n * @returns Promise que resuelve true si se confirmó\n */\n async warning(options: {\n title: string;\n message: string;\n confirmText?: string;\n cancelText?: string;\n allowHtml?: boolean;\n }): Promise<boolean> {\n const { title, message, confirmText = 'Entendido', cancelText = 'Cancelar', allowHtml } = options;\n return this.showModal({\n title,\n message,\n type: 'warning',\n confirmText,\n cancelText,\n allowHtml,\n }).then((result) => result.confirmed);\n }\n\n /**\n *\n * @param title\n * @param message\n * @param confirmText\n * @param allowHtml\n * @returns Promise que resuelve true si se confirmó\n */\n async error(\n title: string,\n message: string,\n confirmText = 'Entendido',\n allowHtml?: boolean\n ): Promise<void> {\n return this.showModal({\n title,\n message,\n type: 'error',\n confirmText,\n allowHtml,\n }).then(() => void 0);\n }\n\n /**\n * Maneja el resultado del modal y resuelve la promesa\n * @param result - Resultado de la acción del modal\n */\n handleResult(result: ModalResult): void {\n if (this.resolvePromise) {\n this.resolvePromise(result);\n this.resolvePromise = undefined;\n }\n this.closeModal();\n }\n\n /**\n * Cierra el modal actual\n */\n closeModal(): void {\n this.isOpen.set(false);\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal.types.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.types.ts"],"names":[],"mappings":"","sourcesContent":["export type ModalType = 'info' | 'confirm' | 'yesNo' | 'warning' | 'error';\n\nexport interface ModalConfig {\n title: string;\n message: string;\n type?: ModalType;\n confirmText?: string;\n cancelText?: string;\n yesText?: string;\n noText?: string;\n showCancel?: boolean;\n}\n\nexport interface ModalResult {\n action: 'confirm' | 'cancel' | 'yes' | 'no';\n confirmed: boolean;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"modal.types.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.types.ts"],"names":[],"mappings":"","sourcesContent":["export type ModalType = 'info' | 'confirm' | 'yesNo' | 'warning' | 'error';\n\nexport interface ModalConfig {\n title: string;\n message: string;\n type?: ModalType;\n confirmText?: string;\n cancelText?: string;\n yesText?: string;\n noText?: string;\n showCancel?: boolean;\n allowHtml?: boolean;\n}\n\nexport interface ModalResult {\n action: 'confirm' | 'cancel' | 'yes' | 'no';\n confirmed: boolean;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/navigation-card/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC","sourcesContent":["export * from './navigation-card.component';\nexport * from './navigation-card.types';\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Component, input, output, ChangeDetectionStrategy } from '@angular/core';
|
|
2
|
+
import { IconComponent } from '../icon';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export class NavigationCardComponent {
|
|
5
|
+
card = input.required(...(ngDevMode ? [{ debugName: "card" }] : []));
|
|
6
|
+
active = input(false, ...(ngDevMode ? [{ debugName: "active" }] : []));
|
|
7
|
+
cardClick = output();
|
|
8
|
+
onCardClick() {
|
|
9
|
+
this.cardClick.emit(this.card());
|
|
10
|
+
}
|
|
11
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: NavigationCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.10", type: NavigationCardComponent, isStandalone: true, selector: "c80-navigation-card", inputs: { card: { classPropertyName: "card", publicName: "card", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cardClick: "cardClick" }, ngImport: i0, template: "<button type=\"button\" class=\"nav-card\" [class.active]=\"active()\" (click)=\"onCardClick()\">\n <c80-icon [icon]=\"card().icon\" [size]=\"1.7\" class=\"card-icon\" />\n <h3 class=\"card-title\">{{ card().title }}</h3>\n</button>", styles: [".nav-card{background:var(--color-bg-primary);border:1px solid var(--color-border-default);border-radius:12px;padding:24px;cursor:pointer;transition:all .1s ease;display:flex;flex-direction:column;align-items:center;text-align:center;min-height:140px;justify-content:center;width:100%;font-family:inherit;font-size:inherit}.nav-card:hover{background:var(--color-bg-hover);box-shadow:var(--shadow-md);transform:translateY(-1px);border-color:var(--color-border-medium)}.nav-card.active{background:var(--color-bg-tertiary);border-color:var(--color-text-primary)}.nav-card:focus-visible{outline:none}.nav-card .card-icon{margin-bottom:12px;display:flex;justify-content:center;align-items:center}.nav-card .card-title{font-size:16px;font-weight:600;margin:0;color:var(--color-text-primary);transition:color .2s}@media(max-width:768px){.nav-card{min-height:120px;padding:20px}.nav-card .card-icon{font-size:40px;width:40px;height:40px}.nav-card .card-title{font-size:14px}}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight", "dark"], outputs: ["iconClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13
|
+
}
|
|
14
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: NavigationCardComponent, decorators: [{
|
|
15
|
+
type: Component,
|
|
16
|
+
args: [{ selector: 'c80-navigation-card', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<button type=\"button\" class=\"nav-card\" [class.active]=\"active()\" (click)=\"onCardClick()\">\n <c80-icon [icon]=\"card().icon\" [size]=\"1.7\" class=\"card-icon\" />\n <h3 class=\"card-title\">{{ card().title }}</h3>\n</button>", styles: [".nav-card{background:var(--color-bg-primary);border:1px solid var(--color-border-default);border-radius:12px;padding:24px;cursor:pointer;transition:all .1s ease;display:flex;flex-direction:column;align-items:center;text-align:center;min-height:140px;justify-content:center;width:100%;font-family:inherit;font-size:inherit}.nav-card:hover{background:var(--color-bg-hover);box-shadow:var(--shadow-md);transform:translateY(-1px);border-color:var(--color-border-medium)}.nav-card.active{background:var(--color-bg-tertiary);border-color:var(--color-text-primary)}.nav-card:focus-visible{outline:none}.nav-card .card-icon{margin-bottom:12px;display:flex;justify-content:center;align-items:center}.nav-card .card-title{font-size:16px;font-weight:600;margin:0;color:var(--color-text-primary);transition:color .2s}@media(max-width:768px){.nav-card{min-height:120px;padding:20px}.nav-card .card-icon{font-size:40px;width:40px;height:40px}.nav-card .card-title{font-size:14px}}\n"] }]
|
|
17
|
+
}], propDecorators: { card: [{ type: i0.Input, args: [{ isSignal: true, alias: "card", required: true }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], cardClick: [{ type: i0.Output, args: ["cardClick"] }] } });
|
|
18
|
+
//# sourceMappingURL=navigation-card.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-card.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/navigation-card/navigation-card.component.ts","../../../../../libs/ui/src/lib/navigation-card/navigation-card.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;;AAaxC,MAAM,OAAO,uBAAuB;IACvB,IAAI,GAAG,KAAK,CAAC,QAAQ,+CAAkB,CAAC;IACxC,MAAM,GAAG,KAAK,CAAU,KAAK,kDAAC,CAAC;IAC/B,SAAS,GAAG,MAAM,EAAkB,CAAC;IAE9C,WAAW;QACP,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;wGAPQ,uBAAuB;4FAAvB,uBAAuB,+WCdpC,gPAGS,kgCDMK,aAAa;;4FAKd,uBAAuB;kBATnC,SAAS;+BAEI,qBAAqB,cACnB,IAAI,WACP,CAAC,aAAa,CAAC,mBAGP,uBAAuB,CAAC,MAAM","sourcesContent":["import { Component, input, output, ChangeDetectionStrategy } from '@angular/core';\nimport { IconComponent } from '../icon';\nimport type { NavigationCard } from './navigation-card.types';\n\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-navigation-card',\n standalone: true,\n imports: [IconComponent],\n templateUrl: './navigation-card.component.html',\n styleUrl: './navigation-card.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class NavigationCardComponent {\n readonly card = input.required<NavigationCard>();\n readonly active = input<boolean>(false);\n readonly cardClick = output<NavigationCard>();\n\n onCardClick(): void {\n this.cardClick.emit(this.card());\n }\n}\n","<button type=\"button\" class=\"nav-card\" [class.active]=\"active()\" (click)=\"onCardClick()\">\n <c80-icon [icon]=\"card().icon\" [size]=\"1.7\" class=\"card-icon\" />\n <h3 class=\"card-title\">{{ card().title }}</h3>\n</button>"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-card.types.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/navigation-card/navigation-card.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { IconType } from '../icon';\n\nexport interface NavigationCard {\n readonly title: string;\n readonly icon: IconType;\n readonly route: string;\n readonly permission?: string;\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Injectable } from '@angular/core';
|
|
1
|
+
import { Injectable, inject } from '@angular/core';
|
|
2
|
+
import { TableDataConverterService } from './table-data-converter.service';
|
|
2
3
|
import * as i0 from "@angular/core";
|
|
3
4
|
/**
|
|
4
5
|
* Servicio para mapear automáticamente datos de tabla a DTOs
|
|
@@ -7,9 +8,15 @@ import * as i0 from "@angular/core";
|
|
|
7
8
|
* Reglas de exclusión:
|
|
8
9
|
* - readOnly: true → campo NO se incluye
|
|
9
10
|
* - accessor: 'id' → campo NO se incluye (IDs van en URL, no en body)
|
|
11
|
+
* - undefined / null → campo NO se incluye (no hubo cambio)
|
|
12
|
+
* - '' (cadena vacía) → se envía null para LIMPIAR el campo
|
|
10
13
|
* - readOnly: false o undefined → campo se incluye
|
|
14
|
+
*
|
|
15
|
+
* La conversión de tipos delega en TableDataConverterService (que acepta
|
|
16
|
+
* strings, tal como llegan desde los inputs HTML).
|
|
11
17
|
*/
|
|
12
18
|
export class TableDtoMapperService {
|
|
19
|
+
converter = inject(TableDataConverterService);
|
|
13
20
|
/**
|
|
14
21
|
* Mapea un objeto de fila a DTO, excluyendo campos readOnly e id
|
|
15
22
|
* @param row - Datos de la fila
|
|
@@ -23,10 +30,16 @@ export class TableDtoMapperService {
|
|
|
23
30
|
const editableColumns = columns.filter(col => !col.readOnly && col.accessor !== 'id');
|
|
24
31
|
for (const col of editableColumns) {
|
|
25
32
|
const value = row[col.accessor];
|
|
26
|
-
//
|
|
27
|
-
if (value
|
|
28
|
-
|
|
33
|
+
// undefined / null: el campo no cambió, no se incluye
|
|
34
|
+
if (value === undefined || value === null) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// Cadena vacía: se interpreta como "limpiar el campo" → null explícito
|
|
38
|
+
if (value === '') {
|
|
39
|
+
dto[col.accessor] = null;
|
|
40
|
+
continue;
|
|
29
41
|
}
|
|
42
|
+
dto[col.accessor] = this.convertValue(value, col);
|
|
30
43
|
}
|
|
31
44
|
// Agregar campos adicionales (ej: boxId, profileId)
|
|
32
45
|
if (additionalFields) {
|
|
@@ -35,7 +48,8 @@ export class TableDtoMapperService {
|
|
|
35
48
|
return dto;
|
|
36
49
|
}
|
|
37
50
|
/**
|
|
38
|
-
* Convierte un valor según el tipo de columna
|
|
51
|
+
* Convierte un valor según el tipo de columna, reutilizando
|
|
52
|
+
* TableDataConverterService (acepta strings provenientes de inputs HTML).
|
|
39
53
|
* @param value - Valor a convertir
|
|
40
54
|
* @param col - Definición de columna
|
|
41
55
|
* @returns Valor convertido
|
|
@@ -43,49 +57,32 @@ export class TableDtoMapperService {
|
|
|
43
57
|
convertValue(value, col) {
|
|
44
58
|
switch (col.type) {
|
|
45
59
|
case 'integer':
|
|
46
|
-
return this.toInteger(value, col);
|
|
60
|
+
return this.applyBounds(this.converter.toInteger(value), col);
|
|
47
61
|
case 'number':
|
|
48
|
-
return this.toNumber(value);
|
|
62
|
+
return this.converter.toNumber(value);
|
|
49
63
|
case 'boolean':
|
|
50
|
-
return this.toBoolean(value);
|
|
64
|
+
return this.converter.toBoolean(value);
|
|
51
65
|
case 'string':
|
|
52
66
|
case 'password':
|
|
53
67
|
case 'enum':
|
|
54
|
-
return this.
|
|
68
|
+
return this.converter.toStringValue(value);
|
|
55
69
|
default:
|
|
56
70
|
return value;
|
|
57
71
|
}
|
|
58
72
|
}
|
|
59
|
-
|
|
60
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Aplica los límites min/max declarados en la columna a un valor numérico.
|
|
75
|
+
*/
|
|
76
|
+
applyBounds(value, col) {
|
|
77
|
+
if (value === undefined)
|
|
61
78
|
return undefined;
|
|
62
|
-
let result =
|
|
63
|
-
// Aplicar min/max si existen
|
|
79
|
+
let result = value;
|
|
64
80
|
if (col.min !== undefined)
|
|
65
81
|
result = Math.max(result, col.min);
|
|
66
82
|
if (col.max !== undefined)
|
|
67
83
|
result = Math.min(result, col.max);
|
|
68
84
|
return result;
|
|
69
85
|
}
|
|
70
|
-
toNumber(value) {
|
|
71
|
-
if (typeof value === 'number')
|
|
72
|
-
return value;
|
|
73
|
-
if (typeof value === 'string') {
|
|
74
|
-
const num = Number(value);
|
|
75
|
-
return Number.isNaN(num) ? undefined : num;
|
|
76
|
-
}
|
|
77
|
-
return undefined;
|
|
78
|
-
}
|
|
79
|
-
toBoolean(value) {
|
|
80
|
-
if (typeof value === 'boolean')
|
|
81
|
-
return value;
|
|
82
|
-
if (typeof value === 'string')
|
|
83
|
-
return value.toLowerCase() === 'true';
|
|
84
|
-
return Boolean(value);
|
|
85
|
-
}
|
|
86
|
-
toString(value) {
|
|
87
|
-
return String(value);
|
|
88
|
-
}
|
|
89
86
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: TableDtoMapperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
90
87
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: TableDtoMapperService, providedIn: 'root' });
|
|
91
88
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-dto-mapper.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-dto-mapper.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;;
|
|
1
|
+
{"version":3,"file":"table-dto-mapper.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-dto-mapper.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;;AAE3E;;;;;;;;;;;;;GAaG;AAIH,MAAM,OAAO,qBAAqB;IAEb,SAAS,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAE/D;;;;;;OAMG;IACH,QAAQ,CACJ,GAA4B,EAC5B,OAAsB,EACtB,gBAA0C;QAE1C,MAAM,GAAG,GAA4B,EAAE,CAAC;QAExC,2CAA2C;QAC3C,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACzC,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,IAAI,CACzC,CAAC;QAEF,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAEhC,sDAAsD;YACtD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACxC,SAAS;YACb,CAAC;YAED,uEAAuE;YACvE,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;gBACf,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;gBACzB,SAAS;YACb,CAAC;YAED,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACtD,CAAC;QAED,oDAAoD;QACpD,IAAI,gBAAgB,EAAE,CAAC;YACnB,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QACzC,CAAC;QAED,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;;;;;OAMG;IACK,YAAY,CAAC,KAAc,EAAE,GAAgB;QACjD,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACf,KAAK,SAAS;gBACV,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;YAClE,KAAK,QAAQ;gBACT,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC1C,KAAK,SAAS;gBACV,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC3C,KAAK,QAAQ,CAAC;YACd,KAAK,UAAU,CAAC;YAChB,KAAK,MAAM;gBACP,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC/C;gBACI,OAAO,KAAK,CAAC;QACrB,CAAC;IACL,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,KAAyB,EAAE,GAAgB;QAC3D,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAE1C,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS;YAAE,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9D,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS;YAAE,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QAE9D,OAAO,MAAM,CAAC;IAClB,CAAC;wGAnFQ,qBAAqB;4GAArB,qBAAqB,cAFlB,MAAM;;4FAET,qBAAqB;kBAHjC,UAAU;mBAAC;oBACR,UAAU,EAAE,MAAM;iBACrB","sourcesContent":["import { Injectable, inject } from '@angular/core';\nimport type { TableColDef } from './table.types';\nimport { TableDataConverterService } from './table-data-converter.service';\n\n/**\n * Servicio para mapear automáticamente datos de tabla a DTOs\n * basándose en la configuración de TableColDef.\n *\n * Reglas de exclusión:\n * - readOnly: true → campo NO se incluye\n * - accessor: 'id' → campo NO se incluye (IDs van en URL, no en body)\n * - undefined / null → campo NO se incluye (no hubo cambio)\n * - '' (cadena vacía) → se envía null para LIMPIAR el campo\n * - readOnly: false o undefined → campo se incluye\n *\n * La conversión de tipos delega en TableDataConverterService (que acepta\n * strings, tal como llegan desde los inputs HTML).\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableDtoMapperService {\n\n private readonly converter = inject(TableDataConverterService);\n\n /**\n * Mapea un objeto de fila a DTO, excluyendo campos readOnly e id\n * @param row - Datos de la fila\n * @param columns - Definiciones de columnas\n * @param additionalFields - Campos adicionales a agregar al DTO (ej: boxId)\n * @returns DTO con solo campos editables (sin id)\n */\n mapToDto(\n row: Record<string, unknown>,\n columns: TableColDef[],\n additionalFields?: Record<string, unknown>\n ): Record<string, unknown> {\n const dto: Record<string, unknown> = {};\n\n // Mapear solo columnas NO readOnly y NO id\n const editableColumns = columns.filter(col =>\n !col.readOnly && col.accessor !== 'id'\n );\n\n for (const col of editableColumns) {\n const value = row[col.accessor];\n\n // undefined / null: el campo no cambió, no se incluye\n if (value === undefined || value === null) {\n continue;\n }\n\n // Cadena vacía: se interpreta como \"limpiar el campo\" → null explícito\n if (value === '') {\n dto[col.accessor] = null;\n continue;\n }\n\n dto[col.accessor] = this.convertValue(value, col);\n }\n\n // Agregar campos adicionales (ej: boxId, profileId)\n if (additionalFields) {\n Object.assign(dto, additionalFields);\n }\n\n return dto;\n }\n\n /**\n * Convierte un valor según el tipo de columna, reutilizando\n * TableDataConverterService (acepta strings provenientes de inputs HTML).\n * @param value - Valor a convertir\n * @param col - Definición de columna\n * @returns Valor convertido\n */\n private convertValue(value: unknown, col: TableColDef): unknown {\n switch (col.type) {\n case 'integer':\n return this.applyBounds(this.converter.toInteger(value), col);\n case 'number':\n return this.converter.toNumber(value);\n case 'boolean':\n return this.converter.toBoolean(value);\n case 'string':\n case 'password':\n case 'enum':\n return this.converter.toStringValue(value);\n default:\n return value;\n }\n }\n\n /**\n * Aplica los límites min/max declarados en la columna a un valor numérico.\n */\n private applyBounds(value: number | undefined, col: TableColDef): number | undefined {\n if (value === undefined) return undefined;\n\n let result = value;\n if (col.min !== undefined) result = Math.max(result, col.min);\n if (col.max !== undefined) result = Math.min(result, col.max);\n\n return result;\n }\n}\n"]}
|
|
@@ -14,7 +14,7 @@ export class TableSelectionService {
|
|
|
14
14
|
* Inicializa el estado de selección para una nueva tabla
|
|
15
15
|
* @returns Objeto con signals y métodos de selección
|
|
16
16
|
*/
|
|
17
|
-
createSelectionState() {
|
|
17
|
+
createSelectionState(getRowId = (item) => item['id']) {
|
|
18
18
|
const selectedItems = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
|
|
19
19
|
const selectAllChecked = signal(false, ...(ngDevMode ? [{ debugName: "selectAllChecked" }] : []));
|
|
20
20
|
const selectAllIndeterminate = signal(false, ...(ngDevMode ? [{ debugName: "selectAllIndeterminate" }] : []));
|
|
@@ -24,11 +24,11 @@ export class TableSelectionService {
|
|
|
24
24
|
selectAllChecked: selectAllChecked.asReadonly(),
|
|
25
25
|
selectAllIndeterminate: selectAllIndeterminate.asReadonly(),
|
|
26
26
|
clearSelection: () => this.clearSelection(signals),
|
|
27
|
-
toggleSelectAll: (allItems) => this.toggleSelectAll(signals, allItems),
|
|
28
|
-
toggleItemSelection: (item, multiple) => this.toggleItemSelection(selectedItems, item, multiple),
|
|
29
|
-
isItemSelected: (item) => this.isItemSelected(selectedItems, item),
|
|
30
|
-
preserveSelection: (newData) => this.preserveSelection(signals, newData),
|
|
31
|
-
getSelectedItems: (allData) => this.getSelectedItems(selectedItems, allData),
|
|
27
|
+
toggleSelectAll: (allItems) => this.toggleSelectAll(signals, allItems, getRowId),
|
|
28
|
+
toggleItemSelection: (item, multiple) => this.toggleItemSelection(selectedItems, item, multiple, getRowId),
|
|
29
|
+
isItemSelected: (item) => this.isItemSelected(selectedItems, item, getRowId),
|
|
30
|
+
preserveSelection: (newData) => this.preserveSelection(signals, newData, getRowId),
|
|
31
|
+
getSelectedItems: (allData) => this.getSelectedItems(selectedItems, allData, getRowId),
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
clearSelection(signals) {
|
|
@@ -36,7 +36,7 @@ export class TableSelectionService {
|
|
|
36
36
|
signals.selectAllChecked.set(false);
|
|
37
37
|
signals.selectAllIndeterminate.set(false);
|
|
38
38
|
}
|
|
39
|
-
toggleSelectAll(signals, allItems) {
|
|
39
|
+
toggleSelectAll(signals, allItems, getRowId) {
|
|
40
40
|
const currentSelection = signals.selectedItems();
|
|
41
41
|
if (currentSelection.size === allItems.length) {
|
|
42
42
|
signals.selectedItems.set(new Set());
|
|
@@ -44,7 +44,7 @@ export class TableSelectionService {
|
|
|
44
44
|
signals.selectAllIndeterminate.set(false);
|
|
45
45
|
}
|
|
46
46
|
else {
|
|
47
|
-
const allIds = new Set(allItems.map(
|
|
47
|
+
const allIds = new Set(allItems.map(getRowId));
|
|
48
48
|
signals.selectedItems.set(allIds);
|
|
49
49
|
this.updateSelectAllState({
|
|
50
50
|
allItems,
|
|
@@ -54,8 +54,8 @@ export class TableSelectionService {
|
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
toggleItemSelection(selectedItems, item, multiple) {
|
|
58
|
-
const id = item
|
|
57
|
+
toggleItemSelection(selectedItems, item, multiple, getRowId) {
|
|
58
|
+
const id = getRowId(item);
|
|
59
59
|
const currentSelection = new Set(selectedItems());
|
|
60
60
|
if (!multiple) {
|
|
61
61
|
currentSelection.clear();
|
|
@@ -71,16 +71,16 @@ export class TableSelectionService {
|
|
|
71
71
|
}
|
|
72
72
|
selectedItems.set(currentSelection);
|
|
73
73
|
}
|
|
74
|
-
isItemSelected(selectedItems, item) {
|
|
75
|
-
return selectedItems().has(item
|
|
74
|
+
isItemSelected(selectedItems, item, getRowId) {
|
|
75
|
+
return selectedItems().has(getRowId(item));
|
|
76
76
|
}
|
|
77
|
-
preserveSelection(signals, newData) {
|
|
77
|
+
preserveSelection(signals, newData, getRowId) {
|
|
78
78
|
const currentSelection = signals.selectedItems();
|
|
79
79
|
if (currentSelection.size === 0 || newData.length === 0) {
|
|
80
80
|
this.clearSelection(signals);
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
83
|
-
const availableIds = new Set(newData.map(
|
|
83
|
+
const availableIds = new Set(newData.map(getRowId));
|
|
84
84
|
const preservedSelection = new Set(Array.from(currentSelection).filter(id => availableIds.has(id)));
|
|
85
85
|
signals.selectedItems.set(preservedSelection);
|
|
86
86
|
this.updateSelectAllState({
|
|
@@ -90,9 +90,9 @@ export class TableSelectionService {
|
|
|
90
90
|
selectAllIndeterminate: signals.selectAllIndeterminate
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
|
-
getSelectedItems(selectedItems, allData) {
|
|
93
|
+
getSelectedItems(selectedItems, allData, getRowId) {
|
|
94
94
|
const selectedIds = selectedItems();
|
|
95
|
-
return allData.filter(item => selectedIds.has(item
|
|
95
|
+
return allData.filter(item => selectedIds.has(getRowId(item)));
|
|
96
96
|
}
|
|
97
97
|
updateSelectAllState(context) {
|
|
98
98
|
const { allItems, selectedCount, selectAllChecked, selectAllIndeterminate } = context;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-selection.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-selection.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { type OutputEmitterRef, Injectable, signal, type Signal } from '@angular/core';\n\ninterface SelectionState<T extends Record<string, unknown>> {\n selectedItems: Signal<Set<string>>;\n selectAllChecked: Signal<boolean>;\n selectAllIndeterminate: Signal<boolean>;\n clearSelection: () => void;\n toggleSelectAll: (allItems: T[]) => void;\n toggleItemSelection: (item: T, multiple: boolean) => void;\n isItemSelected: (item: T) => boolean;\n preserveSelection: (newData: T[]) => void;\n getSelectedItems: (allData: T[]) => T[];\n}\n\n/**\n * Servicio para gestionar la selección de elementos en tablas C80\n *\n * Maneja:\n * - Selección simple y múltiple\n * - Estado de selección completa\n * - Preservación de selección tras actualizaciones de datos\n * - Emisión de eventos de selección\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableSelectionService {\n\n /**\n * Inicializa el estado de selección para una nueva tabla\n * @returns Objeto con signals y métodos de selección\n */\n createSelectionState<T extends Record<string, unknown>>(): SelectionState<T> {\n const selectedItems = signal<Set<string>>(new Set());\n const selectAllChecked = signal(false);\n const selectAllIndeterminate = signal(false);\n\n const signals = { selectedItems, selectAllChecked, selectAllIndeterminate };\n\n return {\n selectedItems: selectedItems.asReadonly(),\n selectAllChecked: selectAllChecked.asReadonly(),\n selectAllIndeterminate: selectAllIndeterminate.asReadonly(),\n clearSelection: () => this.clearSelection(signals),\n toggleSelectAll: (allItems: T[]) => this.toggleSelectAll(signals, allItems),\n toggleItemSelection: (item: T, multiple: boolean) => this.toggleItemSelection(selectedItems, item, multiple),\n isItemSelected: (item: T) => this.isItemSelected(selectedItems, item),\n preserveSelection: (newData: T[]) => this.preserveSelection(signals, newData),\n getSelectedItems: (allData: T[]) => this.getSelectedItems(selectedItems, allData),\n };\n }\n\n private clearSelection(signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n }): void {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n }\n\n private toggleSelectAll<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n allItems: T[]\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === allItems.length) {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n } else {\n const allIds = new Set(allItems.map(item => item['id'] as string));\n signals.selectedItems.set(allIds);\n this.updateSelectAllState({\n allItems,\n selectedCount: allIds.size,\n selectAllChecked: signals.selectAllChecked,\n selectAllIndeterminate: signals.selectAllIndeterminate\n });\n }\n }\n\n private toggleItemSelection<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T,\n multiple: boolean\n ): void {\n const id = item['id'] as string;\n const currentSelection = new Set(selectedItems());\n\n if (!multiple) {\n currentSelection.clear();\n if (!selectedItems().has(id)) {\n currentSelection.add(id);\n }\n } else if (currentSelection.has(id)) {\n currentSelection.delete(id);\n } else {\n currentSelection.add(id);\n }\n\n selectedItems.set(currentSelection);\n }\n\n private isItemSelected<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T\n ): boolean {\n return selectedItems().has(item['id'] as string);\n }\n\n private preserveSelection<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n newData: T[]\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === 0 || newData.length === 0) {\n this.clearSelection(signals);\n return;\n }\n\n const availableIds = new Set(newData.map(item => item['id'] as string));\n const preservedSelection = new Set(\n Array.from(currentSelection).filter(id => availableIds.has(id))\n );\n\n signals.selectedItems.set(preservedSelection);\n this.updateSelectAllState({\n allItems: newData,\n selectedCount: preservedSelection.size,\n selectAllChecked: signals.selectAllChecked,\n selectAllIndeterminate: signals.selectAllIndeterminate\n });\n }\n\n private getSelectedItems<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n allData: T[]\n ): T[] {\n const selectedIds = selectedItems();\n return allData.filter(item => selectedIds.has(item['id'] as string));\n }\n\n private updateSelectAllState<T extends Record<string, unknown>>(context: {\n allItems: T[];\n selectedCount: number;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n }): void {\n const { allItems, selectedCount, selectAllChecked, selectAllIndeterminate } = context;\n const totalCount = allItems.length;\n\n if (selectedCount === 0) {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(false);\n } else if (selectedCount === totalCount) {\n selectAllChecked.set(true);\n selectAllIndeterminate.set(false);\n } else {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(true);\n }\n }\n\n /**\n * Emite los elementos seleccionados a través del output proporcionado\n * @param selectionState - Estado de selección\n * @param allData - Todos los datos de la tabla\n * @param selectableEmitter - Output para emitir la selección\n */\n emitSelection<T extends Record<string, unknown>>(\n selectionState: { getSelectedItems: (allData: T[]) => T[] },\n allData: T[],\n selectableEmitter: OutputEmitterRef<T[]>\n ): void {\n const selectedItems = selectionState.getSelectedItems(allData);\n selectableEmitter.emit(selectedItems);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"table-selection.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-selection.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { type OutputEmitterRef, Injectable, signal, type Signal } from '@angular/core';\n\ninterface SelectionState<T extends Record<string, unknown>> {\n selectedItems: Signal<Set<string>>;\n selectAllChecked: Signal<boolean>;\n selectAllIndeterminate: Signal<boolean>;\n clearSelection: () => void;\n toggleSelectAll: (allItems: T[]) => void;\n toggleItemSelection: (item: T, multiple: boolean) => void;\n isItemSelected: (item: T) => boolean;\n preserveSelection: (newData: T[]) => void;\n getSelectedItems: (allData: T[]) => T[];\n}\n\n/**\n * Servicio para gestionar la selección de elementos en tablas C80\n *\n * Maneja:\n * - Selección simple y múltiple\n * - Estado de selección completa\n * - Preservación de selección tras actualizaciones de datos\n * - Emisión de eventos de selección\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableSelectionService {\n\n /**\n * Inicializa el estado de selección para una nueva tabla\n * @returns Objeto con signals y métodos de selección\n */\n createSelectionState<T extends Record<string, unknown>>(\n getRowId: (item: T) => string = (item) => item['id'] as string\n ): SelectionState<T> {\n const selectedItems = signal<Set<string>>(new Set());\n const selectAllChecked = signal(false);\n const selectAllIndeterminate = signal(false);\n\n const signals = { selectedItems, selectAllChecked, selectAllIndeterminate };\n\n return {\n selectedItems: selectedItems.asReadonly(),\n selectAllChecked: selectAllChecked.asReadonly(),\n selectAllIndeterminate: selectAllIndeterminate.asReadonly(),\n clearSelection: () => this.clearSelection(signals),\n toggleSelectAll: (allItems: T[]) => this.toggleSelectAll(signals, allItems, getRowId),\n toggleItemSelection: (item: T, multiple: boolean) => this.toggleItemSelection(selectedItems, item, multiple, getRowId),\n isItemSelected: (item: T) => this.isItemSelected(selectedItems, item, getRowId),\n preserveSelection: (newData: T[]) => this.preserveSelection(signals, newData, getRowId),\n getSelectedItems: (allData: T[]) => this.getSelectedItems(selectedItems, allData, getRowId),\n };\n }\n\n private clearSelection(signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n }): void {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n }\n\n private toggleSelectAll<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n allItems: T[],\n getRowId: (item: T) => string\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === allItems.length) {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n } else {\n const allIds = new Set(allItems.map(getRowId));\n signals.selectedItems.set(allIds);\n this.updateSelectAllState({\n allItems,\n selectedCount: allIds.size,\n selectAllChecked: signals.selectAllChecked,\n selectAllIndeterminate: signals.selectAllIndeterminate\n });\n }\n }\n\n private toggleItemSelection<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T,\n multiple: boolean,\n getRowId: (item: T) => string\n ): void {\n const id = getRowId(item);\n const currentSelection = new Set(selectedItems());\n\n if (!multiple) {\n currentSelection.clear();\n if (!selectedItems().has(id)) {\n currentSelection.add(id);\n }\n } else if (currentSelection.has(id)) {\n currentSelection.delete(id);\n } else {\n currentSelection.add(id);\n }\n\n selectedItems.set(currentSelection);\n }\n\n private isItemSelected<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T,\n getRowId: (item: T) => string\n ): boolean {\n return selectedItems().has(getRowId(item));\n }\n\n private preserveSelection<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n newData: T[],\n getRowId: (item: T) => string\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === 0 || newData.length === 0) {\n this.clearSelection(signals);\n return;\n }\n\n const availableIds = new Set(newData.map(getRowId));\n const preservedSelection = new Set(\n Array.from(currentSelection).filter(id => availableIds.has(id))\n );\n\n signals.selectedItems.set(preservedSelection);\n this.updateSelectAllState({\n allItems: newData,\n selectedCount: preservedSelection.size,\n selectAllChecked: signals.selectAllChecked,\n selectAllIndeterminate: signals.selectAllIndeterminate\n });\n }\n\n private getSelectedItems<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n allData: T[],\n getRowId: (item: T) => string\n ): T[] {\n const selectedIds = selectedItems();\n return allData.filter(item => selectedIds.has(getRowId(item)));\n }\n\n private updateSelectAllState<T extends Record<string, unknown>>(context: {\n allItems: T[];\n selectedCount: number;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n }): void {\n const { allItems, selectedCount, selectAllChecked, selectAllIndeterminate } = context;\n const totalCount = allItems.length;\n\n if (selectedCount === 0) {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(false);\n } else if (selectedCount === totalCount) {\n selectAllChecked.set(true);\n selectAllIndeterminate.set(false);\n } else {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(true);\n }\n }\n\n /**\n * Emite los elementos seleccionados a través del output proporcionado\n * @param selectionState - Estado de selección\n * @param allData - Todos los datos de la tabla\n * @param selectableEmitter - Output para emitir la selección\n */\n emitSelection<T extends Record<string, unknown>>(\n selectionState: { getSelectedItems: (allData: T[]) => T[] },\n allData: T[],\n selectableEmitter: OutputEmitterRef<T[]>\n ): void {\n const selectedItems = selectionState.getSelectedItems(allData);\n selectableEmitter.emit(selectedItems);\n }\n}\n"]}
|