@memberjunction/ng-entity-relationship-diagram 5.11.0 → 5.13.0
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/components/entity-details/entity-details.component.js +2 -2
- package/dist/lib/components/erd-diagram.component.d.ts +2 -0
- package/dist/lib/components/erd-diagram.component.d.ts.map +1 -1
- package/dist/lib/components/erd-diagram.component.js +46 -27
- package/dist/lib/components/erd-diagram.component.js.map +1 -1
- package/package.json +2 -2
|
@@ -667,11 +667,11 @@ export class EntityDetailsComponent {
|
|
|
667
667
|
i0.ɵɵtextInterpolate1("Related Entities (", ctx.selectedEntity ? ctx.getRelatedEntities(ctx.selectedEntity.ID).length : 0, ")");
|
|
668
668
|
i0.ɵɵadvance();
|
|
669
669
|
i0.ɵɵconditional(ctx.relationshipsSectionExpanded ? 38 : -1);
|
|
670
|
-
} }, styles: ["\n\n\n\n\n\n.details-panel[_ngcontent-%COMP%] {\n height: 100%;\n background: var(--mj-bg-page);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.details-panel[_ngcontent-%COMP%] .panel-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n.details-panel[_ngcontent-%COMP%] .entity-info[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n.details-panel[_ngcontent-%COMP%] .fields-section[_ngcontent-%COMP%], \n.details-panel[_ngcontent-%COMP%] .relationships-section[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-height: 0;\n transition: flex 0.3s ease;\n}\n\n.details-panel[_ngcontent-%COMP%] .fields-section.section-expanded[_ngcontent-%COMP%], \n.details-panel[_ngcontent-%COMP%] .relationships-section.section-expanded[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.details-panel[_ngcontent-%COMP%] .fields-section.section-collapsed[_ngcontent-%COMP%], \n.details-panel[_ngcontent-%COMP%] .relationships-section.section-collapsed[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n}\n\n.details-panel[_ngcontent-%COMP%] .fields-section[_ngcontent-%COMP%]:last-child, \n.details-panel[_ngcontent-%COMP%] .relationships-section[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n\n\n.open-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 6px 12px;\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border: none;\n border-radius: 20px;\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.open-btn[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-md);\n}\n\n\n\n.close-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n\n\n\n.entity-info[_ngcontent-%COMP%] {\n padding: 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.info-row[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n margin-bottom: 8px;\n font-size: 12px;\n}\n\n.info-row[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.info-row[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 60px;\n}\n\n.info-row[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n flex: 1;\n text-align: right;\n}\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: 8px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.status-badge.status-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n}\n\n.status-badge.status-deprecated[_ngcontent-%COMP%] {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-900);\n}\n\n.status-badge.status-disabled[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-color-error-700);\n}\n\n.extra-padding[_ngcontent-%COMP%] {\n padding: 4px;\n}\n\n\n\n.fields-section[_ngcontent-%COMP%], \n.relationships-section[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.fields-section[_ngcontent-%COMP%] .section-header[_ngcontent-%COMP%], \n.relationships-section[_ngcontent-%COMP%] .section-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n padding: 16px 16px 12px 16px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n background: var(--mj-bg-surface-sunken);\n border: none;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.fields-section[_ngcontent-%COMP%] .section-header[_ngcontent-%COMP%] .section-title-group[_ngcontent-%COMP%], \n.relationships-section[_ngcontent-%COMP%] .section-header[_ngcontent-%COMP%] .section-title-group[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.fields-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%], \n.relationships-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n\n.expand-btn[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.expand-btn.expanded[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n transform: rotate(90deg);\n}\n\n.section-title-group[_ngcontent-%COMP%] {\n cursor: pointer;\n user-select: none;\n}\n\n.section-title-group[_ngcontent-%COMP%]:hover {\n opacity: 0.8;\n}\n\n\n\n.field-filters[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.filter-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 4px 10px;\n font-size: 11px;\n background: var(--mj-bg-page);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.filter-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n\n\n.fields-list[_ngcontent-%COMP%], \n.related-entities-list[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 8px;\n overflow-y: auto;\n padding: 6px 16px 16px 16px;\n min-height: 0;\n}\n\n.fields-list[_ngcontent-%COMP%]::-webkit-scrollbar, \n.related-entities-list[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n\n.fields-list[_ngcontent-%COMP%]::-webkit-scrollbar-track, \n.related-entities-list[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n}\n\n.fields-list[_ngcontent-%COMP%]::-webkit-scrollbar-thumb, \n.related-entities-list[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-color-neutral-400);\n border-radius: 3px;\n}\n\n.fields-list[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover, \n.related-entities-list[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-secondary);\n}\n\n\n\n.field-item[_ngcontent-%COMP%] {\n padding: 10px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n font-size: 12px;\n cursor: pointer;\n user-select: none;\n transition: all 0.2s ease;\n}\n\n.field-item[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.field-item.field-expanded[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-lg);\n transform: scale(1.01);\n}\n\n\n\n.field-item.primary-key-field[_ngcontent-%COMP%] {\n border-color: var(--mj-status-success);\n background: var(--mj-color-success-100);\n border-left: 4px solid var(--mj-status-success);\n}\n\n.field-item.primary-key-field.field-expanded[_ngcontent-%COMP%] {\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n}\n\n\n\n.field-item.foreign-key-field[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: var(--mj-color-accent-300);\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n.field-item.foreign-key-field.field-expanded[_ngcontent-%COMP%] {\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n\n\n.field-item.regular-field[_ngcontent-%COMP%] {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n.field-item.regular-field.field-expanded[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-md);\n}\n\n.field-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 4px;\n}\n\n.field-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.field-name[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n.field-icon.fa-key[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.field-icon.fa-link[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n.field-badges[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.field-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 1px 6px;\n border-radius: 4px;\n font-size: 9px;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.field-badge.primary-key[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n color: var(--mj-brand-on-primary);\n}\n\n.field-badge.foreign-key[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.field-type[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 11px;\n}\n\n.field-relation[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 11px;\n margin-top: 4px;\n}\n\n.field-relation[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n margin-right: 4px;\n}\n\n\n\n.field-info-btn[_ngcontent-%COMP%], \n.field-values-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.field-info-btn[_ngcontent-%COMP%]:hover, \n.field-values-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.field-info-btn.expanded[_ngcontent-%COMP%], \n.field-values-btn.expanded[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.field-info-btn[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%], \n.field-values-btn[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n\n.field-description[_ngcontent-%COMP%] {\n margin-top: 8px;\n padding: 8px;\n background: var(--mj-bg-surface-sunken);\n border-left: 3px solid var(--mj-brand-primary);\n border-radius: 0 8px 8px 0;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-in-out;\n}\n\n.field-description[_ngcontent-%COMP%] .description-text[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n font-style: italic;\n}\n\n.field-details[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n transform: translateY(-5px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n\n\n.field-values[_ngcontent-%COMP%] {\n margin-top: 8px;\n padding: 8px;\n background: var(--mj-color-warning-50);\n border-left: 3px solid var(--mj-color-warning-500);\n border-radius: 0 8px 8px 0;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-in-out;\n}\n\n.field-values[_ngcontent-%COMP%] .values-header[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-color-warning-900);\n font-weight: 600;\n margin-bottom: 6px;\n}\n\n.field-values[_ngcontent-%COMP%] .values-list[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n.field-values[_ngcontent-%COMP%] .value-tag[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 2px 8px;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n font-size: 9px;\n border-radius: 12px;\n font-weight: 500;\n white-space: nowrap;\n max-width: 80px;\n overflow: hidden;\n text-overflow: ellipsis;\n border: 1px solid var(--mj-border-default);\n}\n\n.field-values[_ngcontent-%COMP%] .value-tag[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n cursor: default;\n}\n\n\n\n.field-comprehensive-details[_ngcontent-%COMP%] {\n margin-top: 12px;\n padding: 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n animation: _ngcontent-%COMP%_slideDown 0.3s ease-out;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .details-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 10px;\n padding-bottom: 6px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .details-header[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .details-grid[_ngcontent-%COMP%] {\n display: grid;\n gap: 6px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 100px 1fr;\n gap: 8px;\n font-size: 12px;\n align-items: center;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-label[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-align: right;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-family: \"Courier New\", monospace;\n background: var(--mj-bg-page);\n padding: 2px 6px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.nullable-yes[_ngcontent-%COMP%], \n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.nullable-no[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n border-color: var(--mj-border-default);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.virtual-yes[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-900);\n background: var(--mj-color-warning-50);\n border-color: var(--mj-color-warning-500);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.virtual-no[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.default-value[_ngcontent-%COMP%] {\n color: var(--mj-color-success-800);\n background: var(--mj-color-success-100);\n border-color: var(--mj-status-success);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.related-entity[_ngcontent-%COMP%] {\n color: var(--mj-color-brand-900);\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n cursor: pointer;\n user-select: none;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.related-entity[_ngcontent-%COMP%]:hover {\n text-decoration: underline;\n background: color-mix(in srgb, var(--mj-color-accent-300) 80%, var(--mj-brand-primary) 20%);\n transform: translateX(2px);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.related-entity[_ngcontent-%COMP%] .fa-external-link-alt[_ngcontent-%COMP%] {\n font-size: 8px;\n opacity: 0.7;\n transition: opacity 0.2s ease;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.related-entity[_ngcontent-%COMP%]:hover .fa-external-link-alt[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.auto-increment[_ngcontent-%COMP%] {\n color: var(--mj-color-success-800);\n background: var(--mj-color-success-100);\n border-color: var(--mj-status-success);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .comprehensive-description-top[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n padding-bottom: 10px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .comprehensive-description-top[_ngcontent-%COMP%] .description-content[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-primary);\n line-height: 1.4;\n font-style: italic;\n background: var(--mj-color-accent-300);\n padding: 10px;\n border-radius: 8px;\n border: 1px solid var(--mj-brand-primary);\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n padding: 12px;\n background: var(--mj-color-warning-50);\n border: 1px solid var(--mj-color-warning-500);\n border-radius: 8px;\n border-left: 4px solid var(--mj-color-warning-500);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-color-warning-900);\n margin-bottom: 10px;\n padding-bottom: 6px;\n border-bottom: 1px solid color-mix(in srgb, var(--mj-color-warning-500) 30%, transparent);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-header[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-500);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-grid[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n max-height: 200px;\n overflow-y: auto;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-grid[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 4px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-grid[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: var(--mj-color-warning-50);\n border-radius: 2px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-grid[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-color-warning-500);\n border-radius: 2px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-grid[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-color-warning-900);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .value-item[_ngcontent-%COMP%] {\n padding: 8px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .value-item[_ngcontent-%COMP%] .value-main[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 2px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .value-item[_ngcontent-%COMP%] .value-main[_ngcontent-%COMP%] .value-text[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .value-item[_ngcontent-%COMP%] .value-main[_ngcontent-%COMP%] .value-code[_ngcontent-%COMP%] {\n font-size: 9px;\n color: var(--mj-color-warning-900);\n background: var(--mj-color-warning-50);\n padding: 1px 4px;\n border-radius: 4px;\n border: 1px solid var(--mj-color-warning-500);\n font-family: \"Courier New\", monospace;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .value-item[_ngcontent-%COMP%] .value-description[_ngcontent-%COMP%] {\n font-size: 9px;\n color: var(--mj-text-secondary);\n line-height: 1.3;\n font-style: italic;\n margin-top: 2px;\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n max-height: 0;\n }\n to {\n opacity: 1;\n transform: translateY(0);\n max-height: 500px;\n }\n}\n\n\n\n.related-entity-item[_ngcontent-%COMP%] {\n padding: 12px 14px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n transition: all 0.3s ease;\n position: relative;\n max-width: calc(100% - 4px);\n min-width: 0;\n flex-shrink: 1;\n}\n\n.related-entity-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n transform: translateX(4px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.related-entity-item[_ngcontent-%COMP%]:hover .zoom-indicator[_ngcontent-%COMP%] {\n opacity: 1;\n transform: scale(1.1);\n}\n\n.related-entity-item[_ngcontent-%COMP%]:hover .fa-database[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n transform: scale(1.1);\n}\n\n.related-entity-item[_ngcontent-%COMP%]:hover::before {\n content: \"\";\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 3px;\n background: linear-gradient(to bottom, var(--mj-brand-primary), var(--mj-color-warning-500));\n border-radius: 0 3px 3px 0;\n}\n\n.related-entity-item[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n margin-right: 10px;\n color: var(--mj-text-secondary);\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.related-entity-item[_ngcontent-%COMP%] .fa-database[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.related-entity-item[_ngcontent-%COMP%] .entity-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n.related-entity-item[_ngcontent-%COMP%] .zoom-indicator[_ngcontent-%COMP%] {\n opacity: 0.4;\n color: var(--mj-brand-primary);\n font-size: 11px;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}"] });
|
|
670
|
+
} }, styles: ["\n\n\n\n\n\n.details-panel[_ngcontent-%COMP%] {\n height: 100%;\n background: var(--mj-bg-page);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.details-panel[_ngcontent-%COMP%] .panel-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n.details-panel[_ngcontent-%COMP%] .entity-info[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n.details-panel[_ngcontent-%COMP%] .fields-section[_ngcontent-%COMP%], \n.details-panel[_ngcontent-%COMP%] .relationships-section[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-height: 0;\n transition: flex 0.3s ease;\n}\n\n.details-panel[_ngcontent-%COMP%] .fields-section.section-expanded[_ngcontent-%COMP%], \n.details-panel[_ngcontent-%COMP%] .relationships-section.section-expanded[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.details-panel[_ngcontent-%COMP%] .fields-section.section-collapsed[_ngcontent-%COMP%], \n.details-panel[_ngcontent-%COMP%] .relationships-section.section-collapsed[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n}\n\n.details-panel[_ngcontent-%COMP%] .fields-section[_ngcontent-%COMP%]:last-child, \n.details-panel[_ngcontent-%COMP%] .relationships-section[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n\n\n.open-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 6px 12px;\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border: none;\n border-radius: 20px;\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.open-btn[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-md);\n}\n\n\n\n.close-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n\n\n\n.entity-info[_ngcontent-%COMP%] {\n padding: 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.info-row[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n margin-bottom: 8px;\n font-size: 12px;\n}\n\n.info-row[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.info-row[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 60px;\n}\n\n.info-row[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n flex: 1;\n text-align: right;\n}\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: 8px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.status-badge.status-active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface-card));\n color: var(--mj-status-success);\n}\n\n.status-badge.status-deprecated[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface-card));\n color: var(--mj-status-warning);\n}\n\n.status-badge.status-disabled[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface-card));\n color: var(--mj-status-error);\n}\n\n.extra-padding[_ngcontent-%COMP%] {\n padding: 4px;\n}\n\n\n\n.fields-section[_ngcontent-%COMP%], \n.relationships-section[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.fields-section[_ngcontent-%COMP%] .section-header[_ngcontent-%COMP%], \n.relationships-section[_ngcontent-%COMP%] .section-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n padding: 16px 16px 12px 16px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n background: var(--mj-bg-surface-sunken);\n border: none;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.fields-section[_ngcontent-%COMP%] .section-header[_ngcontent-%COMP%] .section-title-group[_ngcontent-%COMP%], \n.relationships-section[_ngcontent-%COMP%] .section-header[_ngcontent-%COMP%] .section-title-group[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.fields-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%], \n.relationships-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n\n.expand-btn[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.expand-btn.expanded[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n transform: rotate(90deg);\n}\n\n.section-title-group[_ngcontent-%COMP%] {\n cursor: pointer;\n user-select: none;\n}\n\n.section-title-group[_ngcontent-%COMP%]:hover {\n opacity: 0.8;\n}\n\n\n\n.field-filters[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.filter-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 4px 10px;\n font-size: 11px;\n background: var(--mj-bg-page);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.filter-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n\n\n.fields-list[_ngcontent-%COMP%], \n.related-entities-list[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 8px;\n overflow-y: auto;\n padding: 6px 16px 16px 16px;\n min-height: 0;\n}\n\n.fields-list[_ngcontent-%COMP%]::-webkit-scrollbar, \n.related-entities-list[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n\n.fields-list[_ngcontent-%COMP%]::-webkit-scrollbar-track, \n.related-entities-list[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n}\n\n.fields-list[_ngcontent-%COMP%]::-webkit-scrollbar-thumb, \n.related-entities-list[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-text-disabled);\n border-radius: 3px;\n}\n\n.fields-list[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover, \n.related-entities-list[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-secondary);\n}\n\n\n\n.field-item[_ngcontent-%COMP%] {\n padding: 10px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n font-size: 12px;\n cursor: pointer;\n user-select: none;\n transition: all 0.2s ease;\n}\n\n.field-item[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.field-item.field-expanded[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-lg);\n transform: scale(1.01);\n}\n\n\n\n.field-item.primary-key-field[_ngcontent-%COMP%] {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface-card));\n border-left: 4px solid var(--mj-status-success);\n}\n\n.field-item.primary-key-field.field-expanded[_ngcontent-%COMP%] {\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n}\n\n\n\n.field-item.foreign-key-field[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface-card));\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n.field-item.foreign-key-field.field-expanded[_ngcontent-%COMP%] {\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n\n\n.field-item.regular-field[_ngcontent-%COMP%] {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n.field-item.regular-field.field-expanded[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-md);\n}\n\n.field-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 4px;\n}\n\n.field-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.field-name[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n.field-icon.fa-key[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.field-icon.fa-link[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n.field-badges[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.field-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 1px 6px;\n border-radius: 4px;\n font-size: 9px;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.field-badge.primary-key[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n color: var(--mj-brand-on-primary);\n}\n\n.field-badge.foreign-key[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.field-type[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 11px;\n}\n\n.field-relation[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 11px;\n margin-top: 4px;\n}\n\n.field-relation[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n margin-right: 4px;\n}\n\n\n\n.field-info-btn[_ngcontent-%COMP%], \n.field-values-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.field-info-btn[_ngcontent-%COMP%]:hover, \n.field-values-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n color: var(--mj-brand-primary);\n}\n\n.field-info-btn.expanded[_ngcontent-%COMP%], \n.field-values-btn.expanded[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n color: var(--mj-brand-primary);\n}\n\n.field-info-btn[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%], \n.field-values-btn[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n\n.field-description[_ngcontent-%COMP%] {\n margin-top: 8px;\n padding: 8px;\n background: var(--mj-bg-surface-sunken);\n border-left: 3px solid var(--mj-brand-primary);\n border-radius: 0 8px 8px 0;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-in-out;\n}\n\n.field-description[_ngcontent-%COMP%] .description-text[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n font-style: italic;\n}\n\n.field-details[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n transform: translateY(-5px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n\n\n.field-values[_ngcontent-%COMP%] {\n margin-top: 8px;\n padding: 8px;\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface-card));\n border-left: 3px solid var(--mj-status-warning);\n border-radius: 0 8px 8px 0;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-in-out;\n}\n\n.field-values[_ngcontent-%COMP%] .values-header[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-primary);\n font-weight: 600;\n margin-bottom: 6px;\n}\n\n.field-values[_ngcontent-%COMP%] .values-list[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n.field-values[_ngcontent-%COMP%] .value-tag[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 2px 8px;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n font-size: 9px;\n border-radius: 12px;\n font-weight: 500;\n white-space: nowrap;\n max-width: 80px;\n overflow: hidden;\n text-overflow: ellipsis;\n border: 1px solid var(--mj-border-default);\n}\n\n.field-values[_ngcontent-%COMP%] .value-tag[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n cursor: default;\n}\n\n\n\n.field-comprehensive-details[_ngcontent-%COMP%] {\n margin-top: 12px;\n padding: 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n animation: _ngcontent-%COMP%_slideDown 0.3s ease-out;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .details-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 10px;\n padding-bottom: 6px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .details-header[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .details-grid[_ngcontent-%COMP%] {\n display: grid;\n gap: 6px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 100px 1fr;\n gap: 8px;\n font-size: 12px;\n align-items: center;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-label[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-align: right;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-family: \"Courier New\", monospace;\n background: var(--mj-bg-page);\n padding: 2px 6px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.nullable-yes[_ngcontent-%COMP%], \n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.nullable-no[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n border-color: var(--mj-border-default);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.virtual-yes[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface-card));\n border-color: var(--mj-status-warning);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.virtual-no[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.default-value[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface-card));\n border-color: var(--mj-status-success);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.related-entity[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n border-color: var(--mj-brand-primary);\n cursor: pointer;\n user-select: none;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.related-entity[_ngcontent-%COMP%]:hover {\n text-decoration: underline;\n background: color-mix(in srgb, var(--mj-brand-primary) 25%, var(--mj-bg-surface-card));\n transform: translateX(2px);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.related-entity[_ngcontent-%COMP%] .fa-external-link-alt[_ngcontent-%COMP%] {\n font-size: 8px;\n opacity: 0.7;\n transition: opacity 0.2s ease;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.related-entity[_ngcontent-%COMP%]:hover .fa-external-link-alt[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .detail-value.auto-increment[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface-card));\n border-color: var(--mj-status-success);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .comprehensive-description-top[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n padding-bottom: 10px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .comprehensive-description-top[_ngcontent-%COMP%] .description-content[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-primary);\n line-height: 1.4;\n font-style: italic;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n padding: 10px;\n border-radius: 8px;\n border: 1px solid var(--mj-brand-primary);\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n padding: 12px;\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface-card));\n border: 1px solid var(--mj-status-warning);\n border-radius: 8px;\n border-left: 4px solid var(--mj-status-warning);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 10px;\n padding-bottom: 6px;\n border-bottom: 1px solid color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-header[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-grid[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n max-height: 200px;\n overflow-y: auto;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-grid[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 4px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-grid[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface-card));\n border-radius: 2px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-grid[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-status-warning);\n border-radius: 2px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .values-grid[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-primary);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .value-item[_ngcontent-%COMP%] {\n padding: 8px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .value-item[_ngcontent-%COMP%] .value-main[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 2px;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .value-item[_ngcontent-%COMP%] .value-main[_ngcontent-%COMP%] .value-text[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .value-item[_ngcontent-%COMP%] .value-main[_ngcontent-%COMP%] .value-code[_ngcontent-%COMP%] {\n font-size: 9px;\n color: var(--mj-text-primary);\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface-card));\n padding: 1px 4px;\n border-radius: 4px;\n border: 1px solid var(--mj-status-warning);\n font-family: \"Courier New\", monospace;\n}\n\n.field-comprehensive-details[_ngcontent-%COMP%] .field-values-comprehensive[_ngcontent-%COMP%] .value-item[_ngcontent-%COMP%] .value-description[_ngcontent-%COMP%] {\n font-size: 9px;\n color: var(--mj-text-secondary);\n line-height: 1.3;\n font-style: italic;\n margin-top: 2px;\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n max-height: 0;\n }\n to {\n opacity: 1;\n transform: translateY(0);\n max-height: 500px;\n }\n}\n\n\n\n.related-entity-item[_ngcontent-%COMP%] {\n padding: 12px 14px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n transition: all 0.3s ease;\n position: relative;\n max-width: calc(100% - 4px);\n min-width: 0;\n flex-shrink: 1;\n}\n\n.related-entity-item[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n border-color: var(--mj-brand-primary);\n transform: translateX(4px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.related-entity-item[_ngcontent-%COMP%]:hover .zoom-indicator[_ngcontent-%COMP%] {\n opacity: 1;\n transform: scale(1.1);\n}\n\n.related-entity-item[_ngcontent-%COMP%]:hover .fa-database[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n transform: scale(1.1);\n}\n\n.related-entity-item[_ngcontent-%COMP%]:hover::before {\n content: \"\";\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 3px;\n background: linear-gradient(to bottom, var(--mj-brand-primary), var(--mj-status-warning));\n border-radius: 0 3px 3px 0;\n}\n\n.related-entity-item[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n margin-right: 10px;\n color: var(--mj-text-secondary);\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.related-entity-item[_ngcontent-%COMP%] .fa-database[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.related-entity-item[_ngcontent-%COMP%] .entity-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n.related-entity-item[_ngcontent-%COMP%] .zoom-indicator[_ngcontent-%COMP%] {\n opacity: 0.4;\n color: var(--mj-brand-primary);\n font-size: 11px;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}"] });
|
|
671
671
|
}
|
|
672
672
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EntityDetailsComponent, [{
|
|
673
673
|
type: Component,
|
|
674
|
-
args: [{ standalone: false, selector: 'mj-entity-details', template: "<div class=\"details-panel\">\n <div class=\"panel-header\">\n <h3>{{ selectedEntity?.Name || selectedEntity?.SchemaName }}</h3>\n <div class=\"panel-actions\">\n <button class=\"open-btn\" (click)=\"onOpenEntity()\" title=\"Open Entity Record\">\n <span class=\"fa-solid fa-external-link-alt\"></span>\n Open\n </button>\n <button class=\"close-btn\" (click)=\"onClosePanel()\">\n <span class=\"fa-solid fa-times\"></span>\n </button>\n </div>\n </div>\n\n <div class=\"entity-info\">\n <div class=\"info-row\">\n <label>Schema:</label>\n <span>{{ selectedEntity?.SchemaName }}</span>\n </div>\n <div class=\"info-row\">\n <label>Table:</label>\n <span>{{ selectedEntity?.BaseTable }}</span>\n </div>\n @if (selectedEntity?.Description) {\n <div class=\"info-row\">\n <label>Description:</label>\n <span>{{ selectedEntity?.Description }}</span>\n </div>\n }\n </div>\n\n <div class=\"fields-section\" [class.section-expanded]=\"fieldsSectionExpanded\" [class.section-collapsed]=\"!fieldsSectionExpanded\">\n <div class=\"section-header extra-padding\">\n <div class=\"section-title-group\" (click)=\"toggleFieldsSection()\">\n <button\n class=\"expand-btn\"\n [class.expanded]=\"fieldsSectionExpanded\"\n title=\"Toggle fields section\">\n <span class=\"fa-solid fa-chevron-right\"></span>\n </button>\n <h4>Fields ({{ selectedEntity ? getEntityFields(selectedEntity.ID).length : 0 }})</h4>\n </div>\n @if (fieldsSectionExpanded) {\n <div class=\"field-filters\">\n <button\n class=\"filter-btn\"\n [class.active]=\"fieldFilter === 'all'\"\n (click)=\"setFieldFilter('all')\"\n title=\"Show all fields\">\n All\n </button>\n <button\n class=\"filter-btn\"\n [class.active]=\"fieldFilter === 'keys'\"\n (click)=\"setFieldFilter('keys')\"\n title=\"Show primary keys and ID fields\">\n Keys\n </button>\n <button\n class=\"filter-btn\"\n [class.active]=\"fieldFilter === 'foreign_keys'\"\n (click)=\"setFieldFilter('foreign_keys')\"\n title=\"Show foreign key fields only\">\n FKs\n </button>\n <button\n class=\"filter-btn\"\n [class.active]=\"fieldFilter === 'regular'\"\n (click)=\"setFieldFilter('regular')\"\n title=\"Show regular data fields\">\n Regular\n </button>\n </div>\n }\n </div>\n @if (fieldsSectionExpanded) {\n <div class=\"fields-list\" #fieldsListContainer>\n @for (field of getEntityFields(selectedEntity?.ID || ''); track field.ID) {\n <div class=\"field-item\"\n [class]=\"{\n 'primary-key-field': field.IsPrimaryKey,\n 'foreign-key-field': field.RelatedEntityID && !field.IsPrimaryKey,\n 'regular-field': !field.IsPrimaryKey && !field.RelatedEntityID,\n 'field-expanded': isFieldDetailsExpanded(field.ID)\n }\"\n (click)=\"onFieldClick(field)\"\n [title]=\"'Click to see more details about ' + field.Name\">\n <div class=\"field-header\">\n <div class=\"field-name\">\n @if (field.IsPrimaryKey) {\n <span class=\"field-icon fa-solid fa-key\" title=\"Primary Key\"></span>\n } @else if (field.RelatedEntityID) {\n <span class=\"field-icon fa-solid fa-link\" title=\"Foreign Key\"></span>\n }\n {{ field.Name }}\n </div>\n <div class=\"field-actions\">\n @if (hasFieldPossibleValues(field)) {\n <button\n class=\"field-values-btn\"\n (click)=\"toggleFieldValues(field.ID)\"\n [class.expanded]=\"isFieldValuesExpanded(field.ID)\"\n title=\"Toggle possible values\">\n <span class=\"fa-solid fa-list\"></span>\n </button>\n }\n @if (field.Description) {\n <button\n class=\"field-info-btn\"\n (click)=\"toggleFieldDescription(field.ID)\"\n [class.expanded]=\"isFieldDescriptionExpanded(field.ID)\"\n title=\"Toggle field description\">\n <span class=\"fa-solid fa-info-circle\"></span>\n </button>\n }\n <div class=\"field-badges\">\n @if (field.IsPrimaryKey) {\n <span class=\"field-badge primary-key\">PK</span>\n }\n @if (field.RelatedEntityID && !field.IsPrimaryKey) {\n <span class=\"field-badge foreign-key\">FK</span>\n }\n </div>\n </div>\n </div>\n <div class=\"field-details\">\n <div class=\"field-type\">{{ field.Type }}</div>\n @if (field.RelatedEntityID) {\n <div class=\"field-relation\">\n <span class=\"fa-solid fa-arrow-right\"></span>\n Related Entity\n </div>\n }\n </div>\n @if (field.Description && isFieldDescriptionExpanded(field.ID)) {\n <div class=\"field-description\">\n <div class=\"description-text\">{{ field.Description }}</div>\n </div>\n }\n @if (hasFieldPossibleValues(field) && isFieldValuesExpanded(field.ID)) {\n <div class=\"field-values\">\n <div class=\"values-header\">Possible Values:</div>\n <div class=\"values-list\">\n @for (value of getFieldPossibleValues(field); track value; let i = $index) {\n <span class=\"value-tag\">{{ value }}</span>\n }\n </div>\n </div>\n }\n @if (isFieldDetailsExpanded(field.ID)) {\n <div class=\"field-comprehensive-details\">\n @if (field.Description) {\n <div class=\"comprehensive-description-top\">\n <div class=\"description-content\">{{ field.Description }}</div>\n </div>\n }\n @if (field.EntityFieldValues && field.EntityFieldValues.length > 0) {\n <div class=\"field-values-comprehensive\">\n <div class=\"values-header\">\n <span class=\"fa-solid fa-list\"></span>\n Possible Values ({{ field.EntityFieldValues.length }})\n </div>\n <div class=\"values-grid\">\n @for (fieldValue of getSortedEntityFieldValues(field); track fieldValue.ID) {\n <div class=\"value-item\">\n <div class=\"value-main\">\n <span class=\"value-text\">{{ fieldValue.Value }}</span>\n @if (fieldValue.Code && fieldValue.Code !== fieldValue.Value) {\n <span class=\"value-code\">[{{ fieldValue.Code }}]</span>\n }\n </div>\n @if (fieldValue.Description && fieldValue.Description !== fieldValue.Value) {\n <div class=\"value-description\">{{ fieldValue.Description }}</div>\n }\n </div>\n }\n </div>\n </div>\n }\n <div class=\"details-grid\">\n <div class=\"detail-row\">\n <span class=\"detail-label\">Data Type:</span>\n <span class=\"detail-value\">{{ field.Type }}</span>\n </div>\n <div class=\"detail-row\">\n <span class=\"detail-label\">Nullable:</span>\n <span class=\"detail-value\" [class]=\"field.AllowsNull ? 'nullable-yes' : 'nullable-no'\">\n {{ field.AllowsNull ? 'Yes' : 'No' }}\n </span>\n </div>\n @if (field.Length && field.Length > 0) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Max Length:</span>\n <span class=\"detail-value\">{{ field.Length }}</span>\n </div>\n }\n @if (field.Precision && field.Precision > 0) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Precision:</span>\n <span class=\"detail-value\">{{ field.Precision }}</span>\n </div>\n }\n @if (field.Scale && field.Scale > 0) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Scale:</span>\n <span class=\"detail-value\">{{ field.Scale }}</span>\n </div>\n }\n <div class=\"detail-row\">\n <span class=\"detail-label\">Virtual Field:</span>\n <span class=\"detail-value\" [class]=\"field.IsVirtual ? 'virtual-yes' : 'virtual-no'\">\n {{ field.IsVirtual ? 'Yes' : 'No' }}\n </span>\n </div>\n @if (field.DefaultValue) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Default Value:</span>\n <span class=\"detail-value default-value\">{{ field.DefaultValue }}</span>\n </div>\n }\n @if (field.RelatedEntityID) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Related Entity:</span>\n <span class=\"detail-value related-entity\"\n (click)=\"onRelatedEntityClick($event, field)\"\n title=\"Click to select {{ field.RelatedEntity }} in ERD\">\n {{ field.RelatedEntity }}\n <span class=\"fa-solid fa-arrow-right\"></span>\n </span>\n </div>\n }\n @if (field.AutoIncrement) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Auto Increment:</span>\n <span class=\"detail-value auto-increment\">Yes</span>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <div class=\"relationships-section\" [class.section-expanded]=\"relationshipsSectionExpanded\" [class.section-collapsed]=\"!relationshipsSectionExpanded\">\n <div class=\"section-header extra-padding\">\n <div class=\"section-title-group\" (click)=\"toggleRelationshipsSection()\">\n <button\n class=\"expand-btn\"\n [class.expanded]=\"relationshipsSectionExpanded\"\n title=\"Toggle relationships section\">\n <span class=\"fa-solid fa-chevron-right\"></span>\n </button>\n <h4>Related Entities ({{ selectedEntity ? getRelatedEntities(selectedEntity.ID).length : 0 }})</h4>\n </div>\n </div>\n @if (relationshipsSectionExpanded) {\n <div class=\"related-entities-list\" #relationshipsListContainer>\n @for (relatedEntity of getRelatedEntities(selectedEntity?.ID || ''); track relatedEntity.ID) {\n <div class=\"related-entity-item\" (click)=\"selectEntity(relatedEntity, true)\">\n <span class=\"fa-solid fa-database\"></span>\n <span class=\"entity-name\">{{ relatedEntity.Name || relatedEntity.SchemaName }}</span>\n <span class=\"zoom-indicator fa-solid fa-search-plus\" title=\"Click to zoom to entity\"></span>\n </div>\n }\n </div>\n }\n </div>\n</div>\n", styles: ["/**\n * Entity Details Component - MJ Design Token Styled\n * MemberJunction design tokens for the entity details panel\n */\n\n.details-panel {\n height: 100%;\n background: var(--mj-bg-page);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.details-panel .panel-header {\n flex-shrink: 0;\n}\n\n.details-panel .entity-info {\n flex-shrink: 0;\n}\n\n.details-panel .fields-section,\n.details-panel .relationships-section {\n display: flex;\n flex-direction: column;\n min-height: 0;\n transition: flex 0.3s ease;\n}\n\n.details-panel .fields-section.section-expanded,\n.details-panel .relationships-section.section-expanded {\n flex: 1;\n}\n\n.details-panel .fields-section.section-collapsed,\n.details-panel .relationships-section.section-collapsed {\n flex: 0 0 auto;\n}\n\n.details-panel .fields-section:last-child,\n.details-panel .relationships-section:last-child {\n border-bottom: none;\n}\n\n/* Panel Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.panel-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n/* Filled Button for Open */\n.open-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 6px 12px;\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border: none;\n border-radius: 20px;\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.open-btn:hover {\n box-shadow: var(--mj-shadow-md);\n}\n\n/* Icon Button for Close */\n.close-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.close-btn:hover {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n\n/* Entity Info Section */\n.entity-info {\n padding: 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.info-row {\n display: flex;\n justify-content: space-between;\n margin-bottom: 8px;\n font-size: 12px;\n}\n\n.info-row:last-child {\n margin-bottom: 0;\n}\n\n.info-row label {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 60px;\n}\n\n.info-row span {\n color: var(--mj-text-primary);\n flex: 1;\n text-align: right;\n}\n\n/* Status Badges */\n.status-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: 8px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.status-badge.status-active {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n}\n\n.status-badge.status-deprecated {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-900);\n}\n\n.status-badge.status-disabled {\n background: var(--mj-color-error-100);\n color: var(--mj-color-error-700);\n}\n\n.extra-padding {\n padding: 4px;\n}\n\n/* Fields and Relationships Sections */\n.fields-section,\n.relationships-section {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.fields-section .section-header,\n.relationships-section .section-header {\n flex-shrink: 0;\n padding: 16px 16px 12px 16px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n background: var(--mj-bg-surface-sunken);\n border: none;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.fields-section .section-header .section-title-group,\n.relationships-section .section-header .section-title-group {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.fields-section h4,\n.relationships-section h4 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n/* Expand Button */\n.expand-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.expand-btn:hover {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n\n.expand-btn .fa-solid {\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.expand-btn.expanded .fa-solid {\n transform: rotate(90deg);\n}\n\n.section-title-group {\n cursor: pointer;\n user-select: none;\n}\n\n.section-title-group:hover {\n opacity: 0.8;\n}\n\n/* Field Filter Buttons */\n.field-filters {\n display: flex;\n gap: 4px;\n}\n\n.filter-btn {\n display: inline-flex;\n align-items: center;\n padding: 4px 10px;\n font-size: 11px;\n background: var(--mj-bg-page);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.filter-btn:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-btn.active {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n/* Fields and Related Entities Lists */\n.fields-list,\n.related-entities-list {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 8px;\n overflow-y: auto;\n padding: 6px 16px 16px 16px;\n min-height: 0;\n}\n\n.fields-list::-webkit-scrollbar,\n.related-entities-list::-webkit-scrollbar {\n width: 6px;\n}\n\n.fields-list::-webkit-scrollbar-track,\n.related-entities-list::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n}\n\n.fields-list::-webkit-scrollbar-thumb,\n.related-entities-list::-webkit-scrollbar-thumb {\n background: var(--mj-color-neutral-400);\n border-radius: 3px;\n}\n\n.fields-list::-webkit-scrollbar-thumb:hover,\n.related-entities-list::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-secondary);\n}\n\n/* Field Items - Card Style */\n.field-item {\n padding: 10px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n font-size: 12px;\n cursor: pointer;\n user-select: none;\n transition: all 0.2s ease;\n}\n\n.field-item:hover {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.field-item.field-expanded {\n box-shadow: var(--mj-shadow-lg);\n transform: scale(1.01);\n}\n\n/* Primary Key Field - Success Accent */\n.field-item.primary-key-field {\n border-color: var(--mj-status-success);\n background: var(--mj-color-success-100);\n border-left: 4px solid var(--mj-status-success);\n}\n\n.field-item.primary-key-field.field-expanded {\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n}\n\n/* Foreign Key Field - Primary Accent */\n.field-item.foreign-key-field {\n border-color: var(--mj-brand-primary);\n background: var(--mj-color-accent-300);\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n.field-item.foreign-key-field.field-expanded {\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n/* Regular Field */\n.field-item.regular-field {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n.field-item.regular-field.field-expanded {\n box-shadow: var(--mj-shadow-md);\n}\n\n.field-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 4px;\n}\n\n.field-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.field-name {\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-icon {\n font-size: 10px;\n}\n\n.field-icon.fa-key {\n color: var(--mj-status-success);\n}\n\n.field-icon.fa-link {\n color: var(--mj-brand-primary);\n}\n\n/* Field Badges */\n.field-badges {\n display: flex;\n gap: 4px;\n}\n\n.field-badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 6px;\n border-radius: 4px;\n font-size: 9px;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.field-badge.primary-key {\n background: var(--mj-status-success);\n color: var(--mj-brand-on-primary);\n}\n\n.field-badge.foreign-key {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.field-type {\n color: var(--mj-text-secondary);\n font-size: 11px;\n}\n\n.field-relation {\n color: var(--mj-brand-primary);\n font-size: 11px;\n margin-top: 4px;\n}\n\n.field-relation .fa-solid {\n margin-right: 4px;\n}\n\n/* Field Info and Values Buttons */\n.field-info-btn,\n.field-values-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.field-info-btn:hover,\n.field-values-btn:hover {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.field-info-btn.expanded,\n.field-values-btn.expanded {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.field-info-btn .fa-solid,\n.field-values-btn .fa-solid {\n font-size: 10px;\n}\n\n/* Field Description */\n.field-description {\n margin-top: 8px;\n padding: 8px;\n background: var(--mj-bg-surface-sunken);\n border-left: 3px solid var(--mj-brand-primary);\n border-radius: 0 8px 8px 0;\n animation: fadeIn 0.3s ease-in-out;\n}\n\n.field-description .description-text {\n font-size: 12px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n font-style: italic;\n}\n\n.field-details {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n transform: translateY(-5px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Field Values - Warning Accent */\n.field-values {\n margin-top: 8px;\n padding: 8px;\n background: var(--mj-color-warning-50);\n border-left: 3px solid var(--mj-color-warning-500);\n border-radius: 0 8px 8px 0;\n animation: fadeIn 0.3s ease-in-out;\n}\n\n.field-values .values-header {\n font-size: 11px;\n color: var(--mj-color-warning-900);\n font-weight: 600;\n margin-bottom: 6px;\n}\n\n.field-values .values-list {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n.field-values .value-tag {\n display: inline-block;\n padding: 2px 8px;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n font-size: 9px;\n border-radius: 12px;\n font-weight: 500;\n white-space: nowrap;\n max-width: 80px;\n overflow: hidden;\n text-overflow: ellipsis;\n border: 1px solid var(--mj-border-default);\n}\n\n.field-values .value-tag:hover {\n background: var(--mj-bg-surface-active);\n cursor: default;\n}\n\n/* Field Comprehensive Details */\n.field-comprehensive-details {\n margin-top: 12px;\n padding: 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n animation: slideDown 0.3s ease-out;\n}\n\n.field-comprehensive-details .details-header {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 10px;\n padding-bottom: 6px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details .details-header .fa-solid {\n color: var(--mj-text-secondary);\n}\n\n.field-comprehensive-details .details-grid {\n display: grid;\n gap: 6px;\n}\n\n.field-comprehensive-details .detail-row {\n display: grid;\n grid-template-columns: 100px 1fr;\n gap: 8px;\n font-size: 12px;\n align-items: center;\n}\n\n.field-comprehensive-details .detail-label {\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-align: right;\n}\n\n.field-comprehensive-details .detail-value {\n color: var(--mj-text-primary);\n font-family: \"Courier New\", monospace;\n background: var(--mj-bg-page);\n padding: 2px 6px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details .detail-value.nullable-yes,\n.field-comprehensive-details .detail-value.nullable-no {\n color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n border-color: var(--mj-border-default);\n}\n\n.field-comprehensive-details .detail-value.virtual-yes {\n color: var(--mj-color-warning-900);\n background: var(--mj-color-warning-50);\n border-color: var(--mj-color-warning-500);\n}\n\n.field-comprehensive-details .detail-value.virtual-no {\n color: var(--mj-text-secondary);\n}\n\n.field-comprehensive-details .detail-value.default-value {\n color: var(--mj-color-success-800);\n background: var(--mj-color-success-100);\n border-color: var(--mj-status-success);\n}\n\n.field-comprehensive-details .detail-value.related-entity {\n color: var(--mj-color-brand-900);\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n cursor: pointer;\n user-select: none;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-comprehensive-details .detail-value.related-entity:hover {\n text-decoration: underline;\n background: color-mix(in srgb, var(--mj-color-accent-300) 80%, var(--mj-brand-primary) 20%);\n transform: translateX(2px);\n}\n\n.field-comprehensive-details .detail-value.related-entity .fa-external-link-alt {\n font-size: 8px;\n opacity: 0.7;\n transition: opacity 0.2s ease;\n}\n\n.field-comprehensive-details .detail-value.related-entity:hover .fa-external-link-alt {\n opacity: 1;\n}\n\n.field-comprehensive-details .detail-value.auto-increment {\n color: var(--mj-color-success-800);\n background: var(--mj-color-success-100);\n border-color: var(--mj-status-success);\n}\n\n.field-comprehensive-details .comprehensive-description-top {\n margin-bottom: 12px;\n padding-bottom: 10px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details .comprehensive-description-top .description-content {\n font-size: 12px;\n color: var(--mj-text-primary);\n line-height: 1.4;\n font-style: italic;\n background: var(--mj-color-accent-300);\n padding: 10px;\n border-radius: 8px;\n border: 1px solid var(--mj-brand-primary);\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n/* Field Values in Comprehensive Details */\n.field-comprehensive-details .field-values-comprehensive {\n margin-bottom: 12px;\n padding: 12px;\n background: var(--mj-color-warning-50);\n border: 1px solid var(--mj-color-warning-500);\n border-radius: 8px;\n border-left: 4px solid var(--mj-color-warning-500);\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-header {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-color-warning-900);\n margin-bottom: 10px;\n padding-bottom: 6px;\n border-bottom: 1px solid color-mix(in srgb, var(--mj-color-warning-500) 30%, transparent);\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-header .fa-solid {\n color: var(--mj-color-warning-500);\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-grid {\n display: flex;\n flex-direction: column;\n gap: 6px;\n max-height: 200px;\n overflow-y: auto;\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-grid::-webkit-scrollbar {\n width: 4px;\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-grid::-webkit-scrollbar-track {\n background: var(--mj-color-warning-50);\n border-radius: 2px;\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-grid::-webkit-scrollbar-thumb {\n background: var(--mj-color-warning-500);\n border-radius: 2px;\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-grid::-webkit-scrollbar-thumb:hover {\n background: var(--mj-color-warning-900);\n}\n\n.field-comprehensive-details .field-values-comprehensive .value-item {\n padding: 8px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.field-comprehensive-details .field-values-comprehensive .value-item .value-main {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 2px;\n}\n\n.field-comprehensive-details .field-values-comprehensive .value-item .value-main .value-text {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.field-comprehensive-details .field-values-comprehensive .value-item .value-main .value-code {\n font-size: 9px;\n color: var(--mj-color-warning-900);\n background: var(--mj-color-warning-50);\n padding: 1px 4px;\n border-radius: 4px;\n border: 1px solid var(--mj-color-warning-500);\n font-family: \"Courier New\", monospace;\n}\n\n.field-comprehensive-details .field-values-comprehensive .value-item .value-description {\n font-size: 9px;\n color: var(--mj-text-secondary);\n line-height: 1.3;\n font-style: italic;\n margin-top: 2px;\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n max-height: 0;\n }\n to {\n opacity: 1;\n transform: translateY(0);\n max-height: 500px;\n }\n}\n\n/* Related Entity Items - List Item Style */\n.related-entity-item {\n padding: 12px 14px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n transition: all 0.3s ease;\n position: relative;\n max-width: calc(100% - 4px);\n min-width: 0;\n flex-shrink: 1;\n}\n\n.related-entity-item:hover {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n transform: translateX(4px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.related-entity-item:hover .zoom-indicator {\n opacity: 1;\n transform: scale(1.1);\n}\n\n.related-entity-item:hover .fa-database {\n color: var(--mj-brand-primary);\n transform: scale(1.1);\n}\n\n.related-entity-item:hover::before {\n content: \"\";\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 3px;\n background: linear-gradient(to bottom, var(--mj-brand-primary), var(--mj-color-warning-500));\n border-radius: 0 3px 3px 0;\n}\n\n.related-entity-item .fa-solid {\n margin-right: 10px;\n color: var(--mj-text-secondary);\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.related-entity-item .fa-database {\n font-size: 14px;\n}\n\n.related-entity-item .entity-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n.related-entity-item .zoom-indicator {\n opacity: 0.4;\n color: var(--mj-brand-primary);\n font-size: 11px;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n"] }]
|
|
674
|
+
args: [{ standalone: false, selector: 'mj-entity-details', template: "<div class=\"details-panel\">\n <div class=\"panel-header\">\n <h3>{{ selectedEntity?.Name || selectedEntity?.SchemaName }}</h3>\n <div class=\"panel-actions\">\n <button class=\"open-btn\" (click)=\"onOpenEntity()\" title=\"Open Entity Record\">\n <span class=\"fa-solid fa-external-link-alt\"></span>\n Open\n </button>\n <button class=\"close-btn\" (click)=\"onClosePanel()\">\n <span class=\"fa-solid fa-times\"></span>\n </button>\n </div>\n </div>\n\n <div class=\"entity-info\">\n <div class=\"info-row\">\n <label>Schema:</label>\n <span>{{ selectedEntity?.SchemaName }}</span>\n </div>\n <div class=\"info-row\">\n <label>Table:</label>\n <span>{{ selectedEntity?.BaseTable }}</span>\n </div>\n @if (selectedEntity?.Description) {\n <div class=\"info-row\">\n <label>Description:</label>\n <span>{{ selectedEntity?.Description }}</span>\n </div>\n }\n </div>\n\n <div class=\"fields-section\" [class.section-expanded]=\"fieldsSectionExpanded\" [class.section-collapsed]=\"!fieldsSectionExpanded\">\n <div class=\"section-header extra-padding\">\n <div class=\"section-title-group\" (click)=\"toggleFieldsSection()\">\n <button\n class=\"expand-btn\"\n [class.expanded]=\"fieldsSectionExpanded\"\n title=\"Toggle fields section\">\n <span class=\"fa-solid fa-chevron-right\"></span>\n </button>\n <h4>Fields ({{ selectedEntity ? getEntityFields(selectedEntity.ID).length : 0 }})</h4>\n </div>\n @if (fieldsSectionExpanded) {\n <div class=\"field-filters\">\n <button\n class=\"filter-btn\"\n [class.active]=\"fieldFilter === 'all'\"\n (click)=\"setFieldFilter('all')\"\n title=\"Show all fields\">\n All\n </button>\n <button\n class=\"filter-btn\"\n [class.active]=\"fieldFilter === 'keys'\"\n (click)=\"setFieldFilter('keys')\"\n title=\"Show primary keys and ID fields\">\n Keys\n </button>\n <button\n class=\"filter-btn\"\n [class.active]=\"fieldFilter === 'foreign_keys'\"\n (click)=\"setFieldFilter('foreign_keys')\"\n title=\"Show foreign key fields only\">\n FKs\n </button>\n <button\n class=\"filter-btn\"\n [class.active]=\"fieldFilter === 'regular'\"\n (click)=\"setFieldFilter('regular')\"\n title=\"Show regular data fields\">\n Regular\n </button>\n </div>\n }\n </div>\n @if (fieldsSectionExpanded) {\n <div class=\"fields-list\" #fieldsListContainer>\n @for (field of getEntityFields(selectedEntity?.ID || ''); track field.ID) {\n <div class=\"field-item\"\n [class]=\"{\n 'primary-key-field': field.IsPrimaryKey,\n 'foreign-key-field': field.RelatedEntityID && !field.IsPrimaryKey,\n 'regular-field': !field.IsPrimaryKey && !field.RelatedEntityID,\n 'field-expanded': isFieldDetailsExpanded(field.ID)\n }\"\n (click)=\"onFieldClick(field)\"\n [title]=\"'Click to see more details about ' + field.Name\">\n <div class=\"field-header\">\n <div class=\"field-name\">\n @if (field.IsPrimaryKey) {\n <span class=\"field-icon fa-solid fa-key\" title=\"Primary Key\"></span>\n } @else if (field.RelatedEntityID) {\n <span class=\"field-icon fa-solid fa-link\" title=\"Foreign Key\"></span>\n }\n {{ field.Name }}\n </div>\n <div class=\"field-actions\">\n @if (hasFieldPossibleValues(field)) {\n <button\n class=\"field-values-btn\"\n (click)=\"toggleFieldValues(field.ID)\"\n [class.expanded]=\"isFieldValuesExpanded(field.ID)\"\n title=\"Toggle possible values\">\n <span class=\"fa-solid fa-list\"></span>\n </button>\n }\n @if (field.Description) {\n <button\n class=\"field-info-btn\"\n (click)=\"toggleFieldDescription(field.ID)\"\n [class.expanded]=\"isFieldDescriptionExpanded(field.ID)\"\n title=\"Toggle field description\">\n <span class=\"fa-solid fa-info-circle\"></span>\n </button>\n }\n <div class=\"field-badges\">\n @if (field.IsPrimaryKey) {\n <span class=\"field-badge primary-key\">PK</span>\n }\n @if (field.RelatedEntityID && !field.IsPrimaryKey) {\n <span class=\"field-badge foreign-key\">FK</span>\n }\n </div>\n </div>\n </div>\n <div class=\"field-details\">\n <div class=\"field-type\">{{ field.Type }}</div>\n @if (field.RelatedEntityID) {\n <div class=\"field-relation\">\n <span class=\"fa-solid fa-arrow-right\"></span>\n Related Entity\n </div>\n }\n </div>\n @if (field.Description && isFieldDescriptionExpanded(field.ID)) {\n <div class=\"field-description\">\n <div class=\"description-text\">{{ field.Description }}</div>\n </div>\n }\n @if (hasFieldPossibleValues(field) && isFieldValuesExpanded(field.ID)) {\n <div class=\"field-values\">\n <div class=\"values-header\">Possible Values:</div>\n <div class=\"values-list\">\n @for (value of getFieldPossibleValues(field); track value; let i = $index) {\n <span class=\"value-tag\">{{ value }}</span>\n }\n </div>\n </div>\n }\n @if (isFieldDetailsExpanded(field.ID)) {\n <div class=\"field-comprehensive-details\">\n @if (field.Description) {\n <div class=\"comprehensive-description-top\">\n <div class=\"description-content\">{{ field.Description }}</div>\n </div>\n }\n @if (field.EntityFieldValues && field.EntityFieldValues.length > 0) {\n <div class=\"field-values-comprehensive\">\n <div class=\"values-header\">\n <span class=\"fa-solid fa-list\"></span>\n Possible Values ({{ field.EntityFieldValues.length }})\n </div>\n <div class=\"values-grid\">\n @for (fieldValue of getSortedEntityFieldValues(field); track fieldValue.ID) {\n <div class=\"value-item\">\n <div class=\"value-main\">\n <span class=\"value-text\">{{ fieldValue.Value }}</span>\n @if (fieldValue.Code && fieldValue.Code !== fieldValue.Value) {\n <span class=\"value-code\">[{{ fieldValue.Code }}]</span>\n }\n </div>\n @if (fieldValue.Description && fieldValue.Description !== fieldValue.Value) {\n <div class=\"value-description\">{{ fieldValue.Description }}</div>\n }\n </div>\n }\n </div>\n </div>\n }\n <div class=\"details-grid\">\n <div class=\"detail-row\">\n <span class=\"detail-label\">Data Type:</span>\n <span class=\"detail-value\">{{ field.Type }}</span>\n </div>\n <div class=\"detail-row\">\n <span class=\"detail-label\">Nullable:</span>\n <span class=\"detail-value\" [class]=\"field.AllowsNull ? 'nullable-yes' : 'nullable-no'\">\n {{ field.AllowsNull ? 'Yes' : 'No' }}\n </span>\n </div>\n @if (field.Length && field.Length > 0) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Max Length:</span>\n <span class=\"detail-value\">{{ field.Length }}</span>\n </div>\n }\n @if (field.Precision && field.Precision > 0) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Precision:</span>\n <span class=\"detail-value\">{{ field.Precision }}</span>\n </div>\n }\n @if (field.Scale && field.Scale > 0) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Scale:</span>\n <span class=\"detail-value\">{{ field.Scale }}</span>\n </div>\n }\n <div class=\"detail-row\">\n <span class=\"detail-label\">Virtual Field:</span>\n <span class=\"detail-value\" [class]=\"field.IsVirtual ? 'virtual-yes' : 'virtual-no'\">\n {{ field.IsVirtual ? 'Yes' : 'No' }}\n </span>\n </div>\n @if (field.DefaultValue) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Default Value:</span>\n <span class=\"detail-value default-value\">{{ field.DefaultValue }}</span>\n </div>\n }\n @if (field.RelatedEntityID) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Related Entity:</span>\n <span class=\"detail-value related-entity\"\n (click)=\"onRelatedEntityClick($event, field)\"\n title=\"Click to select {{ field.RelatedEntity }} in ERD\">\n {{ field.RelatedEntity }}\n <span class=\"fa-solid fa-arrow-right\"></span>\n </span>\n </div>\n }\n @if (field.AutoIncrement) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Auto Increment:</span>\n <span class=\"detail-value auto-increment\">Yes</span>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <div class=\"relationships-section\" [class.section-expanded]=\"relationshipsSectionExpanded\" [class.section-collapsed]=\"!relationshipsSectionExpanded\">\n <div class=\"section-header extra-padding\">\n <div class=\"section-title-group\" (click)=\"toggleRelationshipsSection()\">\n <button\n class=\"expand-btn\"\n [class.expanded]=\"relationshipsSectionExpanded\"\n title=\"Toggle relationships section\">\n <span class=\"fa-solid fa-chevron-right\"></span>\n </button>\n <h4>Related Entities ({{ selectedEntity ? getRelatedEntities(selectedEntity.ID).length : 0 }})</h4>\n </div>\n </div>\n @if (relationshipsSectionExpanded) {\n <div class=\"related-entities-list\" #relationshipsListContainer>\n @for (relatedEntity of getRelatedEntities(selectedEntity?.ID || ''); track relatedEntity.ID) {\n <div class=\"related-entity-item\" (click)=\"selectEntity(relatedEntity, true)\">\n <span class=\"fa-solid fa-database\"></span>\n <span class=\"entity-name\">{{ relatedEntity.Name || relatedEntity.SchemaName }}</span>\n <span class=\"zoom-indicator fa-solid fa-search-plus\" title=\"Click to zoom to entity\"></span>\n </div>\n }\n </div>\n }\n </div>\n</div>\n", styles: ["/**\n * Entity Details Component - MJ Design Token Styled\n * MemberJunction design tokens for the entity details panel\n */\n\n.details-panel {\n height: 100%;\n background: var(--mj-bg-page);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.details-panel .panel-header {\n flex-shrink: 0;\n}\n\n.details-panel .entity-info {\n flex-shrink: 0;\n}\n\n.details-panel .fields-section,\n.details-panel .relationships-section {\n display: flex;\n flex-direction: column;\n min-height: 0;\n transition: flex 0.3s ease;\n}\n\n.details-panel .fields-section.section-expanded,\n.details-panel .relationships-section.section-expanded {\n flex: 1;\n}\n\n.details-panel .fields-section.section-collapsed,\n.details-panel .relationships-section.section-collapsed {\n flex: 0 0 auto;\n}\n\n.details-panel .fields-section:last-child,\n.details-panel .relationships-section:last-child {\n border-bottom: none;\n}\n\n/* Panel Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.panel-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n/* Filled Button for Open */\n.open-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 6px 12px;\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border: none;\n border-radius: 20px;\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.open-btn:hover {\n box-shadow: var(--mj-shadow-md);\n}\n\n/* Icon Button for Close */\n.close-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.close-btn:hover {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n\n/* Entity Info Section */\n.entity-info {\n padding: 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.info-row {\n display: flex;\n justify-content: space-between;\n margin-bottom: 8px;\n font-size: 12px;\n}\n\n.info-row:last-child {\n margin-bottom: 0;\n}\n\n.info-row label {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 60px;\n}\n\n.info-row span {\n color: var(--mj-text-primary);\n flex: 1;\n text-align: right;\n}\n\n/* Status Badges */\n.status-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: 8px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.status-badge.status-active {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface-card));\n color: var(--mj-status-success);\n}\n\n.status-badge.status-deprecated {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface-card));\n color: var(--mj-status-warning);\n}\n\n.status-badge.status-disabled {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface-card));\n color: var(--mj-status-error);\n}\n\n.extra-padding {\n padding: 4px;\n}\n\n/* Fields and Relationships Sections */\n.fields-section,\n.relationships-section {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.fields-section .section-header,\n.relationships-section .section-header {\n flex-shrink: 0;\n padding: 16px 16px 12px 16px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n background: var(--mj-bg-surface-sunken);\n border: none;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.fields-section .section-header .section-title-group,\n.relationships-section .section-header .section-title-group {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.fields-section h4,\n.relationships-section h4 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n/* Expand Button */\n.expand-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.expand-btn:hover {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n\n.expand-btn .fa-solid {\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.expand-btn.expanded .fa-solid {\n transform: rotate(90deg);\n}\n\n.section-title-group {\n cursor: pointer;\n user-select: none;\n}\n\n.section-title-group:hover {\n opacity: 0.8;\n}\n\n/* Field Filter Buttons */\n.field-filters {\n display: flex;\n gap: 4px;\n}\n\n.filter-btn {\n display: inline-flex;\n align-items: center;\n padding: 4px 10px;\n font-size: 11px;\n background: var(--mj-bg-page);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.filter-btn:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-btn.active {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n/* Fields and Related Entities Lists */\n.fields-list,\n.related-entities-list {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 8px;\n overflow-y: auto;\n padding: 6px 16px 16px 16px;\n min-height: 0;\n}\n\n.fields-list::-webkit-scrollbar,\n.related-entities-list::-webkit-scrollbar {\n width: 6px;\n}\n\n.fields-list::-webkit-scrollbar-track,\n.related-entities-list::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n}\n\n.fields-list::-webkit-scrollbar-thumb,\n.related-entities-list::-webkit-scrollbar-thumb {\n background: var(--mj-text-disabled);\n border-radius: 3px;\n}\n\n.fields-list::-webkit-scrollbar-thumb:hover,\n.related-entities-list::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-secondary);\n}\n\n/* Field Items - Card Style */\n.field-item {\n padding: 10px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n font-size: 12px;\n cursor: pointer;\n user-select: none;\n transition: all 0.2s ease;\n}\n\n.field-item:hover {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.field-item.field-expanded {\n box-shadow: var(--mj-shadow-lg);\n transform: scale(1.01);\n}\n\n/* Primary Key Field - Success Accent */\n.field-item.primary-key-field {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface-card));\n border-left: 4px solid var(--mj-status-success);\n}\n\n.field-item.primary-key-field.field-expanded {\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n}\n\n/* Foreign Key Field - Primary Accent */\n.field-item.foreign-key-field {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface-card));\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n.field-item.foreign-key-field.field-expanded {\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n/* Regular Field */\n.field-item.regular-field {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n.field-item.regular-field.field-expanded {\n box-shadow: var(--mj-shadow-md);\n}\n\n.field-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 4px;\n}\n\n.field-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.field-name {\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-icon {\n font-size: 10px;\n}\n\n.field-icon.fa-key {\n color: var(--mj-status-success);\n}\n\n.field-icon.fa-link {\n color: var(--mj-brand-primary);\n}\n\n/* Field Badges */\n.field-badges {\n display: flex;\n gap: 4px;\n}\n\n.field-badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 6px;\n border-radius: 4px;\n font-size: 9px;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.field-badge.primary-key {\n background: var(--mj-status-success);\n color: var(--mj-brand-on-primary);\n}\n\n.field-badge.foreign-key {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.field-type {\n color: var(--mj-text-secondary);\n font-size: 11px;\n}\n\n.field-relation {\n color: var(--mj-brand-primary);\n font-size: 11px;\n margin-top: 4px;\n}\n\n.field-relation .fa-solid {\n margin-right: 4px;\n}\n\n/* Field Info and Values Buttons */\n.field-info-btn,\n.field-values-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.field-info-btn:hover,\n.field-values-btn:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n color: var(--mj-brand-primary);\n}\n\n.field-info-btn.expanded,\n.field-values-btn.expanded {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n color: var(--mj-brand-primary);\n}\n\n.field-info-btn .fa-solid,\n.field-values-btn .fa-solid {\n font-size: 10px;\n}\n\n/* Field Description */\n.field-description {\n margin-top: 8px;\n padding: 8px;\n background: var(--mj-bg-surface-sunken);\n border-left: 3px solid var(--mj-brand-primary);\n border-radius: 0 8px 8px 0;\n animation: fadeIn 0.3s ease-in-out;\n}\n\n.field-description .description-text {\n font-size: 12px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n font-style: italic;\n}\n\n.field-details {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n transform: translateY(-5px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Field Values - Warning Accent */\n.field-values {\n margin-top: 8px;\n padding: 8px;\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface-card));\n border-left: 3px solid var(--mj-status-warning);\n border-radius: 0 8px 8px 0;\n animation: fadeIn 0.3s ease-in-out;\n}\n\n.field-values .values-header {\n font-size: 11px;\n color: var(--mj-text-primary);\n font-weight: 600;\n margin-bottom: 6px;\n}\n\n.field-values .values-list {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n.field-values .value-tag {\n display: inline-block;\n padding: 2px 8px;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n font-size: 9px;\n border-radius: 12px;\n font-weight: 500;\n white-space: nowrap;\n max-width: 80px;\n overflow: hidden;\n text-overflow: ellipsis;\n border: 1px solid var(--mj-border-default);\n}\n\n.field-values .value-tag:hover {\n background: var(--mj-bg-surface-active);\n cursor: default;\n}\n\n/* Field Comprehensive Details */\n.field-comprehensive-details {\n margin-top: 12px;\n padding: 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n animation: slideDown 0.3s ease-out;\n}\n\n.field-comprehensive-details .details-header {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 10px;\n padding-bottom: 6px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details .details-header .fa-solid {\n color: var(--mj-text-secondary);\n}\n\n.field-comprehensive-details .details-grid {\n display: grid;\n gap: 6px;\n}\n\n.field-comprehensive-details .detail-row {\n display: grid;\n grid-template-columns: 100px 1fr;\n gap: 8px;\n font-size: 12px;\n align-items: center;\n}\n\n.field-comprehensive-details .detail-label {\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-align: right;\n}\n\n.field-comprehensive-details .detail-value {\n color: var(--mj-text-primary);\n font-family: \"Courier New\", monospace;\n background: var(--mj-bg-page);\n padding: 2px 6px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details .detail-value.nullable-yes,\n.field-comprehensive-details .detail-value.nullable-no {\n color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n border-color: var(--mj-border-default);\n}\n\n.field-comprehensive-details .detail-value.virtual-yes {\n color: var(--mj-text-primary);\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface-card));\n border-color: var(--mj-status-warning);\n}\n\n.field-comprehensive-details .detail-value.virtual-no {\n color: var(--mj-text-secondary);\n}\n\n.field-comprehensive-details .detail-value.default-value {\n color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface-card));\n border-color: var(--mj-status-success);\n}\n\n.field-comprehensive-details .detail-value.related-entity {\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n border-color: var(--mj-brand-primary);\n cursor: pointer;\n user-select: none;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-comprehensive-details .detail-value.related-entity:hover {\n text-decoration: underline;\n background: color-mix(in srgb, var(--mj-brand-primary) 25%, var(--mj-bg-surface-card));\n transform: translateX(2px);\n}\n\n.field-comprehensive-details .detail-value.related-entity .fa-external-link-alt {\n font-size: 8px;\n opacity: 0.7;\n transition: opacity 0.2s ease;\n}\n\n.field-comprehensive-details .detail-value.related-entity:hover .fa-external-link-alt {\n opacity: 1;\n}\n\n.field-comprehensive-details .detail-value.auto-increment {\n color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface-card));\n border-color: var(--mj-status-success);\n}\n\n.field-comprehensive-details .comprehensive-description-top {\n margin-bottom: 12px;\n padding-bottom: 10px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.field-comprehensive-details .comprehensive-description-top .description-content {\n font-size: 12px;\n color: var(--mj-text-primary);\n line-height: 1.4;\n font-style: italic;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n padding: 10px;\n border-radius: 8px;\n border: 1px solid var(--mj-brand-primary);\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n/* Field Values in Comprehensive Details */\n.field-comprehensive-details .field-values-comprehensive {\n margin-bottom: 12px;\n padding: 12px;\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface-card));\n border: 1px solid var(--mj-status-warning);\n border-radius: 8px;\n border-left: 4px solid var(--mj-status-warning);\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-header {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 10px;\n padding-bottom: 6px;\n border-bottom: 1px solid color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-header .fa-solid {\n color: var(--mj-status-warning);\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-grid {\n display: flex;\n flex-direction: column;\n gap: 6px;\n max-height: 200px;\n overflow-y: auto;\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-grid::-webkit-scrollbar {\n width: 4px;\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-grid::-webkit-scrollbar-track {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface-card));\n border-radius: 2px;\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-grid::-webkit-scrollbar-thumb {\n background: var(--mj-status-warning);\n border-radius: 2px;\n}\n\n.field-comprehensive-details .field-values-comprehensive .values-grid::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-primary);\n}\n\n.field-comprehensive-details .field-values-comprehensive .value-item {\n padding: 8px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.field-comprehensive-details .field-values-comprehensive .value-item .value-main {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 2px;\n}\n\n.field-comprehensive-details .field-values-comprehensive .value-item .value-main .value-text {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.field-comprehensive-details .field-values-comprehensive .value-item .value-main .value-code {\n font-size: 9px;\n color: var(--mj-text-primary);\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface-card));\n padding: 1px 4px;\n border-radius: 4px;\n border: 1px solid var(--mj-status-warning);\n font-family: \"Courier New\", monospace;\n}\n\n.field-comprehensive-details .field-values-comprehensive .value-item .value-description {\n font-size: 9px;\n color: var(--mj-text-secondary);\n line-height: 1.3;\n font-style: italic;\n margin-top: 2px;\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n max-height: 0;\n }\n to {\n opacity: 1;\n transform: translateY(0);\n max-height: 500px;\n }\n}\n\n/* Related Entity Items - List Item Style */\n.related-entity-item {\n padding: 12px 14px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n transition: all 0.3s ease;\n position: relative;\n max-width: calc(100% - 4px);\n min-width: 0;\n flex-shrink: 1;\n}\n\n.related-entity-item:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n border-color: var(--mj-brand-primary);\n transform: translateX(4px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.related-entity-item:hover .zoom-indicator {\n opacity: 1;\n transform: scale(1.1);\n}\n\n.related-entity-item:hover .fa-database {\n color: var(--mj-brand-primary);\n transform: scale(1.1);\n}\n\n.related-entity-item:hover::before {\n content: \"\";\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 3px;\n background: linear-gradient(to bottom, var(--mj-brand-primary), var(--mj-status-warning));\n border-radius: 0 3px 3px 0;\n}\n\n.related-entity-item .fa-solid {\n margin-right: 10px;\n color: var(--mj-text-secondary);\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.related-entity-item .fa-database {\n font-size: 14px;\n}\n\n.related-entity-item .entity-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n.related-entity-item .zoom-indicator {\n opacity: 0.4;\n color: var(--mj-brand-primary);\n font-size: 11px;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n"] }]
|
|
675
675
|
}], null, { fieldsListContainer: [{
|
|
676
676
|
type: ViewChild,
|
|
677
677
|
args: ['fieldsListContainer', { static: false }]
|
|
@@ -459,6 +459,8 @@ export declare class ERDDiagramComponent implements AfterViewInit, OnDestroy, On
|
|
|
459
459
|
private usesDagreLayout;
|
|
460
460
|
private createVisualization;
|
|
461
461
|
private renderNodeFields;
|
|
462
|
+
/** Truncate an SVG text element to fit within maxWidth, adding "…" if needed */
|
|
463
|
+
private truncateTextElement;
|
|
462
464
|
private attachNodeEventHandlers;
|
|
463
465
|
private attachLinkEventHandlers;
|
|
464
466
|
private updatePositions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"erd-diagram.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/erd-diagram.component.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"erd-diagram.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/erd-diagram.component.ts"],"names":[],"mappings":"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"}
|
|
@@ -1236,7 +1236,7 @@ export class ERDDiagramComponent {
|
|
|
1236
1236
|
.data(this.visibleLinks)
|
|
1237
1237
|
.enter()
|
|
1238
1238
|
.append('g')
|
|
1239
|
-
.attr('class', 'link-group');
|
|
1239
|
+
.attr('class', (d) => d.isSelfReference ? 'link-group self-reference' : 'link-group');
|
|
1240
1240
|
link
|
|
1241
1241
|
.append('path')
|
|
1242
1242
|
.attr('class', 'link')
|
|
@@ -1247,12 +1247,10 @@ export class ERDDiagramComponent {
|
|
|
1247
1247
|
.attr('marker-end', (d) => (d.isSelfReference ? 'none' : 'url(#end-arrow)'));
|
|
1248
1248
|
if (cfg.showRelationshipLabels) {
|
|
1249
1249
|
// Add background rect for label (will be sized after text is rendered)
|
|
1250
|
-
// Self-referencing links get
|
|
1250
|
+
// Self-referencing links get distinct styling via .self-reference CSS class
|
|
1251
1251
|
link
|
|
1252
1252
|
.append('rect')
|
|
1253
1253
|
.attr('class', 'link-label-bg')
|
|
1254
|
-
.attr('fill', (d) => d.isSelfReference ? '#e8f5e9' : 'white')
|
|
1255
|
-
.attr('stroke', (d) => d.isSelfReference ? '#4CAF50' : colors.linkColor)
|
|
1256
1254
|
.attr('stroke-width', 0.5)
|
|
1257
1255
|
.attr('stroke-opacity', (d) => d.isSelfReference ? 0.6 : 0.4)
|
|
1258
1256
|
.attr('rx', 2)
|
|
@@ -1262,7 +1260,6 @@ export class ERDDiagramComponent {
|
|
|
1262
1260
|
.append('text')
|
|
1263
1261
|
.attr('class', 'link-label')
|
|
1264
1262
|
.attr('font-size', '10px')
|
|
1265
|
-
.attr('fill', (d) => d.isSelfReference ? '#2e7d32' : colors.linkColor)
|
|
1266
1263
|
.attr('text-anchor', 'middle')
|
|
1267
1264
|
.attr('dominant-baseline', 'middle')
|
|
1268
1265
|
.text((d) => d.sourceField.name || '');
|
|
@@ -1314,7 +1311,7 @@ export class ERDDiagramComponent {
|
|
|
1314
1311
|
.attr('y', (d) => -d.height / 2 + 15)
|
|
1315
1312
|
.attr('fill', colors.nodeHeader);
|
|
1316
1313
|
// Node name
|
|
1317
|
-
nodeGroup
|
|
1314
|
+
const entityNameText = nodeGroup
|
|
1318
1315
|
.append('text')
|
|
1319
1316
|
.attr('class', 'entity-name')
|
|
1320
1317
|
.attr('text-anchor', 'middle')
|
|
@@ -1323,6 +1320,10 @@ export class ERDDiagramComponent {
|
|
|
1323
1320
|
.attr('font-weight', 'bold')
|
|
1324
1321
|
.attr('fill', colors.nodeHeaderText)
|
|
1325
1322
|
.text((d) => d.name);
|
|
1323
|
+
// Truncate entity names that overflow the header
|
|
1324
|
+
entityNameText.each((_d, i, nodes) => {
|
|
1325
|
+
this.truncateTextElement(nodes[i], cfg.nodeWidth - 16);
|
|
1326
|
+
});
|
|
1326
1327
|
// Add fields if configured
|
|
1327
1328
|
if (cfg.showFieldDetails) {
|
|
1328
1329
|
this.renderNodeFields(nodeGroup, colors);
|
|
@@ -1408,7 +1409,7 @@ export class ERDDiagramComponent {
|
|
|
1408
1409
|
.attr('font-size', '10px')
|
|
1409
1410
|
.attr('fill', colors.primaryKeyText)
|
|
1410
1411
|
.text('🔑');
|
|
1411
|
-
fieldGroup
|
|
1412
|
+
const pkNameEl = fieldGroup
|
|
1412
1413
|
.append('text')
|
|
1413
1414
|
.attr('class', 'field-name')
|
|
1414
1415
|
.attr('x', -d.width / 2 + 25)
|
|
@@ -1416,7 +1417,10 @@ export class ERDDiagramComponent {
|
|
|
1416
1417
|
.attr('font-size', '11px')
|
|
1417
1418
|
.attr('font-weight', 'bold')
|
|
1418
1419
|
.attr('fill', colors.primaryKeyText)
|
|
1419
|
-
.text(pk.name || '')
|
|
1420
|
+
.text(pk.name || '')
|
|
1421
|
+
.node();
|
|
1422
|
+
if (pkNameEl)
|
|
1423
|
+
this.truncateTextElement(pkNameEl, d.width - 33);
|
|
1420
1424
|
currentY += 20;
|
|
1421
1425
|
});
|
|
1422
1426
|
// Foreign keys
|
|
@@ -1438,18 +1442,41 @@ export class ERDDiagramComponent {
|
|
|
1438
1442
|
.attr('font-size', '10px')
|
|
1439
1443
|
.attr('fill', colors.foreignKeyText)
|
|
1440
1444
|
.text('🔗');
|
|
1441
|
-
fieldGroup
|
|
1445
|
+
const fkNameEl = fieldGroup
|
|
1442
1446
|
.append('text')
|
|
1443
1447
|
.attr('class', 'field-name')
|
|
1444
1448
|
.attr('x', -d.width / 2 + 25)
|
|
1445
1449
|
.attr('y', currentY - 2)
|
|
1446
1450
|
.attr('font-size', '11px')
|
|
1447
1451
|
.attr('fill', colors.foreignKeyText)
|
|
1448
|
-
.text(fk.name || '')
|
|
1452
|
+
.text(fk.name || '')
|
|
1453
|
+
.node();
|
|
1454
|
+
if (fkNameEl)
|
|
1455
|
+
this.truncateTextElement(fkNameEl, d.width - 33);
|
|
1449
1456
|
currentY += 20;
|
|
1450
1457
|
});
|
|
1451
1458
|
});
|
|
1452
1459
|
}
|
|
1460
|
+
/** Truncate an SVG text element to fit within maxWidth, adding "…" if needed */
|
|
1461
|
+
truncateTextElement(textEl, maxWidth) {
|
|
1462
|
+
const original = textEl.textContent || '';
|
|
1463
|
+
if (!original || textEl.getComputedTextLength() <= maxWidth)
|
|
1464
|
+
return;
|
|
1465
|
+
// Binary search for the longest fitting substring
|
|
1466
|
+
let lo = 0;
|
|
1467
|
+
let hi = original.length;
|
|
1468
|
+
while (lo < hi) {
|
|
1469
|
+
const mid = Math.ceil((lo + hi) / 2);
|
|
1470
|
+
textEl.textContent = original.slice(0, mid) + '…';
|
|
1471
|
+
if (textEl.getComputedTextLength() <= maxWidth) {
|
|
1472
|
+
lo = mid;
|
|
1473
|
+
}
|
|
1474
|
+
else {
|
|
1475
|
+
hi = mid - 1;
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
textEl.textContent = lo < original.length ? original.slice(0, lo) + '…' : original;
|
|
1479
|
+
}
|
|
1453
1480
|
attachNodeEventHandlers(nodeGroup) {
|
|
1454
1481
|
nodeGroup
|
|
1455
1482
|
.on('click', (event, d) => {
|
|
@@ -1767,8 +1794,8 @@ export class ERDDiagramComponent {
|
|
|
1767
1794
|
.classed('highlighted', false)
|
|
1768
1795
|
.classed('relationship-highlighted', false)
|
|
1769
1796
|
.classed('connection-highlighted', false)
|
|
1770
|
-
.style('stroke',
|
|
1771
|
-
.style('stroke-width',
|
|
1797
|
+
.style('stroke', null)
|
|
1798
|
+
.style('stroke-width', null)
|
|
1772
1799
|
.style('filter', null);
|
|
1773
1800
|
this.svg.selectAll('.link-group')
|
|
1774
1801
|
.classed('highlighted', false);
|
|
@@ -1780,36 +1807,28 @@ export class ERDDiagramComponent {
|
|
|
1780
1807
|
updateSelectionHighlighting() {
|
|
1781
1808
|
if (!this.svg)
|
|
1782
1809
|
return;
|
|
1783
|
-
// Clear previous selection styling
|
|
1810
|
+
// Clear previous selection styling — remove inline styles so CSS classes take over
|
|
1784
1811
|
this.svg.selectAll('.node')
|
|
1785
1812
|
.classed('selected', false)
|
|
1786
1813
|
.select('.entity-rect')
|
|
1787
|
-
.style('stroke',
|
|
1788
|
-
.style('stroke-width',
|
|
1814
|
+
.style('stroke', null)
|
|
1815
|
+
.style('stroke-width', null)
|
|
1789
1816
|
.style('filter', null);
|
|
1790
1817
|
if (this.selectedNodeId) {
|
|
1791
|
-
const selectedColor = this.mergedConfig.colors?.selectedBorder || '#4CAF50';
|
|
1792
1818
|
this.svg.selectAll('.node')
|
|
1793
1819
|
.filter((d) => d.id === this.selectedNodeId)
|
|
1794
|
-
.classed('selected', true)
|
|
1795
|
-
.select('.entity-rect')
|
|
1796
|
-
.style('stroke', selectedColor)
|
|
1797
|
-
.style('stroke-width', '4px')
|
|
1798
|
-
.style('filter', `drop-shadow(0 0 8px ${selectedColor}80)`);
|
|
1820
|
+
.classed('selected', true);
|
|
1799
1821
|
}
|
|
1800
1822
|
}
|
|
1801
1823
|
updateHighlighting() {
|
|
1802
1824
|
if (!this.svg)
|
|
1803
1825
|
return;
|
|
1804
|
-
const highlightColor = this.mergedConfig.colors?.highlightBorder || '#ff9800';
|
|
1805
1826
|
const highlightSet = new Set(this.highlightedNodeIds);
|
|
1806
1827
|
this.svg.selectAll('.node')
|
|
1807
1828
|
.classed('highlighted', (d) => highlightSet.has(d.id))
|
|
1808
1829
|
.filter((d) => highlightSet.has(d.id))
|
|
1809
1830
|
.select('.entity-rect')
|
|
1810
|
-
.
|
|
1811
|
-
.style('stroke-width', '3px')
|
|
1812
|
-
.style('filter', `drop-shadow(0 0 6px ${highlightColor}80)`);
|
|
1831
|
+
.classed('highlighted', true);
|
|
1813
1832
|
}
|
|
1814
1833
|
emitStateChange() {
|
|
1815
1834
|
const state = this.getState();
|
|
@@ -1875,11 +1894,11 @@ export class ERDDiagramComponent {
|
|
|
1875
1894
|
i0.ɵɵconditional(ctx.showHeader ? 1 : -1);
|
|
1876
1895
|
i0.ɵɵadvance(3);
|
|
1877
1896
|
i0.ɵɵconditional(ctx.isRefreshing ? 4 : -1);
|
|
1878
|
-
} }, styles: ["\n\n\n\n\n\n[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.erd-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.section-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.section-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n color: var(--mj-text-primary);\n}\n\n.erd-controls[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.control-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: var(--mj-bg-page);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.control-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-
|
|
1897
|
+
} }, styles: ["\n\n\n\n\n\n[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.erd-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.section-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.section-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n color: var(--mj-text-primary);\n}\n\n.erd-controls[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.control-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: var(--mj-bg-page);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.control-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n}\n\n.control-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.38;\n cursor: not-allowed;\n}\n\n.erd-container[_ngcontent-%COMP%] {\n flex: 1;\n position: relative;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n width: 100%;\n min-height: 400px;\n box-sizing: border-box;\n}\n\n.erd-container[_ngcontent-%COMP%] svg[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n width: 100% !important;\n height: 100% !important;\n box-sizing: border-box;\n}\n\n\n\n.loading-overlay[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-page);\n opacity: 0.95;\n backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-in-out;\n}\n\n.loading-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n}\n\n.loading-spinner[_ngcontent-%COMP%] {\n position: relative;\n width: 60px;\n height: 60px;\n}\n\n.spinner-ring[_ngcontent-%COMP%] {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-radius: 50%;\n animation: _ngcontent-%COMP%_spin 1.5s linear infinite;\n}\n\n.spinner-ring[_ngcontent-%COMP%]:nth-child(1) {\n border-top-color: var(--mj-brand-primary);\n animation-delay: 0s;\n}\n\n.spinner-ring[_ngcontent-%COMP%]:nth-child(2) {\n border-top-color: var(--mj-status-warning);\n animation-delay: 0.3s;\n transform: scale(0.8);\n}\n\n.spinner-ring[_ngcontent-%COMP%]:nth-child(3) {\n border-top-color: var(--mj-status-success);\n animation-delay: 0.6s;\n transform: scale(0.6);\n}\n\n.loading-text[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-weight: 500;\n text-align: center;\n}\n\n\n\n@keyframes _ngcontent-%COMP%_spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n\n\n[_nghost-%COMP%] .erd-container svg .node .entity-rect {\n fill: var(--mj-bg-surface-card);\n stroke: var(--mj-text-primary);\n}\n\n[_nghost-%COMP%] .erd-container svg .node .entity-header, \n[_nghost-%COMP%] .erd-container svg .node .entity-header-bottom {\n fill: var(--mj-brand-primary);\n}\n\n[_nghost-%COMP%] .erd-container svg .node .entity-name {\n fill: var(--mj-text-inverse);\n}\n\n\n\n[_nghost-%COMP%] .erd-container svg .field-group.primary-key .field-bg {\n fill: color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface-card));\n}\n\n[_nghost-%COMP%] .erd-container svg .field-group.primary-key .field-name, \n[_nghost-%COMP%] .erd-container svg .field-group.primary-key .field-icon {\n fill: var(--mj-text-primary);\n}\n\n[_nghost-%COMP%] .erd-container svg .field-group.foreign-key .field-bg {\n fill: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n}\n\n[_nghost-%COMP%] .erd-container svg .field-group.foreign-key .field-name, \n[_nghost-%COMP%] .erd-container svg .field-group.foreign-key .field-icon {\n fill: var(--mj-text-primary);\n}\n\n\n\n[_nghost-%COMP%] .erd-container svg .link-group .link-label-bg {\n fill: var(--mj-bg-surface-card);\n stroke: var(--mj-text-muted);\n}\n\n[_nghost-%COMP%] .erd-container svg .link-group .link-label {\n fill: var(--mj-text-muted);\n}\n\n[_nghost-%COMP%] .erd-container svg .link-group .link {\n stroke: var(--mj-text-muted);\n}\n\n[_nghost-%COMP%] .erd-container svg #end-arrow path {\n fill: var(--mj-text-muted);\n}\n\n\n\n[_nghost-%COMP%] .erd-container svg .node .entity-rect.highlighted {\n stroke: var(--mj-status-warning) !important;\n stroke-width: 3px !important;\n filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mj-status-warning) 50%, transparent));\n}\n\n[_nghost-%COMP%] .erd-container svg .node.selected .entity-rect {\n stroke: var(--mj-status-success) !important;\n stroke-width: 4px !important;\n filter: drop-shadow(0 0 8px color-mix(in srgb, var(--mj-status-success) 50%, transparent));\n}\n\n[_nghost-%COMP%] .erd-container svg .node.selected .entity-header {\n fill: color-mix(in srgb, var(--mj-status-success) 85%, black) !important;\n}\n\n[_nghost-%COMP%] .erd-container svg .node.selected .entity-header-bottom {\n fill: color-mix(in srgb, var(--mj-status-success) 85%, black) !important;\n}\n\n[_nghost-%COMP%] .erd-container svg .node.selected .entity-name {\n fill: var(--mj-text-inverse) !important;\n font-weight: bold !important;\n}\n\n\n\n[_nghost-%COMP%] .erd-container svg .node.relationship-connected .entity-rect.relationship-highlighted {\n stroke: var(--mj-status-success) !important;\n stroke-width: 3px !important;\n filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mj-status-success) 50%, transparent));\n}\n\n[_nghost-%COMP%] .erd-container svg .node.relationship-connected .entity-header {\n fill: var(--mj-status-success) !important;\n}\n\n[_nghost-%COMP%] .erd-container svg .node.relationship-connected .entity-header-bottom {\n fill: var(--mj-status-success) !important;\n}\n\n[_nghost-%COMP%] .erd-container svg .node.entity-connections-highlighted .entity-rect.connection-highlighted {\n stroke: var(--mj-status-warning) !important;\n stroke-width: 3px !important;\n filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mj-status-warning) 50%, transparent));\n opacity: 0.9;\n}\n\n[_nghost-%COMP%] .erd-container svg .node.entity-connections-highlighted .entity-header {\n fill: var(--mj-status-warning) !important;\n opacity: 0.8;\n}\n\n[_nghost-%COMP%] .erd-container svg .node.entity-connections-highlighted .entity-header-bottom {\n fill: var(--mj-status-warning) !important;\n opacity: 0.8;\n}\n\n\n\n[_nghost-%COMP%] .erd-container svg .link-group.self-reference .link-label-bg {\n fill: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface-card));\n stroke: var(--mj-status-success);\n}\n\n[_nghost-%COMP%] .erd-container svg .link-group.self-reference .link-label {\n fill: color-mix(in srgb, var(--mj-status-success) 80%, var(--mj-text-primary));\n}\n\n\n\n[_nghost-%COMP%] .erd-container svg .link-group .link {\n stroke-width: 2px;\n transition: all 0.2s ease;\n cursor: pointer;\n}\n\n[_nghost-%COMP%] .erd-container svg .link-group .link:hover {\n stroke-width: 3px;\n stroke: var(--mj-status-success);\n opacity: 1;\n}\n\n[_nghost-%COMP%] .erd-container svg .link-group .link.highlighted {\n stroke: var(--mj-status-success) !important;\n stroke-width: 4px !important;\n opacity: 1 !important;\n filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mj-status-success) 60%, transparent));\n}\n\n[_nghost-%COMP%] .erd-container svg .link-group .link-label {\n font-family: Roboto, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n opacity: 0.8;\n pointer-events: none;\n transition: opacity 0.2s ease;\n}\n\n[_nghost-%COMP%] .erd-container svg .link-group .link-label.highlighted {\n opacity: 1;\n font-weight: bold;\n fill: var(--mj-status-success);\n}\n\n[_nghost-%COMP%] .erd-container svg .link-group.highlighted {\n z-index: 10;\n}\n\n\n\n[_nghost-%COMP%] .erd-container svg .field-group .field-bg {\n transition: fill 0.2s;\n}\n\n[_nghost-%COMP%] .erd-container svg .field-group:hover .field-bg {\n fill: color-mix(in srgb, var(--mj-brand-primary) 20%, var(--mj-bg-surface-card)) !important;\n}"] });
|
|
1879
1898
|
}
|
|
1880
1899
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ERDDiagramComponent, [{
|
|
1881
1900
|
type: Component,
|
|
1882
|
-
args: [{ standalone: false, selector: 'mj-erd-diagram', template: "<div class=\"erd-section\">\n @if (showHeader) {\n <div class=\"section-header\">\n <h3>{{ headerTitle }}</h3>\n <div class=\"erd-controls\">\n <button class=\"control-btn\" (click)=\"zoomIn()\" title=\"Zoom In\">\n <span class=\"fa-solid fa-search-plus\"></span>\n </button>\n <button class=\"control-btn\" (click)=\"zoomOut()\" title=\"Zoom Out\">\n <span class=\"fa-solid fa-search-minus\"></span>\n </button>\n <button class=\"control-btn\" (click)=\"resetZoom()\" title=\"Reset Zoom\">\n <span class=\"fa-solid fa-expand\"></span>\n </button>\n <button class=\"control-btn\" (click)=\"refresh(); refreshRequested.emit()\" title=\"Refresh Diagram\">\n <span class=\"fa-solid fa-refresh\"></span>\n </button>\n </div>\n </div>\n }\n <div class=\"erd-container\" #erdContainer>\n @if (isRefreshing) {\n <div class=\"loading-overlay\">\n <div class=\"loading-content\">\n <div class=\"loading-spinner\">\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n </div>\n <div class=\"loading-text\">Loading diagram...</div>\n </div>\n </div>\n }\n </div>\n</div>\n", styles: ["/**\n * ERD Diagram Component - MJ Design Tokens\n * MJ theming for the Entity Relationship Diagram visualization\n */\n\n:host {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.erd-section {\n background: var(--mj-bg-page);\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.section-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.section-header h3 {\n margin: 0;\n color: var(--mj-text-primary);\n}\n\n.erd-controls {\n display: flex;\n gap: 8px;\n}\n\n.control-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: var(--mj-bg-page);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.control-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-color-neutral-400);\n color: var(--mj-text-primary);\n}\n\n.control-btn:disabled {\n opacity: 0.38;\n cursor: not-allowed;\n}\n\n.erd-container {\n flex: 1;\n position: relative;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n width: 100%;\n min-height: 400px;\n box-sizing: border-box;\n}\n\n.erd-container svg {\n position: absolute;\n top: 0;\n left: 0;\n width: 100% !important;\n height: 100% !important;\n box-sizing: border-box;\n}\n\n/* Loading overlay - using mj-loading component styling */\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-page);\n opacity: 0.95;\n backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.3s ease-in-out;\n}\n\n.loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n}\n\n.loading-spinner {\n position: relative;\n width: 60px;\n height: 60px;\n}\n\n.spinner-ring {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-radius: 50%;\n animation: spin 1.5s linear infinite;\n}\n\n.spinner-ring:nth-child(1) {\n border-top-color: var(--mj-brand-primary);\n animation-delay: 0s;\n}\n\n.spinner-ring:nth-child(2) {\n border-top-color: var(--mj-color-warning-500);\n animation-delay: 0.3s;\n transform: scale(0.8);\n}\n\n.spinner-ring:nth-child(3) {\n border-top-color: var(--mj-status-success);\n animation-delay: 0.6s;\n transform: scale(0.6);\n}\n\n.loading-text {\n color: var(--mj-text-secondary);\n font-weight: 500;\n text-align: center;\n}\n\n/* Animations */\n@keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* Node highlighting styles */\n:host ::ng-deep .erd-container svg .node .entity-rect.highlighted {\n stroke: var(--mj-status-success) !important;\n stroke-width: 4px !important;\n filter: drop-shadow(0 0 8px color-mix(in srgb, var(--mj-status-success) 60%, transparent));\n}\n\n:host ::ng-deep .erd-container svg .node.selected .entity-rect {\n stroke: #4CAF50 !important;\n stroke-width: 4px !important;\n filter: drop-shadow(0 0 8px rgba(76, 175, 80, 0.5));\n}\n\n:host ::ng-deep .erd-container svg .node.selected .entity-header {\n fill: #388E3C !important;\n}\n\n:host ::ng-deep .erd-container svg .node.selected .entity-header-bottom {\n fill: #388E3C !important;\n}\n\n:host ::ng-deep .erd-container svg .node.selected .entity-name {\n fill: white !important;\n font-weight: bold !important;\n}\n\n/* Related/connected nodes - using tertiary accent */\n:host ::ng-deep .erd-container svg .node.relationship-connected .entity-rect.relationship-highlighted {\n stroke: var(--mj-status-success) !important;\n stroke-width: 3px !important;\n filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mj-status-success) 50%, transparent));\n}\n\n:host ::ng-deep .erd-container svg .node.relationship-connected .entity-header {\n fill: var(--mj-status-success) !important;\n}\n\n:host ::ng-deep .erd-container svg .node.relationship-connected .entity-header-bottom {\n fill: var(--mj-status-success) !important;\n}\n\n:host ::ng-deep .erd-container svg .node.entity-connections-highlighted .entity-rect.connection-highlighted {\n stroke: var(--mj-color-warning-500) !important;\n stroke-width: 3px !important;\n filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mj-color-warning-500) 50%, transparent));\n opacity: 0.9;\n}\n\n:host ::ng-deep .erd-container svg .node.entity-connections-highlighted .entity-header {\n fill: var(--mj-color-warning-500) !important;\n opacity: 0.8;\n}\n\n:host ::ng-deep .erd-container svg .node.entity-connections-highlighted .entity-header-bottom {\n fill: var(--mj-color-warning-500) !important;\n opacity: 0.8;\n}\n\n/* Link styles */\n:host ::ng-deep .erd-container svg .link-group .link {\n stroke-width: 2px;\n transition: all 0.2s ease;\n cursor: pointer;\n}\n\n:host ::ng-deep .erd-container svg .link-group .link:hover {\n stroke-width: 3px;\n stroke: var(--mj-status-success);\n opacity: 1;\n}\n\n:host ::ng-deep .erd-container svg .link-group .link.highlighted {\n stroke: var(--mj-status-success) !important;\n stroke-width: 4px !important;\n opacity: 1 !important;\n filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mj-status-success) 60%, transparent));\n}\n\n:host ::ng-deep .erd-container svg .link-group .link-label {\n font-family: Roboto, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n opacity: 0.8;\n pointer-events: none;\n transition: opacity 0.2s ease;\n}\n\n:host ::ng-deep .erd-container svg .link-group .link-label.highlighted {\n opacity: 1;\n font-weight: bold;\n fill: var(--mj-status-success);\n}\n\n:host ::ng-deep .erd-container svg .link-group.highlighted {\n z-index: 10;\n}\n\n/* Field hover */\n:host ::ng-deep .erd-container svg .field-group .field-bg {\n transition: fill 0.2s;\n}\n\n:host ::ng-deep .erd-container svg .field-group:hover .field-bg {\n fill: var(--mj-color-accent-300) !important;\n}\n\n"] }]
|
|
1901
|
+
args: [{ standalone: false, selector: 'mj-erd-diagram', template: "<div class=\"erd-section\">\n @if (showHeader) {\n <div class=\"section-header\">\n <h3>{{ headerTitle }}</h3>\n <div class=\"erd-controls\">\n <button class=\"control-btn\" (click)=\"zoomIn()\" title=\"Zoom In\">\n <span class=\"fa-solid fa-search-plus\"></span>\n </button>\n <button class=\"control-btn\" (click)=\"zoomOut()\" title=\"Zoom Out\">\n <span class=\"fa-solid fa-search-minus\"></span>\n </button>\n <button class=\"control-btn\" (click)=\"resetZoom()\" title=\"Reset Zoom\">\n <span class=\"fa-solid fa-expand\"></span>\n </button>\n <button class=\"control-btn\" (click)=\"refresh(); refreshRequested.emit()\" title=\"Refresh Diagram\">\n <span class=\"fa-solid fa-refresh\"></span>\n </button>\n </div>\n </div>\n }\n <div class=\"erd-container\" #erdContainer>\n @if (isRefreshing) {\n <div class=\"loading-overlay\">\n <div class=\"loading-content\">\n <div class=\"loading-spinner\">\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n </div>\n <div class=\"loading-text\">Loading diagram...</div>\n </div>\n </div>\n }\n </div>\n</div>\n", styles: ["/**\n * ERD Diagram Component - MJ Design Tokens\n * MJ theming for the Entity Relationship Diagram visualization\n */\n\n:host {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.erd-section {\n background: var(--mj-bg-page);\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.section-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.section-header h3 {\n margin: 0;\n color: var(--mj-text-primary);\n}\n\n.erd-controls {\n display: flex;\n gap: 8px;\n}\n\n.control-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: var(--mj-bg-page);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.control-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n}\n\n.control-btn:disabled {\n opacity: 0.38;\n cursor: not-allowed;\n}\n\n.erd-container {\n flex: 1;\n position: relative;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n width: 100%;\n min-height: 400px;\n box-sizing: border-box;\n}\n\n.erd-container svg {\n position: absolute;\n top: 0;\n left: 0;\n width: 100% !important;\n height: 100% !important;\n box-sizing: border-box;\n}\n\n/* Loading overlay - using mj-loading component styling */\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-page);\n opacity: 0.95;\n backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.3s ease-in-out;\n}\n\n.loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n}\n\n.loading-spinner {\n position: relative;\n width: 60px;\n height: 60px;\n}\n\n.spinner-ring {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-radius: 50%;\n animation: spin 1.5s linear infinite;\n}\n\n.spinner-ring:nth-child(1) {\n border-top-color: var(--mj-brand-primary);\n animation-delay: 0s;\n}\n\n.spinner-ring:nth-child(2) {\n border-top-color: var(--mj-status-warning);\n animation-delay: 0.3s;\n transform: scale(0.8);\n}\n\n.spinner-ring:nth-child(3) {\n border-top-color: var(--mj-status-success);\n animation-delay: 0.6s;\n transform: scale(0.6);\n}\n\n.loading-text {\n color: var(--mj-text-secondary);\n font-weight: 500;\n text-align: center;\n}\n\n/* Animations */\n@keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* \u2500\u2500 Base node colors (override D3 presentation attributes) \u2500\u2500 */\n:host ::ng-deep .erd-container svg .node .entity-rect {\n fill: var(--mj-bg-surface-card);\n stroke: var(--mj-text-primary);\n}\n\n:host ::ng-deep .erd-container svg .node .entity-header,\n:host ::ng-deep .erd-container svg .node .entity-header-bottom {\n fill: var(--mj-brand-primary);\n}\n\n:host ::ng-deep .erd-container svg .node .entity-name {\n fill: var(--mj-text-inverse);\n}\n\n/* Field backgrounds and text */\n:host ::ng-deep .erd-container svg .field-group.primary-key .field-bg {\n fill: color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface-card));\n}\n\n:host ::ng-deep .erd-container svg .field-group.primary-key .field-name,\n:host ::ng-deep .erd-container svg .field-group.primary-key .field-icon {\n fill: var(--mj-text-primary);\n}\n\n:host ::ng-deep .erd-container svg .field-group.foreign-key .field-bg {\n fill: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface-card));\n}\n\n:host ::ng-deep .erd-container svg .field-group.foreign-key .field-name,\n:host ::ng-deep .erd-container svg .field-group.foreign-key .field-icon {\n fill: var(--mj-text-primary);\n}\n\n/* \u2500\u2500 Link colors \u2500\u2500 */\n:host ::ng-deep .erd-container svg .link-group .link-label-bg {\n fill: var(--mj-bg-surface-card);\n stroke: var(--mj-text-muted);\n}\n\n:host ::ng-deep .erd-container svg .link-group .link-label {\n fill: var(--mj-text-muted);\n}\n\n:host ::ng-deep .erd-container svg .link-group .link {\n stroke: var(--mj-text-muted);\n}\n\n:host ::ng-deep .erd-container svg #end-arrow path {\n fill: var(--mj-text-muted);\n}\n\n/* \u2500\u2500 Node highlighting styles \u2500\u2500 */\n:host ::ng-deep .erd-container svg .node .entity-rect.highlighted {\n stroke: var(--mj-status-warning) !important;\n stroke-width: 3px !important;\n filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mj-status-warning) 50%, transparent));\n}\n\n:host ::ng-deep .erd-container svg .node.selected .entity-rect {\n stroke: var(--mj-status-success) !important;\n stroke-width: 4px !important;\n filter: drop-shadow(0 0 8px color-mix(in srgb, var(--mj-status-success) 50%, transparent));\n}\n\n:host ::ng-deep .erd-container svg .node.selected .entity-header {\n fill: color-mix(in srgb, var(--mj-status-success) 85%, black) !important;\n}\n\n:host ::ng-deep .erd-container svg .node.selected .entity-header-bottom {\n fill: color-mix(in srgb, var(--mj-status-success) 85%, black) !important;\n}\n\n:host ::ng-deep .erd-container svg .node.selected .entity-name {\n fill: var(--mj-text-inverse) !important;\n font-weight: bold !important;\n}\n\n/* Related/connected nodes - using tertiary accent */\n:host ::ng-deep .erd-container svg .node.relationship-connected .entity-rect.relationship-highlighted {\n stroke: var(--mj-status-success) !important;\n stroke-width: 3px !important;\n filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mj-status-success) 50%, transparent));\n}\n\n:host ::ng-deep .erd-container svg .node.relationship-connected .entity-header {\n fill: var(--mj-status-success) !important;\n}\n\n:host ::ng-deep .erd-container svg .node.relationship-connected .entity-header-bottom {\n fill: var(--mj-status-success) !important;\n}\n\n:host ::ng-deep .erd-container svg .node.entity-connections-highlighted .entity-rect.connection-highlighted {\n stroke: var(--mj-status-warning) !important;\n stroke-width: 3px !important;\n filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mj-status-warning) 50%, transparent));\n opacity: 0.9;\n}\n\n:host ::ng-deep .erd-container svg .node.entity-connections-highlighted .entity-header {\n fill: var(--mj-status-warning) !important;\n opacity: 0.8;\n}\n\n:host ::ng-deep .erd-container svg .node.entity-connections-highlighted .entity-header-bottom {\n fill: var(--mj-status-warning) !important;\n opacity: 0.8;\n}\n\n/* Self-referencing links \u2014 distinct green accent */\n:host ::ng-deep .erd-container svg .link-group.self-reference .link-label-bg {\n fill: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface-card));\n stroke: var(--mj-status-success);\n}\n\n:host ::ng-deep .erd-container svg .link-group.self-reference .link-label {\n fill: color-mix(in srgb, var(--mj-status-success) 80%, var(--mj-text-primary));\n}\n\n/* Link styles */\n:host ::ng-deep .erd-container svg .link-group .link {\n stroke-width: 2px;\n transition: all 0.2s ease;\n cursor: pointer;\n}\n\n:host ::ng-deep .erd-container svg .link-group .link:hover {\n stroke-width: 3px;\n stroke: var(--mj-status-success);\n opacity: 1;\n}\n\n:host ::ng-deep .erd-container svg .link-group .link.highlighted {\n stroke: var(--mj-status-success) !important;\n stroke-width: 4px !important;\n opacity: 1 !important;\n filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mj-status-success) 60%, transparent));\n}\n\n:host ::ng-deep .erd-container svg .link-group .link-label {\n font-family: Roboto, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n opacity: 0.8;\n pointer-events: none;\n transition: opacity 0.2s ease;\n}\n\n:host ::ng-deep .erd-container svg .link-group .link-label.highlighted {\n opacity: 1;\n font-weight: bold;\n fill: var(--mj-status-success);\n}\n\n:host ::ng-deep .erd-container svg .link-group.highlighted {\n z-index: 10;\n}\n\n/* Field hover */\n:host ::ng-deep .erd-container svg .field-group .field-bg {\n transition: fill 0.2s;\n}\n\n:host ::ng-deep .erd-container svg .field-group:hover .field-bg {\n fill: color-mix(in srgb, var(--mj-brand-primary) 20%, var(--mj-bg-surface-card)) !important;\n}\n\n"] }]
|
|
1883
1902
|
}], null, { erdContainer: [{
|
|
1884
1903
|
type: ViewChild,
|
|
1885
1904
|
args: ['erdContainer', { static: false }]
|