@memberjunction/ng-dashboards 5.37.0 → 5.38.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/README.md +32 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +14 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +450 -292
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +73 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +512 -127
- package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-resource.component.d.ts +22 -0
- package/dist/ComponentStudio/component-studio-resource.component.d.ts.map +1 -0
- package/dist/ComponentStudio/component-studio-resource.component.js +55 -0
- package/dist/ComponentStudio/component-studio-resource.component.js.map +1 -0
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +104 -45
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +234 -331
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts +54 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js +339 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts +65 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js +492 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts +88 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js +457 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.d.ts +106 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.js +478 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.js.map +1 -0
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts +54 -0
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.js +361 -50
- package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts +10 -0
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +114 -45
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
- package/dist/ComponentStudio/services/canvas-to-code.d.ts +32 -0
- package/dist/ComponentStudio/services/canvas-to-code.d.ts.map +1 -0
- package/dist/ComponentStudio/services/canvas-to-code.js +347 -0
- package/dist/ComponentStudio/services/canvas-to-code.js.map +1 -0
- package/dist/ComponentStudio/services/code-to-canvas.d.ts +32 -0
- package/dist/ComponentStudio/services/code-to-canvas.d.ts.map +1 -0
- package/dist/ComponentStudio/services/code-to-canvas.js +92 -0
- package/dist/ComponentStudio/services/code-to-canvas.js.map +1 -0
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts +29 -0
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
- package/dist/ComponentStudio/services/component-studio-state.service.js +76 -0
- package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
- package/dist/ComponentStudio/services/entity-form-override.service.d.ts +86 -0
- package/dist/ComponentStudio/services/entity-form-override.service.d.ts.map +1 -0
- package/dist/ComponentStudio/services/entity-form-override.service.js +246 -0
- package/dist/ComponentStudio/services/entity-form-override.service.js.map +1 -0
- package/dist/ComponentStudio/services/field-binding-scanner.d.ts +29 -0
- package/dist/ComponentStudio/services/field-binding-scanner.d.ts.map +1 -0
- package/dist/ComponentStudio/services/field-binding-scanner.js +110 -0
- package/dist/ComponentStudio/services/field-binding-scanner.js.map +1 -0
- package/dist/ComponentStudio/services/form-canvas-model.d.ts +56 -0
- package/dist/ComponentStudio/services/form-canvas-model.d.ts.map +1 -0
- package/dist/ComponentStudio/services/form-canvas-model.js +35 -0
- package/dist/ComponentStudio/services/form-canvas-model.js.map +1 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.d.ts +10 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.d.ts.map +1 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.js +10 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.js.map +1 -0
- package/dist/DataExplorer/data-explorer-dashboard.component.js +2 -2
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/FormBuilder/form-builder-resource.component.d.ts +964 -0
- package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -0
- package/dist/FormBuilder/form-builder-resource.component.js +4487 -0
- package/dist/FormBuilder/form-builder-resource.component.js.map +1 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts +55 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts.map +1 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.js +73 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.js.map +1 -0
- package/dist/Home/home-application.d.ts +21 -1
- package/dist/Home/home-application.d.ts.map +1 -1
- package/dist/Home/home-application.js +60 -8
- package/dist/Home/home-application.js.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts +14 -14
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +11 -10
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/component-studio-dashboards.module.d.ts +34 -22
- package/dist/component-studio-dashboards.module.d.ts.map +1 -1
- package/dist/component-studio-dashboards.module.js +65 -9
- package/dist/component-studio-dashboards.module.js.map +1 -1
- package/package.json +54 -53
|
@@ -13,33 +13,36 @@ import { Subject, takeUntil } from 'rxjs';
|
|
|
13
13
|
import { ComponentStudioStateService } from './services/component-studio-state.service';
|
|
14
14
|
import { ComponentVersionService } from './services/component-version.service';
|
|
15
15
|
import { RunView } from '@memberjunction/core';
|
|
16
|
+
import { generateCanvasId, } from './services/form-canvas-model';
|
|
17
|
+
import { generateCodeFromCanvas } from './services/canvas-to-code';
|
|
16
18
|
import * as i0 from "@angular/core";
|
|
17
19
|
import * as i1 from "./services/component-studio-state.service";
|
|
18
20
|
import * as i2 from "./services/component-version.service";
|
|
19
21
|
import * as i3 from "@memberjunction/ng-notifications";
|
|
22
|
+
import * as i4 from "./services/entity-form-override.service";
|
|
20
23
|
const _c0 = ["fileInput"];
|
|
21
24
|
function ComponentStudioDashboardComponent_Conditional_5_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
22
|
-
i0.ɵɵelementStart(0, "span",
|
|
23
|
-
i0.ɵɵelement(1, "span",
|
|
25
|
+
i0.ɵɵelementStart(0, "span", 37);
|
|
26
|
+
i0.ɵɵelement(1, "span", 39);
|
|
24
27
|
i0.ɵɵtext(2, " Running ");
|
|
25
28
|
i0.ɵɵelementEnd();
|
|
26
29
|
} }
|
|
27
30
|
function ComponentStudioDashboardComponent_Conditional_5_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
28
|
-
i0.ɵɵelement(0, "span",
|
|
31
|
+
i0.ɵɵelement(0, "span", 38);
|
|
29
32
|
} }
|
|
30
33
|
function ComponentStudioDashboardComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
31
|
-
i0.ɵɵelementStart(0, "span",
|
|
32
|
-
i0.ɵɵelement(1, "i",
|
|
34
|
+
i0.ɵɵelementStart(0, "span", 33);
|
|
35
|
+
i0.ɵɵelement(1, "i", 25);
|
|
33
36
|
i0.ɵɵtext(2);
|
|
34
37
|
i0.ɵɵelementEnd();
|
|
35
|
-
i0.ɵɵelementStart(3, "span",
|
|
36
|
-
i0.ɵɵelement(4, "i",
|
|
38
|
+
i0.ɵɵelementStart(3, "span", 34);
|
|
39
|
+
i0.ɵɵelement(4, "i", 35);
|
|
37
40
|
i0.ɵɵelementEnd();
|
|
38
|
-
i0.ɵɵelementStart(5, "span",
|
|
41
|
+
i0.ɵɵelementStart(5, "span", 36);
|
|
39
42
|
i0.ɵɵtext(6);
|
|
40
43
|
i0.ɵɵelementEnd();
|
|
41
|
-
i0.ɵɵconditionalCreate(7, ComponentStudioDashboardComponent_Conditional_5_Conditional_7_Template, 3, 0, "span",
|
|
42
|
-
i0.ɵɵconditionalCreate(8, ComponentStudioDashboardComponent_Conditional_5_Conditional_8_Template, 1, 0, "span",
|
|
44
|
+
i0.ɵɵconditionalCreate(7, ComponentStudioDashboardComponent_Conditional_5_Conditional_7_Template, 3, 0, "span", 37);
|
|
45
|
+
i0.ɵɵconditionalCreate(8, ComponentStudioDashboardComponent_Conditional_5_Conditional_8_Template, 1, 0, "span", 38);
|
|
43
46
|
} if (rf & 2) {
|
|
44
47
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
45
48
|
i0.ɵɵadvance(2);
|
|
@@ -53,15 +56,15 @@ function ComponentStudioDashboardComponent_Conditional_5_Template(rf, ctx) { if
|
|
|
53
56
|
} }
|
|
54
57
|
function ComponentStudioDashboardComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
55
58
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
56
|
-
i0.ɵɵelementStart(0, "button",
|
|
59
|
+
i0.ɵɵelementStart(0, "button", 40);
|
|
57
60
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_8_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SaveVersion()); });
|
|
58
|
-
i0.ɵɵelement(1, "i",
|
|
61
|
+
i0.ɵɵelement(1, "i", 41);
|
|
59
62
|
i0.ɵɵtext(2, " Save ");
|
|
60
63
|
i0.ɵɵelementEnd();
|
|
61
64
|
} }
|
|
62
65
|
function ComponentStudioDashboardComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
63
66
|
const _r4 = i0.ɵɵgetCurrentView();
|
|
64
|
-
i0.ɵɵelementStart(0, "button",
|
|
67
|
+
i0.ɵɵelementStart(0, "button", 42);
|
|
65
68
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.RefreshComponent()); });
|
|
66
69
|
i0.ɵɵelement(1, "i", 17);
|
|
67
70
|
i0.ɵɵtext(2, " Refresh ");
|
|
@@ -69,31 +72,31 @@ function ComponentStudioDashboardComponent_Conditional_9_Template(rf, ctx) { if
|
|
|
69
72
|
} }
|
|
70
73
|
function ComponentStudioDashboardComponent_Conditional_10_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
71
74
|
const _r6 = i0.ɵɵgetCurrentView();
|
|
72
|
-
i0.ɵɵelementStart(0, "div",
|
|
75
|
+
i0.ɵɵelementStart(0, "div", 47)(1, "button", 48);
|
|
73
76
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_10_Conditional_5_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ExportToArtifact()); });
|
|
74
|
-
i0.ɵɵelement(2, "i",
|
|
77
|
+
i0.ɵɵelement(2, "i", 41);
|
|
75
78
|
i0.ɵɵtext(3, " To Artifact ");
|
|
76
79
|
i0.ɵɵelementEnd();
|
|
77
|
-
i0.ɵɵelementStart(4, "button",
|
|
80
|
+
i0.ɵɵelementStart(4, "button", 48);
|
|
78
81
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_10_Conditional_5_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ExportToFile()); });
|
|
79
|
-
i0.ɵɵelement(5, "i",
|
|
82
|
+
i0.ɵɵelement(5, "i", 49);
|
|
80
83
|
i0.ɵɵtext(6, " To File ");
|
|
81
84
|
i0.ɵɵelementEnd();
|
|
82
|
-
i0.ɵɵelementStart(7, "button",
|
|
85
|
+
i0.ɵɵelementStart(7, "button", 48);
|
|
83
86
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_10_Conditional_5_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ExportToClipboard()); });
|
|
84
|
-
i0.ɵɵelement(8, "i",
|
|
87
|
+
i0.ɵɵelement(8, "i", 50);
|
|
85
88
|
i0.ɵɵtext(9, " To Clipboard ");
|
|
86
89
|
i0.ɵɵelementEnd()();
|
|
87
90
|
} }
|
|
88
91
|
function ComponentStudioDashboardComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
89
92
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
90
|
-
i0.ɵɵelementStart(0, "div",
|
|
93
|
+
i0.ɵɵelementStart(0, "div", 43)(1, "button", 44);
|
|
91
94
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_10_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ToggleExportDropdown()); });
|
|
92
|
-
i0.ɵɵelement(2, "i",
|
|
95
|
+
i0.ɵɵelement(2, "i", 45);
|
|
93
96
|
i0.ɵɵtext(3, " Export ");
|
|
94
|
-
i0.ɵɵelement(4, "i",
|
|
97
|
+
i0.ɵɵelement(4, "i", 46);
|
|
95
98
|
i0.ɵɵelementEnd();
|
|
96
|
-
i0.ɵɵconditionalCreate(5, ComponentStudioDashboardComponent_Conditional_10_Conditional_5_Template, 10, 0, "div",
|
|
99
|
+
i0.ɵɵconditionalCreate(5, ComponentStudioDashboardComponent_Conditional_10_Conditional_5_Template, 10, 0, "div", 47);
|
|
97
100
|
i0.ɵɵelementEnd();
|
|
98
101
|
} if (rf & 2) {
|
|
99
102
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -103,10 +106,10 @@ function ComponentStudioDashboardComponent_Conditional_10_Template(rf, ctx) { if
|
|
|
103
106
|
} }
|
|
104
107
|
function ComponentStudioDashboardComponent_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
105
108
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
106
|
-
i0.ɵɵelementStart(0, "div",
|
|
109
|
+
i0.ɵɵelementStart(0, "div", 51)(1, "mj-component-browser", 52);
|
|
107
110
|
i0.ɵɵlistener("NewComponent", function ComponentStudioDashboardComponent_Conditional_21_Template_mj_component_browser_NewComponent_1_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnNewComponent()); })("ImportFromFile", function ComponentStudioDashboardComponent_Conditional_21_Template_mj_component_browser_ImportFromFile_1_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ImportFromFile()); })("ImportFromText", function ComponentStudioDashboardComponent_Conditional_21_Template_mj_component_browser_ImportFromText_1_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ImportFromText()); })("ImportFromArtifact", function ComponentStudioDashboardComponent_Conditional_21_Template_mj_component_browser_ImportFromArtifact_1_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ImportFromArtifact()); });
|
|
108
111
|
i0.ɵɵelementEnd()();
|
|
109
|
-
i0.ɵɵelementStart(2, "div",
|
|
112
|
+
i0.ɵɵelementStart(2, "div", 53);
|
|
110
113
|
i0.ɵɵlistener("mousedown", function ComponentStudioDashboardComponent_Conditional_21_Template_div_mousedown_2_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnLeftResizeStart($event)); });
|
|
111
114
|
i0.ɵɵelementEnd();
|
|
112
115
|
} if (rf & 2) {
|
|
@@ -115,13 +118,13 @@ function ComponentStudioDashboardComponent_Conditional_21_Template(rf, ctx) { if
|
|
|
115
118
|
} }
|
|
116
119
|
function ComponentStudioDashboardComponent_Conditional_23_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
117
120
|
const _r9 = i0.ɵɵgetCurrentView();
|
|
118
|
-
i0.ɵɵelementStart(0, "div",
|
|
121
|
+
i0.ɵɵelementStart(0, "div", 65);
|
|
119
122
|
i0.ɵɵlistener("mousedown", function ComponentStudioDashboardComponent_Conditional_23_Conditional_11_Template_div_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnCenterResizeStart($event)); });
|
|
120
|
-
i0.ɵɵelement(1, "div",
|
|
123
|
+
i0.ɵɵelement(1, "div", 66);
|
|
121
124
|
i0.ɵɵelementEnd();
|
|
122
125
|
} }
|
|
123
126
|
function ComponentStudioDashboardComponent_Conditional_23_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
124
|
-
i0.ɵɵelementStart(0, "div",
|
|
127
|
+
i0.ɵɵelementStart(0, "div", 67);
|
|
125
128
|
i0.ɵɵelement(1, "mj-editor-tabs");
|
|
126
129
|
i0.ɵɵelementEnd();
|
|
127
130
|
} if (rf & 2) {
|
|
@@ -130,20 +133,20 @@ function ComponentStudioDashboardComponent_Conditional_23_Conditional_12_Templat
|
|
|
130
133
|
} }
|
|
131
134
|
function ComponentStudioDashboardComponent_Conditional_23_Template(rf, ctx) { if (rf & 1) {
|
|
132
135
|
const _r8 = i0.ɵɵgetCurrentView();
|
|
133
|
-
i0.ɵɵelementStart(0, "div",
|
|
134
|
-
i0.ɵɵelement(3, "i",
|
|
136
|
+
i0.ɵɵelementStart(0, "div", 54)(1, "div", 55)(2, "div", 56);
|
|
137
|
+
i0.ɵɵelement(3, "i", 57);
|
|
135
138
|
i0.ɵɵelementStart(4, "span");
|
|
136
139
|
i0.ɵɵtext(5, "Preview");
|
|
137
140
|
i0.ɵɵelementEnd()();
|
|
138
|
-
i0.ɵɵelementStart(6, "div",
|
|
141
|
+
i0.ɵɵelementStart(6, "div", 58)(7, "button", 59);
|
|
139
142
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_23_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ToggleEditorPanel()); });
|
|
140
|
-
i0.ɵɵelement(8, "i",
|
|
143
|
+
i0.ɵɵelement(8, "i", 60);
|
|
141
144
|
i0.ɵɵelementEnd()()();
|
|
142
|
-
i0.ɵɵelementStart(9, "div",
|
|
145
|
+
i0.ɵɵelementStart(9, "div", 61)(10, "mj-component-preview", 62);
|
|
143
146
|
i0.ɵɵlistener("AskAIToFix", function ComponentStudioDashboardComponent_Conditional_23_Template_mj_component_preview_AskAIToFix_10_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnAskAIToFix($event)); });
|
|
144
147
|
i0.ɵɵelementEnd()()();
|
|
145
|
-
i0.ɵɵconditionalCreate(11, ComponentStudioDashboardComponent_Conditional_23_Conditional_11_Template, 2, 0, "div",
|
|
146
|
-
i0.ɵɵconditionalCreate(12, ComponentStudioDashboardComponent_Conditional_23_Conditional_12_Template, 2, 2, "div",
|
|
148
|
+
i0.ɵɵconditionalCreate(11, ComponentStudioDashboardComponent_Conditional_23_Conditional_11_Template, 2, 0, "div", 63);
|
|
149
|
+
i0.ɵɵconditionalCreate(12, ComponentStudioDashboardComponent_Conditional_23_Conditional_12_Template, 2, 2, "div", 64);
|
|
147
150
|
} if (rf & 2) {
|
|
148
151
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
149
152
|
i0.ɵɵstyleProp("flex", ctx_r1.IsEditorPanelCollapsed ? "1 1 100%" : ctx_r1.previewFlex);
|
|
@@ -157,8 +160,8 @@ function ComponentStudioDashboardComponent_Conditional_23_Template(rf, ctx) { if
|
|
|
157
160
|
} }
|
|
158
161
|
function ComponentStudioDashboardComponent_Conditional_24_Template(rf, ctx) { if (rf & 1) {
|
|
159
162
|
const _r10 = i0.ɵɵgetCurrentView();
|
|
160
|
-
i0.ɵɵelementStart(0, "div", 21)(1, "div",
|
|
161
|
-
i0.ɵɵelement(3, "i",
|
|
163
|
+
i0.ɵɵelementStart(0, "div", 21)(1, "div", 68)(2, "div", 69);
|
|
164
|
+
i0.ɵɵelement(3, "i", 70);
|
|
162
165
|
i0.ɵɵelementEnd();
|
|
163
166
|
i0.ɵɵelementStart(4, "h2");
|
|
164
167
|
i0.ɵɵtext(5, "Ready to Build");
|
|
@@ -166,57 +169,70 @@ function ComponentStudioDashboardComponent_Conditional_24_Template(rf, ctx) { if
|
|
|
166
169
|
i0.ɵɵelementStart(6, "p");
|
|
167
170
|
i0.ɵɵtext(7, "Select a component from the browser or create a new one to get started");
|
|
168
171
|
i0.ɵɵelementEnd();
|
|
169
|
-
i0.ɵɵelementStart(8, "div",
|
|
172
|
+
i0.ɵɵelementStart(8, "div", 71)(9, "button", 72);
|
|
170
173
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_24_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnNewComponent()); });
|
|
171
|
-
i0.ɵɵelement(10, "span",
|
|
174
|
+
i0.ɵɵelement(10, "span", 73);
|
|
172
175
|
i0.ɵɵtext(11, " New Component ");
|
|
173
176
|
i0.ɵɵelementEnd();
|
|
174
|
-
i0.ɵɵelementStart(12, "button",
|
|
177
|
+
i0.ɵɵelementStart(12, "button", 74);
|
|
175
178
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_24_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ImportFromFile()); });
|
|
176
|
-
i0.ɵɵelement(13, "span",
|
|
179
|
+
i0.ɵɵelement(13, "span", 75);
|
|
177
180
|
i0.ɵɵtext(14, " Import ");
|
|
178
181
|
i0.ɵɵelementEnd()();
|
|
179
|
-
i0.ɵɵelementStart(15, "div",
|
|
182
|
+
i0.ɵɵelementStart(15, "div", 76)(16, "span", 77);
|
|
180
183
|
i0.ɵɵtext(17, "Quick start:");
|
|
181
184
|
i0.ɵɵelementEnd();
|
|
182
|
-
i0.ɵɵelementStart(18, "button",
|
|
185
|
+
i0.ɵɵelementStart(18, "button", 78);
|
|
183
186
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_24_Template_button_click_18_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnQuickStart("dashboard")); });
|
|
184
|
-
i0.ɵɵelement(19, "i",
|
|
187
|
+
i0.ɵɵelement(19, "i", 79);
|
|
185
188
|
i0.ɵɵtext(20, " Dashboard ");
|
|
186
189
|
i0.ɵɵelementEnd();
|
|
187
|
-
i0.ɵɵelementStart(21, "button",
|
|
190
|
+
i0.ɵɵelementStart(21, "button", 78);
|
|
188
191
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_24_Template_button_click_21_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnQuickStart("report")); });
|
|
189
|
-
i0.ɵɵelement(22, "i",
|
|
192
|
+
i0.ɵɵelement(22, "i", 80);
|
|
190
193
|
i0.ɵɵtext(23, " Report ");
|
|
191
194
|
i0.ɵɵelementEnd();
|
|
192
|
-
i0.ɵɵelementStart(24, "button",
|
|
195
|
+
i0.ɵɵelementStart(24, "button", 78);
|
|
193
196
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_24_Template_button_click_24_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnQuickStart("chart")); });
|
|
194
|
-
i0.ɵɵelement(25, "i",
|
|
197
|
+
i0.ɵɵelement(25, "i", 81);
|
|
195
198
|
i0.ɵɵtext(26, " Chart ");
|
|
196
199
|
i0.ɵɵelementEnd();
|
|
197
|
-
i0.ɵɵelementStart(27, "button",
|
|
200
|
+
i0.ɵɵelementStart(27, "button", 78);
|
|
198
201
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_24_Template_button_click_27_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnQuickStart("form")); });
|
|
199
|
-
i0.ɵɵelement(28, "i",
|
|
202
|
+
i0.ɵɵelement(28, "i", 82);
|
|
200
203
|
i0.ɵɵtext(29, " Form ");
|
|
201
204
|
i0.ɵɵelementEnd()()()();
|
|
202
205
|
} }
|
|
206
|
+
function ComponentStudioDashboardComponent_Conditional_25_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
207
|
+
const _r12 = i0.ɵɵgetCurrentView();
|
|
208
|
+
i0.ɵɵelementStart(0, "mj-form-builder-right-panel", 85);
|
|
209
|
+
i0.ɵɵlistener("ElementChanged", function ComponentStudioDashboardComponent_Conditional_25_Conditional_2_Template_mj_form_builder_right_panel_ElementChanged_0_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnFormBuilderElementChanged($event)); })("SectionChanged", function ComponentStudioDashboardComponent_Conditional_25_Conditional_2_Template_mj_form_builder_right_panel_SectionChanged_0_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnFormBuilderSectionChanged($event)); })("ElementDeleted", function ComponentStudioDashboardComponent_Conditional_25_Conditional_2_Template_mj_form_builder_right_panel_ElementDeleted_0_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnFormBuilderElementDeleted($event)); })("SectionDeleted", function ComponentStudioDashboardComponent_Conditional_25_Conditional_2_Template_mj_form_builder_right_panel_SectionDeleted_0_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnFormBuilderSectionDeleted($event)); })("FieldAdded", function ComponentStudioDashboardComponent_Conditional_25_Conditional_2_Template_mj_form_builder_right_panel_FieldAdded_0_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnFormBuilderFieldAdded($event)); });
|
|
210
|
+
i0.ɵɵelementEnd();
|
|
211
|
+
} if (rf & 2) {
|
|
212
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
213
|
+
i0.ɵɵproperty("Schema", ctx_r1.state.FormSchema)("Canvas", ctx_r1.state.FormCanvas)("SelectedElementId", ctx_r1.state.FormSelectedElementId)("SelectedSectionId", ctx_r1.state.FormSelectedSectionId);
|
|
214
|
+
} }
|
|
215
|
+
function ComponentStudioDashboardComponent_Conditional_25_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
216
|
+
i0.ɵɵelement(0, "mj-ai-assistant-panel");
|
|
217
|
+
} }
|
|
203
218
|
function ComponentStudioDashboardComponent_Conditional_25_Template(rf, ctx) { if (rf & 1) {
|
|
204
219
|
const _r11 = i0.ɵɵgetCurrentView();
|
|
205
|
-
i0.ɵɵelementStart(0, "div",
|
|
220
|
+
i0.ɵɵelementStart(0, "div", 53);
|
|
206
221
|
i0.ɵɵlistener("mousedown", function ComponentStudioDashboardComponent_Conditional_25_Template_div_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnRightResizeStart($event)); });
|
|
207
222
|
i0.ɵɵelementEnd();
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
i0.ɵɵelementStart(0, "div", 84);
|
|
211
|
-
i0.ɵɵelement(1, "mj-ai-assistant-panel");
|
|
223
|
+
i0.ɵɵelementStart(1, "div", 83);
|
|
224
|
+
i0.ɵɵconditionalCreate(2, ComponentStudioDashboardComponent_Conditional_25_Conditional_2_Template, 1, 4, "mj-form-builder-right-panel", 84)(3, ComponentStudioDashboardComponent_Conditional_25_Conditional_3_Template, 1, 0, "mj-ai-assistant-panel");
|
|
212
225
|
i0.ɵɵelementEnd();
|
|
213
226
|
} if (rf & 2) {
|
|
214
227
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
228
|
+
i0.ɵɵadvance();
|
|
215
229
|
i0.ɵɵstyleProp("width", ctx_r1.rightPanelWidth, "px");
|
|
230
|
+
i0.ɵɵadvance();
|
|
231
|
+
i0.ɵɵconditional(ctx_r1.IsFormRoleComponent ? 2 : 3);
|
|
216
232
|
} }
|
|
217
|
-
function
|
|
218
|
-
i0.ɵɵelementStart(0, "span",
|
|
219
|
-
i0.ɵɵelement(1, "i",
|
|
233
|
+
function ComponentStudioDashboardComponent_Conditional_32_Template(rf, ctx) { if (rf & 1) {
|
|
234
|
+
i0.ɵɵelementStart(0, "span", 24);
|
|
235
|
+
i0.ɵɵelement(1, "i", 86);
|
|
220
236
|
i0.ɵɵtext(2);
|
|
221
237
|
i0.ɵɵpipe(3, "date");
|
|
222
238
|
i0.ɵɵelementEnd();
|
|
@@ -225,96 +241,96 @@ function ComponentStudioDashboardComponent_Conditional_33_Template(rf, ctx) { if
|
|
|
225
241
|
i0.ɵɵadvance(2);
|
|
226
242
|
i0.ɵɵtextInterpolate1(" Saved ", i0.ɵɵpipeBind2(3, 1, ctx_r1.LastSavedTime, "shortTime"), " ");
|
|
227
243
|
} }
|
|
228
|
-
function
|
|
229
|
-
const
|
|
230
|
-
i0.ɵɵelementStart(0, "div",
|
|
231
|
-
i0.ɵɵlistener("click", function
|
|
232
|
-
i0.ɵɵelementStart(1, "div",
|
|
233
|
-
i0.ɵɵlistener("click", function
|
|
234
|
-
i0.ɵɵelementStart(2, "div",
|
|
244
|
+
function ComponentStudioDashboardComponent_Conditional_37_Template(rf, ctx) { if (rf & 1) {
|
|
245
|
+
const _r13 = i0.ɵɵgetCurrentView();
|
|
246
|
+
i0.ɵɵelementStart(0, "div", 87);
|
|
247
|
+
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_37_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ShowKeyboardShortcuts = false); });
|
|
248
|
+
i0.ɵɵelementStart(1, "div", 88);
|
|
249
|
+
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_37_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r13); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
250
|
+
i0.ɵɵelementStart(2, "div", 89)(3, "h3");
|
|
235
251
|
i0.ɵɵtext(4, "Keyboard Shortcuts");
|
|
236
252
|
i0.ɵɵelementEnd();
|
|
237
|
-
i0.ɵɵelementStart(5, "button",
|
|
238
|
-
i0.ɵɵlistener("click", function
|
|
239
|
-
i0.ɵɵelement(6, "i",
|
|
253
|
+
i0.ɵɵelementStart(5, "button", 90);
|
|
254
|
+
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Conditional_37_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ShowKeyboardShortcuts = false); });
|
|
255
|
+
i0.ɵɵelement(6, "i", 91);
|
|
240
256
|
i0.ɵɵelementEnd()();
|
|
241
|
-
i0.ɵɵelementStart(7, "div",
|
|
257
|
+
i0.ɵɵelementStart(7, "div", 92)(8, "div", 93)(9, "h4");
|
|
242
258
|
i0.ɵɵtext(10, "General");
|
|
243
259
|
i0.ɵɵelementEnd();
|
|
244
|
-
i0.ɵɵelementStart(11, "div",
|
|
260
|
+
i0.ɵɵelementStart(11, "div", 94)(12, "span", 95)(13, "kbd");
|
|
245
261
|
i0.ɵɵtext(14, "Ctrl");
|
|
246
262
|
i0.ɵɵelementEnd();
|
|
247
263
|
i0.ɵɵtext(15, " + ");
|
|
248
264
|
i0.ɵɵelementStart(16, "kbd");
|
|
249
265
|
i0.ɵɵtext(17, "S");
|
|
250
266
|
i0.ɵɵelementEnd()();
|
|
251
|
-
i0.ɵɵelementStart(18, "span",
|
|
267
|
+
i0.ɵɵelementStart(18, "span", 96);
|
|
252
268
|
i0.ɵɵtext(19, "Save version");
|
|
253
269
|
i0.ɵɵelementEnd()();
|
|
254
|
-
i0.ɵɵelementStart(20, "div",
|
|
270
|
+
i0.ɵɵelementStart(20, "div", 94)(21, "span", 95)(22, "kbd");
|
|
255
271
|
i0.ɵɵtext(23, "Ctrl");
|
|
256
272
|
i0.ɵɵelementEnd();
|
|
257
273
|
i0.ɵɵtext(24, " + ");
|
|
258
274
|
i0.ɵɵelementStart(25, "kbd");
|
|
259
275
|
i0.ɵɵtext(26, "N");
|
|
260
276
|
i0.ɵɵelementEnd()();
|
|
261
|
-
i0.ɵɵelementStart(27, "span",
|
|
277
|
+
i0.ɵɵelementStart(27, "span", 96);
|
|
262
278
|
i0.ɵɵtext(28, "New component");
|
|
263
279
|
i0.ɵɵelementEnd()();
|
|
264
|
-
i0.ɵɵelementStart(29, "div",
|
|
280
|
+
i0.ɵɵelementStart(29, "div", 94)(30, "span", 95)(31, "kbd");
|
|
265
281
|
i0.ɵɵtext(32, "?");
|
|
266
282
|
i0.ɵɵelementEnd()();
|
|
267
|
-
i0.ɵɵelementStart(33, "span",
|
|
283
|
+
i0.ɵɵelementStart(33, "span", 96);
|
|
268
284
|
i0.ɵɵtext(34, "Toggle shortcuts");
|
|
269
285
|
i0.ɵɵelementEnd()();
|
|
270
|
-
i0.ɵɵelementStart(35, "div",
|
|
286
|
+
i0.ɵɵelementStart(35, "div", 94)(36, "span", 95)(37, "kbd");
|
|
271
287
|
i0.ɵɵtext(38, "Esc");
|
|
272
288
|
i0.ɵɵelementEnd()();
|
|
273
|
-
i0.ɵɵelementStart(39, "span",
|
|
289
|
+
i0.ɵɵelementStart(39, "span", 96);
|
|
274
290
|
i0.ɵɵtext(40, "Close overlay");
|
|
275
291
|
i0.ɵɵelementEnd()()()()()();
|
|
276
292
|
} }
|
|
277
|
-
function
|
|
278
|
-
const
|
|
279
|
-
i0.ɵɵelementStart(0, "mj-new-component-dialog",
|
|
280
|
-
i0.ɵɵlistener("Close", function
|
|
293
|
+
function ComponentStudioDashboardComponent_Conditional_38_Template(rf, ctx) { if (rf & 1) {
|
|
294
|
+
const _r14 = i0.ɵɵgetCurrentView();
|
|
295
|
+
i0.ɵɵelementStart(0, "mj-new-component-dialog", 97);
|
|
296
|
+
i0.ɵɵlistener("Close", function ComponentStudioDashboardComponent_Conditional_38_Template_mj_new_component_dialog_Close_0_listener($event) { i0.ɵɵrestoreView(_r14); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnNewComponentDialogClose($event)); });
|
|
281
297
|
i0.ɵɵelementEnd();
|
|
282
298
|
} if (rf & 2) {
|
|
283
299
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
284
300
|
i0.ɵɵproperty("Visible", ctx_r1.ShowNewComponentDialog);
|
|
285
301
|
} }
|
|
286
|
-
function
|
|
287
|
-
const
|
|
288
|
-
i0.ɵɵelementStart(0, "mj-save-version-dialog",
|
|
289
|
-
i0.ɵɵlistener("Save", function
|
|
302
|
+
function ComponentStudioDashboardComponent_Conditional_39_Template(rf, ctx) { if (rf & 1) {
|
|
303
|
+
const _r15 = i0.ɵɵgetCurrentView();
|
|
304
|
+
i0.ɵɵelementStart(0, "mj-save-version-dialog", 98);
|
|
305
|
+
i0.ɵɵlistener("Save", function ComponentStudioDashboardComponent_Conditional_39_Template_mj_save_version_dialog_Save_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnSaveVersionConfirm($event)); })("Cancel", function ComponentStudioDashboardComponent_Conditional_39_Template_mj_save_version_dialog_Cancel_0_listener() { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ShowSaveVersionDialog = false); });
|
|
290
306
|
i0.ɵɵelementEnd();
|
|
291
307
|
} if (rf & 2) {
|
|
292
308
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
293
309
|
i0.ɵɵproperty("Visible", ctx_r1.ShowSaveVersionDialog)("CurrentVersion", ctx_r1.versionService.CurrentVersionNumber);
|
|
294
310
|
} }
|
|
295
311
|
function ComponentStudioDashboardComponent_Conditional_41_Template(rf, ctx) { if (rf & 1) {
|
|
296
|
-
const
|
|
297
|
-
i0.ɵɵelementStart(0, "mj-dialog",
|
|
298
|
-
i0.ɵɵlistener("Close", function ComponentStudioDashboardComponent_Conditional_41_Template_mj_dialog_Close_0_listener() { i0.ɵɵrestoreView(
|
|
299
|
-
i0.ɵɵelementStart(1, "app-text-import-dialog",
|
|
300
|
-
i0.ɵɵlistener("importSpec", function ComponentStudioDashboardComponent_Conditional_41_Template_app_text_import_dialog_importSpec_1_listener($event) { i0.ɵɵrestoreView(
|
|
312
|
+
const _r16 = i0.ɵɵgetCurrentView();
|
|
313
|
+
i0.ɵɵelementStart(0, "mj-dialog", 99);
|
|
314
|
+
i0.ɵɵlistener("Close", function ComponentStudioDashboardComponent_Conditional_41_Template_mj_dialog_Close_0_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnTextImportCancel()); });
|
|
315
|
+
i0.ɵɵelementStart(1, "app-text-import-dialog", 100);
|
|
316
|
+
i0.ɵɵlistener("importSpec", function ComponentStudioDashboardComponent_Conditional_41_Template_app_text_import_dialog_importSpec_1_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnTextImportSpec($event)); })("cancelDialog", function ComponentStudioDashboardComponent_Conditional_41_Template_app_text_import_dialog_cancelDialog_1_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnTextImportCancel()); });
|
|
301
317
|
i0.ɵɵelementEnd()();
|
|
302
318
|
} if (rf & 2) {
|
|
303
319
|
i0.ɵɵproperty("Visible", true)("Width", 700)("MinWidth", 500);
|
|
304
320
|
} }
|
|
305
321
|
function ComponentStudioDashboardComponent_Conditional_42_Template(rf, ctx) { if (rf & 1) {
|
|
306
|
-
const
|
|
307
|
-
i0.ɵɵelementStart(0, "app-artifact-load-dialog",
|
|
308
|
-
i0.ɵɵlistener("Close", function ComponentStudioDashboardComponent_Conditional_42_Template_app_artifact_load_dialog_Close_0_listener($event) { i0.ɵɵrestoreView(
|
|
322
|
+
const _r17 = i0.ɵɵgetCurrentView();
|
|
323
|
+
i0.ɵɵelementStart(0, "app-artifact-load-dialog", 97);
|
|
324
|
+
i0.ɵɵlistener("Close", function ComponentStudioDashboardComponent_Conditional_42_Template_app_artifact_load_dialog_Close_0_listener($event) { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnArtifactLoadClose($event)); });
|
|
309
325
|
i0.ɵɵelementEnd();
|
|
310
326
|
} if (rf & 2) {
|
|
311
327
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
312
328
|
i0.ɵɵproperty("Visible", ctx_r1.ShowArtifactLoadDialog);
|
|
313
329
|
} }
|
|
314
330
|
function ComponentStudioDashboardComponent_Conditional_43_Template(rf, ctx) { if (rf & 1) {
|
|
315
|
-
const
|
|
316
|
-
i0.ɵɵelementStart(0, "app-artifact-selection-dialog",
|
|
317
|
-
i0.ɵɵlistener("Close", function ComponentStudioDashboardComponent_Conditional_43_Template_app_artifact_selection_dialog_Close_0_listener($event) { i0.ɵɵrestoreView(
|
|
331
|
+
const _r18 = i0.ɵɵgetCurrentView();
|
|
332
|
+
i0.ɵɵelementStart(0, "app-artifact-selection-dialog", 97);
|
|
333
|
+
i0.ɵɵlistener("Close", function ComponentStudioDashboardComponent_Conditional_43_Template_app_artifact_selection_dialog_Close_0_listener($event) { i0.ɵɵrestoreView(_r18); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnArtifactSelectionClose($event)); });
|
|
318
334
|
i0.ɵɵelementEnd();
|
|
319
335
|
} if (rf & 2) {
|
|
320
336
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -326,6 +342,7 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
326
342
|
versionService;
|
|
327
343
|
cdr;
|
|
328
344
|
notificationService;
|
|
345
|
+
entityFormOverrideService;
|
|
329
346
|
static USER_PREFS_KEY = 'ComponentStudio.UserPreferences';
|
|
330
347
|
// --- Panel widths ---
|
|
331
348
|
leftPanelWidth = 340;
|
|
@@ -350,6 +367,14 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
350
367
|
ShowTextImportDialog = false;
|
|
351
368
|
ShowArtifactLoadDialog = false;
|
|
352
369
|
ShowArtifactSelectionDialog = false;
|
|
370
|
+
/** Toggled after a form-role Component is saved (see OnSaveVersionConfirm). */
|
|
371
|
+
ShowFormOverrideDialog = false;
|
|
372
|
+
/** ComponentID of the just-saved Component, set when ShowFormOverrideDialog flips on. */
|
|
373
|
+
PendingOverrideComponentID = null;
|
|
374
|
+
/** Entity name to seed the override dialog from (mirrors state.FormTargetEntityName). */
|
|
375
|
+
PendingOverrideEntityName = '';
|
|
376
|
+
/** Component name to seed the override Name field. */
|
|
377
|
+
PendingOverrideComponentName = '';
|
|
353
378
|
// --- Status bar ---
|
|
354
379
|
LastSavedTime = null;
|
|
355
380
|
// --- Preferences ---
|
|
@@ -357,12 +382,13 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
357
382
|
fileInput;
|
|
358
383
|
destroy$ = new Subject();
|
|
359
384
|
get metadata() { return this.ProviderToUse; }
|
|
360
|
-
constructor(state, versionService, cdr, notificationService) {
|
|
385
|
+
constructor(state, versionService, cdr, notificationService, entityFormOverrideService) {
|
|
361
386
|
super();
|
|
362
387
|
this.state = state;
|
|
363
388
|
this.versionService = versionService;
|
|
364
389
|
this.cdr = cdr;
|
|
365
390
|
this.notificationService = notificationService;
|
|
391
|
+
this.entityFormOverrideService = entityFormOverrideService;
|
|
366
392
|
}
|
|
367
393
|
async GetResourceDisplayName(data) {
|
|
368
394
|
return 'Component Studio';
|
|
@@ -373,6 +399,10 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
373
399
|
this.state.StateChanged.pipe(takeUntil(this.destroy$)).subscribe(() => {
|
|
374
400
|
this.cdr.detectChanges();
|
|
375
401
|
});
|
|
402
|
+
// Form Builder tab "Open in Chat" — relay to NavigationService.
|
|
403
|
+
this.state.OpenInChatRequested.pipe(takeUntil(this.destroy$)).subscribe(() => {
|
|
404
|
+
this.OnOpenFormInChat();
|
|
405
|
+
});
|
|
376
406
|
this.loadUserPreferences();
|
|
377
407
|
await this.state.LoadComponents();
|
|
378
408
|
this.NotifyLoadComplete();
|
|
@@ -505,6 +535,16 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
505
535
|
}
|
|
506
536
|
async OnSaveVersionConfirm(result) {
|
|
507
537
|
this.ShowSaveVersionDialog = false;
|
|
538
|
+
// If the Form Builder tab is the active surface and the canvas has
|
|
539
|
+
// content, serialize it to JSX BEFORE the version save so the canvas
|
|
540
|
+
// edits actually persist. If the user is in the Code tab instead, the
|
|
541
|
+
// EditableCode they hand-edited is already the source of truth.
|
|
542
|
+
if (this.IsFormRoleComponent && this.state.ActiveTab === 5 && this.state.FormCanvas && this.state.FormSchema) {
|
|
543
|
+
const canvas = this.state.FormCanvas;
|
|
544
|
+
const schema = this.state.FormSchema;
|
|
545
|
+
const name = canvas.title?.trim() || schema.displayName;
|
|
546
|
+
this.state.EditableCode = generateCodeFromCanvas(canvas, schema, name);
|
|
547
|
+
}
|
|
508
548
|
let success;
|
|
509
549
|
if (result.Mode === 'update') {
|
|
510
550
|
success = await this.versionService.UpdateCurrentVersion(result.Comment || undefined);
|
|
@@ -516,12 +556,62 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
516
556
|
this.LastSavedTime = new Date();
|
|
517
557
|
this.notificationService.CreateSimpleNotification(`Saved as v${this.versionService.CurrentVersionNumber}`, 'success', 3000);
|
|
518
558
|
this.state.HasUnsavedChanges = false;
|
|
559
|
+
// For form-role Components, prompt the user to create an
|
|
560
|
+
// EntityFormOverride so the saved Component actually activates for
|
|
561
|
+
// someone. Skip silently if the post-save state didn't yield a
|
|
562
|
+
// ComponentID (loading state, network blip).
|
|
563
|
+
if (this.IsFormRoleComponent && this.state.FormTargetEntityName) {
|
|
564
|
+
const spec = this.state.GetCurrentSpec?.();
|
|
565
|
+
const componentID = spec?.id ?? null;
|
|
566
|
+
if (componentID) {
|
|
567
|
+
this.PendingOverrideComponentID = componentID;
|
|
568
|
+
this.PendingOverrideEntityName = this.state.FormTargetEntityName;
|
|
569
|
+
this.PendingOverrideComponentName = spec?.name ?? '';
|
|
570
|
+
this.ShowFormOverrideDialog = true;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
519
573
|
}
|
|
520
574
|
else {
|
|
521
575
|
this.notificationService.CreateSimpleNotification('Failed to save version', 'error');
|
|
522
576
|
}
|
|
523
577
|
this.cdr.detectChanges();
|
|
524
578
|
}
|
|
579
|
+
/**
|
|
580
|
+
* Handle the post-save override dialog. Persists an EntityFormOverride
|
|
581
|
+
* row via {@link EntityFormOverrideService}. Currently surfaces an error
|
|
582
|
+
* because the underlying write is blocked on the generated
|
|
583
|
+
* `EntityFormOverrideEntity` class (Task 15) — the UI is wired so the
|
|
584
|
+
* unblock is one swap of the service stub.
|
|
585
|
+
*/
|
|
586
|
+
async OnFormOverrideDialogConfirm(result) {
|
|
587
|
+
this.ShowFormOverrideDialog = false;
|
|
588
|
+
if (!this.PendingOverrideComponentID) {
|
|
589
|
+
this.cdr.detectChanges();
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
const overrideService = this.entityFormOverrideService;
|
|
593
|
+
const provider = this.ProviderToUse;
|
|
594
|
+
const user = provider?.CurrentUser;
|
|
595
|
+
if (!user) {
|
|
596
|
+
this.notificationService.CreateSimpleNotification('No current user — cannot create override.', 'error');
|
|
597
|
+
this.cdr.detectChanges();
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
const writeResult = await overrideService.CreateOverride(this.PendingOverrideComponentID, result, user, provider);
|
|
601
|
+
if (writeResult.Success) {
|
|
602
|
+
this.notificationService.CreateSimpleNotification(`Override "${result.Name}" created. Next time you open a ${result.EntityName} record you'll see this form.`, 'success', 4000);
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
this.notificationService.CreateSimpleNotification(writeResult.Error || 'Failed to create override.', 'warning', 6000);
|
|
606
|
+
}
|
|
607
|
+
this.PendingOverrideComponentID = null;
|
|
608
|
+
this.cdr.detectChanges();
|
|
609
|
+
}
|
|
610
|
+
OnFormOverrideDialogDismiss() {
|
|
611
|
+
this.ShowFormOverrideDialog = false;
|
|
612
|
+
this.PendingOverrideComponentID = null;
|
|
613
|
+
this.cdr.detectChanges();
|
|
614
|
+
}
|
|
525
615
|
// ============================================================
|
|
526
616
|
// REFRESH COMPONENT
|
|
527
617
|
// ============================================================
|
|
@@ -562,6 +652,180 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
562
652
|
this.ShowNewComponentDialog = true;
|
|
563
653
|
this.cdr.detectChanges();
|
|
564
654
|
}
|
|
655
|
+
/**
|
|
656
|
+
* True iff the currently-loaded Component declares itself as a form-role
|
|
657
|
+
* component. Controls whether the right rail renders the field-binding
|
|
658
|
+
* inspector or the default AI assistant panel.
|
|
659
|
+
*/
|
|
660
|
+
get IsFormRoleComponent() {
|
|
661
|
+
const spec = this.state.GetCurrentSpec?.();
|
|
662
|
+
return spec?.componentRole === 'form' || spec?.type === 'form';
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Forwards a snippet emitted by the field-binding inspector to the code
|
|
666
|
+
* editor. Inserts at the end of the current code with a leading blank
|
|
667
|
+
* line so it lands inside the function body but doesn't clobber the
|
|
668
|
+
* cursor's current position. (Cursor-aware insertion is a follow-up —
|
|
669
|
+
* it requires plumbing EditorView refs from this component through
|
|
670
|
+
* EditorTabs → CodeEditorPanel → mj-code-editor.)
|
|
671
|
+
*/
|
|
672
|
+
OnFieldSnippetRequested(snippet) {
|
|
673
|
+
if (!snippet)
|
|
674
|
+
return;
|
|
675
|
+
const existing = this.state.EditableCode ?? '';
|
|
676
|
+
const separator = existing.endsWith('\n') ? '\n' : '\n\n';
|
|
677
|
+
this.state.EditableCode = existing + separator + snippet + '\n';
|
|
678
|
+
this.cdr.detectChanges();
|
|
679
|
+
}
|
|
680
|
+
// ============================================================
|
|
681
|
+
// FORM BUILDER — right-panel event handlers
|
|
682
|
+
// (Mirrors what the Form Builder tab does internally, but routed
|
|
683
|
+
// through here so the right panel works regardless of which editor
|
|
684
|
+
// tab is currently active.)
|
|
685
|
+
// ============================================================
|
|
686
|
+
OnFormBuilderElementChanged(next) {
|
|
687
|
+
const canvas = this.state.FormCanvas;
|
|
688
|
+
if (!canvas)
|
|
689
|
+
return;
|
|
690
|
+
const updated = {
|
|
691
|
+
...canvas,
|
|
692
|
+
sections: canvas.sections.map(s => ({
|
|
693
|
+
...s,
|
|
694
|
+
elements: s.elements.map(e => e.id === next.id ? next : e),
|
|
695
|
+
})),
|
|
696
|
+
};
|
|
697
|
+
this.applyCanvasUpdate(updated);
|
|
698
|
+
}
|
|
699
|
+
OnFormBuilderSectionChanged(next) {
|
|
700
|
+
const canvas = this.state.FormCanvas;
|
|
701
|
+
if (!canvas)
|
|
702
|
+
return;
|
|
703
|
+
const updated = {
|
|
704
|
+
...canvas,
|
|
705
|
+
sections: canvas.sections.map(s => s.id === next.id ? next : s),
|
|
706
|
+
};
|
|
707
|
+
this.applyCanvasUpdate(updated);
|
|
708
|
+
}
|
|
709
|
+
OnFormBuilderElementDeleted(elementId) {
|
|
710
|
+
const canvas = this.state.FormCanvas;
|
|
711
|
+
if (!canvas)
|
|
712
|
+
return;
|
|
713
|
+
const updated = {
|
|
714
|
+
...canvas,
|
|
715
|
+
sections: canvas.sections.map(s => ({
|
|
716
|
+
...s,
|
|
717
|
+
elements: s.elements.filter(e => e.id !== elementId),
|
|
718
|
+
})),
|
|
719
|
+
};
|
|
720
|
+
this.state.FormSelectedElementId = null;
|
|
721
|
+
this.applyCanvasUpdate(updated);
|
|
722
|
+
}
|
|
723
|
+
OnFormBuilderSectionDeleted(sectionId) {
|
|
724
|
+
const canvas = this.state.FormCanvas;
|
|
725
|
+
if (!canvas)
|
|
726
|
+
return;
|
|
727
|
+
const updated = {
|
|
728
|
+
...canvas,
|
|
729
|
+
sections: canvas.sections.filter(s => s.id !== sectionId),
|
|
730
|
+
};
|
|
731
|
+
this.state.FormSelectedSectionId = null;
|
|
732
|
+
this.applyCanvasUpdate(updated);
|
|
733
|
+
}
|
|
734
|
+
OnFormBuilderFieldAdded(payload) {
|
|
735
|
+
const canvas = this.state.FormCanvas;
|
|
736
|
+
if (!canvas)
|
|
737
|
+
return;
|
|
738
|
+
const targetId = this.state.FormSelectedSectionId
|
|
739
|
+
?? canvas.sections.find(s => s.elements.some(e => e.id === this.state.FormSelectedElementId))?.id
|
|
740
|
+
?? canvas.sections[0]?.id;
|
|
741
|
+
if (!targetId)
|
|
742
|
+
return;
|
|
743
|
+
const updated = {
|
|
744
|
+
...canvas,
|
|
745
|
+
sections: canvas.sections.map(s => s.id === targetId
|
|
746
|
+
? { ...s, elements: [...s.elements, {
|
|
747
|
+
id: generateCanvasId('field'),
|
|
748
|
+
type: 'field',
|
|
749
|
+
fieldName: payload.fieldName,
|
|
750
|
+
span: 1,
|
|
751
|
+
}] }
|
|
752
|
+
: s),
|
|
753
|
+
};
|
|
754
|
+
this.applyCanvasUpdate(updated);
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Persist the canvas mutation, mirror it into code, mark the dashboard
|
|
758
|
+
* dirty. Centralised so right-panel events and tab events share the same
|
|
759
|
+
* pipeline.
|
|
760
|
+
*/
|
|
761
|
+
applyCanvasUpdate(next) {
|
|
762
|
+
this.state.FormCanvas = next;
|
|
763
|
+
this.state.HasUnsavedChanges = true;
|
|
764
|
+
this.regenerateFormCodeFromCanvas();
|
|
765
|
+
this.cdr.detectChanges();
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Serialise the canvas → JSX into state.EditableCode. Quietly no-ops if
|
|
769
|
+
* we don't have both a canvas and a schema (the FormSelected* events
|
|
770
|
+
* shouldn't fire in that case anyway).
|
|
771
|
+
*/
|
|
772
|
+
regenerateFormCodeFromCanvas() {
|
|
773
|
+
const canvas = this.state.FormCanvas;
|
|
774
|
+
const schema = this.state.FormSchema;
|
|
775
|
+
if (!canvas || !schema)
|
|
776
|
+
return;
|
|
777
|
+
const name = canvas.title?.trim() || schema.displayName;
|
|
778
|
+
this.state.EditableCode = generateCodeFromCanvas(canvas, schema, name);
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Bridge the Form Builder tab's "Open in Chat" button to NavigationService.
|
|
782
|
+
* Publishes the active canvas as agent context and registers an UpdateForm
|
|
783
|
+
* tool so Sage can mutate the canvas live. Falls back to clipboard if the
|
|
784
|
+
* navigation service isn't available (e.g. embedded host).
|
|
785
|
+
*/
|
|
786
|
+
async OnOpenFormInChat() {
|
|
787
|
+
const canvas = this.state.FormCanvas;
|
|
788
|
+
if (!canvas) {
|
|
789
|
+
this.notificationService.CreateSimpleNotification('No active form to send to chat.', 'warning');
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
try {
|
|
793
|
+
this.navigationService?.SetAgentContext(this, {
|
|
794
|
+
activeForm: {
|
|
795
|
+
entityName: canvas.entityName,
|
|
796
|
+
title: canvas.title,
|
|
797
|
+
sections: canvas.sections,
|
|
798
|
+
},
|
|
799
|
+
});
|
|
800
|
+
this.navigationService?.SetAgentClientTools(this, [{
|
|
801
|
+
Name: 'UpdateForm',
|
|
802
|
+
Description: 'Replace the canvas model of the active form. Accepts a FormCanvasModel JSON object.',
|
|
803
|
+
ParameterSchema: {
|
|
804
|
+
type: 'object',
|
|
805
|
+
properties: { canvas: { type: 'object', description: 'A FormCanvasModel matching the Form Builder shape.' } },
|
|
806
|
+
required: ['canvas'],
|
|
807
|
+
},
|
|
808
|
+
Handler: async (params) => {
|
|
809
|
+
const next = params['canvas'] ?? null;
|
|
810
|
+
if (next && Array.isArray(next.sections)) {
|
|
811
|
+
this.applyCanvasUpdate(next);
|
|
812
|
+
return { Success: true };
|
|
813
|
+
}
|
|
814
|
+
return { Success: false, Error: 'Missing or malformed canvas payload.' };
|
|
815
|
+
},
|
|
816
|
+
}]);
|
|
817
|
+
this.notificationService.CreateSimpleNotification('Form context sent to chat. Open the chat panel to continue.', 'info', 4000);
|
|
818
|
+
}
|
|
819
|
+
catch {
|
|
820
|
+
try {
|
|
821
|
+
await navigator.clipboard.writeText(JSON.stringify(canvas, null, 2));
|
|
822
|
+
this.notificationService.CreateSimpleNotification('Canvas JSON copied to clipboard. Paste it into chat.', 'info', 4000);
|
|
823
|
+
}
|
|
824
|
+
catch {
|
|
825
|
+
this.notificationService.CreateSimpleNotification('Could not hand off to chat.', 'warning');
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
565
829
|
OnNewComponentDialogClose(result) {
|
|
566
830
|
this.ShowNewComponentDialog = false;
|
|
567
831
|
if (!result) {
|
|
@@ -587,17 +851,26 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
587
851
|
});
|
|
588
852
|
}
|
|
589
853
|
createComponentFromResult(result) {
|
|
854
|
+
const isForm = result.type === 'form';
|
|
590
855
|
const newSpec = {
|
|
591
856
|
name: result.name,
|
|
592
857
|
title: result.title,
|
|
593
858
|
description: result.description,
|
|
594
859
|
type: result.type,
|
|
860
|
+
// Form-role components opt in to the FormHostProps contract so the
|
|
861
|
+
// resolver mounts them via InteractiveFormComponent at runtime and
|
|
862
|
+
// the linter enforces form-specific shape checks.
|
|
863
|
+
componentRole: isForm ? 'form' : undefined,
|
|
595
864
|
location: 'embedded',
|
|
596
865
|
exampleUsage: '',
|
|
597
866
|
code: this.getTemplateCode(result.name, result.type),
|
|
598
|
-
functionalRequirements:
|
|
867
|
+
functionalRequirements: isForm
|
|
868
|
+
? 'Renders a single entity record using FormHostProps. Supports view / edit / create modes. Emits BeforeSave with the dirty-field diff and BeforeDelete; the Angular wrapper owns BaseEntity persistence.'
|
|
869
|
+
: '',
|
|
599
870
|
dataRequirements: { mode: 'views', entities: [], queries: [], description: '' },
|
|
600
|
-
technicalDesign:
|
|
871
|
+
technicalDesign: isForm
|
|
872
|
+
? 'Form-role component. Local React state holds a draft diff that overlays FormHostProps.record. Save dispatches NotifyEvent(\'BeforeSave\', { dirtyFields }) — the host applies the diff to the BaseEntity. Mode flips are requested via EditModeChangeRequested, never set locally.'
|
|
873
|
+
: ''
|
|
601
874
|
};
|
|
602
875
|
const fileComponent = {
|
|
603
876
|
id: this.state.GenerateId(),
|
|
@@ -615,6 +888,9 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
615
888
|
this.state.RunComponent(fileComponent);
|
|
616
889
|
}
|
|
617
890
|
getTemplateCode(name, type) {
|
|
891
|
+
if (type === 'form') {
|
|
892
|
+
return this.getFormTemplateCode(name);
|
|
893
|
+
}
|
|
618
894
|
return `function Component({ utilities, settings }) {
|
|
619
895
|
const React = utilities.React;
|
|
620
896
|
const { useState } = React;
|
|
@@ -627,6 +903,113 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
627
903
|
);
|
|
628
904
|
}`;
|
|
629
905
|
}
|
|
906
|
+
/**
|
|
907
|
+
* JSX skeleton for form-role components. Pre-wires destructured
|
|
908
|
+
* FormHostProps, local `draft` state for the dirty-field diff, and the
|
|
909
|
+
* three canonical lifecycle events (BeforeSave, BeforeDelete,
|
|
910
|
+
* EditModeChangeRequested). Authors fill in the field rendering; the
|
|
911
|
+
* persistence path is already correct.
|
|
912
|
+
*/
|
|
913
|
+
getFormTemplateCode(name) {
|
|
914
|
+
const componentName = this.toIdentifier(name) || 'Form';
|
|
915
|
+
return `function ${componentName}({
|
|
916
|
+
// FormHostProps (from the Angular wrapper)
|
|
917
|
+
entityName,
|
|
918
|
+
primaryKey,
|
|
919
|
+
record,
|
|
920
|
+
entityMetadata,
|
|
921
|
+
mode,
|
|
922
|
+
canEdit,
|
|
923
|
+
canDelete,
|
|
924
|
+
canCreate,
|
|
925
|
+
// Standard interactive-component props
|
|
926
|
+
utilities,
|
|
927
|
+
styles,
|
|
928
|
+
components,
|
|
929
|
+
callbacks,
|
|
930
|
+
savedUserSettings,
|
|
931
|
+
onSaveUserSettings,
|
|
932
|
+
}) {
|
|
933
|
+
const [draft, setDraft] = React.useState({});
|
|
934
|
+
|
|
935
|
+
// Track latest draft in a ref so the methods we register below always
|
|
936
|
+
// see the current value without re-registering on every keystroke.
|
|
937
|
+
const draftRef = React.useRef({});
|
|
938
|
+
React.useEffect(() => { draftRef.current = draft; }, [draft]);
|
|
939
|
+
|
|
940
|
+
const isCreate = mode === "create";
|
|
941
|
+
const isEdit = mode === "edit";
|
|
942
|
+
const isView = mode === "view";
|
|
943
|
+
const editing = isEdit || isCreate;
|
|
944
|
+
|
|
945
|
+
// Reset the draft diff whenever a new record loads or we return to view.
|
|
946
|
+
React.useEffect(() => {
|
|
947
|
+
setDraft({});
|
|
948
|
+
}, [primaryKey && JSON.stringify(primaryKey), isView]);
|
|
949
|
+
|
|
950
|
+
// Register the host-callable methods exactly once. The wrapper invokes
|
|
951
|
+
// these when the toolbar (above this component) fires Save / Cancel.
|
|
952
|
+
React.useEffect(() => {
|
|
953
|
+
callbacks?.RegisterMethod?.("RequestSave", () => {
|
|
954
|
+
callbacks?.NotifyEvent?.("BeforeSave", {
|
|
955
|
+
dirtyFields: { ...draftRef.current },
|
|
956
|
+
cancel: false,
|
|
957
|
+
timestamp: new Date(),
|
|
958
|
+
});
|
|
959
|
+
});
|
|
960
|
+
callbacks?.RegisterMethod?.("RequestCancel", () => {
|
|
961
|
+
setDraft({});
|
|
962
|
+
});
|
|
963
|
+
}, []);
|
|
964
|
+
|
|
965
|
+
const value = (f) => (f in draft ? draft[f] : record?.[f] ?? "");
|
|
966
|
+
|
|
967
|
+
const setField = (f, v) => {
|
|
968
|
+
setDraft((d) => ({ ...d, [f]: v }));
|
|
969
|
+
callbacks?.NotifyEvent?.("FieldChanged", {
|
|
970
|
+
fieldName: f,
|
|
971
|
+
oldValue: record?.[f],
|
|
972
|
+
newValue: v,
|
|
973
|
+
timestamp: new Date(),
|
|
974
|
+
});
|
|
975
|
+
};
|
|
976
|
+
|
|
977
|
+
if (!record && !isCreate) {
|
|
978
|
+
return <div style={{ padding: 24 }}>No record loaded.</div>;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
return (
|
|
982
|
+
<div style={{
|
|
983
|
+
padding: 24,
|
|
984
|
+
background: "var(--mj-bg-surface, #fff)",
|
|
985
|
+
color: "var(--mj-text-primary, #1f2937)",
|
|
986
|
+
borderRadius: 8,
|
|
987
|
+
border: "1px solid var(--mj-border-default, #e0e0e0)",
|
|
988
|
+
}}>
|
|
989
|
+
<h2 style={{ margin: 0, marginBottom: 16 }}>
|
|
990
|
+
{isCreate ? "New " + (entityMetadata?.displayName || entityName) : value(entityMetadata?.nameField || "Name") || "(unnamed)"}
|
|
991
|
+
</h2>
|
|
992
|
+
|
|
993
|
+
{/* TODO: render each entityMetadata.fields entry as an input.
|
|
994
|
+
Use value(fieldName) to read, setField(fieldName, newValue) to write.
|
|
995
|
+
See the form-builder template at metadata/prompts/templates/sage/form-builder.template.md
|
|
996
|
+
for full guidance, or open this component in chat to have the
|
|
997
|
+
Form Builder agent extend it.
|
|
998
|
+
|
|
999
|
+
DO NOT render Save / Cancel / Edit / Delete buttons here — the
|
|
1000
|
+
host toolbar above this component provides all four. Save is
|
|
1001
|
+
wired via the RequestSave method registered above. */}
|
|
1002
|
+
</div>
|
|
1003
|
+
);
|
|
1004
|
+
}`;
|
|
1005
|
+
}
|
|
1006
|
+
/** Sanitises a human-readable component name into a JS identifier. */
|
|
1007
|
+
toIdentifier(name) {
|
|
1008
|
+
const cleaned = name.replace(/[^A-Za-z0-9]/g, '');
|
|
1009
|
+
if (!cleaned)
|
|
1010
|
+
return '';
|
|
1011
|
+
return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
|
|
1012
|
+
}
|
|
630
1013
|
// ============================================================
|
|
631
1014
|
// IMPORT / EXPORT
|
|
632
1015
|
// ============================================================
|
|
@@ -892,7 +1275,7 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
892
1275
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
893
1276
|
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
894
1277
|
}
|
|
895
|
-
static ɵfac = function ComponentStudioDashboardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ComponentStudioDashboardComponent)(i0.ɵɵdirectiveInject(i1.ComponentStudioStateService), i0.ɵɵdirectiveInject(i2.ComponentVersionService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i3.MJNotificationService)); };
|
|
1278
|
+
static ɵfac = function ComponentStudioDashboardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ComponentStudioDashboardComponent)(i0.ɵɵdirectiveInject(i1.ComponentStudioStateService), i0.ɵɵdirectiveInject(i2.ComponentVersionService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i3.MJNotificationService), i0.ɵɵdirectiveInject(i4.EntityFormOverrideService)); };
|
|
896
1279
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ComponentStudioDashboardComponent, selectors: [["mj-component-studio-dashboard"]], viewQuery: function ComponentStudioDashboardComponent_Query(rf, ctx) { if (rf & 1) {
|
|
897
1280
|
i0.ɵɵviewQuery(_c0, 5);
|
|
898
1281
|
} if (rf & 2) {
|
|
@@ -900,7 +1283,7 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
900
1283
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.fileInput = _t.first);
|
|
901
1284
|
} }, hostBindings: function ComponentStudioDashboardComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
902
1285
|
i0.ɵɵlistener("keydown", function ComponentStudioDashboardComponent_keydown_HostBindingHandler($event) { return ctx.OnKeyDown($event); }, i0.ɵɵresolveDocument)("click", function ComponentStudioDashboardComponent_click_HostBindingHandler($event) { return ctx.OnDocumentClick($event); }, i0.ɵɵresolveDocument);
|
|
903
|
-
} }, standalone: false, features: [i0.ɵɵProvidersFeature([ComponentStudioStateService, ComponentVersionService]), i0.ɵɵInheritDefinitionFeature], decls: 44, vars:
|
|
1286
|
+
} }, standalone: false, features: [i0.ɵɵProvidersFeature([ComponentStudioStateService, ComponentVersionService]), i0.ɵɵInheritDefinitionFeature], decls: 44, vars: 25, consts: [["fileInput", ""], [1, "component-studio"], [1, "studio-toolbar"], [1, "toolbar-context"], ["title", "Toggle browser panel", 1, "tb-btn", "icon-only", 3, "click"], [1, "fa-solid", "fa-bars"], [1, "toolbar-spacer"], [1, "toolbar-actions"], ["title", "Save version (Ctrl+S)", 1, "tb-btn", "primary"], ["title", "Refresh component", 1, "tb-btn"], [1, "header-dropdown", 3, "open"], [1, "toolbar-divider"], [1, "tb-btn", "icon-only", 3, "click", "title"], [1, "fa-solid", "fa-robot"], ["title", "Keyboard shortcuts (?)", 1, "tb-btn", "icon-only", 3, "click"], [1, "fa-solid", "fa-keyboard"], ["title", "Refresh data", 1, "tb-btn", "icon-only", 3, "click", "disabled"], [1, "fa-solid", "fa-arrows-rotate"], ["type", "file", "accept", ".json", 2, "display", "none", 3, "change"], [1, "studio-body"], [1, "panel", "panel-center"], [1, "empty-state"], [1, "status-bar"], [1, "status-left"], [1, "status-item"], [1, "fa-solid", "fa-cube"], [1, "status-right"], [1, "status-item", "shortcut-hint"], [1, "shortcuts-overlay"], [3, "Visible"], [3, "Visible", "CurrentVersion"], [3, "confirmed", "dismissed", "Visible", "ComponentName", "EntityName"], ["Title", "Import Component from Text", 3, "Visible", "Width", "MinWidth"], [1, "breadcrumb-type"], [1, "breadcrumb-sep"], [1, "fa-solid", "fa-chevron-right"], [1, "component-label"], [1, "running-badge"], ["title", "Unsaved changes", 1, "unsaved-dot"], [1, "running-dot-small"], ["title", "Save version (Ctrl+S)", 1, "tb-btn", "primary", 3, "click"], [1, "fa-solid", "fa-save"], ["title", "Refresh component", 1, "tb-btn", 3, "click"], [1, "header-dropdown"], [1, "tb-btn", 3, "click"], [1, "fa-solid", "fa-file-export"], [1, "fa-solid", "fa-chevron-down", "dropdown-icon"], [1, "dropdown-menu"], [1, "dropdown-item", 3, "click"], [1, "fa-solid", "fa-file"], [1, "fa-solid", "fa-clipboard"], [1, "panel", "panel-left"], [3, "NewComponent", "ImportFromFile", "ImportFromText", "ImportFromArtifact"], [1, "resize-handle", 3, "mousedown"], [1, "workspace-preview"], [1, "preview-sub-header"], [1, "preview-sub-left"], [1, "fa-solid", "fa-eye"], [1, "preview-sub-right"], ["title", "Toggle editor panel", 1, "toggle-editors-btn", 3, "click"], [1, "fa-solid", "fa-columns"], [1, "preview-body"], [3, "AskAIToFix"], [1, "resize-handle", "center-divider"], [1, "workspace-editors", 3, "flex"], [1, "resize-handle", "center-divider", 3, "mousedown"], [1, "divider-grip"], [1, "workspace-editors"], [1, "empty-state-content"], [1, "empty-state-icon"], [1, "fa-solid", "fa-rocket"], [1, "empty-state-actions"], ["mjButton", "", "variant", "primary", 3, "click"], [1, "fa-solid", "fa-plus"], ["mjButton", "", 3, "click"], [1, "fa-solid", "fa-file-import"], [1, "quick-start-templates"], [1, "quick-start-label"], [1, "quick-start-btn", 3, "click"], [1, "fa-solid", "fa-chart-line"], [1, "fa-solid", "fa-file-alt"], [1, "fa-solid", "fa-chart-pie"], [1, "fa-solid", "fa-edit"], [1, "panel", "panel-right"], [3, "Schema", "Canvas", "SelectedElementId", "SelectedSectionId"], [3, "ElementChanged", "SectionChanged", "ElementDeleted", "SectionDeleted", "FieldAdded", "Schema", "Canvas", "SelectedElementId", "SelectedSectionId"], [1, "fa-solid", "fa-check-circle"], [1, "shortcuts-overlay", 3, "click"], [1, "shortcuts-panel", 3, "click"], [1, "shortcuts-header"], [1, "shortcuts-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "shortcuts-body"], [1, "shortcut-group"], [1, "shortcut-row"], [1, "shortcut-keys"], [1, "shortcut-desc"], [3, "Close", "Visible"], [3, "Save", "Cancel", "Visible", "CurrentVersion"], ["Title", "Import Component from Text", 3, "Close", "Visible", "Width", "MinWidth"], [3, "importSpec", "cancelDialog"]], template: function ComponentStudioDashboardComponent_Template(rf, ctx) { if (rf & 1) {
|
|
904
1287
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
905
1288
|
i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "div", 3)(3, "button", 4);
|
|
906
1289
|
i0.ɵɵlistener("click", function ComponentStudioDashboardComponent_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.ToggleLeftPanel()); });
|
|
@@ -934,26 +1317,28 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
934
1317
|
i0.ɵɵelementStart(22, "div", 20);
|
|
935
1318
|
i0.ɵɵconditionalCreate(23, ComponentStudioDashboardComponent_Conditional_23_Template, 13, 8)(24, ComponentStudioDashboardComponent_Conditional_24_Template, 30, 0, "div", 21);
|
|
936
1319
|
i0.ɵɵelementEnd();
|
|
937
|
-
i0.ɵɵconditionalCreate(25, ComponentStudioDashboardComponent_Conditional_25_Template,
|
|
938
|
-
i0.ɵɵconditionalCreate(26, ComponentStudioDashboardComponent_Conditional_26_Template, 2, 2, "div", 23);
|
|
1320
|
+
i0.ɵɵconditionalCreate(25, ComponentStudioDashboardComponent_Conditional_25_Template, 4, 3);
|
|
939
1321
|
i0.ɵɵelementEnd();
|
|
940
|
-
i0.ɵɵelementStart(
|
|
941
|
-
i0.ɵɵelement(
|
|
942
|
-
i0.ɵɵtext(
|
|
1322
|
+
i0.ɵɵelementStart(26, "div", 22)(27, "div", 23)(28, "span", 24);
|
|
1323
|
+
i0.ɵɵelement(29, "i", 25);
|
|
1324
|
+
i0.ɵɵtext(30);
|
|
943
1325
|
i0.ɵɵelementEnd()();
|
|
944
|
-
i0.ɵɵelementStart(
|
|
945
|
-
i0.ɵɵconditionalCreate(
|
|
946
|
-
i0.ɵɵelementStart(
|
|
947
|
-
i0.ɵɵtext(
|
|
1326
|
+
i0.ɵɵelementStart(31, "div", 26);
|
|
1327
|
+
i0.ɵɵconditionalCreate(32, ComponentStudioDashboardComponent_Conditional_32_Template, 4, 4, "span", 24);
|
|
1328
|
+
i0.ɵɵelementStart(33, "span", 27)(34, "kbd");
|
|
1329
|
+
i0.ɵɵtext(35, "?");
|
|
948
1330
|
i0.ɵɵelementEnd();
|
|
949
|
-
i0.ɵɵtext(
|
|
1331
|
+
i0.ɵɵtext(36, " Shortcuts ");
|
|
950
1332
|
i0.ɵɵelementEnd()()();
|
|
951
|
-
i0.ɵɵconditionalCreate(
|
|
952
|
-
i0.ɵɵconditionalCreate(
|
|
953
|
-
i0.ɵɵconditionalCreate(
|
|
954
|
-
i0.ɵɵ
|
|
955
|
-
i0.ɵɵ
|
|
956
|
-
i0.ɵɵ
|
|
1333
|
+
i0.ɵɵconditionalCreate(37, ComponentStudioDashboardComponent_Conditional_37_Template, 41, 0, "div", 28);
|
|
1334
|
+
i0.ɵɵconditionalCreate(38, ComponentStudioDashboardComponent_Conditional_38_Template, 1, 1, "mj-new-component-dialog", 29);
|
|
1335
|
+
i0.ɵɵconditionalCreate(39, ComponentStudioDashboardComponent_Conditional_39_Template, 1, 2, "mj-save-version-dialog", 30);
|
|
1336
|
+
i0.ɵɵelementStart(40, "mj-form-override-dialog", 31);
|
|
1337
|
+
i0.ɵɵlistener("confirmed", function ComponentStudioDashboardComponent_Template_mj_form_override_dialog_confirmed_40_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnFormOverrideDialogConfirm($event)); })("dismissed", function ComponentStudioDashboardComponent_Template_mj_form_override_dialog_dismissed_40_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnFormOverrideDialogDismiss()); });
|
|
1338
|
+
i0.ɵɵelementEnd();
|
|
1339
|
+
i0.ɵɵconditionalCreate(41, ComponentStudioDashboardComponent_Conditional_41_Template, 2, 3, "mj-dialog", 32);
|
|
1340
|
+
i0.ɵɵconditionalCreate(42, ComponentStudioDashboardComponent_Conditional_42_Template, 1, 1, "app-artifact-load-dialog", 29);
|
|
1341
|
+
i0.ɵɵconditionalCreate(43, ComponentStudioDashboardComponent_Conditional_43_Template, 1, 1, "app-artifact-selection-dialog", 29);
|
|
957
1342
|
i0.ɵɵelementEnd();
|
|
958
1343
|
} if (rf & 2) {
|
|
959
1344
|
i0.ɵɵclassProp("resizing", ctx.IsResizing);
|
|
@@ -975,19 +1360,19 @@ let ComponentStudioDashboardComponent = class ComponentStudioDashboardComponent
|
|
|
975
1360
|
i0.ɵɵadvance(2);
|
|
976
1361
|
i0.ɵɵconditional(ctx.state.SelectedComponent ? 23 : 24);
|
|
977
1362
|
i0.ɵɵadvance(2);
|
|
978
|
-
i0.ɵɵconditional(!ctx.state.IsAIPanelCollapsed ? 25 : -1);
|
|
979
|
-
i0.ɵɵadvance();
|
|
980
|
-
i0.ɵɵconditional(!ctx.state.IsAIPanelCollapsed ? 26 : -1);
|
|
1363
|
+
i0.ɵɵconditional(!ctx.state.IsAIPanelCollapsed && ctx.state.SelectedComponent ? 25 : -1);
|
|
981
1364
|
i0.ɵɵadvance(5);
|
|
982
1365
|
i0.ɵɵtextInterpolate2(" ", ctx.state.FilteredComponents.length, " component", ctx.state.FilteredComponents.length !== 1 ? "s" : "", " ");
|
|
983
1366
|
i0.ɵɵadvance(2);
|
|
984
|
-
i0.ɵɵconditional(ctx.LastSavedTime ?
|
|
1367
|
+
i0.ɵɵconditional(ctx.LastSavedTime ? 32 : -1);
|
|
985
1368
|
i0.ɵɵadvance(5);
|
|
986
|
-
i0.ɵɵconditional(ctx.ShowKeyboardShortcuts ?
|
|
1369
|
+
i0.ɵɵconditional(ctx.ShowKeyboardShortcuts ? 37 : -1);
|
|
1370
|
+
i0.ɵɵadvance();
|
|
1371
|
+
i0.ɵɵconditional(ctx.ShowNewComponentDialog ? 38 : -1);
|
|
987
1372
|
i0.ɵɵadvance();
|
|
988
|
-
i0.ɵɵconditional(ctx.
|
|
1373
|
+
i0.ɵɵconditional(ctx.ShowSaveVersionDialog ? 39 : -1);
|
|
989
1374
|
i0.ɵɵadvance();
|
|
990
|
-
i0.ɵɵ
|
|
1375
|
+
i0.ɵɵproperty("Visible", ctx.ShowFormOverrideDialog)("ComponentName", ctx.PendingOverrideComponentName)("EntityName", ctx.PendingOverrideEntityName);
|
|
991
1376
|
i0.ɵɵadvance();
|
|
992
1377
|
i0.ɵɵconditional(ctx.ShowTextImportDialog ? 41 : -1);
|
|
993
1378
|
i0.ɵɵadvance();
|
|
@@ -1002,8 +1387,8 @@ ComponentStudioDashboardComponent = ComponentStudioDashboardComponent_1 = __deco
|
|
|
1002
1387
|
export { ComponentStudioDashboardComponent };
|
|
1003
1388
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ComponentStudioDashboardComponent, [{
|
|
1004
1389
|
type: Component,
|
|
1005
|
-
args: [{ standalone: false, selector: 'mj-component-studio-dashboard', providers: [ComponentStudioStateService, ComponentVersionService], template: "<div class=\"component-studio\" [class.resizing]=\"IsResizing\">\n\n <!-- ============================================================\n TOOLBAR \u2014 Unified bar with integrated breadcrumb\n Left: hamburger + breadcrumb context\n Right: Save | Export | divider | AI | Keyboard | Refresh\n ============================================================ -->\n <div class=\"studio-toolbar\">\n <div class=\"toolbar-context\">\n <!-- Toggle left panel -->\n <button class=\"tb-btn icon-only\" title=\"Toggle browser panel\" (click)=\"ToggleLeftPanel()\">\n <i class=\"fa-solid fa-bars\"></i>\n </button>\n\n @if (state.SelectedComponent) {\n <span class=\"breadcrumb-type\">\n <i class=\"fa-solid fa-cube\"></i>\n {{ state.GetComponentType(state.SelectedComponent) || 'Component' }}\n </span>\n <span class=\"breadcrumb-sep\"><i class=\"fa-solid fa-chevron-right\"></i></span>\n <span class=\"component-label\">{{ state.GetComponentName(state.SelectedComponent) }}</span>\n\n @if (state.IsRunning) {\n <span class=\"running-badge\">\n <span class=\"running-dot-small\"></span>\n Running\n </span>\n }\n @if (state.HasUnsavedChanges) {\n <span class=\"unsaved-dot\" title=\"Unsaved changes\"></span>\n }\n }\n </div>\n\n <div class=\"toolbar-spacer\"></div>\n\n <div class=\"toolbar-actions\">\n <!-- Save Version -->\n @if (state.SelectedComponent) {\n <button class=\"tb-btn primary\" (click)=\"SaveVersion()\" title=\"Save version (Ctrl+S)\">\n <i class=\"fa-solid fa-save\"></i> Save\n </button>\n }\n\n <!-- Refresh Component -->\n @if (state.SelectedComponent && state.IsRunning) {\n <button class=\"tb-btn\" (click)=\"RefreshComponent()\" title=\"Refresh component\">\n <i class=\"fa-solid fa-arrows-rotate\"></i> Refresh\n </button>\n }\n\n <!-- Export -->\n @if (state.SelectedComponent && state.IsRunning) {\n <div class=\"header-dropdown\" [class.open]=\"exportDropdownOpen\">\n <button class=\"tb-btn\" (click)=\"ToggleExportDropdown()\">\n <i class=\"fa-solid fa-file-export\"></i> Export\n <i class=\"fa-solid fa-chevron-down dropdown-icon\"></i>\n </button>\n @if (exportDropdownOpen) {\n <div class=\"dropdown-menu\">\n <button class=\"dropdown-item\" (click)=\"ExportToArtifact()\">\n <i class=\"fa-solid fa-save\"></i> To Artifact\n </button>\n <button class=\"dropdown-item\" (click)=\"ExportToFile()\">\n <i class=\"fa-solid fa-file\"></i> To File\n </button>\n <button class=\"dropdown-item\" (click)=\"ExportToClipboard()\">\n <i class=\"fa-solid fa-clipboard\"></i> To Clipboard\n </button>\n </div>\n }\n </div>\n }\n\n <span class=\"toolbar-divider\"></span>\n\n <!-- AI Panel Toggle -->\n <button class=\"tb-btn icon-only\" [class.active-toggle]=\"!state.IsAIPanelCollapsed\"\n (click)=\"ToggleAIPanel()\"\n [title]=\"state.IsAIPanelCollapsed ? 'Show AI Assistant' : 'Hide AI Assistant'\">\n <i class=\"fa-solid fa-robot\"></i>\n </button>\n\n <!-- Keyboard Shortcuts -->\n <button class=\"tb-btn icon-only\" (click)=\"ShowKeyboardShortcuts = !ShowKeyboardShortcuts\"\n title=\"Keyboard shortcuts (?)\">\n <i class=\"fa-solid fa-keyboard\"></i>\n </button>\n\n <!-- Refresh -->\n <button class=\"tb-btn icon-only\" (click)=\"RefreshData()\" [disabled]=\"state.IsLoading\" title=\"Refresh data\">\n <i class=\"fa-solid fa-arrows-rotate\"></i>\n </button>\n </div>\n\n <!-- Hidden file input -->\n <input #fileInput type=\"file\" accept=\".json\" (change)=\"HandleFileSelect($event)\" style=\"display: none;\" />\n </div>\n\n <!-- ============================================================\n THREE-PANEL BODY\n ============================================================ -->\n <div class=\"studio-body\">\n\n <!-- Left Panel: Component Browser (collapsible) -->\n @if (!IsLeftPanelCollapsed) {\n <div class=\"panel panel-left\" [style.width.px]=\"leftPanelWidth\">\n <mj-component-browser\n (NewComponent)=\"OnNewComponent()\"\n (ImportFromFile)=\"ImportFromFile()\"\n (ImportFromText)=\"ImportFromText()\"\n (ImportFromArtifact)=\"ImportFromArtifact()\">\n </mj-component-browser>\n </div>\n\n <!-- Resize Handle: Left <-> Center -->\n <div class=\"resize-handle\" (mousedown)=\"OnLeftResizeStart($event)\"></div>\n }\n\n <!-- Center Panel: Workspace (side-by-side: Preview LEFT, Editor RIGHT) -->\n <div class=\"panel panel-center\">\n @if (state.SelectedComponent) {\n <!-- Preview (left side) -->\n <div class=\"workspace-preview\" [class.full-width]=\"IsEditorPanelCollapsed\" [style.flex]=\"IsEditorPanelCollapsed ? '1 1 100%' : previewFlex\">\n <div class=\"preview-sub-header\">\n <div class=\"preview-sub-left\">\n <i class=\"fa-solid fa-eye\"></i>\n <span>Preview</span>\n </div>\n <div class=\"preview-sub-right\">\n <!-- Toggle editor panel -->\n <button class=\"toggle-editors-btn\" [class.active]=\"!IsEditorPanelCollapsed\"\n (click)=\"ToggleEditorPanel()\" title=\"Toggle editor panel\">\n <i class=\"fa-solid fa-columns\"></i>\n </button>\n </div>\n </div>\n <div class=\"preview-body\">\n <mj-component-preview\n (AskAIToFix)=\"OnAskAIToFix($event)\">\n </mj-component-preview>\n </div>\n </div>\n\n <!-- Resize Handle: Preview <-> Editor (obvious center divider) -->\n @if (!IsEditorPanelCollapsed) {\n <div class=\"resize-handle center-divider\" (mousedown)=\"OnCenterResizeStart($event)\">\n <div class=\"divider-grip\"></div>\n </div>\n }\n\n <!-- Editor Tabs (right side, collapsible) -->\n @if (!IsEditorPanelCollapsed) {\n <div class=\"workspace-editors\" [style.flex]=\"editorFlex\">\n <mj-editor-tabs></mj-editor-tabs>\n </div>\n }\n } @else {\n <!-- Enhanced Empty State -->\n <div class=\"empty-state\">\n <div class=\"empty-state-content\">\n <div class=\"empty-state-icon\">\n <i class=\"fa-solid fa-rocket\"></i>\n </div>\n <h2>Ready to Build</h2>\n <p>Select a component from the browser or create a new one to get started</p>\n <div class=\"empty-state-actions\">\n <button mjButton variant=\"primary\" (click)=\"OnNewComponent()\">\n <span class=\"fa-solid fa-plus\"></span> New Component\n </button>\n <button mjButton (click)=\"ImportFromFile()\">\n <span class=\"fa-solid fa-file-import\"></span> Import\n </button>\n </div>\n <div class=\"quick-start-templates\">\n <span class=\"quick-start-label\">Quick start:</span>\n <button class=\"quick-start-btn\" (click)=\"OnQuickStart('dashboard')\">\n <i class=\"fa-solid fa-chart-line\"></i> Dashboard\n </button>\n <button class=\"quick-start-btn\" (click)=\"OnQuickStart('report')\">\n <i class=\"fa-solid fa-file-alt\"></i> Report\n </button>\n <button class=\"quick-start-btn\" (click)=\"OnQuickStart('chart')\">\n <i class=\"fa-solid fa-chart-pie\"></i> Chart\n </button>\n <button class=\"quick-start-btn\" (click)=\"OnQuickStart('form')\">\n <i class=\"fa-solid fa-edit\"></i> Form\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Resize Handle: Center <-> Right -->\n @if (!state.IsAIPanelCollapsed) {\n <div class=\"resize-handle\" (mousedown)=\"OnRightResizeStart($event)\"></div>\n }\n\n <!-- Right Panel: AI Assistant -->\n @if (!state.IsAIPanelCollapsed) {\n <div class=\"panel panel-right\" [style.width.px]=\"rightPanelWidth\">\n <mj-ai-assistant-panel></mj-ai-assistant-panel>\n </div>\n }\n </div>\n\n <!-- ============================================================\n STATUS BAR\n ============================================================ -->\n <div class=\"status-bar\">\n <div class=\"status-left\">\n <span class=\"status-item\">\n <i class=\"fa-solid fa-cube\"></i>\n {{ state.FilteredComponents.length }} component{{ state.FilteredComponents.length !== 1 ? 's' : '' }}\n </span>\n </div>\n <div class=\"status-right\">\n @if (LastSavedTime) {\n <span class=\"status-item\">\n <i class=\"fa-solid fa-check-circle\"></i>\n Saved {{ LastSavedTime | date:'shortTime' }}\n </span>\n }\n <span class=\"status-item shortcut-hint\">\n <kbd>?</kbd> Shortcuts\n </span>\n </div>\n </div>\n\n <!-- ============================================================\n KEYBOARD SHORTCUTS OVERLAY\n ============================================================ -->\n @if (ShowKeyboardShortcuts) {\n <div class=\"shortcuts-overlay\" (click)=\"ShowKeyboardShortcuts = false\">\n <div class=\"shortcuts-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"shortcuts-header\">\n <h3>Keyboard Shortcuts</h3>\n <button class=\"shortcuts-close\" (click)=\"ShowKeyboardShortcuts = false\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <div class=\"shortcuts-body\">\n <div class=\"shortcut-group\">\n <h4>General</h4>\n <div class=\"shortcut-row\">\n <span class=\"shortcut-keys\"><kbd>Ctrl</kbd> + <kbd>S</kbd></span>\n <span class=\"shortcut-desc\">Save version</span>\n </div>\n <div class=\"shortcut-row\">\n <span class=\"shortcut-keys\"><kbd>Ctrl</kbd> + <kbd>N</kbd></span>\n <span class=\"shortcut-desc\">New component</span>\n </div>\n <div class=\"shortcut-row\">\n <span class=\"shortcut-keys\"><kbd>?</kbd></span>\n <span class=\"shortcut-desc\">Toggle shortcuts</span>\n </div>\n <div class=\"shortcut-row\">\n <span class=\"shortcut-keys\"><kbd>Esc</kbd></span>\n <span class=\"shortcut-desc\">Close overlay</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- ============================================================\n NEW COMPONENT DIALOG\n ============================================================ -->\n @if (ShowNewComponentDialog) {\n <mj-new-component-dialog\n [Visible]=\"ShowNewComponentDialog\"\n (Close)=\"OnNewComponentDialogClose($event)\">\n </mj-new-component-dialog>\n }\n\n @if (ShowSaveVersionDialog) {\n <mj-save-version-dialog\n [Visible]=\"ShowSaveVersionDialog\"\n [CurrentVersion]=\"versionService.CurrentVersionNumber\"\n (Save)=\"OnSaveVersionConfirm($event)\"\n (Cancel)=\"ShowSaveVersionDialog = false\">\n </mj-save-version-dialog>\n }\n\n <!-- Text Import Dialog -->\n @if (ShowTextImportDialog) {\n <mj-dialog [Visible]=\"true\" Title=\"Import Component from Text\" (Close)=\"OnTextImportCancel()\" [Width]=\"700\" [MinWidth]=\"500\">\n <app-text-import-dialog\n (importSpec)=\"OnTextImportSpec($event)\"\n (cancelDialog)=\"OnTextImportCancel()\">\n </app-text-import-dialog>\n </mj-dialog>\n }\n\n <!-- Artifact Load Dialog -->\n @if (ShowArtifactLoadDialog) {\n <app-artifact-load-dialog\n [Visible]=\"ShowArtifactLoadDialog\"\n (Close)=\"OnArtifactLoadClose($event)\">\n </app-artifact-load-dialog>\n }\n\n <!-- Artifact Selection Dialog -->\n @if (ShowArtifactSelectionDialog) {\n <app-artifact-selection-dialog\n [Visible]=\"ShowArtifactSelectionDialog\"\n (Close)=\"OnArtifactSelectionClose($event)\">\n </app-artifact-selection-dialog>\n }\n</div>\n", styles: [":host {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n.component-studio {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n/* ============================================================\n TOOLBAR \u2014 unified bar with integrated breadcrumb\n ============================================================ */\n\n.component-studio .studio-toolbar {\n display: flex;\n align-items: center;\n padding: 0 8px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n z-index: 10;\n min-height: 42px;\n gap: 8px;\n}\n\n/* Left: hamburger + breadcrumb context */\n.component-studio .toolbar-context {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex-shrink: 1;\n overflow: hidden;\n}\n\n.component-studio .toolbar-spacer {\n flex: 1;\n}\n\n/* Right: action buttons */\n.component-studio .toolbar-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-shrink: 0;\n}\n\n/* ---- Toolbar buttons ---- */\n.component-studio .tb-btn {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 5px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n line-height: 1;\n}\n\n.component-studio .tb-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-default);\n}\n\n.component-studio .tb-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.component-studio .tb-btn i {\n font-size: 12px;\n}\n\n.component-studio .tb-btn.icon-only {\n padding: 5px 7px;\n}\n\n.component-studio .tb-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.component-studio .tb-btn.primary:hover {\n opacity: 0.9;\n}\n\n.component-studio .tb-btn.active-toggle {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n/* ---- Breadcrumb elements inside toolbar ---- */\n.component-studio .breadcrumb-type {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}\n\n.component-studio .breadcrumb-type i {\n font-size: 11px;\n color: var(--mj-brand-primary);\n}\n\n.component-studio .breadcrumb-sep {\n font-size: 9px;\n color: var(--mj-border-default);\n}\n\n.component-studio .component-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 240px;\n}\n\n.component-studio .running-badge {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 2px 8px;\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n font-size: 11px;\n font-weight: 600;\n border-radius: 10px;\n white-space: nowrap;\n}\n\n.component-studio .running-dot-small {\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-success);\n animation: pulse 1.5s ease-in-out infinite;\n}\n\n.component-studio .unsaved-dot {\n display: inline-block;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n animation: pulse 2s infinite;\n flex-shrink: 0;\n}\n\n.component-studio .toolbar-divider {\n width: 1px;\n height: 18px;\n background: var(--mj-border-default);\n margin: 0 2px;\n flex-shrink: 0;\n}\n\n.component-studio .dropdown-icon {\n font-size: 9px;\n opacity: 0.6;\n}\n\n/* ---- Dropdown menus ---- */\n.component-studio .header-dropdown {\n position: relative;\n}\n\n.component-studio .header-dropdown .dropdown-menu {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 100;\n min-width: 180px;\n overflow: hidden;\n}\n\n.component-studio .header-dropdown .dropdown-menu .dropdown-item {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 16px;\n border: none;\n background: none;\n text-align: left;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: background 0.15s ease;\n}\n\n.component-studio .header-dropdown .dropdown-menu .dropdown-item:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.component-studio .header-dropdown .dropdown-menu .dropdown-item:not(:last-child) {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.component-studio .header-dropdown .dropdown-menu .dropdown-item i {\n width: 16px;\n text-align: center;\n color: var(--mj-brand-primary);\n font-size: 13px;\n}\n\n/* ============================================================\n THREE-PANEL BODY\n ============================================================ */\n\n.component-studio .studio-body {\n display: flex;\n flex: 1;\n overflow: hidden;\n}\n\n.component-studio .panel {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--mj-bg-surface);\n}\n\n.component-studio .panel-left {\n flex-shrink: 0;\n border-right: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n.component-studio .panel-center {\n flex: 1;\n display: flex;\n flex-direction: row;\n min-width: 400px;\n}\n\n/* Preview pane (left side of center) */\n.component-studio .panel-center .workspace-preview {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n border-right: 1px solid var(--mj-border-default);\n}\n\n.component-studio .panel-center .workspace-preview.full-width {\n border-right: none;\n}\n\n/* Preview sub-header */\n.component-studio .preview-sub-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 10px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n min-height: 32px;\n}\n\n.component-studio .preview-sub-left {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.component-studio .preview-sub-left i {\n font-size: 11px;\n color: var(--mj-brand-primary);\n}\n\n.component-studio .preview-sub-right {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.component-studio .toggle-editors-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 12px;\n transition: all 0.15s ease;\n}\n\n.component-studio .toggle-editors-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.component-studio .toggle-editors-btn.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.component-studio .preview-body {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n/* Editor pane (right side of center) */\n.component-studio .panel-center .workspace-editors {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n/* Right panel: AI Assistant */\n.component-studio .panel-right {\n flex-shrink: 0;\n border-left: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n/* ============================================================\n RESIZE HANDLES\n ============================================================ */\n\n.component-studio .resize-handle {\n flex-shrink: 0;\n width: 5px;\n cursor: col-resize;\n background: transparent;\n position: relative;\n z-index: 5;\n transition: background 0.15s ease;\n}\n\n.component-studio .resize-handle:hover,\n.component-studio .resize-handle:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n}\n\n/* Center divider \u2014 more obvious separator between preview and editors */\n.component-studio .resize-handle.center-divider {\n width: 7px;\n background: var(--mj-border-default);\n}\n\n.component-studio .resize-handle.center-divider:hover,\n.component-studio .resize-handle.center-divider:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n.component-studio .resize-handle .divider-grip {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 3px;\n height: 32px;\n border-radius: 2px;\n background: var(--mj-text-secondary);\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.component-studio .resize-handle:hover .divider-grip {\n opacity: 0.5;\n}\n\n/* SMOOTH RESIZE TRANSITIONS */\n.component-studio:not(.resizing) .panel {\n transition: width 0.15s ease, flex 0.15s ease;\n}\n\n.component-studio:not(.resizing) .workspace-preview,\n.component-studio:not(.resizing) .workspace-editors {\n transition: flex 0.15s ease;\n}\n\n/* ============================================================\n STATUS BAR\n ============================================================ */\n\n.component-studio .status-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 2px 16px;\n background: var(--mj-bg-surface-sunken);\n border-top: 1px solid var(--mj-border-default);\n font-size: 11px;\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n min-height: 24px;\n}\n\n.component-studio .status-bar .status-left {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.component-studio .status-bar .status-right {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.component-studio .status-bar .status-item {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.component-studio .status-bar kbd {\n display: inline-block;\n padding: 0 4px;\n font-size: 10px;\n font-family: inherit;\n line-height: 16px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 3px;\n}\n\n.component-studio .status-bar .shortcut-hint {\n display: flex;\n align-items: center;\n gap: 4px;\n opacity: 0.8;\n}\n\n/* ============================================================\n KEYBOARD SHORTCUTS OVERLAY\n ============================================================ */\n\n.component-studio .shortcuts-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n box-shadow: var(--mj-shadow-lg);\n width: 520px;\n max-height: 80vh;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-header button {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 16px;\n padding: 4px;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-header button:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-body {\n padding: 16px 20px;\n overflow-y: auto;\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-body .shortcut-group h4 {\n margin: 0 0 8px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-body .shortcut-group + .shortcut-group {\n margin-top: 16px;\n padding-top: 16px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-body .shortcut-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 0;\n font-size: 13px;\n color: var(--mj-text-primary);\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-body .shortcut-row kbd {\n display: inline-block;\n padding: 2px 8px;\n font-size: 12px;\n font-family: inherit;\n line-height: 20px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n box-shadow: 0 1px 0 var(--mj-border-default);\n min-width: 24px;\n text-align: center;\n}\n\n/* ============================================================\n EMPTY STATE\n ============================================================ */\n\n.component-studio .empty-state {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface-sunken);\n}\n\n.component-studio .empty-state .empty-state-content {\n text-align: center;\n max-width: 400px;\n}\n\n.component-studio .empty-state .empty-state-content .empty-state-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 72px;\n height: 72px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n margin-bottom: 16px;\n}\n\n.component-studio .empty-state .empty-state-content .empty-state-icon i {\n font-size: 28px;\n color: var(--mj-brand-primary);\n}\n\n.component-studio .empty-state .empty-state-content i {\n color: var(--mj-border-default);\n margin-bottom: 16px;\n}\n\n.component-studio .empty-state .empty-state-content h2 {\n margin: 0 0 8px;\n font-size: 22px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.component-studio .empty-state .empty-state-content p {\n margin: 0 0 24px;\n color: var(--mj-text-secondary);\n font-size: 14px;\n line-height: 1.5;\n}\n\n.component-studio .empty-state .empty-state-content .empty-state-actions {\n display: flex;\n gap: 8px;\n justify-content: center;\n}\n\n.component-studio .empty-state .empty-state-content .quick-start-templates {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n flex-wrap: wrap;\n margin-top: 16px;\n}\n\n.component-studio .empty-state .empty-state-content .quick-start-templates .quick-start-label {\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-right: 4px;\n}\n\n.component-studio .empty-state .empty-state-content .quick-start-templates .quick-start-btn {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 4px 12px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.component-studio .empty-state .empty-state-content .quick-start-templates .quick-start-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-default);\n}\n\n.component-studio .empty-state .empty-state-content .quick-start-templates .quick-start-btn i {\n font-size: 11px;\n color: var(--mj-brand-primary);\n margin-bottom: 0;\n}\n\n@keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n}\n"] }]
|
|
1006
|
-
}], () => [{ type: i1.ComponentStudioStateService }, { type: i2.ComponentVersionService }, { type: i0.ChangeDetectorRef }, { type: i3.MJNotificationService }], { fileInput: [{
|
|
1390
|
+
args: [{ standalone: false, selector: 'mj-component-studio-dashboard', providers: [ComponentStudioStateService, ComponentVersionService], template: "<div class=\"component-studio\" [class.resizing]=\"IsResizing\">\n\n <!-- ============================================================\n TOOLBAR \u2014 Unified bar with integrated breadcrumb\n Left: hamburger + breadcrumb context\n Right: Save | Export | divider | AI | Keyboard | Refresh\n ============================================================ -->\n <div class=\"studio-toolbar\">\n <div class=\"toolbar-context\">\n <!-- Toggle left panel -->\n <button class=\"tb-btn icon-only\" title=\"Toggle browser panel\" (click)=\"ToggleLeftPanel()\">\n <i class=\"fa-solid fa-bars\"></i>\n </button>\n\n @if (state.SelectedComponent) {\n <span class=\"breadcrumb-type\">\n <i class=\"fa-solid fa-cube\"></i>\n {{ state.GetComponentType(state.SelectedComponent) || 'Component' }}\n </span>\n <span class=\"breadcrumb-sep\"><i class=\"fa-solid fa-chevron-right\"></i></span>\n <span class=\"component-label\">{{ state.GetComponentName(state.SelectedComponent) }}</span>\n\n @if (state.IsRunning) {\n <span class=\"running-badge\">\n <span class=\"running-dot-small\"></span>\n Running\n </span>\n }\n @if (state.HasUnsavedChanges) {\n <span class=\"unsaved-dot\" title=\"Unsaved changes\"></span>\n }\n }\n </div>\n\n <div class=\"toolbar-spacer\"></div>\n\n <div class=\"toolbar-actions\">\n <!-- Save Version -->\n @if (state.SelectedComponent) {\n <button class=\"tb-btn primary\" (click)=\"SaveVersion()\" title=\"Save version (Ctrl+S)\">\n <i class=\"fa-solid fa-save\"></i> Save\n </button>\n }\n\n <!-- Refresh Component -->\n @if (state.SelectedComponent && state.IsRunning) {\n <button class=\"tb-btn\" (click)=\"RefreshComponent()\" title=\"Refresh component\">\n <i class=\"fa-solid fa-arrows-rotate\"></i> Refresh\n </button>\n }\n\n <!-- Export -->\n @if (state.SelectedComponent && state.IsRunning) {\n <div class=\"header-dropdown\" [class.open]=\"exportDropdownOpen\">\n <button class=\"tb-btn\" (click)=\"ToggleExportDropdown()\">\n <i class=\"fa-solid fa-file-export\"></i> Export\n <i class=\"fa-solid fa-chevron-down dropdown-icon\"></i>\n </button>\n @if (exportDropdownOpen) {\n <div class=\"dropdown-menu\">\n <button class=\"dropdown-item\" (click)=\"ExportToArtifact()\">\n <i class=\"fa-solid fa-save\"></i> To Artifact\n </button>\n <button class=\"dropdown-item\" (click)=\"ExportToFile()\">\n <i class=\"fa-solid fa-file\"></i> To File\n </button>\n <button class=\"dropdown-item\" (click)=\"ExportToClipboard()\">\n <i class=\"fa-solid fa-clipboard\"></i> To Clipboard\n </button>\n </div>\n }\n </div>\n }\n\n <span class=\"toolbar-divider\"></span>\n\n <!-- AI Panel Toggle -->\n <button class=\"tb-btn icon-only\" [class.active-toggle]=\"!state.IsAIPanelCollapsed\"\n (click)=\"ToggleAIPanel()\"\n [title]=\"state.IsAIPanelCollapsed ? 'Show AI Assistant' : 'Hide AI Assistant'\">\n <i class=\"fa-solid fa-robot\"></i>\n </button>\n\n <!-- Keyboard Shortcuts -->\n <button class=\"tb-btn icon-only\" (click)=\"ShowKeyboardShortcuts = !ShowKeyboardShortcuts\"\n title=\"Keyboard shortcuts (?)\">\n <i class=\"fa-solid fa-keyboard\"></i>\n </button>\n\n <!-- Refresh -->\n <button class=\"tb-btn icon-only\" (click)=\"RefreshData()\" [disabled]=\"state.IsLoading\" title=\"Refresh data\">\n <i class=\"fa-solid fa-arrows-rotate\"></i>\n </button>\n </div>\n\n <!-- Hidden file input -->\n <input #fileInput type=\"file\" accept=\".json\" (change)=\"HandleFileSelect($event)\" style=\"display: none;\" />\n </div>\n\n <!-- ============================================================\n THREE-PANEL BODY\n ============================================================ -->\n <div class=\"studio-body\">\n\n <!-- Left Panel: Component Browser (collapsible) -->\n @if (!IsLeftPanelCollapsed) {\n <div class=\"panel panel-left\" [style.width.px]=\"leftPanelWidth\">\n <mj-component-browser\n (NewComponent)=\"OnNewComponent()\"\n (ImportFromFile)=\"ImportFromFile()\"\n (ImportFromText)=\"ImportFromText()\"\n (ImportFromArtifact)=\"ImportFromArtifact()\">\n </mj-component-browser>\n </div>\n\n <!-- Resize Handle: Left <-> Center -->\n <div class=\"resize-handle\" (mousedown)=\"OnLeftResizeStart($event)\"></div>\n }\n\n <!-- Center Panel: Workspace (side-by-side: Preview LEFT, Editor RIGHT) -->\n <div class=\"panel panel-center\">\n @if (state.SelectedComponent) {\n <!-- Preview (left side) -->\n <div class=\"workspace-preview\" [class.full-width]=\"IsEditorPanelCollapsed\" [style.flex]=\"IsEditorPanelCollapsed ? '1 1 100%' : previewFlex\">\n <div class=\"preview-sub-header\">\n <div class=\"preview-sub-left\">\n <i class=\"fa-solid fa-eye\"></i>\n <span>Preview</span>\n </div>\n <div class=\"preview-sub-right\">\n <!-- Toggle editor panel -->\n <button class=\"toggle-editors-btn\" [class.active]=\"!IsEditorPanelCollapsed\"\n (click)=\"ToggleEditorPanel()\" title=\"Toggle editor panel\">\n <i class=\"fa-solid fa-columns\"></i>\n </button>\n </div>\n </div>\n <div class=\"preview-body\">\n <mj-component-preview\n (AskAIToFix)=\"OnAskAIToFix($event)\">\n </mj-component-preview>\n </div>\n </div>\n\n <!-- Resize Handle: Preview <-> Editor (obvious center divider) -->\n @if (!IsEditorPanelCollapsed) {\n <div class=\"resize-handle center-divider\" (mousedown)=\"OnCenterResizeStart($event)\">\n <div class=\"divider-grip\"></div>\n </div>\n }\n\n <!-- Editor Tabs (right side, collapsible) -->\n @if (!IsEditorPanelCollapsed) {\n <div class=\"workspace-editors\" [style.flex]=\"editorFlex\">\n <mj-editor-tabs></mj-editor-tabs>\n </div>\n }\n } @else {\n <!-- Enhanced Empty State -->\n <div class=\"empty-state\">\n <div class=\"empty-state-content\">\n <div class=\"empty-state-icon\">\n <i class=\"fa-solid fa-rocket\"></i>\n </div>\n <h2>Ready to Build</h2>\n <p>Select a component from the browser or create a new one to get started</p>\n <div class=\"empty-state-actions\">\n <button mjButton variant=\"primary\" (click)=\"OnNewComponent()\">\n <span class=\"fa-solid fa-plus\"></span> New Component\n </button>\n <button mjButton (click)=\"ImportFromFile()\">\n <span class=\"fa-solid fa-file-import\"></span> Import\n </button>\n </div>\n <div class=\"quick-start-templates\">\n <span class=\"quick-start-label\">Quick start:</span>\n <button class=\"quick-start-btn\" (click)=\"OnQuickStart('dashboard')\">\n <i class=\"fa-solid fa-chart-line\"></i> Dashboard\n </button>\n <button class=\"quick-start-btn\" (click)=\"OnQuickStart('report')\">\n <i class=\"fa-solid fa-file-alt\"></i> Report\n </button>\n <button class=\"quick-start-btn\" (click)=\"OnQuickStart('chart')\">\n <i class=\"fa-solid fa-chart-pie\"></i> Chart\n </button>\n <button class=\"quick-start-btn\" (click)=\"OnQuickStart('form')\">\n <i class=\"fa-solid fa-edit\"></i> Form\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Right panel \u2014 only renders when the user has actively selected a\n component (form palette OR AI assistant). Showing an empty chat\n against no component is more noise than help, so we collapse the\n whole pane in that case. The collapse-button state is still\n honored: user can also explicitly hide. -->\n @if (!state.IsAIPanelCollapsed && state.SelectedComponent) {\n <!-- Resize Handle: Center <-> Right -->\n <div class=\"resize-handle\" (mousedown)=\"OnRightResizeStart($event)\"></div>\n <div class=\"panel panel-right\" [style.width.px]=\"rightPanelWidth\">\n @if (IsFormRoleComponent) {\n <mj-form-builder-right-panel\n [Schema]=\"state.FormSchema\"\n [Canvas]=\"state.FormCanvas\"\n [SelectedElementId]=\"state.FormSelectedElementId\"\n [SelectedSectionId]=\"state.FormSelectedSectionId\"\n (ElementChanged)=\"OnFormBuilderElementChanged($event)\"\n (SectionChanged)=\"OnFormBuilderSectionChanged($event)\"\n (ElementDeleted)=\"OnFormBuilderElementDeleted($event)\"\n (SectionDeleted)=\"OnFormBuilderSectionDeleted($event)\"\n (FieldAdded)=\"OnFormBuilderFieldAdded($event)\">\n </mj-form-builder-right-panel>\n } @else {\n <mj-ai-assistant-panel></mj-ai-assistant-panel>\n }\n </div>\n }\n </div>\n\n <!-- ============================================================\n STATUS BAR\n ============================================================ -->\n <div class=\"status-bar\">\n <div class=\"status-left\">\n <span class=\"status-item\">\n <i class=\"fa-solid fa-cube\"></i>\n {{ state.FilteredComponents.length }} component{{ state.FilteredComponents.length !== 1 ? 's' : '' }}\n </span>\n </div>\n <div class=\"status-right\">\n @if (LastSavedTime) {\n <span class=\"status-item\">\n <i class=\"fa-solid fa-check-circle\"></i>\n Saved {{ LastSavedTime | date:'shortTime' }}\n </span>\n }\n <span class=\"status-item shortcut-hint\">\n <kbd>?</kbd> Shortcuts\n </span>\n </div>\n </div>\n\n <!-- ============================================================\n KEYBOARD SHORTCUTS OVERLAY\n ============================================================ -->\n @if (ShowKeyboardShortcuts) {\n <div class=\"shortcuts-overlay\" (click)=\"ShowKeyboardShortcuts = false\">\n <div class=\"shortcuts-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"shortcuts-header\">\n <h3>Keyboard Shortcuts</h3>\n <button class=\"shortcuts-close\" (click)=\"ShowKeyboardShortcuts = false\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <div class=\"shortcuts-body\">\n <div class=\"shortcut-group\">\n <h4>General</h4>\n <div class=\"shortcut-row\">\n <span class=\"shortcut-keys\"><kbd>Ctrl</kbd> + <kbd>S</kbd></span>\n <span class=\"shortcut-desc\">Save version</span>\n </div>\n <div class=\"shortcut-row\">\n <span class=\"shortcut-keys\"><kbd>Ctrl</kbd> + <kbd>N</kbd></span>\n <span class=\"shortcut-desc\">New component</span>\n </div>\n <div class=\"shortcut-row\">\n <span class=\"shortcut-keys\"><kbd>?</kbd></span>\n <span class=\"shortcut-desc\">Toggle shortcuts</span>\n </div>\n <div class=\"shortcut-row\">\n <span class=\"shortcut-keys\"><kbd>Esc</kbd></span>\n <span class=\"shortcut-desc\">Close overlay</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- ============================================================\n NEW COMPONENT DIALOG\n ============================================================ -->\n @if (ShowNewComponentDialog) {\n <mj-new-component-dialog\n [Visible]=\"ShowNewComponentDialog\"\n (Close)=\"OnNewComponentDialogClose($event)\">\n </mj-new-component-dialog>\n }\n\n @if (ShowSaveVersionDialog) {\n <mj-save-version-dialog\n [Visible]=\"ShowSaveVersionDialog\"\n [CurrentVersion]=\"versionService.CurrentVersionNumber\"\n (Save)=\"OnSaveVersionConfirm($event)\"\n (Cancel)=\"ShowSaveVersionDialog = false\">\n </mj-save-version-dialog>\n }\n\n <!-- Post-save Override dialog for form-role Components. Fires after a\n successful version save when the spec declares componentRole='form'\n and the user has picked a target entity in the Field Binding inspector. -->\n <mj-form-override-dialog\n [Visible]=\"ShowFormOverrideDialog\"\n [ComponentName]=\"PendingOverrideComponentName\"\n [EntityName]=\"PendingOverrideEntityName\"\n (confirmed)=\"OnFormOverrideDialogConfirm($event)\"\n (dismissed)=\"OnFormOverrideDialogDismiss()\">\n </mj-form-override-dialog>\n\n <!-- Text Import Dialog -->\n @if (ShowTextImportDialog) {\n <mj-dialog [Visible]=\"true\" Title=\"Import Component from Text\" (Close)=\"OnTextImportCancel()\" [Width]=\"700\" [MinWidth]=\"500\">\n <app-text-import-dialog\n (importSpec)=\"OnTextImportSpec($event)\"\n (cancelDialog)=\"OnTextImportCancel()\">\n </app-text-import-dialog>\n </mj-dialog>\n }\n\n <!-- Artifact Load Dialog -->\n @if (ShowArtifactLoadDialog) {\n <app-artifact-load-dialog\n [Visible]=\"ShowArtifactLoadDialog\"\n (Close)=\"OnArtifactLoadClose($event)\">\n </app-artifact-load-dialog>\n }\n\n <!-- Artifact Selection Dialog -->\n @if (ShowArtifactSelectionDialog) {\n <app-artifact-selection-dialog\n [Visible]=\"ShowArtifactSelectionDialog\"\n (Close)=\"OnArtifactSelectionClose($event)\">\n </app-artifact-selection-dialog>\n }\n</div>\n", styles: [":host {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n.component-studio {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n/* ============================================================\n TOOLBAR \u2014 unified bar with integrated breadcrumb\n ============================================================ */\n\n.component-studio .studio-toolbar {\n display: flex;\n align-items: center;\n padding: 0 8px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n z-index: 10;\n min-height: 42px;\n gap: 8px;\n}\n\n/* Left: hamburger + breadcrumb context */\n.component-studio .toolbar-context {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex-shrink: 1;\n overflow: hidden;\n}\n\n.component-studio .toolbar-spacer {\n flex: 1;\n}\n\n/* Right: action buttons */\n.component-studio .toolbar-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-shrink: 0;\n}\n\n/* ---- Toolbar buttons ---- */\n.component-studio .tb-btn {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 5px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n line-height: 1;\n}\n\n.component-studio .tb-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-default);\n}\n\n.component-studio .tb-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.component-studio .tb-btn i {\n font-size: 12px;\n}\n\n.component-studio .tb-btn.icon-only {\n padding: 5px 7px;\n}\n\n.component-studio .tb-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.component-studio .tb-btn.primary:hover {\n opacity: 0.9;\n}\n\n.component-studio .tb-btn.active-toggle {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n/* ---- Breadcrumb elements inside toolbar ---- */\n.component-studio .breadcrumb-type {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}\n\n.component-studio .breadcrumb-type i {\n font-size: 11px;\n color: var(--mj-brand-primary);\n}\n\n.component-studio .breadcrumb-sep {\n font-size: 9px;\n color: var(--mj-border-default);\n}\n\n.component-studio .component-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 240px;\n}\n\n.component-studio .running-badge {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 2px 8px;\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n font-size: 11px;\n font-weight: 600;\n border-radius: 10px;\n white-space: nowrap;\n}\n\n.component-studio .running-dot-small {\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-success);\n animation: pulse 1.5s ease-in-out infinite;\n}\n\n.component-studio .unsaved-dot {\n display: inline-block;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n animation: pulse 2s infinite;\n flex-shrink: 0;\n}\n\n.component-studio .toolbar-divider {\n width: 1px;\n height: 18px;\n background: var(--mj-border-default);\n margin: 0 2px;\n flex-shrink: 0;\n}\n\n.component-studio .dropdown-icon {\n font-size: 9px;\n opacity: 0.6;\n}\n\n/* ---- Dropdown menus ---- */\n.component-studio .header-dropdown {\n position: relative;\n}\n\n.component-studio .header-dropdown .dropdown-menu {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 100;\n min-width: 180px;\n overflow: hidden;\n}\n\n.component-studio .header-dropdown .dropdown-menu .dropdown-item {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 16px;\n border: none;\n background: none;\n text-align: left;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: background 0.15s ease;\n}\n\n.component-studio .header-dropdown .dropdown-menu .dropdown-item:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.component-studio .header-dropdown .dropdown-menu .dropdown-item:not(:last-child) {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.component-studio .header-dropdown .dropdown-menu .dropdown-item i {\n width: 16px;\n text-align: center;\n color: var(--mj-brand-primary);\n font-size: 13px;\n}\n\n/* ============================================================\n THREE-PANEL BODY\n ============================================================ */\n\n.component-studio .studio-body {\n display: flex;\n flex: 1;\n overflow: hidden;\n}\n\n.component-studio .panel {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--mj-bg-surface);\n}\n\n.component-studio .panel-left {\n flex-shrink: 0;\n border-right: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n.component-studio .panel-center {\n flex: 1;\n display: flex;\n flex-direction: row;\n min-width: 400px;\n}\n\n/* Preview pane (left side of center) */\n.component-studio .panel-center .workspace-preview {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n border-right: 1px solid var(--mj-border-default);\n}\n\n.component-studio .panel-center .workspace-preview.full-width {\n border-right: none;\n}\n\n/* Preview sub-header */\n.component-studio .preview-sub-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 10px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n min-height: 32px;\n}\n\n.component-studio .preview-sub-left {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.component-studio .preview-sub-left i {\n font-size: 11px;\n color: var(--mj-brand-primary);\n}\n\n.component-studio .preview-sub-right {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.component-studio .toggle-editors-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 12px;\n transition: all 0.15s ease;\n}\n\n.component-studio .toggle-editors-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.component-studio .toggle-editors-btn.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.component-studio .preview-body {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n/* Editor pane (right side of center) */\n.component-studio .panel-center .workspace-editors {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n/* Right panel: AI Assistant */\n.component-studio .panel-right {\n flex-shrink: 0;\n border-left: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n/* ============================================================\n RESIZE HANDLES\n ============================================================ */\n\n.component-studio .resize-handle {\n flex-shrink: 0;\n width: 5px;\n cursor: col-resize;\n background: transparent;\n position: relative;\n z-index: 5;\n transition: background 0.15s ease;\n}\n\n.component-studio .resize-handle:hover,\n.component-studio .resize-handle:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n}\n\n/* Center divider \u2014 more obvious separator between preview and editors */\n.component-studio .resize-handle.center-divider {\n width: 7px;\n background: var(--mj-border-default);\n}\n\n.component-studio .resize-handle.center-divider:hover,\n.component-studio .resize-handle.center-divider:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n.component-studio .resize-handle .divider-grip {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 3px;\n height: 32px;\n border-radius: 2px;\n background: var(--mj-text-secondary);\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.component-studio .resize-handle:hover .divider-grip {\n opacity: 0.5;\n}\n\n/* SMOOTH RESIZE TRANSITIONS */\n.component-studio:not(.resizing) .panel {\n transition: width 0.15s ease, flex 0.15s ease;\n}\n\n.component-studio:not(.resizing) .workspace-preview,\n.component-studio:not(.resizing) .workspace-editors {\n transition: flex 0.15s ease;\n}\n\n/* ============================================================\n STATUS BAR\n ============================================================ */\n\n.component-studio .status-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 2px 16px;\n background: var(--mj-bg-surface-sunken);\n border-top: 1px solid var(--mj-border-default);\n font-size: 11px;\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n min-height: 24px;\n}\n\n.component-studio .status-bar .status-left {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.component-studio .status-bar .status-right {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.component-studio .status-bar .status-item {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.component-studio .status-bar kbd {\n display: inline-block;\n padding: 0 4px;\n font-size: 10px;\n font-family: inherit;\n line-height: 16px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 3px;\n}\n\n.component-studio .status-bar .shortcut-hint {\n display: flex;\n align-items: center;\n gap: 4px;\n opacity: 0.8;\n}\n\n/* ============================================================\n KEYBOARD SHORTCUTS OVERLAY\n ============================================================ */\n\n.component-studio .shortcuts-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n box-shadow: var(--mj-shadow-lg);\n width: 520px;\n max-height: 80vh;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-header button {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 16px;\n padding: 4px;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-header button:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-body {\n padding: 16px 20px;\n overflow-y: auto;\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-body .shortcut-group h4 {\n margin: 0 0 8px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-body .shortcut-group + .shortcut-group {\n margin-top: 16px;\n padding-top: 16px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-body .shortcut-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 0;\n font-size: 13px;\n color: var(--mj-text-primary);\n}\n\n.component-studio .shortcuts-overlay .shortcuts-panel .shortcuts-body .shortcut-row kbd {\n display: inline-block;\n padding: 2px 8px;\n font-size: 12px;\n font-family: inherit;\n line-height: 20px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n box-shadow: 0 1px 0 var(--mj-border-default);\n min-width: 24px;\n text-align: center;\n}\n\n/* ============================================================\n EMPTY STATE\n ============================================================ */\n\n.component-studio .empty-state {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface-sunken);\n}\n\n.component-studio .empty-state .empty-state-content {\n text-align: center;\n max-width: 400px;\n}\n\n.component-studio .empty-state .empty-state-content .empty-state-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 72px;\n height: 72px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n margin-bottom: 16px;\n}\n\n.component-studio .empty-state .empty-state-content .empty-state-icon i {\n font-size: 28px;\n color: var(--mj-brand-primary);\n}\n\n.component-studio .empty-state .empty-state-content i {\n color: var(--mj-border-default);\n margin-bottom: 16px;\n}\n\n.component-studio .empty-state .empty-state-content h2 {\n margin: 0 0 8px;\n font-size: 22px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.component-studio .empty-state .empty-state-content p {\n margin: 0 0 24px;\n color: var(--mj-text-secondary);\n font-size: 14px;\n line-height: 1.5;\n}\n\n.component-studio .empty-state .empty-state-content .empty-state-actions {\n display: flex;\n gap: 8px;\n justify-content: center;\n}\n\n.component-studio .empty-state .empty-state-content .quick-start-templates {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n flex-wrap: wrap;\n margin-top: 16px;\n}\n\n.component-studio .empty-state .empty-state-content .quick-start-templates .quick-start-label {\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-right: 4px;\n}\n\n.component-studio .empty-state .empty-state-content .quick-start-templates .quick-start-btn {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 4px 12px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.component-studio .empty-state .empty-state-content .quick-start-templates .quick-start-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-default);\n}\n\n.component-studio .empty-state .empty-state-content .quick-start-templates .quick-start-btn i {\n font-size: 11px;\n color: var(--mj-brand-primary);\n margin-bottom: 0;\n}\n\n@keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n}\n"] }]
|
|
1391
|
+
}], () => [{ type: i1.ComponentStudioStateService }, { type: i2.ComponentVersionService }, { type: i0.ChangeDetectorRef }, { type: i3.MJNotificationService }, { type: i4.EntityFormOverrideService }], { fileInput: [{
|
|
1007
1392
|
type: ViewChild,
|
|
1008
1393
|
args: ['fileInput', { static: false }]
|
|
1009
1394
|
}], OnKeyDown: [{
|
|
@@ -1013,5 +1398,5 @@ export { ComponentStudioDashboardComponent };
|
|
|
1013
1398
|
type: HostListener,
|
|
1014
1399
|
args: ['document:click', ['$event']]
|
|
1015
1400
|
}] }); })();
|
|
1016
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ComponentStudioDashboardComponent, { className: "ComponentStudioDashboardComponent", filePath: "src/ComponentStudio/component-studio-dashboard.component.ts", lineNumber:
|
|
1401
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ComponentStudioDashboardComponent, { className: "ComponentStudioDashboardComponent", filePath: "src/ComponentStudio/component-studio-dashboard.component.ts", lineNumber: 61 }); })();
|
|
1017
1402
|
//# sourceMappingURL=component-studio-dashboard.component.js.map
|