@memberjunction/ng-entity-viewer 6.2.0-edge.0 → 6.2.0-edge.1
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/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts +22 -0
- package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts.map +1 -1
- package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js +57 -13
- package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js.map +1 -1
- package/dist/lib/entity-cards/entity-cards.component.d.ts +67 -5
- package/dist/lib/entity-cards/entity-cards.component.d.ts.map +1 -1
- package/dist/lib/entity-cards/entity-cards.component.js +202 -71
- package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +159 -16
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.js +446 -147
- package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
- package/dist/lib/entity-data-grid/events/grid-events.js +67 -67
- package/dist/lib/entity-data-grid/events/grid-events.js.map +1 -1
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts +112 -8
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts.map +1 -1
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js +245 -61
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts +6 -0
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.js +28 -9
- package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
- package/dist/lib/pill/pill.component.d.ts +13 -3
- package/dist/lib/pill/pill.component.d.ts.map +1 -1
- package/dist/lib/pill/pill.component.js +34 -10
- package/dist/lib/pill/pill.component.js.map +1 -1
- package/dist/lib/quick-save-dialog/quick-save-dialog.component.d.ts +29 -3
- package/dist/lib/quick-save-dialog/quick-save-dialog.component.d.ts.map +1 -1
- package/dist/lib/quick-save-dialog/quick-save-dialog.component.js +173 -114
- package/dist/lib/quick-save-dialog/quick-save-dialog.component.js.map +1 -1
- package/dist/lib/recycle-bin/recycle-bin.component.d.ts +4 -0
- package/dist/lib/recycle-bin/recycle-bin.component.d.ts.map +1 -1
- package/dist/lib/recycle-bin/recycle-bin.component.js +10 -2
- package/dist/lib/recycle-bin/recycle-bin.component.js.map +1 -1
- package/dist/lib/utils/highlight.util.d.ts +6 -0
- package/dist/lib/utils/highlight.util.d.ts.map +1 -1
- package/dist/lib/utils/highlight.util.js +23 -11
- package/dist/lib/utils/highlight.util.js.map +1 -1
- package/dist/lib/utils/record.util.d.ts +10 -0
- package/dist/lib/utils/record.util.d.ts.map +1 -1
- package/dist/lib/utils/record.util.js +20 -4
- package/dist/lib/utils/record.util.js.map +1 -1
- package/dist/lib/view-config-panel/view-config-panel.component.d.ts +17 -1
- package/dist/lib/view-config-panel/view-config-panel.component.d.ts.map +1 -1
- package/dist/lib/view-config-panel/view-config-panel.component.js +39 -6
- package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -1
- package/dist/lib/view-selector/view-selector.component.js +2 -2
- package/dist/lib/view-types/renderers/cards-view-renderer.component.d.ts +15 -3
- package/dist/lib/view-types/renderers/cards-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/cards-view-renderer.component.js +33 -5
- package/dist/lib/view-types/renderers/cards-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts +70 -2
- package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/grid-view-renderer.component.js +155 -33
- package/dist/lib/view-types/renderers/grid-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts +16 -2
- package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/map-view-renderer.component.js +37 -9
- package/dist/lib/view-types/renderers/map-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/view-type.contracts.d.ts +8 -0
- package/dist/lib/view-types/view-type.contracts.d.ts.map +1 -1
- package/dist/lib/view-types/view-type.contracts.js.map +1 -1
- package/dist/lib/view-workspace/view-workspace.component.d.ts +243 -25
- package/dist/lib/view-workspace/view-workspace.component.d.ts.map +1 -1
- package/dist/lib/view-workspace/view-workspace.component.js +631 -180
- package/dist/lib/view-workspace/view-workspace.component.js.map +1 -1
- package/package.json +21 -20
|
@@ -867,11 +867,11 @@ export class ViewSelectorComponent extends BaseAngularComponent {
|
|
|
867
867
|
i0.ɵɵconditional(ctx.IsDropdownOpen ? 9 : -1);
|
|
868
868
|
i0.ɵɵadvance();
|
|
869
869
|
i0.ɵɵconditional(ctx.SelectedViewID ? 10 : -1);
|
|
870
|
-
} }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJEmptyStateComponent], styles: ["/* ========================================\n VIEW SELECTOR - All classes prefixed vs-\n to avoid conflicts (ViewEncapsulation.None)\n ======================================== */\n\n/* Container */\n.vs-container {\n display: flex;\n align-items: center;\n gap: 4px;\n position: relative;\n}\n\n/* Backdrop for closing panel */\n.vs-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.vs-wrapper {\n position: relative;\n}\n\n/* Main Button */\n.vs-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 140px;\n max-width: 280px;\n}\n\n.vs-button:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.vs-button.open {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button.modified {\n border-color: var(--mj-status-warning);\n}\n\n.vs-btn-icon {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.vs-btn-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.vs-modified-dot {\n color: var(--mj-status-warning);\n font-weight: bold;\n font-size: 18px;\n line-height: 1;\n}\n\n.vs-arrow {\n color: var(--mj-text-muted);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.vs-arrow.rotated {\n transform: rotate(180deg);\n}\n\n/* ========================================\n RICH VIEW PANEL\n Styles ported directly from prototype\n ======================================== */\n\n/* Reset inherited styles inside panel */\n.vs-panel,\n.vs-panel * {\n box-sizing: border-box;\n line-height: 1.5;\n text-align: left;\n}\n\n.vs-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n width: 400px;\n max-width: calc(100vw - 40px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.16);\n z-index: 1000;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--mj-text-primary);\n}\n\n/* Panel Header */\n.vs-panel-header {\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-header-icon {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.vs-panel-title {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.vs-entity-badge {\n font-size: 11px;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.vs-close-btn {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 16px;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-close-btn:hover {\n color: var(--mj-text-primary);\n}\n\n/* Panel Search */\n.vs-panel-search {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-search-input {\n width: 100%;\n padding: 6px 12px 6px 32px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n font-size: 13px;\n background: var(--mj-bg-surface-card) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='%23999'%3E%3Cpath d='M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208z'/%3E%3C/svg%3E\") no-repeat 10px center;\n background-size: 14px;\n box-sizing: border-box;\n font-family: inherit;\n}\n\n.vs-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n}\n\n.vs-search-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n/* Panel Body */\n.vs-panel-body {\n max-height: 400px;\n overflow-y: auto;\n}\n\n/* View Section */\n.vs-section {\n padding: 8px 0;\n}\n\n.vs-section-header {\n padding: 6px 20px;\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-section-header i {\n font-size: 10px;\n}\n\n.vs-section-count {\n background: var(--mj-border-default);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n}\n\n/* View Card */\n.vs-card {\n padding: 10px 20px;\n cursor: pointer;\n transition: background 0.1s;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.vs-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-card.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n padding-left: 17px;\n}\n\n/* View Card Icon */\n.vs-card-icon {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card-icon.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.vs-card-icon.shared {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-muted);\n}\n\n/* View Card Content */\n.vs-card-content {\n flex: 1;\n min-width: 0;\n padding-top: 4px;\n}\n\n.vs-card-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-card.active .vs-card-name {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.vs-default-badge {\n font-size: 9px;\n font-weight: 600;\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n padding: 1px 5px;\n border-radius: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.vs-shared-badge {\n font-size: 9px;\n font-weight: 600;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 1px 5px;\n border-radius: 6px;\n}\n\n.vs-shared-badge.editable {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.vs-card-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.vs-card-meta {\n display: flex;\n gap: 10px;\n margin-top: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.vs-card-meta span {\n display: flex;\n align-items: center;\n gap: 3px;\n}\n\n.vs-card-meta i {\n font-size: 10px;\n}\n\n/* View Card Check */\n.vs-card-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n/* View Card Actions (hover reveal) */\n.vs-card-actions {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.15s;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card:hover .vs-card-actions {\n opacity: 1;\n}\n\n.vs-action-btn {\n width: 26px;\n height: 26px;\n border-radius: 4px;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-action-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n}\n\n/* Loading */\n.vs-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n text-align: center;\n}\n\n/* Panel Footer */\n.vs-panel-footer {\n padding: 12px 20px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n gap: 8px;\n}\n\n.vs-panel-btn {\n flex: 1;\n padding: 8px 12px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.15s;\n font-family: inherit;\n text-align: center;\n}\n\n.vs-panel-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.vs-panel-btn i {\n font-size: 11px;\n}\n\n/* ========================================\n ICON BUTTONS (outside panel)\n ======================================== */\n\n.vs-icon-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n\n.vs-icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n color: var(--mj-brand-primary);\n}\n\n.vs-icon-btn i {\n font-size: 12px;\n}\n\n.vs-export-btn:hover {\n color: var(--mj-status-success);\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .vs-button {\n min-width: 100px;\n max-width: 180px;\n padding: 6px 10px;\n }\n\n .vs-panel {\n width: calc(100vw - 32px);\n max-width: 400px;\n }\n}\n"], encapsulation: 2 });
|
|
870
|
+
} }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJEmptyStateComponent], styles: ["/* ========================================\n VIEW SELECTOR - All classes prefixed vs-\n to avoid conflicts (ViewEncapsulation.None)\n ======================================== */\n\n/* Container */\n.vs-container {\n display: flex;\n align-items: center;\n gap: 4px;\n position: relative;\n}\n\n/* Backdrop for closing panel */\n.vs-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.vs-wrapper {\n position: relative;\n}\n\n/* Main Button */\n.vs-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 140px;\n max-width: 280px;\n}\n\n.vs-button:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.vs-button.open {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button.modified {\n border-color: var(--mj-status-warning);\n}\n\n.vs-btn-icon {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.vs-btn-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.vs-modified-dot {\n color: var(--mj-status-warning);\n font-weight: bold;\n font-size: 18px;\n line-height: 1;\n}\n\n.vs-arrow {\n color: var(--mj-text-muted);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.vs-arrow.rotated {\n transform: rotate(180deg);\n}\n\n/* ========================================\n RICH VIEW PANEL\n Styles ported directly from prototype\n ======================================== */\n\n/* Reset inherited styles inside panel */\n.vs-panel,\n.vs-panel * {\n box-sizing: border-box;\n line-height: 1.5;\n text-align: left;\n}\n\n.vs-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n width: 400px;\n max-width: calc(100vw - 40px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.16);\n z-index: 1000;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--mj-text-primary);\n}\n\n/* Panel Header */\n.vs-panel-header {\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-header-icon {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.vs-panel-title {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.vs-entity-badge {\n font-size: 11px;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.vs-close-btn {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 16px;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-close-btn:hover {\n color: var(--mj-text-primary);\n}\n\n/* Panel Search */\n.vs-panel-search {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-search-input {\n width: 100%;\n padding: 6px 12px 6px 32px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n font-size: 13px;\n background: var(--mj-bg-surface-card) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='%23999'%3E%3Cpath d='M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208z'/%3E%3C/svg%3E\") no-repeat 10px center;\n background-size: 14px;\n box-sizing: border-box;\n font-family: inherit;\n}\n\n.vs-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n}\n\n.vs-search-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n/* Panel Body */\n.vs-panel-body {\n max-height: 400px;\n overflow-y: auto;\n}\n\n/* View Section */\n.vs-section {\n padding: 8px 0;\n}\n\n.vs-section-header {\n padding: 6px 20px;\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-section-header i {\n font-size: 10px;\n}\n\n.vs-section-count {\n background: var(--mj-border-default);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n}\n\n/* View Card */\n.vs-card {\n padding: 10px 20px;\n cursor: pointer;\n transition: background 0.1s;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.vs-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-card.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n padding-left: 17px;\n}\n\n/* View Card Icon */\n.vs-card-icon {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card-icon.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.vs-card-icon.shared {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-muted);\n}\n\n/* View Card Content */\n.vs-card-content {\n flex: 1;\n min-width: 0;\n padding-top: 4px;\n}\n\n.vs-card-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-card.active .vs-card-name {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.vs-default-badge {\n font-size: 9px;\n font-weight: 600;\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n padding: 1px 5px;\n border-radius: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.vs-shared-badge {\n font-size: 9px;\n font-weight: 600;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 1px 5px;\n border-radius: 6px;\n}\n\n.vs-shared-badge.editable {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.vs-card-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.vs-card-meta {\n display: flex;\n gap: 10px;\n margin-top: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.vs-card-meta span {\n display: flex;\n align-items: center;\n gap: 3px;\n}\n\n.vs-card-meta i {\n font-size: 10px;\n}\n\n/* View Card Check */\n.vs-card-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n/* View Card Actions (hover reveal) */\n.vs-card-actions {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.15s;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n/* :focus-within matters as much as :hover \u2014 these buttons (Duplicate, Configure,\n Open in Tab) were reachable ONLY by pointer. A keyboard user could tab into them\n and see nothing at opacity 0, and anything driving the page without a hover\n (assistive tech, automation) could not reach them at all. */\n.vs-card:hover .vs-card-actions,\n.vs-card:focus-within .vs-card-actions {\n opacity: 1;\n}\n\n.vs-action-btn {\n width: 26px;\n height: 26px;\n border-radius: 4px;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-action-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n}\n\n/* Loading */\n.vs-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n text-align: center;\n}\n\n/* Panel Footer */\n.vs-panel-footer {\n padding: 12px 20px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n gap: 8px;\n}\n\n.vs-panel-btn {\n flex: 1;\n padding: 8px 12px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.15s;\n font-family: inherit;\n text-align: center;\n}\n\n.vs-panel-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.vs-panel-btn i {\n font-size: 11px;\n}\n\n/* ========================================\n ICON BUTTONS (outside panel)\n ======================================== */\n\n.vs-icon-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n\n.vs-icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n color: var(--mj-brand-primary);\n}\n\n.vs-icon-btn i {\n font-size: 12px;\n}\n\n.vs-export-btn:hover {\n color: var(--mj-status-success);\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .vs-button {\n min-width: 100px;\n max-width: 180px;\n padding: 6px 10px;\n }\n\n .vs-panel {\n width: calc(100vw - 32px);\n max-width: 400px;\n }\n}\n"], encapsulation: 2 });
|
|
871
871
|
}
|
|
872
872
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ViewSelectorComponent, [{
|
|
873
873
|
type: Component,
|
|
874
|
-
args: [{ standalone: false, selector: 'mj-view-selector', encapsulation: ViewEncapsulation.None, template: "<div class=\"vs-container\">\n <!-- Backdrop for closing panel -->\n @if (IsDropdownOpen) {\n <div class=\"vs-backdrop\" (click)=\"CloseDropdown()\"></div>\n }\n\n <!-- Main View Selector Button -->\n <div class=\"vs-wrapper\">\n <button\n class=\"vs-button\"\n [class.modified]=\"ViewModified\"\n [class.open]=\"IsDropdownOpen\"\n (click)=\"ToggleDropdown()\"\n [disabled]=\"IsLoading\"\n title=\"Select a saved view\">\n <i class=\"fa-solid fa-layer-group vs-btn-icon\"></i>\n <span class=\"vs-btn-name\">{{ DisplayName }}</span>\n @if (ViewModified) {\n <span class=\"vs-modified-dot\" title=\"View has unsaved changes\">\u2022</span>\n }\n <i class=\"fa-solid fa-chevron-down vs-arrow\" [class.rotated]=\"IsDropdownOpen\"></i>\n </button>\n\n <!-- Rich View Panel -->\n @if (IsDropdownOpen) {\n <div class=\"vs-panel\">\n <!-- Panel Header -->\n <div class=\"vs-panel-header\">\n <i class=\"fa-solid fa-table-list vs-header-icon\"></i>\n <span class=\"vs-panel-title\">Views</span>\n @if (Entity) {\n <span class=\"vs-Entity-badge\">{{ Entity.DisplayNameOrName }}</span>\n }\n <button class=\"vs-close-btn\" (click)=\"CloseDropdown()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Search -->\n <div class=\"vs-panel-search\">\n <input\n type=\"text\"\n class=\"vs-search-input\"\n placeholder=\"Search views...\"\n [(ngModel)]=\"SearchText\"\n (keydown.escape)=\"SearchText = ''\"\n />\n </div>\n\n <!-- Panel Body -->\n <div class=\"vs-panel-body\">\n <!-- Default Option -->\n <div class=\"vs-section\">\n <div\n class=\"vs-card\"\n [class.active]=\"!SelectedViewID\"\n (click)=\"SelectDefault()\">\n <div class=\"vs-card-icon\" [class.active]=\"!SelectedViewID\">\n <i class=\"fa-solid fa-table\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">(Default)</div>\n </div>\n @if (!SelectedViewID) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n </div>\n\n <!-- My Views Section -->\n @if (FilteredMyViews.length > 0) {\n <div class=\"vs-section\">\n <div class=\"vs-section-header\">\n <i class=\"fa-solid fa-user\"></i>\n <span>My Views</span>\n <span class=\"vs-section-count\">{{ FilteredMyViews.length }}</span>\n </div>\n @for (view of FilteredMyViews; track view.id) {\n <div\n class=\"vs-card\"\n [class.active]=\"SelectedViewID === view.id\"\n (click)=\"SelectView(view)\">\n <div class=\"vs-card-icon\" [class.active]=\"SelectedViewID === view.id\">\n <i class=\"fa-solid fa-table-list\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">\n {{ view.name }}\n @if (view.isDefault) {\n <span class=\"vs-default-badge\">Default</span>\n }\n </div>\n @if (view.entity.Description) {\n <div class=\"vs-card-desc\">{{ view.entity.Description }}</div>\n }\n @if (GetViewFilterCount(view) > 0 || GetViewColumnCount(view) > 0 || GetViewSortInfo(view)) {\n <div class=\"vs-card-meta\">\n @if (GetViewFilterCount(view) > 0) {\n <span><i class=\"fa-solid fa-filter\"></i> {{ GetViewFilterCount(view) }} filter{{ GetViewFilterCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewColumnCount(view) > 0) {\n <span><i class=\"fa-solid fa-table-columns\"></i> {{ GetViewColumnCount(view) }} col{{ GetViewColumnCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewSortInfo(view)) {\n <span><i class=\"fa-solid fa-arrow-down-short-wide\"></i> {{ GetViewSortInfo(view) }}</span>\n }\n </div>\n }\n </div>\n <div class=\"vs-card-actions\">\n <button\n class=\"vs-action-btn\"\n (click)=\"OnDuplicateView(view.id, $event)\"\n title=\"Duplicate\">\n <i class=\"fa-regular fa-copy\"></i>\n </button>\n <button\n class=\"vs-action-btn\"\n (click)=\"OnConfigureViewById(view.id, $event)\"\n title=\"Configure\">\n <i class=\"fa-solid fa-sliders\"></i>\n </button>\n <button\n class=\"vs-action-btn\"\n (click)=\"OnOpenViewInTab(view.id, $event)\"\n title=\"Open in Tab\">\n <i class=\"fa-solid fa-up-right-from-square\"></i>\n </button>\n </div>\n @if (SelectedViewID === view.id) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n }\n </div>\n }\n\n <!-- Shared Views Section -->\n @if (FilteredSharedViews.length > 0) {\n <div class=\"vs-section\">\n <div class=\"vs-section-header\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n <span>Shared With Me</span>\n <span class=\"vs-section-count\">{{ FilteredSharedViews.length }}</span>\n </div>\n @for (view of FilteredSharedViews; track view.id) {\n <div\n class=\"vs-card\"\n [class.active]=\"SelectedViewID === view.id\"\n (click)=\"SelectView(view)\">\n <div class=\"vs-card-icon shared\">\n <i class=\"fa-solid fa-users\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">\n {{ view.name }}\n @if (!view.userCanEdit) {\n <span class=\"vs-shared-badge\">View Only</span>\n } @else {\n <span class=\"vs-shared-badge editable\">Can Edit</span>\n }\n </div>\n @if (view.entity.Description) {\n <div class=\"vs-card-desc\">{{ view.entity.Description }}</div>\n }\n @if (GetViewFilterCount(view) > 0 || GetViewColumnCount(view) > 0) {\n <div class=\"vs-card-meta\">\n @if (GetViewFilterCount(view) > 0) {\n <span><i class=\"fa-solid fa-filter\"></i> {{ GetViewFilterCount(view) }} filter{{ GetViewFilterCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewColumnCount(view) > 0) {\n <span><i class=\"fa-solid fa-table-columns\"></i> {{ GetViewColumnCount(view) }} col{{ GetViewColumnCount(view) !== 1 ? 's' : '' }}</span>\n }\n </div>\n }\n </div>\n <div class=\"vs-card-actions\">\n <button\n class=\"vs-action-btn\"\n (click)=\"OnDuplicateView(view.id, $event)\"\n title=\"Duplicate as My View\">\n <i class=\"fa-regular fa-copy\"></i>\n </button>\n @if (view.userCanEdit) {\n <button\n class=\"vs-action-btn\"\n (click)=\"OnConfigureViewById(view.id, $event)\"\n title=\"Configure\">\n <i class=\"fa-solid fa-sliders\"></i>\n </button>\n }\n </div>\n @if (SelectedViewID === view.id) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n }\n </div>\n }\n\n <!-- No Views Message -->\n @if (!HasViews && !IsLoading) {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-bookmark\"\n Title=\"No saved views yet\"\n Message=\"Save your current configuration as a view\" />\n }\n\n <!-- No Search Results -->\n @if (HasViews && FilteredMyViews.length === 0 && FilteredSharedViews.length === 0 && SearchText) {\n <mj-empty-state\n Size=\"compact\"\n Variant=\"no-results\"\n [Title]=\"NoViewsMatchMessage\" />\n }\n\n <!-- Loading Indicator -->\n @if (IsLoading) {\n <div class=\"vs-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading views...</span>\n </div>\n }\n </div>\n\n <!-- Panel Footer -->\n <div class=\"vs-panel-footer\">\n <button\n class=\"vs-panel-btn primary\"\n (click)=\"OnQuickSave()\"\n title=\"Save current view configuration\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New View</span>\n </button>\n <button\n class=\"vs-panel-btn\"\n (click)=\"OnResetToDefault()\"\n title=\"Reset to default view\">\n <i class=\"fa-solid fa-arrow-rotate-left\"></i>\n <span>Reset to Default</span>\n </button>\n </div>\n </div>\n }\n </div>\n\n <!-- Open in Tab Button (only visible when a view is selected) -->\n @if (SelectedViewID) {\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnOpenInTab()\"\n title=\"Open this view in a new tab\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n\n <!-- Configure View Button -->\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnConfigureView()\"\n title=\"Configure view settings (columns, filters, sorting)\">\n <i class=\"fa-solid fa-sliders-h\"></i>\n </button>\n\n <!-- Create New Record Button -->\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnCreateNewRecord()\"\n title=\"Create new record\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n\n <!-- Export Button -->\n <button\n class=\"vs-icon-btn vs-export-btn\"\n (click)=\"OnExport()\"\n title=\"Export\">\n <i class=\"fa-solid fa-file-excel\"></i>\n </button>\n</div>\n", styles: ["/* ========================================\n VIEW SELECTOR - All classes prefixed vs-\n to avoid conflicts (ViewEncapsulation.None)\n ======================================== */\n\n/* Container */\n.vs-container {\n display: flex;\n align-items: center;\n gap: 4px;\n position: relative;\n}\n\n/* Backdrop for closing panel */\n.vs-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.vs-wrapper {\n position: relative;\n}\n\n/* Main Button */\n.vs-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 140px;\n max-width: 280px;\n}\n\n.vs-button:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.vs-button.open {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button.modified {\n border-color: var(--mj-status-warning);\n}\n\n.vs-btn-icon {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.vs-btn-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.vs-modified-dot {\n color: var(--mj-status-warning);\n font-weight: bold;\n font-size: 18px;\n line-height: 1;\n}\n\n.vs-arrow {\n color: var(--mj-text-muted);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.vs-arrow.rotated {\n transform: rotate(180deg);\n}\n\n/* ========================================\n RICH VIEW PANEL\n Styles ported directly from prototype\n ======================================== */\n\n/* Reset inherited styles inside panel */\n.vs-panel,\n.vs-panel * {\n box-sizing: border-box;\n line-height: 1.5;\n text-align: left;\n}\n\n.vs-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n width: 400px;\n max-width: calc(100vw - 40px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.16);\n z-index: 1000;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--mj-text-primary);\n}\n\n/* Panel Header */\n.vs-panel-header {\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-header-icon {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.vs-panel-title {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.vs-entity-badge {\n font-size: 11px;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.vs-close-btn {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 16px;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-close-btn:hover {\n color: var(--mj-text-primary);\n}\n\n/* Panel Search */\n.vs-panel-search {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-search-input {\n width: 100%;\n padding: 6px 12px 6px 32px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n font-size: 13px;\n background: var(--mj-bg-surface-card) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='%23999'%3E%3Cpath d='M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208z'/%3E%3C/svg%3E\") no-repeat 10px center;\n background-size: 14px;\n box-sizing: border-box;\n font-family: inherit;\n}\n\n.vs-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n}\n\n.vs-search-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n/* Panel Body */\n.vs-panel-body {\n max-height: 400px;\n overflow-y: auto;\n}\n\n/* View Section */\n.vs-section {\n padding: 8px 0;\n}\n\n.vs-section-header {\n padding: 6px 20px;\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-section-header i {\n font-size: 10px;\n}\n\n.vs-section-count {\n background: var(--mj-border-default);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n}\n\n/* View Card */\n.vs-card {\n padding: 10px 20px;\n cursor: pointer;\n transition: background 0.1s;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.vs-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-card.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n padding-left: 17px;\n}\n\n/* View Card Icon */\n.vs-card-icon {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card-icon.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.vs-card-icon.shared {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-muted);\n}\n\n/* View Card Content */\n.vs-card-content {\n flex: 1;\n min-width: 0;\n padding-top: 4px;\n}\n\n.vs-card-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-card.active .vs-card-name {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.vs-default-badge {\n font-size: 9px;\n font-weight: 600;\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n padding: 1px 5px;\n border-radius: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.vs-shared-badge {\n font-size: 9px;\n font-weight: 600;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 1px 5px;\n border-radius: 6px;\n}\n\n.vs-shared-badge.editable {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.vs-card-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.vs-card-meta {\n display: flex;\n gap: 10px;\n margin-top: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.vs-card-meta span {\n display: flex;\n align-items: center;\n gap: 3px;\n}\n\n.vs-card-meta i {\n font-size: 10px;\n}\n\n/* View Card Check */\n.vs-card-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n/* View Card Actions (hover reveal) */\n.vs-card-actions {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.15s;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card:hover .vs-card-actions {\n opacity: 1;\n}\n\n.vs-action-btn {\n width: 26px;\n height: 26px;\n border-radius: 4px;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-action-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n}\n\n/* Loading */\n.vs-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n text-align: center;\n}\n\n/* Panel Footer */\n.vs-panel-footer {\n padding: 12px 20px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n gap: 8px;\n}\n\n.vs-panel-btn {\n flex: 1;\n padding: 8px 12px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.15s;\n font-family: inherit;\n text-align: center;\n}\n\n.vs-panel-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.vs-panel-btn i {\n font-size: 11px;\n}\n\n/* ========================================\n ICON BUTTONS (outside panel)\n ======================================== */\n\n.vs-icon-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n\n.vs-icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n color: var(--mj-brand-primary);\n}\n\n.vs-icon-btn i {\n font-size: 12px;\n}\n\n.vs-export-btn:hover {\n color: var(--mj-status-success);\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .vs-button {\n min-width: 100px;\n max-width: 180px;\n padding: 6px 10px;\n }\n\n .vs-panel {\n width: calc(100vw - 32px);\n max-width: 400px;\n }\n}\n"] }]
|
|
874
|
+
args: [{ standalone: false, selector: 'mj-view-selector', encapsulation: ViewEncapsulation.None, template: "<div class=\"vs-container\">\n <!-- Backdrop for closing panel -->\n @if (IsDropdownOpen) {\n <div class=\"vs-backdrop\" (click)=\"CloseDropdown()\"></div>\n }\n\n <!-- Main View Selector Button -->\n <div class=\"vs-wrapper\">\n <button\n class=\"vs-button\"\n [class.modified]=\"ViewModified\"\n [class.open]=\"IsDropdownOpen\"\n (click)=\"ToggleDropdown()\"\n [disabled]=\"IsLoading\"\n title=\"Select a saved view\">\n <i class=\"fa-solid fa-layer-group vs-btn-icon\"></i>\n <span class=\"vs-btn-name\">{{ DisplayName }}</span>\n @if (ViewModified) {\n <span class=\"vs-modified-dot\" title=\"View has unsaved changes\">\u2022</span>\n }\n <i class=\"fa-solid fa-chevron-down vs-arrow\" [class.rotated]=\"IsDropdownOpen\"></i>\n </button>\n\n <!-- Rich View Panel -->\n @if (IsDropdownOpen) {\n <div class=\"vs-panel\">\n <!-- Panel Header -->\n <div class=\"vs-panel-header\">\n <i class=\"fa-solid fa-table-list vs-header-icon\"></i>\n <span class=\"vs-panel-title\">Views</span>\n @if (Entity) {\n <span class=\"vs-Entity-badge\">{{ Entity.DisplayNameOrName }}</span>\n }\n <button class=\"vs-close-btn\" (click)=\"CloseDropdown()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Search -->\n <div class=\"vs-panel-search\">\n <input\n type=\"text\"\n class=\"vs-search-input\"\n placeholder=\"Search views...\"\n [(ngModel)]=\"SearchText\"\n (keydown.escape)=\"SearchText = ''\"\n />\n </div>\n\n <!-- Panel Body -->\n <div class=\"vs-panel-body\">\n <!-- Default Option -->\n <div class=\"vs-section\">\n <div\n class=\"vs-card\"\n [class.active]=\"!SelectedViewID\"\n (click)=\"SelectDefault()\">\n <div class=\"vs-card-icon\" [class.active]=\"!SelectedViewID\">\n <i class=\"fa-solid fa-table\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">(Default)</div>\n </div>\n @if (!SelectedViewID) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n </div>\n\n <!-- My Views Section -->\n @if (FilteredMyViews.length > 0) {\n <div class=\"vs-section\">\n <div class=\"vs-section-header\">\n <i class=\"fa-solid fa-user\"></i>\n <span>My Views</span>\n <span class=\"vs-section-count\">{{ FilteredMyViews.length }}</span>\n </div>\n @for (view of FilteredMyViews; track view.id) {\n <div\n class=\"vs-card\"\n [class.active]=\"SelectedViewID === view.id\"\n (click)=\"SelectView(view)\">\n <div class=\"vs-card-icon\" [class.active]=\"SelectedViewID === view.id\">\n <i class=\"fa-solid fa-table-list\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">\n {{ view.name }}\n @if (view.isDefault) {\n <span class=\"vs-default-badge\">Default</span>\n }\n </div>\n @if (view.entity.Description) {\n <div class=\"vs-card-desc\">{{ view.entity.Description }}</div>\n }\n @if (GetViewFilterCount(view) > 0 || GetViewColumnCount(view) > 0 || GetViewSortInfo(view)) {\n <div class=\"vs-card-meta\">\n @if (GetViewFilterCount(view) > 0) {\n <span><i class=\"fa-solid fa-filter\"></i> {{ GetViewFilterCount(view) }} filter{{ GetViewFilterCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewColumnCount(view) > 0) {\n <span><i class=\"fa-solid fa-table-columns\"></i> {{ GetViewColumnCount(view) }} col{{ GetViewColumnCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewSortInfo(view)) {\n <span><i class=\"fa-solid fa-arrow-down-short-wide\"></i> {{ GetViewSortInfo(view) }}</span>\n }\n </div>\n }\n </div>\n <div class=\"vs-card-actions\">\n <button\n class=\"vs-action-btn\"\n (click)=\"OnDuplicateView(view.id, $event)\"\n title=\"Duplicate\">\n <i class=\"fa-regular fa-copy\"></i>\n </button>\n <button\n class=\"vs-action-btn\"\n (click)=\"OnConfigureViewById(view.id, $event)\"\n title=\"Configure\">\n <i class=\"fa-solid fa-sliders\"></i>\n </button>\n <button\n class=\"vs-action-btn\"\n (click)=\"OnOpenViewInTab(view.id, $event)\"\n title=\"Open in Tab\">\n <i class=\"fa-solid fa-up-right-from-square\"></i>\n </button>\n </div>\n @if (SelectedViewID === view.id) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n }\n </div>\n }\n\n <!-- Shared Views Section -->\n @if (FilteredSharedViews.length > 0) {\n <div class=\"vs-section\">\n <div class=\"vs-section-header\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n <span>Shared With Me</span>\n <span class=\"vs-section-count\">{{ FilteredSharedViews.length }}</span>\n </div>\n @for (view of FilteredSharedViews; track view.id) {\n <div\n class=\"vs-card\"\n [class.active]=\"SelectedViewID === view.id\"\n (click)=\"SelectView(view)\">\n <div class=\"vs-card-icon shared\">\n <i class=\"fa-solid fa-users\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">\n {{ view.name }}\n @if (!view.userCanEdit) {\n <span class=\"vs-shared-badge\">View Only</span>\n } @else {\n <span class=\"vs-shared-badge editable\">Can Edit</span>\n }\n </div>\n @if (view.entity.Description) {\n <div class=\"vs-card-desc\">{{ view.entity.Description }}</div>\n }\n @if (GetViewFilterCount(view) > 0 || GetViewColumnCount(view) > 0) {\n <div class=\"vs-card-meta\">\n @if (GetViewFilterCount(view) > 0) {\n <span><i class=\"fa-solid fa-filter\"></i> {{ GetViewFilterCount(view) }} filter{{ GetViewFilterCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewColumnCount(view) > 0) {\n <span><i class=\"fa-solid fa-table-columns\"></i> {{ GetViewColumnCount(view) }} col{{ GetViewColumnCount(view) !== 1 ? 's' : '' }}</span>\n }\n </div>\n }\n </div>\n <div class=\"vs-card-actions\">\n <button\n class=\"vs-action-btn\"\n (click)=\"OnDuplicateView(view.id, $event)\"\n title=\"Duplicate as My View\">\n <i class=\"fa-regular fa-copy\"></i>\n </button>\n @if (view.userCanEdit) {\n <button\n class=\"vs-action-btn\"\n (click)=\"OnConfigureViewById(view.id, $event)\"\n title=\"Configure\">\n <i class=\"fa-solid fa-sliders\"></i>\n </button>\n }\n </div>\n @if (SelectedViewID === view.id) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n }\n </div>\n }\n\n <!-- No Views Message -->\n @if (!HasViews && !IsLoading) {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-bookmark\"\n Title=\"No saved views yet\"\n Message=\"Save your current configuration as a view\" />\n }\n\n <!-- No Search Results -->\n @if (HasViews && FilteredMyViews.length === 0 && FilteredSharedViews.length === 0 && SearchText) {\n <mj-empty-state\n Size=\"compact\"\n Variant=\"no-results\"\n [Title]=\"NoViewsMatchMessage\" />\n }\n\n <!-- Loading Indicator -->\n @if (IsLoading) {\n <div class=\"vs-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading views...</span>\n </div>\n }\n </div>\n\n <!-- Panel Footer -->\n <div class=\"vs-panel-footer\">\n <button\n class=\"vs-panel-btn primary\"\n (click)=\"OnQuickSave()\"\n title=\"Save current view configuration\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New View</span>\n </button>\n <button\n class=\"vs-panel-btn\"\n (click)=\"OnResetToDefault()\"\n title=\"Reset to default view\">\n <i class=\"fa-solid fa-arrow-rotate-left\"></i>\n <span>Reset to Default</span>\n </button>\n </div>\n </div>\n }\n </div>\n\n <!-- Open in Tab Button (only visible when a view is selected) -->\n @if (SelectedViewID) {\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnOpenInTab()\"\n title=\"Open this view in a new tab\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n\n <!-- Configure View Button -->\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnConfigureView()\"\n title=\"Configure view settings (columns, filters, sorting)\">\n <i class=\"fa-solid fa-sliders-h\"></i>\n </button>\n\n <!-- Create New Record Button -->\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnCreateNewRecord()\"\n title=\"Create new record\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n\n <!-- Export Button -->\n <button\n class=\"vs-icon-btn vs-export-btn\"\n (click)=\"OnExport()\"\n title=\"Export\">\n <i class=\"fa-solid fa-file-excel\"></i>\n </button>\n</div>\n", styles: ["/* ========================================\n VIEW SELECTOR - All classes prefixed vs-\n to avoid conflicts (ViewEncapsulation.None)\n ======================================== */\n\n/* Container */\n.vs-container {\n display: flex;\n align-items: center;\n gap: 4px;\n position: relative;\n}\n\n/* Backdrop for closing panel */\n.vs-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.vs-wrapper {\n position: relative;\n}\n\n/* Main Button */\n.vs-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 140px;\n max-width: 280px;\n}\n\n.vs-button:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.vs-button.open {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button.modified {\n border-color: var(--mj-status-warning);\n}\n\n.vs-btn-icon {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.vs-btn-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.vs-modified-dot {\n color: var(--mj-status-warning);\n font-weight: bold;\n font-size: 18px;\n line-height: 1;\n}\n\n.vs-arrow {\n color: var(--mj-text-muted);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.vs-arrow.rotated {\n transform: rotate(180deg);\n}\n\n/* ========================================\n RICH VIEW PANEL\n Styles ported directly from prototype\n ======================================== */\n\n/* Reset inherited styles inside panel */\n.vs-panel,\n.vs-panel * {\n box-sizing: border-box;\n line-height: 1.5;\n text-align: left;\n}\n\n.vs-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n width: 400px;\n max-width: calc(100vw - 40px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.16);\n z-index: 1000;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--mj-text-primary);\n}\n\n/* Panel Header */\n.vs-panel-header {\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-header-icon {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.vs-panel-title {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.vs-entity-badge {\n font-size: 11px;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.vs-close-btn {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 16px;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-close-btn:hover {\n color: var(--mj-text-primary);\n}\n\n/* Panel Search */\n.vs-panel-search {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-search-input {\n width: 100%;\n padding: 6px 12px 6px 32px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n font-size: 13px;\n background: var(--mj-bg-surface-card) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='%23999'%3E%3Cpath d='M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208z'/%3E%3C/svg%3E\") no-repeat 10px center;\n background-size: 14px;\n box-sizing: border-box;\n font-family: inherit;\n}\n\n.vs-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n}\n\n.vs-search-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n/* Panel Body */\n.vs-panel-body {\n max-height: 400px;\n overflow-y: auto;\n}\n\n/* View Section */\n.vs-section {\n padding: 8px 0;\n}\n\n.vs-section-header {\n padding: 6px 20px;\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-section-header i {\n font-size: 10px;\n}\n\n.vs-section-count {\n background: var(--mj-border-default);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n}\n\n/* View Card */\n.vs-card {\n padding: 10px 20px;\n cursor: pointer;\n transition: background 0.1s;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.vs-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-card.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n padding-left: 17px;\n}\n\n/* View Card Icon */\n.vs-card-icon {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card-icon.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.vs-card-icon.shared {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-muted);\n}\n\n/* View Card Content */\n.vs-card-content {\n flex: 1;\n min-width: 0;\n padding-top: 4px;\n}\n\n.vs-card-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-card.active .vs-card-name {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.vs-default-badge {\n font-size: 9px;\n font-weight: 600;\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n padding: 1px 5px;\n border-radius: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.vs-shared-badge {\n font-size: 9px;\n font-weight: 600;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 1px 5px;\n border-radius: 6px;\n}\n\n.vs-shared-badge.editable {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.vs-card-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.vs-card-meta {\n display: flex;\n gap: 10px;\n margin-top: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.vs-card-meta span {\n display: flex;\n align-items: center;\n gap: 3px;\n}\n\n.vs-card-meta i {\n font-size: 10px;\n}\n\n/* View Card Check */\n.vs-card-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n/* View Card Actions (hover reveal) */\n.vs-card-actions {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.15s;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n/* :focus-within matters as much as :hover \u2014 these buttons (Duplicate, Configure,\n Open in Tab) were reachable ONLY by pointer. A keyboard user could tab into them\n and see nothing at opacity 0, and anything driving the page without a hover\n (assistive tech, automation) could not reach them at all. */\n.vs-card:hover .vs-card-actions,\n.vs-card:focus-within .vs-card-actions {\n opacity: 1;\n}\n\n.vs-action-btn {\n width: 26px;\n height: 26px;\n border-radius: 4px;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-action-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n}\n\n/* Loading */\n.vs-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n text-align: center;\n}\n\n/* Panel Footer */\n.vs-panel-footer {\n padding: 12px 20px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n gap: 8px;\n}\n\n.vs-panel-btn {\n flex: 1;\n padding: 8px 12px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.15s;\n font-family: inherit;\n text-align: center;\n}\n\n.vs-panel-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.vs-panel-btn i {\n font-size: 11px;\n}\n\n/* ========================================\n ICON BUTTONS (outside panel)\n ======================================== */\n\n.vs-icon-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n\n.vs-icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n color: var(--mj-brand-primary);\n}\n\n.vs-icon-btn i {\n font-size: 12px;\n}\n\n.vs-export-btn:hover {\n color: var(--mj-status-success);\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .vs-button {\n min-width: 100px;\n max-width: 180px;\n padding: 6px 10px;\n }\n\n .vs-panel {\n width: calc(100vw - 32px);\n max-width: 400px;\n }\n}\n"] }]
|
|
875
875
|
}], () => [{ type: i0.ChangeDetectorRef }], { Entity: [{
|
|
876
876
|
type: Input
|
|
877
877
|
}], SelectedViewID: [{
|
|
@@ -54,14 +54,22 @@ export declare class CardsViewRendererComponent extends BaseAngularComponent imp
|
|
|
54
54
|
* type's `config`), so the host sets it via a guarded `setInput`. Type matches
|
|
55
55
|
* {@link EntityCardsComponent.cardTemplate}.
|
|
56
56
|
*/
|
|
57
|
-
|
|
57
|
+
CardTemplate: CardTemplate | null;
|
|
58
|
+
/** @deprecated Use {@link CardTemplate}. */
|
|
59
|
+
set cardTemplate(value: CardTemplate | null);
|
|
60
|
+
/** @deprecated Use {@link CardTemplate}. */
|
|
61
|
+
get cardTemplate(): CardTemplate | null;
|
|
58
62
|
/**
|
|
59
63
|
* Optional map of record primary-key strings → hidden field names that matched the active
|
|
60
64
|
* filter, used by the cards view to flag matches in non-visible fields. Host-level config,
|
|
61
65
|
* set by the host via a guarded `setInput`. Type matches
|
|
62
66
|
* {@link EntityCardsComponent.hiddenFieldMatches}.
|
|
63
67
|
*/
|
|
64
|
-
|
|
68
|
+
HiddenFieldMatches: Map<string, string>;
|
|
69
|
+
/** @deprecated Use {@link HiddenFieldMatches}. */
|
|
70
|
+
set hiddenFieldMatches(value: Map<string, string>);
|
|
71
|
+
/** @deprecated Use {@link HiddenFieldMatches}. */
|
|
72
|
+
get hiddenFieldMatches(): Map<string, string>;
|
|
65
73
|
/** Emitted when a record is selected (single click) — payload is the raw record object. */
|
|
66
74
|
recordSelected: EventEmitter<unknown>;
|
|
67
75
|
/** Emitted when a record should be opened (double-click / open) — payload is the raw record object. */
|
|
@@ -75,14 +83,18 @@ export declare class CardsViewRendererComponent extends BaseAngularComponent imp
|
|
|
75
83
|
* Relay `<mj-entity-cards>`'s selection event, normalizing to the raw record the host
|
|
76
84
|
* expects (the host builds the composite key itself).
|
|
77
85
|
*/
|
|
86
|
+
OnRecordSelected(event: RecordSelectedEvent): void;
|
|
87
|
+
/** @deprecated Use {@link OnRecordSelected}. */
|
|
78
88
|
onRecordSelected(event: RecordSelectedEvent): void;
|
|
79
89
|
/**
|
|
80
90
|
* Relay `<mj-entity-cards>`'s open event, normalizing to the raw record the host expects
|
|
81
91
|
* (the host builds the composite key itself).
|
|
82
92
|
*/
|
|
93
|
+
OnRecordOpened(event: RecordOpenedEvent): void;
|
|
94
|
+
/** @deprecated Use {@link OnRecordOpened}. */
|
|
83
95
|
onRecordOpened(event: RecordOpenedEvent): void;
|
|
84
96
|
static ɵfac: i0.ɵɵFactoryDeclaration<CardsViewRendererComponent, never>;
|
|
85
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<CardsViewRendererComponent, "mj-cards-view-renderer", never, { "entity": { "alias": "entity"; "required": false; }; "records": { "alias": "records"; "required": false; }; "selectedRecordId": { "alias": "selectedRecordId"; "required": false; }; "filterText": { "alias": "filterText"; "required": false; }; "config": { "alias": "config"; "required": false; }; "cardTemplate": { "alias": "cardTemplate"; "required": false; }; "hiddenFieldMatches": { "alias": "hiddenFieldMatches"; "required": false; }; }, { "recordSelected": "recordSelected"; "recordOpened": "recordOpened"; "configChanged": "configChanged"; }, never, never, false, never>;
|
|
97
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<CardsViewRendererComponent, "mj-cards-view-renderer", never, { "entity": { "alias": "entity"; "required": false; }; "records": { "alias": "records"; "required": false; }; "selectedRecordId": { "alias": "selectedRecordId"; "required": false; }; "filterText": { "alias": "filterText"; "required": false; }; "config": { "alias": "config"; "required": false; }; "CardTemplate": { "alias": "CardTemplate"; "required": false; }; "cardTemplate": { "alias": "cardTemplate"; "required": false; }; "HiddenFieldMatches": { "alias": "HiddenFieldMatches"; "required": false; }; "hiddenFieldMatches": { "alias": "hiddenFieldMatches"; "required": false; }; }, { "recordSelected": "recordSelected"; "recordOpened": "recordOpened"; "configChanged": "configChanged"; }, never, never, false, never>;
|
|
86
98
|
}
|
|
87
99
|
/**
|
|
88
100
|
* Tree-shaking guard. Force-references this renderer so bundlers (ESBuild/Vite) don't drop the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cards-view-renderer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/view-types/renderers/cards-view-renderer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAqB,MAAM,eAAe,CAAC;AAC1F,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;;AAGnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBA2Ba,0BAA2B,SAAQ,oBAAqB,YAAW,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAGpH,mDAAmD;IAC1C,MAAM,EAAE,UAAU,GAAG,IAAI,CAAQ;IAE1C,mEAAmE;IAC1D,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAM;IAEjD,mEAAmE;IAC1D,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEhD,0EAA0E;IACjE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE1C;;;OAGG;IACM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM;IAI9C;;;;OAIG;IACM,YAAY,EAAE,YAAY,GAAG,IAAI,CAAQ;IAElD;;;;;OAKG;IACM,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAa;
|
|
1
|
+
{"version":3,"file":"cards-view-renderer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/view-types/renderers/cards-view-renderer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAqB,MAAM,eAAe,CAAC;AAC1F,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;;AAGnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBA2Ba,0BAA2B,SAAQ,oBAAqB,YAAW,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAGpH,mDAAmD;IAC1C,MAAM,EAAE,UAAU,GAAG,IAAI,CAAQ;IAE1C,mEAAmE;IAC1D,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAM;IAEjD,mEAAmE;IAC1D,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEhD,0EAA0E;IACjE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE1C;;;OAGG;IACM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM;IAI9C;;;;OAIG;IACM,YAAY,EAAE,YAAY,GAAG,IAAI,CAAQ;IAElD,4CAA4C;IAC5C,IAAa,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,EAEnD;IACD,4CAA4C;IAC5C,IAAI,YAAY,IAAI,YAAY,GAAG,IAAI,CAEtC;IAED;;;;;OAKG;IACM,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAa;IAE7D,kDAAkD;IAClD,IAAa,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAEzD;IACD,kDAAkD;IAClD,IAAI,kBAAkB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAE5C;IAID,2FAA2F;IACjF,cAAc,wBAA+B;IAEvD,uGAAuG;IAC7F,YAAY,wBAA+B;IAErD;;;OAGG;IACO,aAAa,wCAA+C;IAEtE;;;OAGG;IACH,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAIlD,gDAAgD;IAChD,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAIlD;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAI9C,8CAA8C;IAC9C,cAAc,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;yCA5FnC,0BAA0B;2CAA1B,0BAA0B;CA+FtC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
|
|
@@ -54,14 +54,30 @@ export class CardsViewRendererComponent extends BaseAngularComponent {
|
|
|
54
54
|
* type's `config`), so the host sets it via a guarded `setInput`. Type matches
|
|
55
55
|
* {@link EntityCardsComponent.cardTemplate}.
|
|
56
56
|
*/
|
|
57
|
-
|
|
57
|
+
CardTemplate = null;
|
|
58
|
+
/** @deprecated Use {@link CardTemplate}. */
|
|
59
|
+
set cardTemplate(value) {
|
|
60
|
+
this.CardTemplate = value;
|
|
61
|
+
}
|
|
62
|
+
/** @deprecated Use {@link CardTemplate}. */
|
|
63
|
+
get cardTemplate() {
|
|
64
|
+
return this.CardTemplate;
|
|
65
|
+
}
|
|
58
66
|
/**
|
|
59
67
|
* Optional map of record primary-key strings → hidden field names that matched the active
|
|
60
68
|
* filter, used by the cards view to flag matches in non-visible fields. Host-level config,
|
|
61
69
|
* set by the host via a guarded `setInput`. Type matches
|
|
62
70
|
* {@link EntityCardsComponent.hiddenFieldMatches}.
|
|
63
71
|
*/
|
|
64
|
-
|
|
72
|
+
HiddenFieldMatches = new Map();
|
|
73
|
+
/** @deprecated Use {@link HiddenFieldMatches}. */
|
|
74
|
+
set hiddenFieldMatches(value) {
|
|
75
|
+
this.HiddenFieldMatches = value;
|
|
76
|
+
}
|
|
77
|
+
/** @deprecated Use {@link HiddenFieldMatches}. */
|
|
78
|
+
get hiddenFieldMatches() {
|
|
79
|
+
return this.HiddenFieldMatches;
|
|
80
|
+
}
|
|
65
81
|
// ---- IViewRenderer outputs ----
|
|
66
82
|
/** Emitted when a record is selected (single click) — payload is the raw record object. */
|
|
67
83
|
recordSelected = new EventEmitter();
|
|
@@ -76,18 +92,26 @@ export class CardsViewRendererComponent extends BaseAngularComponent {
|
|
|
76
92
|
* Relay `<mj-entity-cards>`'s selection event, normalizing to the raw record the host
|
|
77
93
|
* expects (the host builds the composite key itself).
|
|
78
94
|
*/
|
|
79
|
-
|
|
95
|
+
OnRecordSelected(event) {
|
|
80
96
|
this.recordSelected.emit(event.record);
|
|
81
97
|
}
|
|
98
|
+
/** @deprecated Use {@link OnRecordSelected}. */
|
|
99
|
+
onRecordSelected(event) {
|
|
100
|
+
return this.OnRecordSelected(event);
|
|
101
|
+
}
|
|
82
102
|
/**
|
|
83
103
|
* Relay `<mj-entity-cards>`'s open event, normalizing to the raw record the host expects
|
|
84
104
|
* (the host builds the composite key itself).
|
|
85
105
|
*/
|
|
86
|
-
|
|
106
|
+
OnRecordOpened(event) {
|
|
87
107
|
this.recordOpened.emit(event.record);
|
|
88
108
|
}
|
|
109
|
+
/** @deprecated Use {@link OnRecordOpened}. */
|
|
110
|
+
onRecordOpened(event) {
|
|
111
|
+
return this.OnRecordOpened(event);
|
|
112
|
+
}
|
|
89
113
|
static ɵfac = /*@__PURE__*/ (() => { let ɵCardsViewRendererComponent_BaseFactory; return function CardsViewRendererComponent_Factory(__ngFactoryType__) { return (ɵCardsViewRendererComponent_BaseFactory || (ɵCardsViewRendererComponent_BaseFactory = i0.ɵɵgetInheritedFactory(CardsViewRendererComponent)))(__ngFactoryType__ || CardsViewRendererComponent); }; })();
|
|
90
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CardsViewRendererComponent, selectors: [["mj-cards-view-renderer"]], inputs: { entity: "entity", records: "records", selectedRecordId: "selectedRecordId", filterText: "filterText", config: "config", cardTemplate: "cardTemplate", hiddenFieldMatches: "hiddenFieldMatches" }, outputs: { recordSelected: "recordSelected", recordOpened: "recordOpened", configChanged: "configChanged" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 7, consts: [[3, "recordSelected", "recordOpened", "Provider", "entity", "records", "selectedRecordId", "cardTemplate", "hiddenFieldMatches", "filterText"]], template: function CardsViewRendererComponent_Template(rf, ctx) { if (rf & 1) {
|
|
114
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CardsViewRendererComponent, selectors: [["mj-cards-view-renderer"]], inputs: { entity: "entity", records: "records", selectedRecordId: "selectedRecordId", filterText: "filterText", config: "config", CardTemplate: "CardTemplate", cardTemplate: "cardTemplate", HiddenFieldMatches: "HiddenFieldMatches", hiddenFieldMatches: "hiddenFieldMatches" }, outputs: { recordSelected: "recordSelected", recordOpened: "recordOpened", configChanged: "configChanged" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 7, consts: [[3, "recordSelected", "recordOpened", "Provider", "entity", "records", "selectedRecordId", "cardTemplate", "hiddenFieldMatches", "filterText"]], template: function CardsViewRendererComponent_Template(rf, ctx) { if (rf & 1) {
|
|
91
115
|
i0.ɵɵelementStart(0, "mj-entity-cards", 0);
|
|
92
116
|
i0.ɵɵlistener("recordSelected", function CardsViewRendererComponent_Template_mj_entity_cards_recordSelected_0_listener($event) { return ctx.onRecordSelected($event); })("recordOpened", function CardsViewRendererComponent_Template_mj_entity_cards_recordOpened_0_listener($event) { return ctx.onRecordOpened($event); });
|
|
93
117
|
i0.ɵɵelementEnd();
|
|
@@ -121,8 +145,12 @@ export class CardsViewRendererComponent extends BaseAngularComponent {
|
|
|
121
145
|
type: Input
|
|
122
146
|
}], config: [{
|
|
123
147
|
type: Input
|
|
148
|
+
}], CardTemplate: [{
|
|
149
|
+
type: Input
|
|
124
150
|
}], cardTemplate: [{
|
|
125
151
|
type: Input
|
|
152
|
+
}], HiddenFieldMatches: [{
|
|
153
|
+
type: Input
|
|
126
154
|
}], hiddenFieldMatches: [{
|
|
127
155
|
type: Input
|
|
128
156
|
}], recordSelected: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cards-view-renderer.component.js","sourceRoot":"","sources":["../../../../src/lib/view-types/renderers/cards-view-renderer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;;AAKrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AA4BH,MAAM,OAAO,0BAA2B,SAAQ,oBAAoB;IAClE,mEAAmE;IAEnE,mDAAmD;IAC1C,MAAM,GAAsB,IAAI,CAAC;IAE1C,mEAAmE;IAC1D,OAAO,GAA8B,EAAE,CAAC;IAEjD,mEAAmE;IAC1D,gBAAgB,GAAkB,IAAI,CAAC;IAEhD,0EAA0E;IACjE,UAAU,GAAkB,IAAI,CAAC;IAE1C;;;OAGG;IACM,MAAM,GAA4B,EAAE,CAAC;IAE9C,0EAA0E;IAE1E;;;;OAIG;IACM,YAAY,GAAwB,IAAI,CAAC;IAElD;;;;;OAKG;IACM,kBAAkB,GAAwB,IAAI,GAAG,EAAE,CAAC;IAE7D,kCAAkC;IAElC,2FAA2F;IACjF,cAAc,GAAG,IAAI,YAAY,EAAW,CAAC;IAEvD,uGAAuG;IAC7F,YAAY,GAAG,IAAI,YAAY,EAAW,CAAC;IAErD;;;OAGG;IACO,aAAa,GAAG,IAAI,YAAY,EAA2B,CAAC;IAEtE;;;OAGG;IACH,gBAAgB,CAAC,KAA0B;QACzC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED;;;OAGG;IACH,cAAc,CAAC,KAAwB;QACrC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;
|
|
1
|
+
{"version":3,"file":"cards-view-renderer.component.js","sourceRoot":"","sources":["../../../../src/lib/view-types/renderers/cards-view-renderer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;;AAKrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AA4BH,MAAM,OAAO,0BAA2B,SAAQ,oBAAoB;IAClE,mEAAmE;IAEnE,mDAAmD;IAC1C,MAAM,GAAsB,IAAI,CAAC;IAE1C,mEAAmE;IAC1D,OAAO,GAA8B,EAAE,CAAC;IAEjD,mEAAmE;IAC1D,gBAAgB,GAAkB,IAAI,CAAC;IAEhD,0EAA0E;IACjE,UAAU,GAAkB,IAAI,CAAC;IAE1C;;;OAGG;IACM,MAAM,GAA4B,EAAE,CAAC;IAE9C,0EAA0E;IAE1E;;;;OAIG;IACM,YAAY,GAAwB,IAAI,CAAC;IAElD,4CAA4C;IAC5C,IAAa,YAAY,CAAC,KAA0B;QAClD,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;IAC5B,CAAC;IACD,4CAA4C;IAC5C,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED;;;;;OAKG;IACM,kBAAkB,GAAwB,IAAI,GAAG,EAAE,CAAC;IAE7D,kDAAkD;IAClD,IAAa,kBAAkB,CAAC,KAA0B;QACxD,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC;IAClC,CAAC;IACD,kDAAkD;IAClD,IAAI,kBAAkB;QACpB,OAAO,IAAI,CAAC,kBAAkB,CAAC;IACjC,CAAC;IAED,kCAAkC;IAElC,2FAA2F;IACjF,cAAc,GAAG,IAAI,YAAY,EAAW,CAAC;IAEvD,uGAAuG;IAC7F,YAAY,GAAG,IAAI,YAAY,EAAW,CAAC;IAErD;;;OAGG;IACO,aAAa,GAAG,IAAI,YAAY,EAA2B,CAAC;IAEtE;;;OAGG;IACH,gBAAgB,CAAC,KAA0B;QACzC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED,gDAAgD;IAChD,gBAAgB,CAAC,KAA0B;QACzC,OAAO,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IAED;;;OAGG;IACH,cAAc,CAAC,KAAwB;QACrC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,8CAA8C;IAC9C,cAAc,CAAC,KAAwB;QACrC,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;qRA9FU,0BAA0B,yBAA1B,0BAA0B;6DAA1B,0BAA0B;YAtBnC,0CAUC;YADC,AADA,wIAAkB,4BAAwB,IAAC,uHAC3B,0BAAsB,IAAC;YAEzC,iBAAkB;;YAJhB,AADA,AADA,AADA,AADA,AADA,AADA,uCAAqB,sBACJ,wBACE,0CACkB,kCACR,8CACY,oCACV;;;iFAexB,0BAA0B;cA3BtC,SAAS;6BACI,KAAK,YACP,wBAAwB,iBACnB,iBAAiB,CAAC,IAAI,YAC3B;;;;;;;;;;;;;GAaT;;kBAcA,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAML,KAAK;;kBASL,KAAK;;kBAGL,KAAK;;kBAcL,KAAK;;kBAGL,KAAK;;kBAWL,MAAM;;kBAGN,MAAM;;kBAMN,MAAM;;kFApEI,0BAA0B;AAiGvC;;;;GAIG;AACH,MAAM,UAAU,qBAAqB;IACnC,0DAA0D;AAC5D,CAAC","sourcesContent":["import { Component, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core';\nimport { EntityInfo } from '@memberjunction/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { IViewRenderer } from '../view-type.contracts';\nimport { CardTemplate, RecordSelectedEvent, RecordOpenedEvent } from '../../types';\nimport { EntityCardsComponent } from '../../entity-cards/entity-cards.component';\n\n/**\n * CardsViewRendererComponent\n * --------------------------\n * The Cards **view type** renderer — a thin {@link IViewRenderer} adapter that hosts the\n * existing {@link EntityCardsComponent} (`<mj-entity-cards>`) inside the entity-viewer's\n * pluggable view-type system. It is the dynamic-mounted plug-in that the `CardsViewType`\n * descriptor points at, replacing the descriptor's previous direct reference to\n * `EntityCardsComponent` (which did not honor the {@link IViewRenderer} contract).\n *\n * The host feeds the standard renderer inputs (`entity` / `records` / `selectedRecordId` /\n * `filterText` / `config`) via `setInput` and listens for `recordSelected` / `recordOpened`.\n * Two extra inputs (`cardTemplate`, `hiddenFieldMatches`) reproduce the host-level bindings\n * that `<mj-entity-cards>` was previously given directly in `entity-viewer.component.html` —\n * the host sets them via a guarded `setInput`.\n *\n * **Payload normalization:** `<mj-entity-cards>` emits the rich {@link RecordSelectedEvent} /\n * {@link RecordOpenedEvent} objects (`{ record, entity, compositeKey }`), but the host's\n * dynamic renderer handler expects the **raw record** and builds the composite key itself.\n * This adapter therefore extracts `.record` and re-emits just that object, matching the\n * other plug-in renderers (e.g. the Cluster renderer emits raw record objects).\n *\n * This is an NgModule-declared (`standalone: false`) component, declared in `EntityViewerModule`\n * alongside {@link EntityCardsComponent} — so it renders `<mj-entity-cards>` directly from the\n * module's compilation scope with no `imports` array and no self-import of the module (the module\n * loads the view-type descriptors, which reference these wrappers, so a wrapper importing the\n * module back would form a runtime import cycle — NG0919).\n *\n * Inputs use the camelCase names mandated by the {@link IViewRenderer} contract (the host\n * binds them by those exact names via `setInput`), rather than MJ's usual PascalCase for public\n * members — mirroring the Cluster renderer.\n */\n@Component({\n standalone: false,\n selector: 'mj-cards-view-renderer',\n encapsulation: ViewEncapsulation.None,\n template: `\n <mj-entity-cards\n [Provider]=\"Provider\"\n [entity]=\"entity\"\n [records]=\"records\"\n [selectedRecordId]=\"selectedRecordId\"\n [cardTemplate]=\"cardTemplate\"\n [hiddenFieldMatches]=\"hiddenFieldMatches\"\n [filterText]=\"filterText ?? ''\"\n (recordSelected)=\"onRecordSelected($event)\"\n (recordOpened)=\"onRecordOpened($event)\"\n >\n </mj-entity-cards>\n `,\n styles: [\n `\n :host {\n display: block;\n height: 100%;\n }\n `,\n ],\n})\nexport class CardsViewRendererComponent extends BaseAngularComponent implements IViewRenderer<Record<string, unknown>> {\n // ---- IViewRenderer inputs (camelCase per the host contract) ----\n\n /** The entity whose records are being rendered. */\n @Input() entity: EntityInfo | null = null;\n\n /** The records to render (already loaded/filtered by the host). */\n @Input() records: Record<string, unknown>[] = [];\n\n /** Primary-key string of the currently selected record, if any. */\n @Input() selectedRecordId: string | null = null;\n\n /** Active filter text (used by the cards view for match highlighting). */\n @Input() filterText: string | null = null;\n\n /**\n * View-type-specific configuration. Cards has no per-view config — this is accepted to\n * satisfy the {@link IViewRenderer} contract and is otherwise unused (no-op).\n */\n @Input() config: Record<string, unknown> = {};\n\n // ---- Host-level inputs for <mj-entity-cards> (not per-view config) ----\n\n /**\n * Optional custom card template. This is host-level configuration (not stored in the view\n * type's `config`), so the host sets it via a guarded `setInput`. Type matches\n * {@link EntityCardsComponent.cardTemplate}.\n */\n @Input() CardTemplate: CardTemplate | null = null;\n\n /** @deprecated Use {@link CardTemplate}. */\n @Input() set cardTemplate(value: CardTemplate | null) {\n this.CardTemplate = value;\n }\n /** @deprecated Use {@link CardTemplate}. */\n get cardTemplate(): CardTemplate | null {\n return this.CardTemplate;\n }\n\n /**\n * Optional map of record primary-key strings → hidden field names that matched the active\n * filter, used by the cards view to flag matches in non-visible fields. Host-level config,\n * set by the host via a guarded `setInput`. Type matches\n * {@link EntityCardsComponent.hiddenFieldMatches}.\n */\n @Input() HiddenFieldMatches: Map<string, string> = new Map();\n\n /** @deprecated Use {@link HiddenFieldMatches}. */\n @Input() set hiddenFieldMatches(value: Map<string, string>) {\n this.HiddenFieldMatches = value;\n }\n /** @deprecated Use {@link HiddenFieldMatches}. */\n get hiddenFieldMatches(): Map<string, string> {\n return this.HiddenFieldMatches;\n }\n\n // ---- IViewRenderer outputs ----\n\n /** Emitted when a record is selected (single click) — payload is the raw record object. */\n @Output() recordSelected = new EventEmitter<unknown>();\n\n /** Emitted when a record should be opened (double-click / open) — payload is the raw record object. */\n @Output() recordOpened = new EventEmitter<unknown>();\n\n /**\n * Required by {@link IViewRenderer}; the cards view never mutates its own config, so this\n * never emits. Declared so the host's uniform output subscription is satisfied.\n */\n @Output() configChanged = new EventEmitter<Record<string, unknown>>();\n\n /**\n * Relay `<mj-entity-cards>`'s selection event, normalizing to the raw record the host\n * expects (the host builds the composite key itself).\n */\n OnRecordSelected(event: RecordSelectedEvent): void {\n this.recordSelected.emit(event.record);\n }\n\n /** @deprecated Use {@link OnRecordSelected}. */\n onRecordSelected(event: RecordSelectedEvent): void {\n return this.OnRecordSelected(event);\n }\n\n /**\n * Relay `<mj-entity-cards>`'s open event, normalizing to the raw record the host expects\n * (the host builds the composite key itself).\n */\n OnRecordOpened(event: RecordOpenedEvent): void {\n this.recordOpened.emit(event.record);\n }\n\n /** @deprecated Use {@link OnRecordOpened}. */\n onRecordOpened(event: RecordOpenedEvent): void {\n return this.OnRecordOpened(event);\n }\n}\n\n/**\n * Tree-shaking guard. Force-references this renderer so bundlers (ESBuild/Vite) don't drop the\n * component in builds that only mount it dynamically via the ClassFactory/descriptor. Mirrors\n * the Cluster renderer's load guard; the parent wires this into a barrel/module load path.\n */\nexport function LoadCardsViewRenderer(): void {\n // no-op; presence prevents tree-shaking of this component\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventEmitter, OnDestroy } from '@angular/core';
|
|
2
2
|
import { EntityInfo, RunViewParams, CompositeKey } from '@memberjunction/core';
|
|
3
|
+
import { ExportColumn } from '@memberjunction/export-engine';
|
|
3
4
|
import { type FieldComparison, type MergeConfig, type MergeConfirmedEvent } from '@memberjunction/ng-record-merge';
|
|
4
5
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
5
6
|
import { PageChangeEvent } from '@memberjunction/ng-pagination';
|
|
@@ -113,7 +114,11 @@ export declare class GridViewRendererComponent extends BaseAngularComponent impl
|
|
|
113
114
|
* Optional full-result-set fetcher supplied by the host, forwarded to the grid's ExportDataProvider
|
|
114
115
|
* so exports cover every matching row rather than just the loaded page (bug C1).
|
|
115
116
|
*/
|
|
116
|
-
|
|
117
|
+
ExportDataProvider: (() => Promise<Record<string, unknown>[]>) | null;
|
|
118
|
+
/** @deprecated Use {@link ExportDataProvider}. */
|
|
119
|
+
set exportDataProvider(value: (() => Promise<Record<string, unknown>[]>) | null);
|
|
120
|
+
/** @deprecated Use {@link ExportDataProvider}. */
|
|
121
|
+
get exportDataProvider(): (() => Promise<Record<string, unknown>[]>) | null;
|
|
117
122
|
/** Primary-key string of the currently selected record, if any. */
|
|
118
123
|
selectedRecordId: string | null;
|
|
119
124
|
/** Active filter text — passed through for the grid's cell highlighting. */
|
|
@@ -171,6 +176,8 @@ export declare class GridViewRendererComponent extends BaseAngularComponent impl
|
|
|
171
176
|
* @returns true when the export succeeded, false when the grid isn't ready or the export failed.
|
|
172
177
|
*/
|
|
173
178
|
exportRecords(format?: 'csv' | 'excel' | 'json'): Promise<boolean>;
|
|
179
|
+
/** The hosted grid's on-screen columns ({@link IViewRenderer.GetExportColumns}); empty before it mounts. */
|
|
180
|
+
GetExportColumns(): ExportColumn[];
|
|
174
181
|
/** Whether the add-to-list dialog is visible. Toggled internally by {@link onAddToListRequested}. */
|
|
175
182
|
protected showListManagementDialog: boolean;
|
|
176
183
|
/** Config fed into `<mj-list-management-dialog>`. Built from the entity + selected records. */
|
|
@@ -182,32 +189,50 @@ export declare class GridViewRendererComponent extends BaseAngularComponent impl
|
|
|
182
189
|
/** Dynamic message for the delete-confirmation dialog (reflects the staged record count). */
|
|
183
190
|
protected deleteConfirmMessage: string;
|
|
184
191
|
/** Effective toolbar visibility — defaults to `true` when not set in config. */
|
|
192
|
+
get EffectiveShowToolbar(): boolean;
|
|
193
|
+
/** @deprecated Use {@link EffectiveShowToolbar}. */
|
|
185
194
|
get effectiveShowToolbar(): boolean;
|
|
186
195
|
/**
|
|
187
196
|
* Grid search defaults OFF when hosted in entity-viewer. The container already owns
|
|
188
197
|
* `filterText` ("Filter records..."). Opt in with `toolbarConfig.showSearch: true`.
|
|
189
198
|
*/
|
|
199
|
+
get EffectiveShowSearch(): boolean;
|
|
200
|
+
/** @deprecated Use {@link EffectiveShowSearch}. */
|
|
190
201
|
get effectiveShowSearch(): boolean;
|
|
191
202
|
/** Effective selection mode — defaults to `'checkbox'` when not set in config. */
|
|
203
|
+
get EffectiveSelectionMode(): GridSelectionMode;
|
|
204
|
+
/** @deprecated Use {@link EffectiveSelectionMode}. */
|
|
192
205
|
get effectiveSelectionMode(): GridSelectionMode;
|
|
193
206
|
/** Effective add-to-list button visibility — defaults to `true` when not set in config. */
|
|
207
|
+
get EffectiveShowAddToListButton(): boolean;
|
|
208
|
+
/** @deprecated Use {@link EffectiveShowAddToListButton}. */
|
|
194
209
|
get effectiveShowAddToListButton(): boolean;
|
|
195
210
|
/** Effective pager visibility — defaults to `true` when not set in config. */
|
|
211
|
+
get EffectiveShowPager(): boolean;
|
|
212
|
+
/** @deprecated Use {@link EffectiveShowPager}. */
|
|
196
213
|
get effectiveShowPager(): boolean;
|
|
197
214
|
/** Effective page size — config wins, else the generic `pageSize` input, else the grid's own default. */
|
|
215
|
+
get EffectivePageSize(): number;
|
|
216
|
+
/** @deprecated Use {@link EffectivePageSize}. */
|
|
198
217
|
get effectivePageSize(): number;
|
|
199
218
|
/**
|
|
200
219
|
* Effective RunViewParams for the grid. Uses `config.params` when supplied; otherwise builds a
|
|
201
220
|
* minimal dynamic-view params object from {@link entity}. Returns `null` when no entity is known
|
|
202
221
|
* yet (the grid renders empty until the host provides one).
|
|
203
222
|
*/
|
|
223
|
+
get EffectiveParams(): RunViewParams | null;
|
|
224
|
+
/** @deprecated Use {@link EffectiveParams}. */
|
|
204
225
|
get effectiveParams(): RunViewParams | null;
|
|
205
226
|
/**
|
|
206
227
|
* Row single-click → {@link recordSelected}. Extracts the raw record (`event.row`) so the host
|
|
207
228
|
* builds the composite key itself, matching the other renderers.
|
|
208
229
|
*/
|
|
230
|
+
OnAfterRowClick(event: AfterRowClickEventArgs): void;
|
|
231
|
+
/** @deprecated Use {@link OnAfterRowClick}. */
|
|
209
232
|
onAfterRowClick(event: AfterRowClickEventArgs): void;
|
|
210
233
|
/** Row double-click → {@link recordOpened} (NAVIGATION), emitting the raw record object. */
|
|
234
|
+
OnAfterRowDoubleClick(event: AfterRowDoubleClickEventArgs): void;
|
|
235
|
+
/** @deprecated Use {@link OnAfterRowDoubleClick}. */
|
|
211
236
|
onAfterRowDoubleClick(event: AfterRowDoubleClickEventArgs): void;
|
|
212
237
|
/**
|
|
213
238
|
* Sort change → both generic coordination channels:
|
|
@@ -215,17 +240,23 @@ export declare class GridViewRendererComponent extends BaseAngularComponent impl
|
|
|
215
240
|
* 2. persists the sort into `config.gridState.sortSettings` and emits {@link configChanged} so
|
|
216
241
|
* the grid's sort survives view reloads via the opaque config channel.
|
|
217
242
|
*/
|
|
243
|
+
OnAfterSort(event: AfterSortEventArgs): void;
|
|
244
|
+
/** @deprecated Use {@link OnAfterSort}. */
|
|
218
245
|
onAfterSort(event: AfterSortEventArgs): void;
|
|
219
246
|
/**
|
|
220
247
|
* Generic grid-state change (column resize / reorder / visibility) → merge the grid's updated
|
|
221
248
|
* {@link ViewGridState} into the opaque config and emit {@link configChanged}; the host persists
|
|
222
249
|
* the blob verbatim. No `dataRequest` here — column changes don't alter the loaded record set.
|
|
223
250
|
*/
|
|
251
|
+
OnGridStateChanged(event: GridStateChangedEvent): void;
|
|
252
|
+
/** @deprecated Use {@link OnGridStateChanged}. */
|
|
224
253
|
onGridStateChanged(event: GridStateChangedEvent): void;
|
|
225
254
|
/**
|
|
226
255
|
* Selection change → kept INTERNAL. The grid drives its own add-to-list from the selection, so the
|
|
227
256
|
* wrapper has no need to surface it. We intentionally do not bubble selection anywhere.
|
|
228
257
|
*/
|
|
258
|
+
OnSelectionChange(_selectedKeys: string[]): void;
|
|
259
|
+
/** @deprecated Use {@link OnSelectionChange}. */
|
|
229
260
|
onSelectionChange(_selectedKeys: string[]): void;
|
|
230
261
|
/**
|
|
231
262
|
* Foreign-key link click → {@link openRelatedRecordRequested} (NAVIGATION). Maps the grid's
|
|
@@ -233,20 +264,28 @@ export declare class GridViewRendererComponent extends BaseAngularComponent impl
|
|
|
233
264
|
* {@link ViewRelatedRecordNavigation} the container forwards to the outer app for routing. The
|
|
234
265
|
* related entity name is taken from the event when present, else resolved from the metadata by ID.
|
|
235
266
|
*/
|
|
267
|
+
OnForeignKeyClick(event: ForeignKeyClickEvent): void;
|
|
268
|
+
/** @deprecated Use {@link OnForeignKeyClick}. */
|
|
236
269
|
onForeignKeyClick(event: ForeignKeyClickEvent): void;
|
|
237
270
|
/** New button → {@link createRecordRequested} (NAVIGATION) — opening the create form is routing. */
|
|
271
|
+
OnNewButtonClick(): void;
|
|
272
|
+
/** @deprecated Use {@link OnNewButtonClick}. */
|
|
238
273
|
onNewButtonClick(): void;
|
|
239
274
|
/**
|
|
240
275
|
* Pager navigation → generic {@link dataRequest}. Maps the grid's {@link PageChangeEvent}
|
|
241
276
|
* (`PageNumber` is already 1-based, `PageSize`) onto the generic `{ page, pageSize }` shape the
|
|
242
277
|
* host honors against its own RunView.
|
|
243
278
|
*/
|
|
279
|
+
OnPageChange(event: PageChangeEvent): void;
|
|
280
|
+
/** @deprecated Use {@link OnPageChange}. */
|
|
244
281
|
onPageChange(event: PageChangeEvent): void;
|
|
245
282
|
/**
|
|
246
283
|
* Refresh button → re-emit {@link dataRequest} so the host reloads the current page. This is
|
|
247
284
|
* generic container ↔ plug-in coordination (a data-access request), NOT a feature event surfaced
|
|
248
285
|
* to the outer app.
|
|
249
286
|
*/
|
|
287
|
+
OnRefreshButtonClick(): void;
|
|
288
|
+
/** @deprecated Use {@link OnRefreshButtonClick}. */
|
|
250
289
|
onRefreshButtonClick(): void;
|
|
251
290
|
/**
|
|
252
291
|
* Add-to-list button → build a {@link ListManagementDialogConfig} from the entity + the records the
|
|
@@ -254,14 +293,24 @@ export declare class GridViewRendererComponent extends BaseAngularComponent impl
|
|
|
254
293
|
* changes itself — nothing bubbles up. Mirrors the config construction the legacy host did in
|
|
255
294
|
* `data-explorer-dashboard`'s `onAddToListRequested()`.
|
|
256
295
|
*/
|
|
296
|
+
OnAddToListRequested(event: {
|
|
297
|
+
entityInfo: EntityInfo;
|
|
298
|
+
records: Record<string, unknown>[];
|
|
299
|
+
recordIds: string[];
|
|
300
|
+
}): void;
|
|
301
|
+
/** @deprecated Use {@link OnAddToListRequested}. */
|
|
257
302
|
onAddToListRequested(event: {
|
|
258
303
|
entityInfo: EntityInfo;
|
|
259
304
|
records: Record<string, unknown>[];
|
|
260
305
|
recordIds: string[];
|
|
261
306
|
}): void;
|
|
262
307
|
/** List-management dialog completed (membership changes applied) → tear down state. */
|
|
308
|
+
OnListManagementComplete(_result: ListManagementResult): void;
|
|
309
|
+
/** @deprecated Use {@link OnListManagementComplete}. */
|
|
263
310
|
onListManagementComplete(_result: ListManagementResult): void;
|
|
264
311
|
/** List-management dialog cancelled → tear down state. */
|
|
312
|
+
OnListManagementCancel(): void;
|
|
313
|
+
/** @deprecated Use {@link OnListManagementCancel}. */
|
|
265
314
|
onListManagementCancel(): void;
|
|
266
315
|
/**
|
|
267
316
|
* Resolve a human-friendly display name for a record using the entity's NameField, falling back to
|
|
@@ -279,6 +328,8 @@ export declare class GridViewRendererComponent extends BaseAngularComponent impl
|
|
|
279
328
|
* Delete button → stage the records and open the Generic confirm dialog. The actual delete happens
|
|
280
329
|
* in {@link onDeleteConfirmed} after the user confirms — nothing bubbles up.
|
|
281
330
|
*/
|
|
331
|
+
OnDeleteButtonClick(records: Record<string, unknown>[]): void;
|
|
332
|
+
/** @deprecated Use {@link OnDeleteButtonClick}. */
|
|
282
333
|
onDeleteButtonClick(records: Record<string, unknown>[]): void;
|
|
283
334
|
/**
|
|
284
335
|
* Delete confirmed → delete each staged record through the MJ entity layer
|
|
@@ -286,8 +337,12 @@ export declare class GridViewRendererComponent extends BaseAngularComponent impl
|
|
|
286
337
|
* result and surfacing failures via {@link LogError}. After deletion, re-request the current page
|
|
287
338
|
* so the host reloads. Self-contained — no feature event leaves the wrapper.
|
|
288
339
|
*/
|
|
340
|
+
OnDeleteConfirmed(): Promise<void>;
|
|
341
|
+
/** @deprecated Use {@link OnDeleteConfirmed}. */
|
|
289
342
|
onDeleteConfirmed(): Promise<void>;
|
|
290
343
|
/** Delete cancelled → discard the staged records and close the confirm dialog. */
|
|
344
|
+
OnDeleteCancelled(): void;
|
|
345
|
+
/** @deprecated Use {@link OnDeleteCancelled}. */
|
|
291
346
|
onDeleteCancelled(): void;
|
|
292
347
|
/**
|
|
293
348
|
* The in-flight merge, or null when the panel is closed. Holds everything the panel needs
|
|
@@ -315,6 +370,8 @@ export declare class GridViewRendererComponent extends BaseAngularComponent impl
|
|
|
315
370
|
private readonly comparison;
|
|
316
371
|
ngOnDestroy(): void;
|
|
317
372
|
/** Dismiss the merge notice from its own close button. */
|
|
373
|
+
OnDismissMergeNotice(): void;
|
|
374
|
+
/** @deprecated Use {@link OnDismissMergeNotice}. */
|
|
318
375
|
onDismissMergeNotice(): void;
|
|
319
376
|
/**
|
|
320
377
|
* Set (or clear) the merge notice, replacing any pending auto-dismiss. Every write to
|
|
@@ -332,16 +389,27 @@ export declare class GridViewRendererComponent extends BaseAngularComponent impl
|
|
|
332
389
|
* The grid asked to merge the selected rows. Compare them, preview what will move, and open
|
|
333
390
|
* the panel — nothing is written until the user confirms.
|
|
334
391
|
*/
|
|
392
|
+
OnMergeRequested(event: {
|
|
393
|
+
entityInfo: EntityInfo;
|
|
394
|
+
records: Record<string, unknown>[];
|
|
395
|
+
}): Promise<void>;
|
|
396
|
+
/** @deprecated Use {@link OnMergeRequested}. */
|
|
335
397
|
onMergeRequested(event: {
|
|
336
398
|
entityInfo: EntityInfo;
|
|
337
399
|
records: Record<string, unknown>[];
|
|
338
400
|
}): Promise<void>;
|
|
339
401
|
/** The user chose which record survives; differing fields default to that record's values. */
|
|
402
|
+
OnSurvivorChange(side: 'left' | 'right'): void;
|
|
403
|
+
/** @deprecated Use {@link OnSurvivorChange}. */
|
|
340
404
|
onSurvivorChange(side: 'left' | 'right'): void;
|
|
341
405
|
private prepareMerge;
|
|
342
406
|
/** The user confirmed: merge, then reload the page so the loser disappears from the grid. */
|
|
407
|
+
OnMergeConfirmed(event: MergeConfirmedEvent): Promise<void>;
|
|
408
|
+
/** @deprecated Use {@link OnMergeConfirmed}. */
|
|
343
409
|
onMergeConfirmed(event: MergeConfirmedEvent): Promise<void>;
|
|
344
410
|
/** Merge cancelled → close the panel, write nothing. */
|
|
411
|
+
OnMergeCancelled(): void;
|
|
412
|
+
/** @deprecated Use {@link OnMergeCancelled}. */
|
|
345
413
|
onMergeCancelled(): void;
|
|
346
414
|
/**
|
|
347
415
|
* Fields whose resolution has to travel, and only those: the survivor already holds the value
|
|
@@ -386,7 +454,7 @@ export declare class GridViewRendererComponent extends BaseAngularComponent impl
|
|
|
386
454
|
*/
|
|
387
455
|
private resolveEntityNameById;
|
|
388
456
|
static ɵfac: i0.ɵɵFactoryDeclaration<GridViewRendererComponent, never>;
|
|
389
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<GridViewRendererComponent, "mj-grid-view-renderer", never, { "entity": { "alias": "entity"; "required": false; }; "records": { "alias": "records"; "required": false; }; "exportDataProvider": { "alias": "exportDataProvider"; "required": false; }; "selectedRecordId": { "alias": "selectedRecordId"; "required": false; }; "filterText": { "alias": "filterText"; "required": false; }; "config": { "alias": "config"; "required": false; }; "AutoLoadEntityActions": { "alias": "AutoLoadEntityActions"; "required": false; }; "totalRecordCount": { "alias": "totalRecordCount"; "required": false; }; "page": { "alias": "page"; "required": false; }; "pageSize": { "alias": "pageSize"; "required": false; }; "isLoading": { "alias": "isLoading"; "required": false; }; }, { "recordSelected": "recordSelected"; "recordOpened": "recordOpened"; "configChanged": "configChanged"; "dataRequest": "dataRequest"; "configureRequested": "configureRequested"; "openRelatedRecordRequested": "openRelatedRecordRequested"; "createRecordRequested": "createRecordRequested"; }, never, never, false, never>;
|
|
457
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<GridViewRendererComponent, "mj-grid-view-renderer", never, { "entity": { "alias": "entity"; "required": false; }; "records": { "alias": "records"; "required": false; }; "ExportDataProvider": { "alias": "ExportDataProvider"; "required": false; }; "exportDataProvider": { "alias": "exportDataProvider"; "required": false; }; "selectedRecordId": { "alias": "selectedRecordId"; "required": false; }; "filterText": { "alias": "filterText"; "required": false; }; "config": { "alias": "config"; "required": false; }; "AutoLoadEntityActions": { "alias": "AutoLoadEntityActions"; "required": false; }; "totalRecordCount": { "alias": "totalRecordCount"; "required": false; }; "page": { "alias": "page"; "required": false; }; "pageSize": { "alias": "pageSize"; "required": false; }; "isLoading": { "alias": "isLoading"; "required": false; }; }, { "recordSelected": "recordSelected"; "recordOpened": "recordOpened"; "configChanged": "configChanged"; "dataRequest": "dataRequest"; "configureRequested": "configureRequested"; "openRelatedRecordRequested": "openRelatedRecordRequested"; "createRecordRequested": "createRecordRequested"; }, never, never, false, never>;
|
|
390
458
|
}
|
|
391
459
|
/**
|
|
392
460
|
* Tree-shaking guard. Force-references this renderer so bundlers (ESBuild/Vite) don't drop the
|