@memberjunction/ng-dashboard-viewer 5.11.0 → 5.12.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/breadcrumb/dashboard-breadcrumb.component.js +2 -2
- package/dist/lib/config-dialogs/confirm-dialog.component.js +2 -2
- package/dist/lib/config-panels/artifact-config-panel.component.js +2 -2
- package/dist/lib/config-panels/query-config-panel.component.js +2 -2
- package/dist/lib/config-panels/view-config-panel.component.js +2 -2
- package/dist/lib/config-panels/weburl-config-panel.component.js +2 -2
- package/dist/lib/dashboard-browser/dashboard-browser.component.js +5 -5
- package/dist/lib/dashboard-browser/dashboard-browser.component.js.map +1 -1
- package/dist/lib/dashboard-viewer/dashboard-viewer.component.js +54 -54
- package/dist/lib/dashboard-viewer/dashboard-viewer.component.js.map +1 -1
- package/dist/lib/dialogs/add-panel-dialog/add-panel-dialog.component.js +2 -2
- package/dist/lib/dialogs/edit-part-dialog/edit-part-dialog.component.js +2 -2
- package/dist/lib/parts/artifact-part.component.js +2 -2
- package/dist/lib/parts/artifact-part.component.js.map +1 -1
- package/dist/lib/parts/query-part.component.js +2 -2
- package/dist/lib/parts/query-part.component.js.map +1 -1
- package/dist/lib/parts/view-part.component.js +2 -2
- package/dist/lib/parts/view-part.component.js.map +1 -1
- package/dist/lib/parts/weburl-part.component.js +2 -2
- package/dist/lib/parts/weburl-part.component.js.map +1 -1
- package/dist/lib/services/golden-layout-wrapper.service.js +1 -1
- package/dist/lib/services/golden-layout-wrapper.service.js.map +1 -1
- package/package.json +9 -9
|
@@ -669,7 +669,7 @@ export class DashboardViewerComponent {
|
|
|
669
669
|
// Create the panel wrapper with header and content
|
|
670
670
|
const wrapper = document.createElement('div');
|
|
671
671
|
wrapper.className = 'dashboard-part-wrapper';
|
|
672
|
-
wrapper.style.cssText = 'display: flex; flex-direction: column; height: 100%; background:
|
|
672
|
+
wrapper.style.cssText = 'display: flex; flex-direction: column; height: 100%; background: var(--mj-bg-surface);';
|
|
673
673
|
// Only show header in edit mode - GL tabs already display the title in view mode
|
|
674
674
|
if (this.isEditing) {
|
|
675
675
|
const header = this.createPartHeader(panel, panel.id);
|
|
@@ -745,16 +745,16 @@ export class DashboardViewerComponent {
|
|
|
745
745
|
align-items: center;
|
|
746
746
|
gap: 8px;
|
|
747
747
|
padding: 10px 12px;
|
|
748
|
-
background:
|
|
749
|
-
border-bottom: 1px solid
|
|
748
|
+
background: var(--mj-bg-surface-card);
|
|
749
|
+
border-bottom: 1px solid var(--mj-border-default);
|
|
750
750
|
min-height: 40px;
|
|
751
751
|
`;
|
|
752
752
|
// Icon and title
|
|
753
753
|
const titleSection = document.createElement('div');
|
|
754
754
|
titleSection.style.cssText = 'display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0;';
|
|
755
755
|
titleSection.innerHTML = `
|
|
756
|
-
<i class="${panel.icon || 'fa-solid fa-puzzle-piece'}" style="color:
|
|
757
|
-
<span style="font-weight: 500; font-size: 14px; color:
|
|
756
|
+
<i class="${panel.icon || 'fa-solid fa-puzzle-piece'}" style="color: var(--mj-brand-primary); font-size: 14px;"></i>
|
|
757
|
+
<span style="font-weight: 500; font-size: 14px; color: var(--mj-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">${panel.title}</span>
|
|
758
758
|
`;
|
|
759
759
|
header.appendChild(titleSection);
|
|
760
760
|
// Action buttons (only in edit mode)
|
|
@@ -774,19 +774,19 @@ export class DashboardViewerComponent {
|
|
|
774
774
|
border: none;
|
|
775
775
|
border-radius: 4px;
|
|
776
776
|
background: transparent;
|
|
777
|
-
color:
|
|
777
|
+
color: var(--mj-text-secondary);
|
|
778
778
|
cursor: pointer;
|
|
779
779
|
transition: all 0.15s;
|
|
780
780
|
`;
|
|
781
781
|
configBtn.innerHTML = '<i class="fa-solid fa-cog" style="font-size: 12px;"></i>';
|
|
782
782
|
configBtn.addEventListener('click', () => this.onConfigurePart(panelId));
|
|
783
783
|
configBtn.addEventListener('mouseenter', () => {
|
|
784
|
-
configBtn.style.background = '
|
|
785
|
-
configBtn.style.color = '
|
|
784
|
+
configBtn.style.background = 'var(--mj-border-default)';
|
|
785
|
+
configBtn.style.color = 'var(--mj-text-primary)';
|
|
786
786
|
});
|
|
787
787
|
configBtn.addEventListener('mouseleave', () => {
|
|
788
788
|
configBtn.style.background = 'transparent';
|
|
789
|
-
configBtn.style.color = '
|
|
789
|
+
configBtn.style.color = 'var(--mj-text-secondary)';
|
|
790
790
|
});
|
|
791
791
|
// Remove button
|
|
792
792
|
const removeBtn = document.createElement('button');
|
|
@@ -801,19 +801,19 @@ export class DashboardViewerComponent {
|
|
|
801
801
|
border: none;
|
|
802
802
|
border-radius: 4px;
|
|
803
803
|
background: transparent;
|
|
804
|
-
color:
|
|
804
|
+
color: var(--mj-text-secondary);
|
|
805
805
|
cursor: pointer;
|
|
806
806
|
transition: all 0.15s;
|
|
807
807
|
`;
|
|
808
808
|
removeBtn.innerHTML = '<i class="fa-solid fa-times" style="font-size: 12px;"></i>';
|
|
809
809
|
removeBtn.addEventListener('click', () => this.onRemovePart(panelId));
|
|
810
810
|
removeBtn.addEventListener('mouseenter', () => {
|
|
811
|
-
removeBtn.style.background = '
|
|
812
|
-
removeBtn.style.color = '
|
|
811
|
+
removeBtn.style.background = 'color-mix(in srgb, var(--mj-status-error) 10%, transparent)';
|
|
812
|
+
removeBtn.style.color = 'var(--mj-status-error)';
|
|
813
813
|
});
|
|
814
814
|
removeBtn.addEventListener('mouseleave', () => {
|
|
815
815
|
removeBtn.style.background = 'transparent';
|
|
816
|
-
removeBtn.style.color = '
|
|
816
|
+
removeBtn.style.color = 'var(--mj-text-secondary)';
|
|
817
817
|
});
|
|
818
818
|
actions.appendChild(configBtn);
|
|
819
819
|
actions.appendChild(removeBtn);
|
|
@@ -844,9 +844,9 @@ export class DashboardViewerComponent {
|
|
|
844
844
|
const url = config['url'];
|
|
845
845
|
if (!url) {
|
|
846
846
|
container.innerHTML = `
|
|
847
|
-
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color:
|
|
848
|
-
<i class="fa-solid fa-globe" style="font-size: 48px; color:
|
|
849
|
-
<h4 style="margin: 0 0 8px 0; color:
|
|
847
|
+
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: var(--mj-text-secondary); text-align: center; padding: 24px;">
|
|
848
|
+
<i class="fa-solid fa-globe" style="font-size: 48px; color: var(--mj-text-muted); margin-bottom: 16px;"></i>
|
|
849
|
+
<h4 style="margin: 0 0 8px 0; color: var(--mj-text-primary);">No URL Configured</h4>
|
|
850
850
|
<p style="margin: 0; font-size: 13px;">Click the configure button to set a URL for this part.</p>
|
|
851
851
|
</div>
|
|
852
852
|
`;
|
|
@@ -876,9 +876,9 @@ export class DashboardViewerComponent {
|
|
|
876
876
|
const entityName = config['entityName'];
|
|
877
877
|
if (!viewId && !entityName) {
|
|
878
878
|
container.innerHTML = `
|
|
879
|
-
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color:
|
|
880
|
-
<i class="fa-solid fa-table" style="font-size: 48px; color:
|
|
881
|
-
<h4 style="margin: 0 0 8px 0; color:
|
|
879
|
+
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: var(--mj-text-secondary); text-align: center; padding: 24px;">
|
|
880
|
+
<i class="fa-solid fa-table" style="font-size: 48px; color: var(--mj-text-muted); margin-bottom: 16px;"></i>
|
|
881
|
+
<h4 style="margin: 0 0 8px 0; color: var(--mj-text-primary);">No View Selected</h4>
|
|
882
882
|
<p style="margin: 0; font-size: 13px;">Click configure to select a view for this part.</p>
|
|
883
883
|
</div>
|
|
884
884
|
`;
|
|
@@ -888,21 +888,21 @@ export class DashboardViewerComponent {
|
|
|
888
888
|
const displayModeValue = config['displayMode'];
|
|
889
889
|
const displayMode = displayModeValue === 'grid' ? 'Grid View' : displayModeValue === 'cards' ? 'Card View' : 'Timeline View';
|
|
890
890
|
container.innerHTML = `
|
|
891
|
-
<div style="display: flex; flex-direction: column; height: 100%; background:
|
|
892
|
-
<div style="padding: 16px 20px; border-bottom: 1px solid
|
|
891
|
+
<div style="display: flex; flex-direction: column; height: 100%; background: var(--mj-bg-surface);">
|
|
892
|
+
<div style="padding: 16px 20px; border-bottom: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card);">
|
|
893
893
|
<div style="display: flex; align-items: center; gap: 12px;">
|
|
894
|
-
<i class="fa-solid fa-table" style="font-size: 20px; color:
|
|
894
|
+
<i class="fa-solid fa-table" style="font-size: 20px; color: var(--mj-brand-primary);"></i>
|
|
895
895
|
<div>
|
|
896
|
-
<div style="font-weight: 500; color:
|
|
897
|
-
<div style="font-size: 12px; color:
|
|
896
|
+
<div style="font-weight: 500; color: var(--mj-text-primary); font-size: 14px;">Entity View</div>
|
|
897
|
+
<div style="font-size: 12px; color: var(--mj-text-secondary);">${entityName || 'View ' + viewInfo}</div>
|
|
898
898
|
</div>
|
|
899
|
-
<span style="margin-left: auto; padding: 4px 10px; background:
|
|
899
|
+
<span style="margin-left: auto; padding: 4px 10px; background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent); color: var(--mj-brand-primary); border-radius: 12px; font-size: 11px; font-weight: 500;">${displayMode}</span>
|
|
900
900
|
</div>
|
|
901
901
|
</div>
|
|
902
|
-
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color:
|
|
902
|
+
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--mj-text-muted); padding: 24px;">
|
|
903
903
|
<i class="fa-solid fa-spinner fa-spin" style="font-size: 24px; margin-bottom: 12px;"></i>
|
|
904
904
|
<p style="margin: 0; font-size: 13px;">Entity grid loading...</p>
|
|
905
|
-
<p style="margin: 8px 0 0 0; font-size: 11px; color:
|
|
905
|
+
<p style="margin: 8px 0 0 0; font-size: 11px; color: var(--mj-text-muted);">Full implementation pending Angular integration</p>
|
|
906
906
|
</div>
|
|
907
907
|
</div>
|
|
908
908
|
`;
|
|
@@ -912,9 +912,9 @@ export class DashboardViewerComponent {
|
|
|
912
912
|
const queryName = config['queryName'];
|
|
913
913
|
if (!queryId && !queryName) {
|
|
914
914
|
container.innerHTML = `
|
|
915
|
-
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color:
|
|
916
|
-
<i class="fa-solid fa-database" style="font-size: 48px; color:
|
|
917
|
-
<h4 style="margin: 0 0 8px 0; color:
|
|
915
|
+
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: var(--mj-text-secondary); text-align: center; padding: 24px;">
|
|
916
|
+
<i class="fa-solid fa-database" style="font-size: 48px; color: var(--mj-text-muted); margin-bottom: 16px;"></i>
|
|
917
|
+
<h4 style="margin: 0 0 8px 0; color: var(--mj-text-primary);">No Query Selected</h4>
|
|
918
918
|
<p style="margin: 0; font-size: 13px;">Click configure to select a query for this part.</p>
|
|
919
919
|
</div>
|
|
920
920
|
`;
|
|
@@ -923,21 +923,21 @@ export class DashboardViewerComponent {
|
|
|
923
923
|
const autoRefreshSeconds = config['autoRefreshSeconds'] || 0;
|
|
924
924
|
const queryInfo = queryName || (queryId ? queryId.substring(0, 8) + '...' : 'Unknown');
|
|
925
925
|
container.innerHTML = `
|
|
926
|
-
<div style="display: flex; flex-direction: column; height: 100%; background:
|
|
927
|
-
<div style="padding: 16px 20px; border-bottom: 1px solid
|
|
926
|
+
<div style="display: flex; flex-direction: column; height: 100%; background: var(--mj-bg-surface);">
|
|
927
|
+
<div style="padding: 16px 20px; border-bottom: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card);">
|
|
928
928
|
<div style="display: flex; align-items: center; gap: 12px;">
|
|
929
|
-
<i class="fa-solid fa-database" style="font-size: 20px; color:
|
|
929
|
+
<i class="fa-solid fa-database" style="font-size: 20px; color: var(--mj-brand-primary);"></i>
|
|
930
930
|
<div>
|
|
931
|
-
<div style="font-weight: 500; color:
|
|
932
|
-
<div style="font-size: 12px; color:
|
|
931
|
+
<div style="font-weight: 500; color: var(--mj-text-primary); font-size: 14px;">Query Results</div>
|
|
932
|
+
<div style="font-size: 12px; color: var(--mj-text-secondary);">${queryInfo}</div>
|
|
933
933
|
</div>
|
|
934
|
-
<span style="margin-left: auto; padding: 4px 10px; background:
|
|
934
|
+
<span style="margin-left: auto; padding: 4px 10px; background: color-mix(in srgb, var(--mj-status-success) 10%, transparent); color: var(--mj-status-success); border-radius: 12px; font-size: 11px; font-weight: 500;">${autoRefreshSeconds > 0 ? 'Refresh: ' + autoRefreshSeconds + 's' : 'Manual refresh'}</span>
|
|
935
935
|
</div>
|
|
936
936
|
</div>
|
|
937
|
-
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color:
|
|
937
|
+
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--mj-text-muted); padding: 24px;">
|
|
938
938
|
<i class="fa-solid fa-spinner fa-spin" style="font-size: 24px; margin-bottom: 12px;"></i>
|
|
939
939
|
<p style="margin: 0; font-size: 13px;">Query grid loading...</p>
|
|
940
|
-
<p style="margin: 8px 0 0 0; font-size: 11px; color:
|
|
940
|
+
<p style="margin: 8px 0 0 0; font-size: 11px; color: var(--mj-text-muted);">Full implementation pending Angular integration</p>
|
|
941
941
|
</div>
|
|
942
942
|
</div>
|
|
943
943
|
`;
|
|
@@ -946,9 +946,9 @@ export class DashboardViewerComponent {
|
|
|
946
946
|
const artifactId = config['artifactId'];
|
|
947
947
|
if (!artifactId) {
|
|
948
948
|
container.innerHTML = `
|
|
949
|
-
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color:
|
|
950
|
-
<i class="fa-solid fa-cube" style="font-size: 48px; color:
|
|
951
|
-
<h4 style="margin: 0 0 8px 0; color:
|
|
949
|
+
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: var(--mj-text-secondary); text-align: center; padding: 24px;">
|
|
950
|
+
<i class="fa-solid fa-cube" style="font-size: 48px; color: var(--mj-text-muted); margin-bottom: 16px;"></i>
|
|
951
|
+
<h4 style="margin: 0 0 8px 0; color: var(--mj-text-primary);">No Artifact Selected</h4>
|
|
952
952
|
<p style="margin: 0; font-size: 13px;">Click configure to select an artifact for this part.</p>
|
|
953
953
|
</div>
|
|
954
954
|
`;
|
|
@@ -958,21 +958,21 @@ export class DashboardViewerComponent {
|
|
|
958
958
|
const artifactInfo = artifactId.substring(0, 8) + '...';
|
|
959
959
|
const versionInfo = versionNumber ? `v${versionNumber}` : 'Latest';
|
|
960
960
|
container.innerHTML = `
|
|
961
|
-
<div style="display: flex; flex-direction: column; height: 100%; background:
|
|
962
|
-
<div style="padding: 16px 20px; border-bottom: 1px solid
|
|
961
|
+
<div style="display: flex; flex-direction: column; height: 100%; background: var(--mj-bg-surface);">
|
|
962
|
+
<div style="padding: 16px 20px; border-bottom: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card);">
|
|
963
963
|
<div style="display: flex; align-items: center; gap: 12px;">
|
|
964
|
-
<i class="fa-solid fa-cube" style="font-size: 20px; color:
|
|
964
|
+
<i class="fa-solid fa-cube" style="font-size: 20px; color: var(--mj-brand-primary);"></i>
|
|
965
965
|
<div>
|
|
966
|
-
<div style="font-weight: 500; color:
|
|
967
|
-
<div style="font-size: 12px; color:
|
|
966
|
+
<div style="font-weight: 500; color: var(--mj-text-primary); font-size: 14px;">Artifact</div>
|
|
967
|
+
<div style="font-size: 12px; color: var(--mj-text-secondary);">ID: ${artifactInfo}</div>
|
|
968
968
|
</div>
|
|
969
|
-
<span style="margin-left: auto; padding: 4px 10px; background:
|
|
969
|
+
<span style="margin-left: auto; padding: 4px 10px; background: color-mix(in srgb, var(--mj-status-error) 10%, transparent); color: var(--mj-status-error); border-radius: 12px; font-size: 11px; font-weight: 500;">${versionInfo}</span>
|
|
970
970
|
</div>
|
|
971
971
|
</div>
|
|
972
|
-
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color:
|
|
972
|
+
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--mj-text-muted); padding: 24px;">
|
|
973
973
|
<i class="fa-solid fa-spinner fa-spin" style="font-size: 24px; margin-bottom: 12px;"></i>
|
|
974
974
|
<p style="margin: 0; font-size: 13px;">Artifact viewer loading...</p>
|
|
975
|
-
<p style="margin: 8px 0 0 0; font-size: 11px; color:
|
|
975
|
+
<p style="margin: 8px 0 0 0; font-size: 11px; color: var(--mj-text-muted);">Full implementation pending Angular integration</p>
|
|
976
976
|
</div>
|
|
977
977
|
</div>
|
|
978
978
|
`;
|
|
@@ -980,9 +980,9 @@ export class DashboardViewerComponent {
|
|
|
980
980
|
renderPlaceholderPart(panel, container, partType) {
|
|
981
981
|
const partTypeName = partType?.Name || 'Custom';
|
|
982
982
|
container.innerHTML = `
|
|
983
|
-
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color:
|
|
984
|
-
<i class="fa-solid fa-puzzle-piece" style="font-size: 48px; color:
|
|
985
|
-
<h4 style="margin: 0 0 8px 0; color:
|
|
983
|
+
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: var(--mj-text-secondary); text-align: center; padding: 24px;">
|
|
984
|
+
<i class="fa-solid fa-puzzle-piece" style="font-size: 48px; color: var(--mj-text-muted); margin-bottom: 16px;"></i>
|
|
985
|
+
<h4 style="margin: 0 0 8px 0; color: var(--mj-text-primary);">${partTypeName} Part</h4>
|
|
986
986
|
<p style="margin: 0; font-size: 13px;">This part type is not yet fully implemented.</p>
|
|
987
987
|
</div>
|
|
988
988
|
`;
|
|
@@ -1076,11 +1076,11 @@ export class DashboardViewerComponent {
|
|
|
1076
1076
|
i0.ɵɵconditional(ctx.isLoading ? 3 : -1);
|
|
1077
1077
|
i0.ɵɵadvance(3);
|
|
1078
1078
|
i0.ɵɵconditional(!ctx.hasPanels && !ctx.isLoading ? 6 : -1);
|
|
1079
|
-
} }, dependencies: [i1.LoadingComponent, i2.DashboardBreadcrumbComponent], styles: ["/**\n * Dashboard Viewer Component Styles\n *\n * IMPORTANT: For Golden Layout tabs to display correctly, you must import\n * Golden Layout's CSS in your application's global styles:\n *\n * @import 'golden-layout/dist/css/goldenlayout-base.css';\n *\n * Or add to your angular.json styles array:\n * \"node_modules/golden-layout/dist/css/goldenlayout-base.css\"\n */\n\n:host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n.dashboard-viewer {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: var(--dashboard-bg, #f5f5f5);\n}\n\n.dashboard-viewer.editing .layout-container {\n outline: 2px dashed var(--dashboard-edit-outline, #5c6bc0);\n outline-offset: -2px;\n}\n\n/* ========================================\n Toolbar\n ======================================== */\n\n.dashboard-toolbar {\n flex: 0 0 48px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 16px;\n background: var(--dashboard-toolbar-bg, #ffffff);\n border-bottom: 1px solid var(--dashboard-border, #e0e0e0);\n box-sizing: border-box;\n z-index: 10;\n}\n\n.toolbar-left,\n.toolbar-center,\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-left {\n flex: 1;\n}\n\n.toolbar-center {\n flex: 0 0 auto;\n}\n\n.toolbar-right {\n flex: 1;\n justify-content: flex-end;\n}\n\n.dashboard-title {\n font-size: 16px;\n font-weight: 500;\n color: var(--dashboard-title-color, #333);\n}\n\n.dashboard-title i {\n margin-right: 8px;\n color: var(--dashboard-title-icon, #5c6bc0);\n}\n\n.unsaved-indicator {\n font-size: 12px;\n color: var(--dashboard-unsaved-color, #ff9800);\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.unsaved-indicator i {\n font-size: 8px;\n}\n\n.toolbar-button {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: 1px solid var(--dashboard-button-border, #ddd);\n border-radius: 4px;\n background: var(--dashboard-button-bg, #fff);\n color: var(--dashboard-button-color, #333);\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.toolbar-button:hover {\n background: var(--dashboard-button-hover-bg, #f5f5f5);\n border-color: var(--dashboard-button-hover-border, #ccc);\n}\n\n.toolbar-button.active {\n background: var(--dashboard-button-active-bg, #e8eaf6);\n border-color: var(--dashboard-button-active-border, #5c6bc0);\n color: var(--dashboard-button-active-color, #5c6bc0);\n}\n\n.toolbar-button.primary {\n background: var(--dashboard-button-primary-bg, #5c6bc0);\n border-color: var(--dashboard-button-primary-border, #3f51b5);\n color: var(--dashboard-button-primary-color, #fff);\n}\n\n.toolbar-button.primary:hover {\n background: var(--dashboard-button-primary-hover-bg, #3f51b5);\n}\n\n.toolbar-button i {\n font-size: 14px;\n}\n\n/* ========================================\n Layout Container\n ======================================== */\n\n/* Layout container fills remaining space in the flex column */\n.layout-container {\n flex: 1;\n position: relative;\n overflow: hidden;\n min-height: 0;\n}\n\n/* ========================================\n Dashboard Panel Content (our wrapper)\n ======================================== */\n\n/* Dashboard panel wrapper (header + content) */\n:host ::ng-deep .dashboard-part-wrapper {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #fff;\n}\n\n/* Dashboard part header */\n:host ::ng-deep .dashboard-part-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);\n border-bottom: 1px solid #e0e0e0;\n min-height: 40px;\n flex-shrink: 0;\n}\n\n/* Dashboard part content */\n:host ::ng-deep .dashboard-part-content {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n/* ========================================\n Loading Overlay\n ======================================== */\n\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(255, 255, 255, 0.9);\n z-index: 100;\n}\n\n/* ========================================\n Empty State\n ======================================== */\n\n.empty-state {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n text-align: center;\n color: var(--dashboard-empty-color, #666);\n max-width: 400px;\n padding: 40px;\n}\n\n.empty-state .empty-icon {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: linear-gradient(135deg, #e8eaf6 0%, #c5cae9 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 24px;\n}\n\n.empty-state .empty-icon i {\n font-size: 36px;\n color: #5c6bc0;\n}\n\n.empty-state h3 {\n margin: 0 0 12px 0;\n font-size: 20px;\n font-weight: 500;\n color: #333;\n}\n\n.empty-state p {\n margin: 0 0 24px 0;\n font-size: 14px;\n color: var(--dashboard-empty-text, #666);\n line-height: 1.5;\n}\n\n.add-part-button {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 12px 24px;\n border: none;\n border-radius: 6px;\n background: linear-gradient(135deg, #5c6bc0 0%, #3f51b5 100%);\n color: #fff;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px rgba(92, 107, 192, 0.3);\n}\n\n.add-part-button:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(92, 107, 192, 0.4);\n}\n\n.add-part-button i {\n font-size: 14px;\n}\n\n/* ========================================\n Panel Error State\n ======================================== */\n\n:host ::ng-deep .panel-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 24px;\n text-align: center;\n color: var(--dashboard-error-color, #d32f2f);\n background: var(--dashboard-error-bg, #ffebee);\n}\n\n:host ::ng-deep .panel-error i {\n font-size: 32px;\n margin-bottom: 12px;\n}\n\n:host ::ng-deep .panel-error span {\n font-size: 14px;\n}\n\n/* ========================================\n Golden Layout Overrides\n These require ViewEncapsulation.None to work on dynamic GL elements\n ======================================== */\n\n/* Override shell's hide-tab-bar rule that hides GL headers when dashboard is inside shell */\n/* The shell hides .lm_header when mj-tab-container has hide-tab-bar class */\n/* We need to ensure OUR Golden Layout headers are always visible */\nmj-dashboard-viewer .lm_header {\n display: block !important;\n}\n\n/* Ensure GL root container fills available space */\nmj-dashboard-viewer .lm_goldenlayout {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure the root layout item fills space */\nmj-dashboard-viewer .lm_root {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure proper box-sizing for all GL layout elements */\nmj-dashboard-viewer .lm_item,\nmj-dashboard-viewer .lm_content,\nmj-dashboard-viewer .lm_stack,\nmj-dashboard-viewer .lm_row,\nmj-dashboard-viewer .lm_column {\n box-sizing: border-box !important;\n}\n\n/* Ensure layout items don't overflow */\nmj-dashboard-viewer .lm_item {\n overflow: hidden !important;\n}\n\n/* Fix for .lm_items - the content container inside stacks */\nmj-dashboard-viewer .lm_items {\n width: 100% !important;\n height: calc(100% - 38px) !important; /* Account for header height (38px) */\n box-sizing: border-box !important;\n position: relative !important;\n}\n\n/* When tabs are maximized, no header visible */\nmj-dashboard-viewer .lm_stack.lm_maximised > .lm_items {\n height: 100% !important;\n}\n\n/* Target the ComponentItem div inside lm_items */\nmj-dashboard-viewer .lm_items > div {\n width: 100% !important;\n height: 100% !important;\n box-sizing: border-box !important;\n flex-direction: column !important;\n}\n\n/* Only apply flex display to the active/visible tab content div */\nmj-dashboard-viewer .lm_items > div:not([style*=\"display: none\"]) {\n display: flex !important;\n}\n\n/* Clearfix for float-based row layout */\nmj-dashboard-viewer .lm_row::after {\n content: \"\" !important;\n display: table !important;\n clear: both !important;\n}\n\n/* Force content children to respect parent bounds */\nmj-dashboard-viewer .lm_content > * {\n max-width: 100% !important;\n width: 100% !important;\n}\n\nmj-dashboard-viewer .lm_content {\n background: white !important;\n display: flex !important;\n flex-direction: column !important;\n height: 100% !important;\n width: 100% !important;\n}\n\nmj-dashboard-viewer .lm_item_container {\n background: white !important;\n}\n\n/* Tab header styling */\nmj-dashboard-viewer .lm_header {\n height: 38px !important;\n padding-top: 2px !important;\n padding-left: 4px !important;\n background: #f5f5f5 !important;\n border-bottom: 1px solid #ebebeb !important;\n overflow: visible !important;\n box-sizing: border-box !important;\n}\n\nmj-dashboard-viewer .lm_tabs {\n height: 36px !important;\n}\n\n/* Hide Golden Layout window controls (popout, maximize) */\nmj-dashboard-viewer .lm_controls {\n display: none !important;\n}\n\n/* Tab styling */\nmj-dashboard-viewer .lm_header .lm_tab {\n padding: 0 16px 0 28px !important; /* Extra left padding for icon */\n font-size: 13px !important;\n height: 35px !important;\n line-height: 35px !important;\n box-sizing: border-box !important;\n cursor: pointer !important;\n user-select: none !important;\n background: transparent !important;\n border: none !important;\n border-bottom: 1px solid #ebebeb !important;\n transition: all 0.15s ease !important;\n position: relative !important;\n z-index: 1 !important;\n margin-right: 1px !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab:hover {\n background: #e8e8e8 !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab.lm_active {\n background: white !important;\n height: 36px !important;\n margin-bottom: -1px !important;\n margin-right: 0 !important;\n border: 1px solid #ebebeb !important;\n border-bottom-color: white !important;\n border-radius: 4px 4px 0 0 !important;\n z-index: 2 !important;\n}\n\nmj-dashboard-viewer .lm_title {\n cursor: pointer !important;\n user-select: none !important;\n}\n\n/* Panel icon styling - icon is direct child of .lm_tab to preserve GL's drag/drop */\n/* Positioned absolutely in the left padding area so it doesn't affect GL's title structure */\nmj-dashboard-viewer .lm_header .lm_tab .panel-icon {\n position: absolute !important;\n left: 10px !important;\n top: 50% !important;\n transform: translateY(-30%) !important; \n font-family: \"Font Awesome 6 Free\", \"Font Awesome 6 Pro\", \"Font Awesome 5 Free\", \"Font Awesome 5 Pro\", FontAwesome !important;\n font-weight: 900 !important; /* Required for solid icons */\n font-size: 12px !important;\n color: #5c6bc0 !important;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\nmj-dashboard-viewer .lm_close_tab {\n position: absolute !important;\n right: 4px !important;\n top: 50% !important;\n transform: translateY(-50%) !important;\n width: 16px !important;\n height: 16px !important;\n cursor: pointer !important;\n opacity: 0 !important;\n transition: all 0.15s ease !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab:hover .lm_close_tab {\n opacity: 0.7 !important;\n}\n\nmj-dashboard-viewer .lm_close_tab:hover {\n opacity: 1 !important;\n color: #c62828 !important;\n}\n\n/* Add padding for close button when editing */\nmj-dashboard-viewer .dashboard-viewer.editing .lm_header .lm_tab {\n padding-right: 24px !important;\n}\n\n/* ========================================\n View Mode (Not Editing) - Lock Layout\n ======================================== */\n\n/* Hide close buttons on tabs when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_close_tab {\n display: none !important;\n}\n\n/* Remove extra padding for close button when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_header .lm_tab {\n padding-right: 16px !important;\n}\n\n/* Disable splitter dragging when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_splitter {\n pointer-events: none !important;\n cursor: default !important;\n}\n\n/* Hide splitter drag handle visual when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_splitter .lm_drag_handle {\n display: none !important;\n}\n\n/* Disable tab dragging cursor when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_header .lm_tab {\n cursor: default !important;\n}\n\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_title {\n cursor: default !important;\n}\n"], encapsulation: 2 });
|
|
1079
|
+
} }, dependencies: [i1.LoadingComponent, i2.DashboardBreadcrumbComponent], styles: ["/**\n * Dashboard Viewer Component Styles\n *\n * IMPORTANT: For Golden Layout tabs to display correctly, you must import\n * Golden Layout's CSS in your application's global styles:\n *\n * @import 'golden-layout/dist/css/goldenlayout-base.css';\n *\n * Or add to your angular.json styles array:\n * \"node_modules/golden-layout/dist/css/goldenlayout-base.css\"\n */\n\n:host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n.dashboard-viewer {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: var(--dashboard-bg, var(--mj-bg-surface-card));\n}\n\n.dashboard-viewer.editing .layout-container {\n outline: 2px dashed var(--dashboard-edit-outline, var(--mj-brand-primary));\n outline-offset: -2px;\n}\n\n/* ========================================\n Toolbar\n ======================================== */\n\n.dashboard-toolbar {\n flex: 0 0 48px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 16px;\n background: var(--dashboard-toolbar-bg, var(--mj-bg-surface));\n border-bottom: 1px solid var(--dashboard-border, var(--mj-border-default));\n box-sizing: border-box;\n z-index: 10;\n}\n\n.toolbar-left,\n.toolbar-center,\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-left {\n flex: 1;\n}\n\n.toolbar-center {\n flex: 0 0 auto;\n}\n\n.toolbar-right {\n flex: 1;\n justify-content: flex-end;\n}\n\n.dashboard-title {\n font-size: 16px;\n font-weight: 500;\n color: var(--dashboard-title-color, var(--mj-text-primary));\n}\n\n.dashboard-title i {\n margin-right: 8px;\n color: var(--dashboard-title-icon, var(--mj-brand-primary));\n}\n\n.unsaved-indicator {\n font-size: 12px;\n color: var(--dashboard-unsaved-color, var(--mj-status-warning));\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.unsaved-indicator i {\n font-size: 8px;\n}\n\n.toolbar-button {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: 1px solid var(--dashboard-button-border, var(--mj-border-strong));\n border-radius: 4px;\n background: var(--dashboard-button-bg, var(--mj-bg-surface));\n color: var(--dashboard-button-color, var(--mj-text-primary));\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.toolbar-button:hover {\n background: var(--dashboard-button-hover-bg, var(--mj-bg-surface-card));\n border-color: var(--dashboard-button-hover-border, var(--mj-border-strong));\n}\n\n.toolbar-button.active {\n background: var(--dashboard-button-active-bg, color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface)));\n border-color: var(--dashboard-button-active-border, var(--mj-brand-primary));\n color: var(--dashboard-button-active-color, var(--mj-brand-primary));\n}\n\n.toolbar-button.primary {\n background: var(--dashboard-button-primary-bg, var(--mj-brand-primary));\n border-color: var(--dashboard-button-primary-border, var(--mj-brand-primary-hover));\n color: var(--dashboard-button-primary-color, var(--mj-text-inverse));\n}\n\n.toolbar-button.primary:hover {\n background: var(--dashboard-button-primary-hover-bg, var(--mj-brand-primary-hover));\n}\n\n.toolbar-button i {\n font-size: 14px;\n}\n\n/* ========================================\n Layout Container\n ======================================== */\n\n/* Layout container fills remaining space in the flex column */\n.layout-container {\n flex: 1;\n position: relative;\n overflow: hidden;\n min-height: 0;\n}\n\n/* ========================================\n Dashboard Panel Content (our wrapper)\n ======================================== */\n\n/* Dashboard panel wrapper (header + content) */\n:host ::ng-deep .dashboard-part-wrapper {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n}\n\n/* Dashboard part header */\n:host ::ng-deep .dashboard-part-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n min-height: 40px;\n flex-shrink: 0;\n}\n\n/* Dashboard part content */\n:host ::ng-deep .dashboard-part-content {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n/* ========================================\n Loading Overlay\n ======================================== */\n\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-bg-surface) 90%, transparent);\n z-index: 100;\n}\n\n/* ========================================\n Empty State\n ======================================== */\n\n.empty-state {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n text-align: center;\n color: var(--dashboard-empty-color, var(--mj-text-secondary));\n max-width: 400px;\n padding: 40px;\n}\n\n.empty-state .empty-icon {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 24px;\n}\n\n.empty-state .empty-icon i {\n font-size: 36px;\n color: var(--mj-brand-primary);\n}\n\n.empty-state h3 {\n margin: 0 0 12px 0;\n font-size: 20px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.empty-state p {\n margin: 0 0 24px 0;\n font-size: 14px;\n color: var(--dashboard-empty-text, var(--mj-text-secondary));\n line-height: 1.5;\n}\n\n.add-part-button {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 12px 24px;\n border: none;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n.add-part-button:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n.add-part-button i {\n font-size: 14px;\n}\n\n/* ========================================\n Panel Error State\n ======================================== */\n\n:host ::ng-deep .panel-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 24px;\n text-align: center;\n color: var(--dashboard-error-color, var(--mj-status-error));\n background: var(--dashboard-error-bg, color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface)));\n}\n\n:host ::ng-deep .panel-error i {\n font-size: 32px;\n margin-bottom: 12px;\n}\n\n:host ::ng-deep .panel-error span {\n font-size: 14px;\n}\n\n/* ========================================\n Golden Layout Overrides\n These require ViewEncapsulation.None to work on dynamic GL elements\n ======================================== */\n\n/* Override shell's hide-tab-bar rule that hides GL headers when dashboard is inside shell */\n/* The shell hides .lm_header when mj-tab-container has hide-tab-bar class */\n/* We need to ensure OUR Golden Layout headers are always visible */\nmj-dashboard-viewer .lm_header {\n display: block !important;\n}\n\n/* Ensure GL root container fills available space */\nmj-dashboard-viewer .lm_goldenlayout {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure the root layout item fills space */\nmj-dashboard-viewer .lm_root {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure proper box-sizing for all GL layout elements */\nmj-dashboard-viewer .lm_item,\nmj-dashboard-viewer .lm_content,\nmj-dashboard-viewer .lm_stack,\nmj-dashboard-viewer .lm_row,\nmj-dashboard-viewer .lm_column {\n box-sizing: border-box !important;\n}\n\n/* Ensure layout items don't overflow */\nmj-dashboard-viewer .lm_item {\n overflow: hidden !important;\n}\n\n/* Fix for .lm_items - the content container inside stacks */\nmj-dashboard-viewer .lm_items {\n width: 100% !important;\n height: calc(100% - 38px) !important; /* Account for header height (38px) */\n box-sizing: border-box !important;\n position: relative !important;\n}\n\n/* When tabs are maximized, no header visible */\nmj-dashboard-viewer .lm_stack.lm_maximised > .lm_items {\n height: 100% !important;\n}\n\n/* Target the ComponentItem div inside lm_items */\nmj-dashboard-viewer .lm_items > div {\n width: 100% !important;\n height: 100% !important;\n box-sizing: border-box !important;\n flex-direction: column !important;\n}\n\n/* Only apply flex display to the active/visible tab content div */\nmj-dashboard-viewer .lm_items > div:not([style*=\"display: none\"]) {\n display: flex !important;\n}\n\n/* Clearfix for float-based row layout */\nmj-dashboard-viewer .lm_row::after {\n content: \"\" !important;\n display: table !important;\n clear: both !important;\n}\n\n/* Force content children to respect parent bounds */\nmj-dashboard-viewer .lm_content > * {\n max-width: 100% !important;\n width: 100% !important;\n}\n\nmj-dashboard-viewer .lm_content {\n background: var(--mj-bg-surface) !important;\n display: flex !important;\n flex-direction: column !important;\n height: 100% !important;\n width: 100% !important;\n}\n\nmj-dashboard-viewer .lm_item_container {\n background: var(--mj-bg-surface) !important;\n}\n\n/* Tab header styling */\nmj-dashboard-viewer .lm_header {\n height: 38px !important;\n padding-top: 2px !important;\n padding-left: 4px !important;\n background: var(--mj-bg-surface-card) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n overflow: visible !important;\n box-sizing: border-box !important;\n}\n\nmj-dashboard-viewer .lm_tabs {\n height: 36px !important;\n}\n\n/* Hide Golden Layout window controls (popout, maximize) */\nmj-dashboard-viewer .lm_controls {\n display: none !important;\n}\n\n/* Tab styling */\nmj-dashboard-viewer .lm_header .lm_tab {\n padding: 0 16px 0 28px !important; /* Extra left padding for icon */\n font-size: 13px !important;\n height: 35px !important;\n line-height: 35px !important;\n box-sizing: border-box !important;\n cursor: pointer !important;\n user-select: none !important;\n background: transparent !important;\n border: none !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n transition: all 0.15s ease !important;\n position: relative !important;\n z-index: 1 !important;\n margin-right: 1px !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab:hover {\n background: var(--mj-bg-surface-sunken) !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab.lm_active {\n background: var(--mj-bg-surface) !important;\n height: 36px !important;\n margin-bottom: -1px !important;\n margin-right: 0 !important;\n border: 1px solid var(--mj-border-default) !important;\n border-bottom-color: var(--mj-bg-surface) !important;\n border-radius: 4px 4px 0 0 !important;\n z-index: 2 !important;\n}\n\nmj-dashboard-viewer .lm_title {\n cursor: pointer !important;\n user-select: none !important;\n}\n\n/* Panel icon styling - icon is direct child of .lm_tab to preserve GL's drag/drop */\n/* Positioned absolutely in the left padding area so it doesn't affect GL's title structure */\nmj-dashboard-viewer .lm_header .lm_tab .panel-icon {\n position: absolute !important;\n left: 10px !important;\n top: 50% !important;\n transform: translateY(-30%) !important;\n font-family: \"Font Awesome 6 Free\", \"Font Awesome 6 Pro\", \"Font Awesome 5 Free\", \"Font Awesome 5 Pro\", FontAwesome !important;\n font-weight: 900 !important; /* Required for solid icons */\n font-size: 12px !important;\n color: var(--mj-brand-primary) !important;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\nmj-dashboard-viewer .lm_close_tab {\n position: absolute !important;\n right: 4px !important;\n top: 50% !important;\n transform: translateY(-50%) !important;\n width: 16px !important;\n height: 16px !important;\n cursor: pointer !important;\n opacity: 0 !important;\n transition: all 0.15s ease !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab:hover .lm_close_tab {\n opacity: 0.7 !important;\n}\n\nmj-dashboard-viewer .lm_close_tab:hover {\n opacity: 1 !important;\n color: var(--mj-status-error) !important;\n}\n\n/* Add padding for close button when editing */\nmj-dashboard-viewer .dashboard-viewer.editing .lm_header .lm_tab {\n padding-right: 24px !important;\n}\n\n/* ========================================\n View Mode (Not Editing) - Lock Layout\n ======================================== */\n\n/* Hide close buttons on tabs when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_close_tab {\n display: none !important;\n}\n\n/* Remove extra padding for close button when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_header .lm_tab {\n padding-right: 16px !important;\n}\n\n/* Disable splitter dragging when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_splitter {\n pointer-events: none !important;\n cursor: default !important;\n}\n\n/* Hide splitter drag handle visual when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_splitter .lm_drag_handle {\n display: none !important;\n}\n\n/* Disable tab dragging cursor when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_header .lm_tab {\n cursor: default !important;\n}\n\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_title {\n cursor: default !important;\n}\n"], encapsulation: 2 });
|
|
1080
1080
|
}
|
|
1081
1081
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DashboardViewerComponent, [{
|
|
1082
1082
|
type: Component,
|
|
1083
|
-
args: [{ standalone: false, selector: 'mj-dashboard-viewer', encapsulation: ViewEncapsulation.None, template: "<!-- Dashboard Viewer Component -->\n<div class=\"dashboard-viewer\" [class.editing]=\"isEditing\" [class.has-toolbar]=\"shouldShowToolbar\">\n <!-- Breadcrumb Navigation (hidden in edit mode) -->\n @if (showBreadcrumb && !isEditing && dashboard) {\n <mj-dashboard-breadcrumb\n [Categories]=\"Categories\"\n [CurrentCategoryId]=\"dashboard.CategoryID\"\n [CurrentDashboard]=\"dashboard\"\n [ShowDashboardName]=\"true\"\n [AllowDragDrop]=\"false\"\n Size=\"large\"\n RootIcon=\"fa-solid fa-gauge-high\"\n RootLabel=\"Dashboards\"\n (Navigate)=\"onBreadcrumbNavigate($event)\">\n </mj-dashboard-breadcrumb>\n }\n\n <!-- Toolbar (auto-hides when all elements are disabled) -->\n @if (shouldShowToolbar) {\n <div class=\"dashboard-toolbar\">\n <div class=\"toolbar-left\">\n @if (dashboard && (isEditing || !showBreadcrumb)) {\n <span class=\"dashboard-title\">\n <i class=\"fa-solid fa-chart-line\"></i>\n {{ dashboard.Name }}\n </span>\n }\n </div>\n <div class=\"toolbar-center\">\n @if (hasUnsavedChanges && isEditing) {\n <span class=\"unsaved-indicator\">\n <i class=\"fa-solid fa-circle\"></i>\n Unsaved changes\n </span>\n }\n </div>\n <div class=\"toolbar-right\">\n <!-- Open in New Tab button (when embedded) -->\n @if (showOpenInTabButton && !isEditing) {\n <button\n class=\"toolbar-button\"\n (click)=\"onOpenInTabClick()\"\n title=\"Open in its own tab\">\n <i class=\"fa-solid fa-up-right-from-square\"></i>\n Open in Tab\n </button>\n }\n @if (isEditing) {\n <button\n class=\"toolbar-button\"\n (click)=\"onAddPanelClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add Part\n </button>\n }\n @if (showEditButton) {\n <button\n class=\"toolbar-button\"\n [class.active]=\"isEditing\"\n (click)=\"toggleEditMode()\">\n <i class=\"fa-solid fa-edit\"></i>\n {{ isEditing ? 'Editing' : 'Edit' }}\n </button>\n }\n @if (isEditing && hasUnsavedChanges) {\n <button\n class=\"toolbar-button primary\"\n (click)=\"save()\">\n <i class=\"fa-solid fa-save\"></i>\n Save\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Loading Overlay -->\n @if (isLoading) {\n <div class=\"loading-overlay\">\n <mj-loading text=\"Loading dashboard...\"></mj-loading>\n </div>\n }\n\n <!-- Layout Container -->\n <div class=\"layout-container\" #layoutContainer>\n <!-- Golden Layout will render panels here -->\n </div>\n\n <!-- Empty State -->\n @if (!hasPanels && !isLoading) {\n <div class=\"empty-state\">\n <div class=\"empty-icon\">\n <i class=\"fa-solid fa-layer-group\"></i>\n </div>\n <h3>No parts configured</h3>\n <p>This dashboard has no parts yet. Add your first part to start visualizing your data.</p>\n @if (isEditing) {\n <button class=\"add-part-button\" (click)=\"onAddPanelClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add Your First Part\n </button>\n }\n </div>\n }\n</div>\n", styles: ["/**\n * Dashboard Viewer Component Styles\n *\n * IMPORTANT: For Golden Layout tabs to display correctly, you must import\n * Golden Layout's CSS in your application's global styles:\n *\n * @import 'golden-layout/dist/css/goldenlayout-base.css';\n *\n * Or add to your angular.json styles array:\n * \"node_modules/golden-layout/dist/css/goldenlayout-base.css\"\n */\n\n:host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n.dashboard-viewer {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: var(--dashboard-bg, #f5f5f5);\n}\n\n.dashboard-viewer.editing .layout-container {\n outline: 2px dashed var(--dashboard-edit-outline, #5c6bc0);\n outline-offset: -2px;\n}\n\n/* ========================================\n Toolbar\n ======================================== */\n\n.dashboard-toolbar {\n flex: 0 0 48px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 16px;\n background: var(--dashboard-toolbar-bg, #ffffff);\n border-bottom: 1px solid var(--dashboard-border, #e0e0e0);\n box-sizing: border-box;\n z-index: 10;\n}\n\n.toolbar-left,\n.toolbar-center,\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-left {\n flex: 1;\n}\n\n.toolbar-center {\n flex: 0 0 auto;\n}\n\n.toolbar-right {\n flex: 1;\n justify-content: flex-end;\n}\n\n.dashboard-title {\n font-size: 16px;\n font-weight: 500;\n color: var(--dashboard-title-color, #333);\n}\n\n.dashboard-title i {\n margin-right: 8px;\n color: var(--dashboard-title-icon, #5c6bc0);\n}\n\n.unsaved-indicator {\n font-size: 12px;\n color: var(--dashboard-unsaved-color, #ff9800);\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.unsaved-indicator i {\n font-size: 8px;\n}\n\n.toolbar-button {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: 1px solid var(--dashboard-button-border, #ddd);\n border-radius: 4px;\n background: var(--dashboard-button-bg, #fff);\n color: var(--dashboard-button-color, #333);\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.toolbar-button:hover {\n background: var(--dashboard-button-hover-bg, #f5f5f5);\n border-color: var(--dashboard-button-hover-border, #ccc);\n}\n\n.toolbar-button.active {\n background: var(--dashboard-button-active-bg, #e8eaf6);\n border-color: var(--dashboard-button-active-border, #5c6bc0);\n color: var(--dashboard-button-active-color, #5c6bc0);\n}\n\n.toolbar-button.primary {\n background: var(--dashboard-button-primary-bg, #5c6bc0);\n border-color: var(--dashboard-button-primary-border, #3f51b5);\n color: var(--dashboard-button-primary-color, #fff);\n}\n\n.toolbar-button.primary:hover {\n background: var(--dashboard-button-primary-hover-bg, #3f51b5);\n}\n\n.toolbar-button i {\n font-size: 14px;\n}\n\n/* ========================================\n Layout Container\n ======================================== */\n\n/* Layout container fills remaining space in the flex column */\n.layout-container {\n flex: 1;\n position: relative;\n overflow: hidden;\n min-height: 0;\n}\n\n/* ========================================\n Dashboard Panel Content (our wrapper)\n ======================================== */\n\n/* Dashboard panel wrapper (header + content) */\n:host ::ng-deep .dashboard-part-wrapper {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #fff;\n}\n\n/* Dashboard part header */\n:host ::ng-deep .dashboard-part-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);\n border-bottom: 1px solid #e0e0e0;\n min-height: 40px;\n flex-shrink: 0;\n}\n\n/* Dashboard part content */\n:host ::ng-deep .dashboard-part-content {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n/* ========================================\n Loading Overlay\n ======================================== */\n\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(255, 255, 255, 0.9);\n z-index: 100;\n}\n\n/* ========================================\n Empty State\n ======================================== */\n\n.empty-state {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n text-align: center;\n color: var(--dashboard-empty-color, #666);\n max-width: 400px;\n padding: 40px;\n}\n\n.empty-state .empty-icon {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: linear-gradient(135deg, #e8eaf6 0%, #c5cae9 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 24px;\n}\n\n.empty-state .empty-icon i {\n font-size: 36px;\n color: #5c6bc0;\n}\n\n.empty-state h3 {\n margin: 0 0 12px 0;\n font-size: 20px;\n font-weight: 500;\n color: #333;\n}\n\n.empty-state p {\n margin: 0 0 24px 0;\n font-size: 14px;\n color: var(--dashboard-empty-text, #666);\n line-height: 1.5;\n}\n\n.add-part-button {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 12px 24px;\n border: none;\n border-radius: 6px;\n background: linear-gradient(135deg, #5c6bc0 0%, #3f51b5 100%);\n color: #fff;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px rgba(92, 107, 192, 0.3);\n}\n\n.add-part-button:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(92, 107, 192, 0.4);\n}\n\n.add-part-button i {\n font-size: 14px;\n}\n\n/* ========================================\n Panel Error State\n ======================================== */\n\n:host ::ng-deep .panel-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 24px;\n text-align: center;\n color: var(--dashboard-error-color, #d32f2f);\n background: var(--dashboard-error-bg, #ffebee);\n}\n\n:host ::ng-deep .panel-error i {\n font-size: 32px;\n margin-bottom: 12px;\n}\n\n:host ::ng-deep .panel-error span {\n font-size: 14px;\n}\n\n/* ========================================\n Golden Layout Overrides\n These require ViewEncapsulation.None to work on dynamic GL elements\n ======================================== */\n\n/* Override shell's hide-tab-bar rule that hides GL headers when dashboard is inside shell */\n/* The shell hides .lm_header when mj-tab-container has hide-tab-bar class */\n/* We need to ensure OUR Golden Layout headers are always visible */\nmj-dashboard-viewer .lm_header {\n display: block !important;\n}\n\n/* Ensure GL root container fills available space */\nmj-dashboard-viewer .lm_goldenlayout {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure the root layout item fills space */\nmj-dashboard-viewer .lm_root {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure proper box-sizing for all GL layout elements */\nmj-dashboard-viewer .lm_item,\nmj-dashboard-viewer .lm_content,\nmj-dashboard-viewer .lm_stack,\nmj-dashboard-viewer .lm_row,\nmj-dashboard-viewer .lm_column {\n box-sizing: border-box !important;\n}\n\n/* Ensure layout items don't overflow */\nmj-dashboard-viewer .lm_item {\n overflow: hidden !important;\n}\n\n/* Fix for .lm_items - the content container inside stacks */\nmj-dashboard-viewer .lm_items {\n width: 100% !important;\n height: calc(100% - 38px) !important; /* Account for header height (38px) */\n box-sizing: border-box !important;\n position: relative !important;\n}\n\n/* When tabs are maximized, no header visible */\nmj-dashboard-viewer .lm_stack.lm_maximised > .lm_items {\n height: 100% !important;\n}\n\n/* Target the ComponentItem div inside lm_items */\nmj-dashboard-viewer .lm_items > div {\n width: 100% !important;\n height: 100% !important;\n box-sizing: border-box !important;\n flex-direction: column !important;\n}\n\n/* Only apply flex display to the active/visible tab content div */\nmj-dashboard-viewer .lm_items > div:not([style*=\"display: none\"]) {\n display: flex !important;\n}\n\n/* Clearfix for float-based row layout */\nmj-dashboard-viewer .lm_row::after {\n content: \"\" !important;\n display: table !important;\n clear: both !important;\n}\n\n/* Force content children to respect parent bounds */\nmj-dashboard-viewer .lm_content > * {\n max-width: 100% !important;\n width: 100% !important;\n}\n\nmj-dashboard-viewer .lm_content {\n background: white !important;\n display: flex !important;\n flex-direction: column !important;\n height: 100% !important;\n width: 100% !important;\n}\n\nmj-dashboard-viewer .lm_item_container {\n background: white !important;\n}\n\n/* Tab header styling */\nmj-dashboard-viewer .lm_header {\n height: 38px !important;\n padding-top: 2px !important;\n padding-left: 4px !important;\n background: #f5f5f5 !important;\n border-bottom: 1px solid #ebebeb !important;\n overflow: visible !important;\n box-sizing: border-box !important;\n}\n\nmj-dashboard-viewer .lm_tabs {\n height: 36px !important;\n}\n\n/* Hide Golden Layout window controls (popout, maximize) */\nmj-dashboard-viewer .lm_controls {\n display: none !important;\n}\n\n/* Tab styling */\nmj-dashboard-viewer .lm_header .lm_tab {\n padding: 0 16px 0 28px !important; /* Extra left padding for icon */\n font-size: 13px !important;\n height: 35px !important;\n line-height: 35px !important;\n box-sizing: border-box !important;\n cursor: pointer !important;\n user-select: none !important;\n background: transparent !important;\n border: none !important;\n border-bottom: 1px solid #ebebeb !important;\n transition: all 0.15s ease !important;\n position: relative !important;\n z-index: 1 !important;\n margin-right: 1px !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab:hover {\n background: #e8e8e8 !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab.lm_active {\n background: white !important;\n height: 36px !important;\n margin-bottom: -1px !important;\n margin-right: 0 !important;\n border: 1px solid #ebebeb !important;\n border-bottom-color: white !important;\n border-radius: 4px 4px 0 0 !important;\n z-index: 2 !important;\n}\n\nmj-dashboard-viewer .lm_title {\n cursor: pointer !important;\n user-select: none !important;\n}\n\n/* Panel icon styling - icon is direct child of .lm_tab to preserve GL's drag/drop */\n/* Positioned absolutely in the left padding area so it doesn't affect GL's title structure */\nmj-dashboard-viewer .lm_header .lm_tab .panel-icon {\n position: absolute !important;\n left: 10px !important;\n top: 50% !important;\n transform: translateY(-30%) !important; \n font-family: \"Font Awesome 6 Free\", \"Font Awesome 6 Pro\", \"Font Awesome 5 Free\", \"Font Awesome 5 Pro\", FontAwesome !important;\n font-weight: 900 !important; /* Required for solid icons */\n font-size: 12px !important;\n color: #5c6bc0 !important;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\nmj-dashboard-viewer .lm_close_tab {\n position: absolute !important;\n right: 4px !important;\n top: 50% !important;\n transform: translateY(-50%) !important;\n width: 16px !important;\n height: 16px !important;\n cursor: pointer !important;\n opacity: 0 !important;\n transition: all 0.15s ease !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab:hover .lm_close_tab {\n opacity: 0.7 !important;\n}\n\nmj-dashboard-viewer .lm_close_tab:hover {\n opacity: 1 !important;\n color: #c62828 !important;\n}\n\n/* Add padding for close button when editing */\nmj-dashboard-viewer .dashboard-viewer.editing .lm_header .lm_tab {\n padding-right: 24px !important;\n}\n\n/* ========================================\n View Mode (Not Editing) - Lock Layout\n ======================================== */\n\n/* Hide close buttons on tabs when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_close_tab {\n display: none !important;\n}\n\n/* Remove extra padding for close button when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_header .lm_tab {\n padding-right: 16px !important;\n}\n\n/* Disable splitter dragging when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_splitter {\n pointer-events: none !important;\n cursor: default !important;\n}\n\n/* Hide splitter drag handle visual when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_splitter .lm_drag_handle {\n display: none !important;\n}\n\n/* Disable tab dragging cursor when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_header .lm_tab {\n cursor: default !important;\n}\n\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_title {\n cursor: default !important;\n}\n"] }]
|
|
1083
|
+
args: [{ standalone: false, selector: 'mj-dashboard-viewer', encapsulation: ViewEncapsulation.None, template: "<!-- Dashboard Viewer Component -->\n<div class=\"dashboard-viewer\" [class.editing]=\"isEditing\" [class.has-toolbar]=\"shouldShowToolbar\">\n <!-- Breadcrumb Navigation (hidden in edit mode) -->\n @if (showBreadcrumb && !isEditing && dashboard) {\n <mj-dashboard-breadcrumb\n [Categories]=\"Categories\"\n [CurrentCategoryId]=\"dashboard.CategoryID\"\n [CurrentDashboard]=\"dashboard\"\n [ShowDashboardName]=\"true\"\n [AllowDragDrop]=\"false\"\n Size=\"large\"\n RootIcon=\"fa-solid fa-gauge-high\"\n RootLabel=\"Dashboards\"\n (Navigate)=\"onBreadcrumbNavigate($event)\">\n </mj-dashboard-breadcrumb>\n }\n\n <!-- Toolbar (auto-hides when all elements are disabled) -->\n @if (shouldShowToolbar) {\n <div class=\"dashboard-toolbar\">\n <div class=\"toolbar-left\">\n @if (dashboard && (isEditing || !showBreadcrumb)) {\n <span class=\"dashboard-title\">\n <i class=\"fa-solid fa-chart-line\"></i>\n {{ dashboard.Name }}\n </span>\n }\n </div>\n <div class=\"toolbar-center\">\n @if (hasUnsavedChanges && isEditing) {\n <span class=\"unsaved-indicator\">\n <i class=\"fa-solid fa-circle\"></i>\n Unsaved changes\n </span>\n }\n </div>\n <div class=\"toolbar-right\">\n <!-- Open in New Tab button (when embedded) -->\n @if (showOpenInTabButton && !isEditing) {\n <button\n class=\"toolbar-button\"\n (click)=\"onOpenInTabClick()\"\n title=\"Open in its own tab\">\n <i class=\"fa-solid fa-up-right-from-square\"></i>\n Open in Tab\n </button>\n }\n @if (isEditing) {\n <button\n class=\"toolbar-button\"\n (click)=\"onAddPanelClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add Part\n </button>\n }\n @if (showEditButton) {\n <button\n class=\"toolbar-button\"\n [class.active]=\"isEditing\"\n (click)=\"toggleEditMode()\">\n <i class=\"fa-solid fa-edit\"></i>\n {{ isEditing ? 'Editing' : 'Edit' }}\n </button>\n }\n @if (isEditing && hasUnsavedChanges) {\n <button\n class=\"toolbar-button primary\"\n (click)=\"save()\">\n <i class=\"fa-solid fa-save\"></i>\n Save\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Loading Overlay -->\n @if (isLoading) {\n <div class=\"loading-overlay\">\n <mj-loading text=\"Loading dashboard...\"></mj-loading>\n </div>\n }\n\n <!-- Layout Container -->\n <div class=\"layout-container\" #layoutContainer>\n <!-- Golden Layout will render panels here -->\n </div>\n\n <!-- Empty State -->\n @if (!hasPanels && !isLoading) {\n <div class=\"empty-state\">\n <div class=\"empty-icon\">\n <i class=\"fa-solid fa-layer-group\"></i>\n </div>\n <h3>No parts configured</h3>\n <p>This dashboard has no parts yet. Add your first part to start visualizing your data.</p>\n @if (isEditing) {\n <button class=\"add-part-button\" (click)=\"onAddPanelClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add Your First Part\n </button>\n }\n </div>\n }\n</div>\n", styles: ["/**\n * Dashboard Viewer Component Styles\n *\n * IMPORTANT: For Golden Layout tabs to display correctly, you must import\n * Golden Layout's CSS in your application's global styles:\n *\n * @import 'golden-layout/dist/css/goldenlayout-base.css';\n *\n * Or add to your angular.json styles array:\n * \"node_modules/golden-layout/dist/css/goldenlayout-base.css\"\n */\n\n:host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n.dashboard-viewer {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: var(--dashboard-bg, var(--mj-bg-surface-card));\n}\n\n.dashboard-viewer.editing .layout-container {\n outline: 2px dashed var(--dashboard-edit-outline, var(--mj-brand-primary));\n outline-offset: -2px;\n}\n\n/* ========================================\n Toolbar\n ======================================== */\n\n.dashboard-toolbar {\n flex: 0 0 48px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 16px;\n background: var(--dashboard-toolbar-bg, var(--mj-bg-surface));\n border-bottom: 1px solid var(--dashboard-border, var(--mj-border-default));\n box-sizing: border-box;\n z-index: 10;\n}\n\n.toolbar-left,\n.toolbar-center,\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-left {\n flex: 1;\n}\n\n.toolbar-center {\n flex: 0 0 auto;\n}\n\n.toolbar-right {\n flex: 1;\n justify-content: flex-end;\n}\n\n.dashboard-title {\n font-size: 16px;\n font-weight: 500;\n color: var(--dashboard-title-color, var(--mj-text-primary));\n}\n\n.dashboard-title i {\n margin-right: 8px;\n color: var(--dashboard-title-icon, var(--mj-brand-primary));\n}\n\n.unsaved-indicator {\n font-size: 12px;\n color: var(--dashboard-unsaved-color, var(--mj-status-warning));\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.unsaved-indicator i {\n font-size: 8px;\n}\n\n.toolbar-button {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: 1px solid var(--dashboard-button-border, var(--mj-border-strong));\n border-radius: 4px;\n background: var(--dashboard-button-bg, var(--mj-bg-surface));\n color: var(--dashboard-button-color, var(--mj-text-primary));\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.toolbar-button:hover {\n background: var(--dashboard-button-hover-bg, var(--mj-bg-surface-card));\n border-color: var(--dashboard-button-hover-border, var(--mj-border-strong));\n}\n\n.toolbar-button.active {\n background: var(--dashboard-button-active-bg, color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface)));\n border-color: var(--dashboard-button-active-border, var(--mj-brand-primary));\n color: var(--dashboard-button-active-color, var(--mj-brand-primary));\n}\n\n.toolbar-button.primary {\n background: var(--dashboard-button-primary-bg, var(--mj-brand-primary));\n border-color: var(--dashboard-button-primary-border, var(--mj-brand-primary-hover));\n color: var(--dashboard-button-primary-color, var(--mj-text-inverse));\n}\n\n.toolbar-button.primary:hover {\n background: var(--dashboard-button-primary-hover-bg, var(--mj-brand-primary-hover));\n}\n\n.toolbar-button i {\n font-size: 14px;\n}\n\n/* ========================================\n Layout Container\n ======================================== */\n\n/* Layout container fills remaining space in the flex column */\n.layout-container {\n flex: 1;\n position: relative;\n overflow: hidden;\n min-height: 0;\n}\n\n/* ========================================\n Dashboard Panel Content (our wrapper)\n ======================================== */\n\n/* Dashboard panel wrapper (header + content) */\n:host ::ng-deep .dashboard-part-wrapper {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n}\n\n/* Dashboard part header */\n:host ::ng-deep .dashboard-part-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n min-height: 40px;\n flex-shrink: 0;\n}\n\n/* Dashboard part content */\n:host ::ng-deep .dashboard-part-content {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n/* ========================================\n Loading Overlay\n ======================================== */\n\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-bg-surface) 90%, transparent);\n z-index: 100;\n}\n\n/* ========================================\n Empty State\n ======================================== */\n\n.empty-state {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n text-align: center;\n color: var(--dashboard-empty-color, var(--mj-text-secondary));\n max-width: 400px;\n padding: 40px;\n}\n\n.empty-state .empty-icon {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 24px;\n}\n\n.empty-state .empty-icon i {\n font-size: 36px;\n color: var(--mj-brand-primary);\n}\n\n.empty-state h3 {\n margin: 0 0 12px 0;\n font-size: 20px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.empty-state p {\n margin: 0 0 24px 0;\n font-size: 14px;\n color: var(--dashboard-empty-text, var(--mj-text-secondary));\n line-height: 1.5;\n}\n\n.add-part-button {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 12px 24px;\n border: none;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n.add-part-button:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n.add-part-button i {\n font-size: 14px;\n}\n\n/* ========================================\n Panel Error State\n ======================================== */\n\n:host ::ng-deep .panel-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 24px;\n text-align: center;\n color: var(--dashboard-error-color, var(--mj-status-error));\n background: var(--dashboard-error-bg, color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface)));\n}\n\n:host ::ng-deep .panel-error i {\n font-size: 32px;\n margin-bottom: 12px;\n}\n\n:host ::ng-deep .panel-error span {\n font-size: 14px;\n}\n\n/* ========================================\n Golden Layout Overrides\n These require ViewEncapsulation.None to work on dynamic GL elements\n ======================================== */\n\n/* Override shell's hide-tab-bar rule that hides GL headers when dashboard is inside shell */\n/* The shell hides .lm_header when mj-tab-container has hide-tab-bar class */\n/* We need to ensure OUR Golden Layout headers are always visible */\nmj-dashboard-viewer .lm_header {\n display: block !important;\n}\n\n/* Ensure GL root container fills available space */\nmj-dashboard-viewer .lm_goldenlayout {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure the root layout item fills space */\nmj-dashboard-viewer .lm_root {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure proper box-sizing for all GL layout elements */\nmj-dashboard-viewer .lm_item,\nmj-dashboard-viewer .lm_content,\nmj-dashboard-viewer .lm_stack,\nmj-dashboard-viewer .lm_row,\nmj-dashboard-viewer .lm_column {\n box-sizing: border-box !important;\n}\n\n/* Ensure layout items don't overflow */\nmj-dashboard-viewer .lm_item {\n overflow: hidden !important;\n}\n\n/* Fix for .lm_items - the content container inside stacks */\nmj-dashboard-viewer .lm_items {\n width: 100% !important;\n height: calc(100% - 38px) !important; /* Account for header height (38px) */\n box-sizing: border-box !important;\n position: relative !important;\n}\n\n/* When tabs are maximized, no header visible */\nmj-dashboard-viewer .lm_stack.lm_maximised > .lm_items {\n height: 100% !important;\n}\n\n/* Target the ComponentItem div inside lm_items */\nmj-dashboard-viewer .lm_items > div {\n width: 100% !important;\n height: 100% !important;\n box-sizing: border-box !important;\n flex-direction: column !important;\n}\n\n/* Only apply flex display to the active/visible tab content div */\nmj-dashboard-viewer .lm_items > div:not([style*=\"display: none\"]) {\n display: flex !important;\n}\n\n/* Clearfix for float-based row layout */\nmj-dashboard-viewer .lm_row::after {\n content: \"\" !important;\n display: table !important;\n clear: both !important;\n}\n\n/* Force content children to respect parent bounds */\nmj-dashboard-viewer .lm_content > * {\n max-width: 100% !important;\n width: 100% !important;\n}\n\nmj-dashboard-viewer .lm_content {\n background: var(--mj-bg-surface) !important;\n display: flex !important;\n flex-direction: column !important;\n height: 100% !important;\n width: 100% !important;\n}\n\nmj-dashboard-viewer .lm_item_container {\n background: var(--mj-bg-surface) !important;\n}\n\n/* Tab header styling */\nmj-dashboard-viewer .lm_header {\n height: 38px !important;\n padding-top: 2px !important;\n padding-left: 4px !important;\n background: var(--mj-bg-surface-card) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n overflow: visible !important;\n box-sizing: border-box !important;\n}\n\nmj-dashboard-viewer .lm_tabs {\n height: 36px !important;\n}\n\n/* Hide Golden Layout window controls (popout, maximize) */\nmj-dashboard-viewer .lm_controls {\n display: none !important;\n}\n\n/* Tab styling */\nmj-dashboard-viewer .lm_header .lm_tab {\n padding: 0 16px 0 28px !important; /* Extra left padding for icon */\n font-size: 13px !important;\n height: 35px !important;\n line-height: 35px !important;\n box-sizing: border-box !important;\n cursor: pointer !important;\n user-select: none !important;\n background: transparent !important;\n border: none !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n transition: all 0.15s ease !important;\n position: relative !important;\n z-index: 1 !important;\n margin-right: 1px !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab:hover {\n background: var(--mj-bg-surface-sunken) !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab.lm_active {\n background: var(--mj-bg-surface) !important;\n height: 36px !important;\n margin-bottom: -1px !important;\n margin-right: 0 !important;\n border: 1px solid var(--mj-border-default) !important;\n border-bottom-color: var(--mj-bg-surface) !important;\n border-radius: 4px 4px 0 0 !important;\n z-index: 2 !important;\n}\n\nmj-dashboard-viewer .lm_title {\n cursor: pointer !important;\n user-select: none !important;\n}\n\n/* Panel icon styling - icon is direct child of .lm_tab to preserve GL's drag/drop */\n/* Positioned absolutely in the left padding area so it doesn't affect GL's title structure */\nmj-dashboard-viewer .lm_header .lm_tab .panel-icon {\n position: absolute !important;\n left: 10px !important;\n top: 50% !important;\n transform: translateY(-30%) !important;\n font-family: \"Font Awesome 6 Free\", \"Font Awesome 6 Pro\", \"Font Awesome 5 Free\", \"Font Awesome 5 Pro\", FontAwesome !important;\n font-weight: 900 !important; /* Required for solid icons */\n font-size: 12px !important;\n color: var(--mj-brand-primary) !important;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\nmj-dashboard-viewer .lm_close_tab {\n position: absolute !important;\n right: 4px !important;\n top: 50% !important;\n transform: translateY(-50%) !important;\n width: 16px !important;\n height: 16px !important;\n cursor: pointer !important;\n opacity: 0 !important;\n transition: all 0.15s ease !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab:hover .lm_close_tab {\n opacity: 0.7 !important;\n}\n\nmj-dashboard-viewer .lm_close_tab:hover {\n opacity: 1 !important;\n color: var(--mj-status-error) !important;\n}\n\n/* Add padding for close button when editing */\nmj-dashboard-viewer .dashboard-viewer.editing .lm_header .lm_tab {\n padding-right: 24px !important;\n}\n\n/* ========================================\n View Mode (Not Editing) - Lock Layout\n ======================================== */\n\n/* Hide close buttons on tabs when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_close_tab {\n display: none !important;\n}\n\n/* Remove extra padding for close button when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_header .lm_tab {\n padding-right: 16px !important;\n}\n\n/* Disable splitter dragging when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_splitter {\n pointer-events: none !important;\n cursor: default !important;\n}\n\n/* Hide splitter drag handle visual when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_splitter .lm_drag_handle {\n display: none !important;\n}\n\n/* Disable tab dragging cursor when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_header .lm_tab {\n cursor: default !important;\n}\n\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_title {\n cursor: default !important;\n}\n"] }]
|
|
1084
1084
|
}], () => [{ type: i0.ChangeDetectorRef }, { type: i0.ApplicationRef }, { type: i0.Injector }, { type: i0.EnvironmentInjector }], { dashboard: [{
|
|
1085
1085
|
type: Input
|
|
1086
1086
|
}], dashboardId: [{
|