@memberjunction/ng-artifacts 5.9.0 → 5.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"data-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/data-artifact-viewer.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/data-artifact-viewer.component.ts"],"names":[],"mappings":"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"}
@@ -312,7 +312,7 @@ function DataArtifactViewerComponent_Conditional_4_Template(rf, ctx) { if (rf &
312
312
  i0.ɵɵelementEnd();
313
313
  } if (rf & 2) {
314
314
  const ctx_r0 = i0.ɵɵnextContext();
315
- i0.ɵɵproperty("QueryName", (ctx_r0.spec == null ? null : ctx_r0.spec.title) || "Untitled Query")("QueryDescription", "")("SQL", (ctx_r0.spec == null ? null : ctx_r0.spec.metadata == null ? null : ctx_r0.spec.metadata.sql) || "");
315
+ i0.ɵɵproperty("QueryName", (ctx_r0.spec == null ? null : ctx_r0.spec.title) || "Untitled Query")("QueryDescription", "")("SQL", (ctx_r0.spec == null ? null : ctx_r0.spec.metadata == null ? null : ctx_r0.spec.metadata.sql) || "")("Plan", (ctx_r0.spec == null ? null : ctx_r0.spec.plan) || "");
316
316
  } }
317
317
  /**
318
318
  * Viewer component for Data artifacts.
@@ -706,6 +706,9 @@ let DataArtifactViewerComponent = class DataArtifactViewerComponent extends Base
706
706
  return;
707
707
  }
708
708
  query.SQL = this.spec.metadata.sql;
709
+ if (this.spec.plan?.trim()) {
710
+ query.TechnicalDescription = this.spec.plan.trim();
711
+ }
709
712
  const saved = await query.Save();
710
713
  if (saved) {
711
714
  // Update spec with new version tracking
@@ -797,10 +800,10 @@ let DataArtifactViewerComponent = class DataArtifactViewerComponent extends Base
797
800
  return tabs;
798
801
  }
799
802
  static ɵfac = function DataArtifactViewerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DataArtifactViewerComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
800
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DataArtifactViewerComponent, selectors: [["mj-data-artifact-viewer"]], outputs: { openEntityRecord: "openEntityRecord", navigationRequest: "navigationRequest" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 3, consts: [[1, "data-artifact-viewer", 3, "ngClass"], [1, "error-state"], [1, "empty-state"], [3, "QueryName", "QueryDescription", "SQL"], [1, "data-toolbar"], [1, "data-title"], [1, "fas", "fa-table"], [1, "live-badge"], [1, "row-count"], [1, "exec-time"], [1, "data-actions"], ["title", "Refresh data", 1, "btn-icon", 3, "disabled"], ["title", "Save as reusable query", 1, "btn-icon", "btn-save"], [1, "grid-container"], [1, "saving-overlay"], ["text", "Loading data..."], ["Height", "100%", 3, "ColumnConfigs", "Data", "ShowToolbar", "ShowRefresh", "PersistState", "SelectionMode"], ["title", "Refresh data", 1, "btn-icon", 3, "click", "disabled"], [1, "fas", "fa-sync-alt"], ["title", "Save as reusable query", 1, "btn-icon", "btn-save", 3, "click"], [1, "fas", "fa-save"], [1, "query-badge", "query-badge-synced"], [1, "fas", "fa-check"], ["title", "Open saved query record", 1, "btn-icon", "btn-open", 3, "click"], [1, "fas", "fa-external-link-alt"], [1, "query-badge", "query-badge-outdated"], [1, "fas", "fa-circle-exclamation"], [1, "dropdown-wrapper"], ["title", "Update or save query", 1, "btn-icon", "btn-warning", 3, "click"], [1, "fas", "fa-caret-down"], [1, "query-dropdown"], [1, "query-dropdown", 3, "click"], [1, "query-dropdown-item", 3, "click"], [1, "fas", "fa-arrow-up-from-bracket", 2, "color", "#d97706"], [1, "dropdown-label"], [1, "dropdown-desc"], [1, "fas", "fa-plus", 2, "color", "#16a34a"], [1, "fas", "fa-external-link-alt", 2, "color", "#6c757d"], [1, "query-badge", "query-badge-muted"], [1, "fas", "fa-clock-rotate-left"], ["title", "Open saved query record", 1, "btn-icon", "btn-muted", 3, "click"], [3, "text"], [1, "error-banner"], [1, "fas", "fa-exclamation-triangle"], [1, "fallback-note"], ["Height", "100%", 3, "EntityLinkClick", "ColumnConfigs", "Data", "ShowToolbar", "ShowRefresh", "PersistState", "SelectionMode"], [1, "fas", "fa-diagram-project"], [1, "plan-content"], [3, "data", "enableMermaid", "enableHighlight", "enableCollapsibleHeadings", "enableSmartypants"], [1, "fas", "fa-inbox"], [3, "Saved", "Cancelled", "QueryName", "QueryDescription", "SQL"]], template: function DataArtifactViewerComponent_Template(rf, ctx) { if (rf & 1) {
803
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DataArtifactViewerComponent, selectors: [["mj-data-artifact-viewer"]], outputs: { openEntityRecord: "openEntityRecord", navigationRequest: "navigationRequest" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 3, consts: [[1, "data-artifact-viewer", 3, "ngClass"], [1, "error-state"], [1, "empty-state"], [3, "QueryName", "QueryDescription", "SQL", "Plan"], [1, "data-toolbar"], [1, "data-title"], [1, "fas", "fa-table"], [1, "live-badge"], [1, "row-count"], [1, "exec-time"], [1, "data-actions"], ["title", "Refresh data", 1, "btn-icon", 3, "disabled"], ["title", "Save as reusable query", 1, "btn-icon", "btn-save"], [1, "grid-container"], [1, "saving-overlay"], ["text", "Loading data..."], ["Height", "100%", 3, "ColumnConfigs", "Data", "ShowToolbar", "ShowRefresh", "PersistState", "SelectionMode"], ["title", "Refresh data", 1, "btn-icon", 3, "click", "disabled"], [1, "fas", "fa-sync-alt"], ["title", "Save as reusable query", 1, "btn-icon", "btn-save", 3, "click"], [1, "fas", "fa-save"], [1, "query-badge", "query-badge-synced"], [1, "fas", "fa-check"], ["title", "Open saved query record", 1, "btn-icon", "btn-open", 3, "click"], [1, "fas", "fa-external-link-alt"], [1, "query-badge", "query-badge-outdated"], [1, "fas", "fa-circle-exclamation"], [1, "dropdown-wrapper"], ["title", "Update or save query", 1, "btn-icon", "btn-warning", 3, "click"], [1, "fas", "fa-caret-down"], [1, "query-dropdown"], [1, "query-dropdown", 3, "click"], [1, "query-dropdown-item", 3, "click"], [1, "fas", "fa-arrow-up-from-bracket", 2, "color", "#d97706"], [1, "dropdown-label"], [1, "dropdown-desc"], [1, "fas", "fa-plus", 2, "color", "#16a34a"], [1, "fas", "fa-external-link-alt", 2, "color", "#6c757d"], [1, "query-badge", "query-badge-muted"], [1, "fas", "fa-clock-rotate-left"], ["title", "Open saved query record", 1, "btn-icon", "btn-muted", 3, "click"], [3, "text"], [1, "error-banner"], [1, "fas", "fa-exclamation-triangle"], [1, "fallback-note"], ["Height", "100%", 3, "EntityLinkClick", "ColumnConfigs", "Data", "ShowToolbar", "ShowRefresh", "PersistState", "SelectionMode"], [1, "fas", "fa-diagram-project"], [1, "plan-content"], [3, "data", "enableMermaid", "enableHighlight", "enableCollapsibleHeadings", "enableSmartypants"], [1, "fas", "fa-inbox"], [3, "Saved", "Cancelled", "QueryName", "QueryDescription", "SQL", "Plan"]], template: function DataArtifactViewerComponent_Template(rf, ctx) { if (rf & 1) {
801
804
  i0.ɵɵelementStart(0, "div", 0);
802
805
  i0.ɵɵconditionalCreate(1, DataArtifactViewerComponent_Conditional_1_Template, 3, 1)(2, DataArtifactViewerComponent_Conditional_2_Template, 4, 1, "div", 1)(3, DataArtifactViewerComponent_Conditional_3_Template, 4, 0, "div", 2);
803
- i0.ɵɵconditionalCreate(4, DataArtifactViewerComponent_Conditional_4_Template, 1, 3, "mj-save-query-panel", 3);
806
+ i0.ɵɵconditionalCreate(4, DataArtifactViewerComponent_Conditional_4_Template, 1, 4, "mj-save-query-panel", 3);
804
807
  i0.ɵɵelementEnd();
805
808
  } if (rf & 2) {
806
809
  i0.ɵɵproperty("ngClass", ctx.cssClass);
@@ -816,7 +819,7 @@ DataArtifactViewerComponent = __decorate([
816
819
  export { DataArtifactViewerComponent };
817
820
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DataArtifactViewerComponent, [{
818
821
  type: Component,
819
- args: [{ standalone: false, selector: 'mj-data-artifact-viewer', template: "<div class=\"data-artifact-viewer\" [ngClass]=\"cssClass\">\n @if (spec) {\n @if (HasData || IsLoading) {\n <!-- Toolbar -->\n <div class=\"data-toolbar\">\n <div class=\"data-title\">\n <i class=\"fas fa-table\"></i>\n <span>{{ spec.title || 'Data Results' }}</span>\n @if (IsLive) {\n <span class=\"live-badge\">Live</span>\n }\n @if (DisplayRowCount != null) {\n <span class=\"row-count\">{{ DisplayRowCount }} rows</span>\n }\n @if (DisplayExecutionTime != null) {\n <span class=\"exec-time\">{{ DisplayExecutionTime }}ms</span>\n }\n </div>\n <div class=\"data-actions\">\n @if (IsLive) {\n <button class=\"btn-icon\" title=\"Refresh data\" (click)=\"OnRefresh()\" [disabled]=\"IsLoading\">\n <i class=\"fas fa-sync-alt\" [class.fa-spin]=\"IsLoading\"></i> Refresh\n </button>\n }\n\n @switch (QuerySyncState) {\n <!-- S1: No saved query, latest version \u2192 Save Query -->\n @case ('no-query-latest') {\n <button class=\"btn-icon btn-save\" title=\"Save as reusable query\"\n (click)=\"OnShowSaveDialog()\">\n <i class=\"fas fa-save\"></i> Save Query\n </button>\n }\n\n <!-- S2: SQL matches \u2192 green badge + Open -->\n @case ('synced') {\n <span class=\"query-badge query-badge-synced\">\n <i class=\"fas fa-check\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-open\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S3: SQL differs, latest version \u2192 amber badge + dropdown -->\n @case ('outdated-latest') {\n <span class=\"query-badge query-badge-outdated\">\n <i class=\"fas fa-circle-exclamation\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <div class=\"dropdown-wrapper\">\n <button class=\"btn-icon btn-warning\" title=\"Update or save query\"\n (click)=\"OnToggleUpdateDropdown()\">\n <i class=\"fas fa-save\"></i> Update Query <i class=\"fas fa-caret-down\"></i>\n </button>\n @if (ShowUpdateDropdown) {\n <div class=\"query-dropdown\" (click)=\"$event.stopPropagation()\">\n <div class=\"query-dropdown-item\" (click)=\"OnUpdateExistingQuery()\">\n <i class=\"fas fa-arrow-up-from-bracket\" style=\"color:#d97706\"></i>\n <div>\n <div class=\"dropdown-label\">Update \"{{ SavedQueryDisplayName }}\"</div>\n <div class=\"dropdown-desc\">Replace saved query SQL with this version's SQL</div>\n </div>\n </div>\n <div class=\"query-dropdown-item\" (click)=\"OnSaveAsNewQuery()\">\n <i class=\"fas fa-plus\" style=\"color:#16a34a\"></i>\n <div>\n <div class=\"dropdown-label\">Save as New Query</div>\n <div class=\"dropdown-desc\">Create a new query, keep the original unchanged</div>\n </div>\n </div>\n <div class=\"query-dropdown-item\" (click)=\"OnOpenSavedQuery(); OnCloseDropdown()\">\n <i class=\"fas fa-external-link-alt\" style=\"color:#6c757d\"></i>\n <div>\n <div class=\"dropdown-label\">Open Saved Query</div>\n <div class=\"dropdown-desc\">View \"{{ SavedQueryDisplayName }}\" (saved at v{{ SavedAtVersion }})</div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- S4: Older version, query was updated ahead -->\n @case ('query-ahead') {\n <span class=\"query-badge query-badge-muted\">\n <i class=\"fas fa-clock-rotate-left\"></i> Query updated at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-muted\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S5: Middle version, saved at older, not latest -->\n @case ('query-behind') {\n <span class=\"query-badge query-badge-muted\">\n <i class=\"fas fa-clock-rotate-left\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-muted\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S6: No saved query, older version \u2192 no actions -->\n @case ('no-query-older') {\n <!-- No query actions available on older versions -->\n }\n }\n </div>\n </div>\n\n <!-- Grid -->\n <div class=\"grid-container\">\n <!-- Saving overlay -->\n @if (IsSaving) {\n <div class=\"saving-overlay\">\n <mj-loading [text]=\"SavingMessage\"></mj-loading>\n </div>\n }\n @if (IsLoading) {\n <mj-loading text=\"Loading data...\"></mj-loading>\n } @else if (HasError && HasData) {\n <div class=\"error-banner\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ ErrorMessage }}</span>\n <span class=\"fallback-note\">(Showing cached data)</span>\n </div>\n <mj-query-data-grid\n [ColumnConfigs]=\"GridColumnConfigs\"\n [Data]=\"GridData\"\n [ShowToolbar]=\"false\"\n [ShowRefresh]=\"false\"\n [PersistState]=\"false\"\n [SelectionMode]=\"'none'\"\n (EntityLinkClick)=\"OnEntityLinkClick($event)\"\n Height=\"100%\">\n </mj-query-data-grid>\n } @else if (HasError) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ ErrorMessage }}</p>\n </div>\n } @else {\n <mj-query-data-grid\n [ColumnConfigs]=\"GridColumnConfigs\"\n [Data]=\"GridData\"\n [ShowToolbar]=\"false\"\n [ShowRefresh]=\"false\"\n [PersistState]=\"false\"\n [SelectionMode]=\"'none'\"\n (EntityLinkClick)=\"OnEntityLinkClick($event)\"\n Height=\"100%\">\n </mj-query-data-grid>\n }\n </div>\n } @else if (spec.plan) {\n <!-- Plan-only view (no results yet) -->\n <div class=\"data-toolbar\">\n <div class=\"data-title\">\n <i class=\"fas fa-diagram-project\"></i>\n <span>{{ spec.title || 'Query Plan' }}</span>\n </div>\n </div>\n <div class=\"plan-content\">\n <mj-markdown\n [data]=\"spec.plan\"\n [enableMermaid]=\"true\"\n [enableHighlight]=\"true\"\n [enableCollapsibleHeadings]=\"false\"\n [enableSmartypants]=\"true\">\n </mj-markdown>\n </div>\n } @else {\n <!-- No data and no plan -->\n <div class=\"empty-state\">\n <i class=\"fas fa-inbox\"></i>\n <p>No data to display</p>\n </div>\n }\n } @else if (HasError) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ ErrorMessage }}</p>\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fas fa-inbox\"></i>\n <p>No data to display</p>\n </div>\n }\n\n <!-- Save Query Panel (slide-in) -->\n @if (ShowSaveDialog) {\n <mj-save-query-panel\n [QueryName]=\"spec?.title || 'Untitled Query'\"\n [QueryDescription]=\"''\"\n [SQL]=\"spec?.metadata?.sql || ''\"\n (Saved)=\"OnQuerySaved($event)\"\n (Cancelled)=\"ShowSaveDialog = false\">\n </mj-save-query-panel>\n }\n</div>\n", styles: [".data-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n.data-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n background: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\n}\n\n.data-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 13px;\n color: #333;\n}\n\n.data-title i {\n color: #6c757d;\n}\n\n.row-count {\n padding: 2px 8px;\n background: #e9ecef;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n color: #495057;\n}\n\n.exec-time {\n padding: 2px 8px;\n background: #d4edda;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n color: #155724;\n}\n\n.live-badge {\n padding: 2px 8px;\n background: #cce5ff;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n color: #004085;\n}\n\n.data-actions {\n display: flex;\n gap: 6px;\n}\n\n.btn-icon {\n padding: 4px 10px;\n background: white;\n border: 1px solid #ced4da;\n border-radius: 4px;\n cursor: pointer;\n font-size: 11px;\n display: flex;\n align-items: center;\n gap: 4px;\n color: #495057;\n}\n\n.btn-icon:hover {\n background: #e9ecef;\n border-color: #adb5bd;\n}\n\n.btn-icon:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-icon.btn-save {\n color: #16a34a;\n border-color: #86efac;\n}\n\n.btn-icon.btn-save:hover {\n background: #f0fdf4;\n border-color: #16a34a;\n}\n\n.btn-icon.btn-open {\n color: #2563eb;\n border-color: #93c5fd;\n}\n\n.btn-icon.btn-open:hover {\n background: #eff6ff;\n border-color: #2563eb;\n}\n\n.grid-container {\n flex: 1;\n overflow: hidden;\n min-height: 200px;\n height: 500px;\n position: relative;\n}\n\n/* Saving overlay \u2014 semi-transparent panel over the grid */\n.saving-overlay {\n position: absolute;\n inset: 0;\n background: rgba(255, 255, 255, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 50;\n}\n\n.error-banner {\n padding: 8px 12px;\n background: #fff3cd;\n border-bottom: 1px solid #ffc107;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: #856404;\n}\n\n.fallback-note {\n font-style: italic;\n color: #6c757d;\n}\n\n.empty-state, .error-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: #6c757d;\n text-align: center;\n gap: 12px;\n}\n\n.empty-state i, .error-state i {\n font-size: 32px;\n}\n\n.error-state {\n color: #dc3545;\n}\n\n.plan-content {\n flex: 1;\n overflow: auto;\n padding: 16px;\n}\n\n/* Query sync badges */\n.query-badge {\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n white-space: nowrap;\n}\n\n.query-badge-synced {\n background: #d1fae5;\n color: #065f46;\n}\n\n.query-badge-outdated {\n background: #fff3cd;\n color: #856404;\n}\n\n.query-badge-muted {\n background: #f3f4f6;\n color: #9ca3af;\n}\n\n/* Dropdown wrapper */\n.dropdown-wrapper {\n position: relative;\n}\n\n.btn-icon.btn-warning {\n color: #d97706;\n border-color: #fcd34d;\n}\n\n.btn-icon.btn-warning:hover {\n background: #fffbeb;\n border-color: #d97706;\n}\n\n.btn-icon.btn-muted {\n color: #9ca3af;\n border-color: #e5e7eb;\n}\n\n/* Query actions dropdown */\n.query-dropdown {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0,0,0,0.12);\n overflow: hidden;\n min-width: 280px;\n z-index: 100;\n}\n\n.query-dropdown-item {\n padding: 10px 14px;\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 12px;\n cursor: pointer;\n border-bottom: 1px solid #f0f0f0;\n transition: background 0.1s;\n}\n\n.query-dropdown-item:last-child {\n border-bottom: none;\n}\n\n.query-dropdown-item:hover {\n background: #f8f9fa;\n}\n\n.query-dropdown-item i {\n width: 16px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.dropdown-label {\n font-weight: 500;\n}\n\n.dropdown-desc {\n font-size: 11px;\n color: #6c757d;\n margin-top: 2px;\n}\n"] }]
822
+ args: [{ standalone: false, selector: 'mj-data-artifact-viewer', template: "<div class=\"data-artifact-viewer\" [ngClass]=\"cssClass\">\n @if (spec) {\n @if (HasData || IsLoading) {\n <!-- Toolbar -->\n <div class=\"data-toolbar\">\n <div class=\"data-title\">\n <i class=\"fas fa-table\"></i>\n <span>{{ spec.title || 'Data Results' }}</span>\n @if (IsLive) {\n <span class=\"live-badge\">Live</span>\n }\n @if (DisplayRowCount != null) {\n <span class=\"row-count\">{{ DisplayRowCount }} rows</span>\n }\n @if (DisplayExecutionTime != null) {\n <span class=\"exec-time\">{{ DisplayExecutionTime }}ms</span>\n }\n </div>\n <div class=\"data-actions\">\n @if (IsLive) {\n <button class=\"btn-icon\" title=\"Refresh data\" (click)=\"OnRefresh()\" [disabled]=\"IsLoading\">\n <i class=\"fas fa-sync-alt\" [class.fa-spin]=\"IsLoading\"></i> Refresh\n </button>\n }\n\n @switch (QuerySyncState) {\n <!-- S1: No saved query, latest version \u2192 Save Query -->\n @case ('no-query-latest') {\n <button class=\"btn-icon btn-save\" title=\"Save as reusable query\"\n (click)=\"OnShowSaveDialog()\">\n <i class=\"fas fa-save\"></i> Save Query\n </button>\n }\n\n <!-- S2: SQL matches \u2192 green badge + Open -->\n @case ('synced') {\n <span class=\"query-badge query-badge-synced\">\n <i class=\"fas fa-check\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-open\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S3: SQL differs, latest version \u2192 amber badge + dropdown -->\n @case ('outdated-latest') {\n <span class=\"query-badge query-badge-outdated\">\n <i class=\"fas fa-circle-exclamation\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <div class=\"dropdown-wrapper\">\n <button class=\"btn-icon btn-warning\" title=\"Update or save query\"\n (click)=\"OnToggleUpdateDropdown()\">\n <i class=\"fas fa-save\"></i> Update Query <i class=\"fas fa-caret-down\"></i>\n </button>\n @if (ShowUpdateDropdown) {\n <div class=\"query-dropdown\" (click)=\"$event.stopPropagation()\">\n <div class=\"query-dropdown-item\" (click)=\"OnUpdateExistingQuery()\">\n <i class=\"fas fa-arrow-up-from-bracket\" style=\"color:#d97706\"></i>\n <div>\n <div class=\"dropdown-label\">Update \"{{ SavedQueryDisplayName }}\"</div>\n <div class=\"dropdown-desc\">Replace saved query SQL with this version's SQL</div>\n </div>\n </div>\n <div class=\"query-dropdown-item\" (click)=\"OnSaveAsNewQuery()\">\n <i class=\"fas fa-plus\" style=\"color:#16a34a\"></i>\n <div>\n <div class=\"dropdown-label\">Save as New Query</div>\n <div class=\"dropdown-desc\">Create a new query, keep the original unchanged</div>\n </div>\n </div>\n <div class=\"query-dropdown-item\" (click)=\"OnOpenSavedQuery(); OnCloseDropdown()\">\n <i class=\"fas fa-external-link-alt\" style=\"color:#6c757d\"></i>\n <div>\n <div class=\"dropdown-label\">Open Saved Query</div>\n <div class=\"dropdown-desc\">View \"{{ SavedQueryDisplayName }}\" (saved at v{{ SavedAtVersion }})</div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- S4: Older version, query was updated ahead -->\n @case ('query-ahead') {\n <span class=\"query-badge query-badge-muted\">\n <i class=\"fas fa-clock-rotate-left\"></i> Query updated at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-muted\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S5: Middle version, saved at older, not latest -->\n @case ('query-behind') {\n <span class=\"query-badge query-badge-muted\">\n <i class=\"fas fa-clock-rotate-left\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-muted\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S6: No saved query, older version \u2192 no actions -->\n @case ('no-query-older') {\n <!-- No query actions available on older versions -->\n }\n }\n </div>\n </div>\n\n <!-- Grid -->\n <div class=\"grid-container\">\n <!-- Saving overlay -->\n @if (IsSaving) {\n <div class=\"saving-overlay\">\n <mj-loading [text]=\"SavingMessage\"></mj-loading>\n </div>\n }\n @if (IsLoading) {\n <mj-loading text=\"Loading data...\"></mj-loading>\n } @else if (HasError && HasData) {\n <div class=\"error-banner\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ ErrorMessage }}</span>\n <span class=\"fallback-note\">(Showing cached data)</span>\n </div>\n <mj-query-data-grid\n [ColumnConfigs]=\"GridColumnConfigs\"\n [Data]=\"GridData\"\n [ShowToolbar]=\"false\"\n [ShowRefresh]=\"false\"\n [PersistState]=\"false\"\n [SelectionMode]=\"'none'\"\n (EntityLinkClick)=\"OnEntityLinkClick($event)\"\n Height=\"100%\">\n </mj-query-data-grid>\n } @else if (HasError) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ ErrorMessage }}</p>\n </div>\n } @else {\n <mj-query-data-grid\n [ColumnConfigs]=\"GridColumnConfigs\"\n [Data]=\"GridData\"\n [ShowToolbar]=\"false\"\n [ShowRefresh]=\"false\"\n [PersistState]=\"false\"\n [SelectionMode]=\"'none'\"\n (EntityLinkClick)=\"OnEntityLinkClick($event)\"\n Height=\"100%\">\n </mj-query-data-grid>\n }\n </div>\n } @else if (spec.plan) {\n <!-- Plan-only view (no results yet) -->\n <div class=\"data-toolbar\">\n <div class=\"data-title\">\n <i class=\"fas fa-diagram-project\"></i>\n <span>{{ spec.title || 'Query Plan' }}</span>\n </div>\n </div>\n <div class=\"plan-content\">\n <mj-markdown\n [data]=\"spec.plan\"\n [enableMermaid]=\"true\"\n [enableHighlight]=\"true\"\n [enableCollapsibleHeadings]=\"false\"\n [enableSmartypants]=\"true\">\n </mj-markdown>\n </div>\n } @else {\n <!-- No data and no plan -->\n <div class=\"empty-state\">\n <i class=\"fas fa-inbox\"></i>\n <p>No data to display</p>\n </div>\n }\n } @else if (HasError) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ ErrorMessage }}</p>\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fas fa-inbox\"></i>\n <p>No data to display</p>\n </div>\n }\n\n <!-- Save Query Panel (slide-in) -->\n @if (ShowSaveDialog) {\n <mj-save-query-panel\n [QueryName]=\"spec?.title || 'Untitled Query'\"\n [QueryDescription]=\"''\"\n [SQL]=\"spec?.metadata?.sql || ''\"\n [Plan]=\"spec?.plan || ''\"\n (Saved)=\"OnQuerySaved($event)\"\n (Cancelled)=\"ShowSaveDialog = false\">\n </mj-save-query-panel>\n }\n</div>\n", styles: [".data-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n.data-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n background: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\n}\n\n.data-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 13px;\n color: #333;\n}\n\n.data-title i {\n color: #6c757d;\n}\n\n.row-count {\n padding: 2px 8px;\n background: #e9ecef;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n color: #495057;\n}\n\n.exec-time {\n padding: 2px 8px;\n background: #d4edda;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n color: #155724;\n}\n\n.live-badge {\n padding: 2px 8px;\n background: #cce5ff;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n color: #004085;\n}\n\n.data-actions {\n display: flex;\n gap: 6px;\n}\n\n.btn-icon {\n padding: 4px 10px;\n background: white;\n border: 1px solid #ced4da;\n border-radius: 4px;\n cursor: pointer;\n font-size: 11px;\n display: flex;\n align-items: center;\n gap: 4px;\n color: #495057;\n}\n\n.btn-icon:hover {\n background: #e9ecef;\n border-color: #adb5bd;\n}\n\n.btn-icon:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-icon.btn-save {\n color: #16a34a;\n border-color: #86efac;\n}\n\n.btn-icon.btn-save:hover {\n background: #f0fdf4;\n border-color: #16a34a;\n}\n\n.btn-icon.btn-open {\n color: #2563eb;\n border-color: #93c5fd;\n}\n\n.btn-icon.btn-open:hover {\n background: #eff6ff;\n border-color: #2563eb;\n}\n\n.grid-container {\n flex: 1;\n overflow: hidden;\n min-height: 200px;\n height: 500px;\n position: relative;\n}\n\n/* Saving overlay \u2014 semi-transparent panel over the grid */\n.saving-overlay {\n position: absolute;\n inset: 0;\n background: rgba(255, 255, 255, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 50;\n}\n\n.error-banner {\n padding: 8px 12px;\n background: #fff3cd;\n border-bottom: 1px solid #ffc107;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: #856404;\n}\n\n.fallback-note {\n font-style: italic;\n color: #6c757d;\n}\n\n.empty-state, .error-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: #6c757d;\n text-align: center;\n gap: 12px;\n}\n\n.empty-state i, .error-state i {\n font-size: 32px;\n}\n\n.error-state {\n color: #dc3545;\n}\n\n.plan-content {\n flex: 1;\n overflow: auto;\n padding: 16px;\n}\n\n/* Query sync badges */\n.query-badge {\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n white-space: nowrap;\n}\n\n.query-badge-synced {\n background: #d1fae5;\n color: #065f46;\n}\n\n.query-badge-outdated {\n background: #fff3cd;\n color: #856404;\n}\n\n.query-badge-muted {\n background: #f3f4f6;\n color: #9ca3af;\n}\n\n/* Dropdown wrapper */\n.dropdown-wrapper {\n position: relative;\n}\n\n.btn-icon.btn-warning {\n color: #d97706;\n border-color: #fcd34d;\n}\n\n.btn-icon.btn-warning:hover {\n background: #fffbeb;\n border-color: #d97706;\n}\n\n.btn-icon.btn-muted {\n color: #9ca3af;\n border-color: #e5e7eb;\n}\n\n/* Query actions dropdown */\n.query-dropdown {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0,0,0,0.12);\n overflow: hidden;\n min-width: 280px;\n z-index: 100;\n}\n\n.query-dropdown-item {\n padding: 10px 14px;\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 12px;\n cursor: pointer;\n border-bottom: 1px solid #f0f0f0;\n transition: background 0.1s;\n}\n\n.query-dropdown-item:last-child {\n border-bottom: none;\n}\n\n.query-dropdown-item:hover {\n background: #f8f9fa;\n}\n\n.query-dropdown-item i {\n width: 16px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.dropdown-label {\n font-weight: 500;\n}\n\n.dropdown-desc {\n font-size: 11px;\n color: #6c757d;\n margin-top: 2px;\n}\n"] }]
820
823
  }], () => [{ type: i0.ChangeDetectorRef }], { openEntityRecord: [{
821
824
  type: Output
822
825
  }], navigationRequest: [{
@@ -1 +1 @@
1
- {"version":3,"file":"data-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/data-artifact-viewer.component.ts","../../../../src/lib/components/plugins/data-artifact-viewer.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ChangeDetectorRef, Output, EventEmitter } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { Metadata, RunQuery, CompositeKey, KeyValuePair } from '@memberjunction/core';\nimport { QueryEngine, ArtifactMetadataEngine } from '@memberjunction/core-entities';\nimport { QueryGridColumnConfig, QueryEntityLinkClickEvent, resolveTargetEntity } from '@memberjunction/ng-query-viewer';\nimport { BaseArtifactViewerPluginComponent, ArtifactViewerTab, NavigationRequest } from '../base-artifact-viewer.component';\nimport { SaveQueryResult } from './save-query-dialog.component';\n\n/**\n * JSON schema for Data artifact content.\n * The agent produces this structure when emitting query/view results.\n */\ninterface DataArtifactSpec {\n /** Data source type */\n source: 'query' | 'view';\n\n /** Display title for the data */\n title?: string;\n\n /** For query source: the query ID to render via mj-query-viewer */\n queryId?: string;\n\n /** For query source: parameter values to pass */\n parameters?: Record<string, string | number | boolean>;\n\n /** For view source: the entity name */\n entityName?: string;\n\n /** For view source: extra WHERE filter */\n extraFilter?: string;\n\n /** Column definitions for inline data display */\n columns?: DataArtifactColumn[];\n\n /** Inline row data (when results are embedded directly) */\n rows?: Record<string, unknown>[];\n\n /** Optional markdown plan/approach description (mermaid diagrams, explanations) */\n plan?: string;\n\n /** Query metadata */\n metadata?: {\n sql?: string;\n rowCount?: number;\n executionTimeMs?: number;\n };\n\n /** ID of saved query (set after user saves from artifact) */\n savedQueryId?: string;\n\n /** Name of saved query (for display) */\n savedQueryName?: string;\n\n /** Version number this query was saved/updated from */\n savedAtVersionNumber?: number;\n}\n\ninterface DataArtifactColumn {\n field: string;\n headerName?: string;\n width?: number;\n\n /** MJ entity name this column originates from (e.g., \"Members\") */\n sourceEntity?: string;\n\n /** Field name in that entity (e.g., \"ID\", \"FirstName\") */\n sourceFieldName?: string;\n\n /** True for calculated expressions (CASE, ROUND, CONCAT, etc.) */\n isComputed?: boolean;\n\n /** True for aggregate functions (SUM, COUNT, AVG, etc.) */\n isSummary?: boolean;\n\n /** SQL data type: int, nvarchar, uniqueidentifier, datetime, decimal, bit, money, etc. */\n sqlBaseType?: string;\n}\n\n/**\n * Describes the relationship between the current artifact version's SQL\n * and the saved query record. Drives the toolbar UI.\n */\ntype QuerySyncState =\n | 'no-query-latest' // No saved query, viewing latest version → show \"Save Query\"\n | 'no-query-older' // No saved query, viewing older version → no actions\n | 'synced' // SQL matches saved query → green badge + \"Open Query\"\n | 'outdated-latest' // SQL differs, viewing latest → amber badge + dropdown\n | 'query-ahead' // Viewing older version, query was updated at a newer version\n | 'query-behind'; // Viewing middle version, saved at older, not latest → muted\n\n/**\n * Viewer component for Data artifacts.\n *\n * Displays tabular data using AG Grid via mj-query-data-grid. Supports two modes:\n * 1. **Live data**: When metadata.sql is present, executes the query dynamically via RunQuery({ SQL })\n * to fetch fresh data on each view. Falls back to inline rows on error.\n * 2. **Inline data**: Rows embedded directly in the artifact JSON (backward compat with older artifacts)\n *\n * The Query Builder agent emits artifacts with metadata.sql for live execution.\n */\n@Component({\n standalone: false,\n selector: 'mj-data-artifact-viewer',\n templateUrl: './data-artifact-viewer.component.html',\n styleUrls: ['./data-artifact-viewer.component.css']\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'DataArtifactViewerPlugin')\nexport class DataArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit {\n @Output() openEntityRecord = new EventEmitter<{entityName: string; compositeKey: CompositeKey}>();\n @Output() override navigationRequest = new EventEmitter<NavigationRequest>();\n public override tabsChanged = new EventEmitter<void>();\n\n public spec: DataArtifactSpec | null = null;\n public GridData: Record<string, unknown>[] = [];\n public GridColumnConfigs: QueryGridColumnConfig[] | null = null;\n public IsLoading = false;\n public IsLive = false;\n public HasError = false;\n public ErrorMessage = '';\n public ShowSaveDialog = false;\n public ShowUpdateDropdown = false;\n public IsSaving = false;\n public SavingMessage = '';\n\n /** Query sync state — drives the toolbar UI for saved query actions */\n public QuerySyncState: QuerySyncState = 'no-query-latest';\n\n /** Latest version number for this artifact (from cache) */\n public LatestVersionNumber = 0;\n\n /** Metadata from live execution (overrides spec.metadata when live) */\n private liveRowCount: number | null = null;\n private liveExecutionTime: number | null = null;\n\n /** SQL from the saved query record (for comparison) */\n private savedQuerySql: string | null = null;\n\n constructor(private cdr: ChangeDetectorRef) {\n super();\n }\n\n public override get hasDisplayContent(): boolean {\n return this.spec != null && (this.HasData || this.IsLoading);\n }\n\n public override get parentShouldShowRawContent(): boolean {\n return true;\n }\n\n public get HasData(): boolean {\n return this.GridData.length > 0;\n }\n\n public get HasInlineData(): boolean {\n return !!(this.spec?.rows && this.spec.rows.length > 0);\n }\n\n public get DisplayRowCount(): number | null {\n return this.liveRowCount ?? this.spec?.metadata?.rowCount ?? null;\n }\n\n public get DisplayExecutionTime(): number | null {\n return this.liveExecutionTime ?? this.spec?.metadata?.executionTimeMs ?? null;\n }\n\n /** Current artifact version number */\n public get CurrentVersionNumber(): number {\n return this.artifactVersion?.VersionNumber || 1;\n }\n\n /** Whether this is the latest version of the artifact */\n public get IsLatestVersion(): boolean {\n return this.CurrentVersionNumber === this.LatestVersionNumber;\n }\n\n /**\n * The effective version number at which the query was last saved/updated.\n * When viewing an older version, this looks ahead through newer versions\n * to find the most recent savedAtVersionNumber for the same query,\n * giving the user accurate context (e.g., \"Query updated at v3\" instead\n * of the stale \"Saved at v1\" from this version's snapshot).\n */\n public EffectiveSavedAtVersion: number | null = null;\n\n /** Alias used by the template */\n public get SavedAtVersion(): number | null {\n return this.EffectiveSavedAtVersion;\n }\n\n /** Display name for the saved query */\n public get SavedQueryDisplayName(): string {\n return this.spec?.savedQueryName || 'Saved Query';\n }\n\n async ngOnInit(): Promise<void> {\n try {\n this.spec = this.parseJsonContent<DataArtifactSpec>();\n if (!this.spec) {\n this.HasError = true;\n this.ErrorMessage = 'Failed to parse data artifact content';\n return;\n }\n\n // Build enriched column configs from agent metadata (if available)\n this.GridColumnConfigs = this.BuildColumnConfigs();\n\n // Set loading early (synchronously) so hasDisplayContent is true immediately.\n // This ensures the Display tab is available when onPluginLoaded fires,\n // showing a loading indicator instead of briefly flashing the Plan tab.\n if (this.spec.metadata?.sql || this.HasInlineData) {\n this.IsLoading = true;\n }\n\n // Load cached metadata and resolve query sync state\n await this.InitQuerySyncState();\n\n // If SQL is available, execute it live\n if (this.spec.metadata?.sql) {\n await this.LoadLiveData();\n } else if (this.HasInlineData) {\n // Fall back to embedded rows\n this.GridData = this.spec.rows!;\n this.IsLoading = false;\n }\n\n // Signal parent that tabs/display content may have changed after async load\n this.tabsChanged.emit();\n } catch (error) {\n this.HasError = true;\n this.ErrorMessage = error instanceof Error ? error.message : 'Failed to load data';\n }\n }\n\n /**\n * Re-execute the live SQL query\n */\n public async OnRefresh(): Promise<void> {\n if (this.spec?.metadata?.sql) {\n await this.LoadLiveData();\n }\n }\n\n /**\n * Handle entity link click from the grid and bubble up as openEntityRecord.\n * Converts the grid's recordId string into a CompositeKey for the artifact viewer pipeline.\n */\n public OnEntityLinkClick(event: QueryEntityLinkClickEvent): void {\n const compositeKey = new CompositeKey([\n new KeyValuePair('ID', event.recordId)\n ]);\n this.openEntityRecord.emit({\n entityName: event.entityName,\n compositeKey\n });\n }\n\n /**\n * Execute the SQL query via RunQuery and populate the grid.\n * Falls back to inline data on error.\n */\n private async LoadLiveData(): Promise<void> {\n this.IsLoading = true;\n this.HasError = false;\n this.cdr.detectChanges();\n\n try {\n const rq = new RunQuery();\n const result = await rq.RunQuery({ SQL: this.spec!.metadata!.sql! });\n\n if (result.Success) {\n this.GridData = result.Results;\n this.liveRowCount = result.RowCount;\n this.liveExecutionTime = result.ExecutionTime;\n this.IsLive = true;\n } else {\n this.HandleQueryError(result.ErrorMessage || 'Query execution failed');\n }\n } catch (error) {\n this.HandleQueryError(error instanceof Error ? error.message : 'Query execution failed');\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Build QueryGridColumnConfig[] from enriched artifact column metadata.\n * Returns null if columns have no entity metadata (grid falls back to auto-inference).\n */\n private BuildColumnConfigs(): QueryGridColumnConfig[] | null {\n if (!this.spec?.columns?.length) return null;\n\n // Only build if at least one column has entity metadata or type info\n const hasMetadata = this.spec.columns.some(c => c.sourceEntity || c.sqlBaseType);\n if (!hasMetadata) return null;\n\n const md = new Metadata();\n return this.spec.columns.map((col, index) => {\n const target = resolveTargetEntity(col.sourceEntity, col.sourceFieldName, md);\n const isEntityLink = !!(target.targetEntityName && (target.isPrimaryKey || target.isForeignKey));\n const baseType = (col.sqlBaseType || 'nvarchar').toLowerCase();\n\n let align: 'left' | 'center' | 'right' = 'left';\n if (['int', 'bigint', 'decimal', 'numeric', 'float', 'money', 'smallmoney', 'real'].includes(baseType)) {\n align = 'right';\n } else if (baseType === 'bit') {\n align = 'center';\n }\n\n return {\n field: col.field,\n title: col.headerName || col.field,\n visible: true,\n sortable: true,\n resizable: true,\n reorderable: true,\n sqlBaseType: col.sqlBaseType || 'nvarchar',\n sqlFullType: col.sqlBaseType || 'nvarchar',\n align,\n order: index,\n sourceEntityName: col.sourceEntity,\n sourceFieldName: col.sourceFieldName,\n isEntityLink,\n targetEntityName: target.targetEntityName,\n targetEntityId: target.targetEntityId,\n targetEntityIcon: target.targetEntityIcon,\n isPrimaryKey: target.isPrimaryKey,\n isForeignKey: target.isForeignKey,\n pinned: null,\n } as QueryGridColumnConfig;\n });\n }\n\n /**\n * Handle a query error by setting error state and falling back to inline data\n */\n private HandleQueryError(message: string): void {\n this.HasError = true;\n this.ErrorMessage = message;\n if (this.HasInlineData) {\n this.GridData = this.spec!.rows!;\n }\n }\n\n // ─── Query Sync State ────────────────────────────────────────────\n\n /**\n * Initialize query sync state by loading cached metadata.\n * Resolves the latest version number and compares saved query SQL.\n */\n private async InitQuerySyncState(): Promise<void> {\n // Ensure artifact cache is loaded (not registered for startup)\n await ArtifactMetadataEngine.Instance.Config(false);\n\n this.LatestVersionNumber = this.resolveLatestVersionNumber();\n\n // If cache is stale (doesn't know about the version we're viewing),\n // force-refresh and re-resolve. This happens when new versions are\n // created during a conversation after the cache was first loaded.\n if (this.LatestVersionNumber < this.CurrentVersionNumber) {\n await ArtifactMetadataEngine.Instance.Config(true);\n this.LatestVersionNumber = this.resolveLatestVersionNumber();\n }\n\n this.EffectiveSavedAtVersion = this.resolveEffectiveSavedAtVersion();\n await this.resolveSavedQuerySql();\n this.QuerySyncState = this.computeQuerySyncState();\n }\n\n /**\n * Determine the latest version number for this artifact from cache.\n * Falls back to current version if cache miss.\n */\n private resolveLatestVersionNumber(): number {\n if (!this.artifactVersion?.ArtifactID) {\n return this.CurrentVersionNumber;\n }\n\n const versions = ArtifactMetadataEngine.Instance.GetVersionsForArtifact(this.artifactVersion.ArtifactID);\n if (versions.length > 0) {\n // GetVersionsForArtifact returns DESC sorted\n return versions[0].VersionNumber || 1;\n }\n\n // Cache miss — current version is our best guess\n return this.CurrentVersionNumber;\n }\n\n /**\n * Scan all versions of this artifact to find the most recent savedAtVersionNumber\n * for the same savedQueryId. When viewing an older version, this tells the user\n * where the query was *actually* last updated, not just what this version's\n * snapshot recorded at the time.\n */\n private resolveEffectiveSavedAtVersion(): number | null {\n const queryId = this.spec?.savedQueryId;\n if (!queryId) return null;\n\n // Start with this version's own value\n let effective = this.spec?.savedAtVersionNumber ?? null;\n\n if (!this.artifactVersion?.ArtifactID) return effective;\n\n // GetVersionsForArtifact returns DESC sorted — scan all versions\n const versions = ArtifactMetadataEngine.Instance.GetVersionsForArtifact(this.artifactVersion.ArtifactID);\n for (const v of versions) {\n try {\n if (!v.Content) continue;\n const content = typeof v.Content === 'string' ? JSON.parse(v.Content) : v.Content;\n if (content.savedQueryId === queryId && content.savedAtVersionNumber != null) {\n const vSavedAt = content.savedAtVersionNumber as number;\n if (effective == null || vSavedAt > effective) {\n effective = vSavedAt;\n }\n }\n } catch {\n // Skip versions with unparseable content\n }\n }\n\n return effective;\n }\n\n /**\n * Look up the saved query's SQL from QueryEngine cache for comparison.\n * Only fetches if savedQueryId is present.\n */\n private async resolveSavedQuerySql(): Promise<void> {\n if (!this.spec?.savedQueryId) {\n this.savedQuerySql = null;\n return;\n }\n\n // QueryEngine is registered for startup, should already be loaded\n let query = QueryEngine.Instance.FindQueryByID(this.spec.savedQueryId);\n\n if (!query) {\n // Cache miss — force refresh and retry\n await QueryEngine.Instance.Config(true);\n query = QueryEngine.Instance.FindQueryByID(this.spec.savedQueryId);\n }\n\n this.savedQuerySql = query?.SQL ?? null;\n }\n\n /**\n * Compute the query sync state from current spec, version, and saved query SQL.\n * Implements the decision tree from the UX design.\n */\n private computeQuerySyncState(): QuerySyncState {\n const hasSavedQuery = !!this.spec?.savedQueryId;\n const isLatest = this.IsLatestVersion;\n\n if (!hasSavedQuery) {\n return isLatest ? 'no-query-latest' : 'no-query-older';\n }\n\n // Compare SQL (normalize whitespace for reliable comparison)\n const specSql = this.normalizeSql(this.spec?.metadata?.sql);\n const querySql = this.normalizeSql(this.savedQuerySql);\n const sqlMatches = specSql != null && querySql != null && specSql === querySql;\n\n // Only truly synced if SQL matches AND this is the version it was saved at.\n // Even with identical SQL, a newer version should show the dropdown so the\n // user can update the version association (re-save at current version).\n const savedAtCurrent = this.EffectiveSavedAtVersion === this.CurrentVersionNumber;\n if (sqlMatches && savedAtCurrent) {\n return 'synced';\n }\n\n // SQL differs — determine position relative to saved version\n if (isLatest) {\n return 'outdated-latest';\n }\n\n // Use effective saved-at (looks ahead through newer versions)\n const savedAt = this.EffectiveSavedAtVersion;\n if (savedAt != null && this.CurrentVersionNumber < savedAt) {\n return 'query-ahead'; // query was updated at a newer version\n }\n\n return 'query-behind'; // ahead of saved but not latest\n }\n\n /** Normalize SQL for comparison: trim and collapse whitespace */\n private normalizeSql(sql: string | null | undefined): string | null {\n if (sql == null) return null;\n return sql.trim().replace(/\\s+/g, ' ');\n }\n\n // ─── Actions ────────────────────────────────────────────────────\n\n /** Navigate to the saved query in the Data Explorer's Queries browser */\n public OnOpenSavedQuery(): void {\n if (!this.spec?.savedQueryId) return;\n this.navigationRequest.emit({\n appName: 'Data Explorer',\n navItemName: 'Queries',\n queryParams: { queryId: this.spec.savedQueryId }\n });\n }\n\n /** Show the save panel for creating a brand-new query */\n public OnShowSaveDialog(): void {\n this.ShowSaveDialog = true;\n this.ShowUpdateDropdown = false;\n }\n\n /** Toggle the update query dropdown */\n public OnToggleUpdateDropdown(): void {\n this.ShowUpdateDropdown = !this.ShowUpdateDropdown;\n }\n\n /** Close the dropdown (e.g., on outside click) */\n public OnCloseDropdown(): void {\n this.ShowUpdateDropdown = false;\n }\n\n /**\n * Update the existing saved query's SQL to match this version.\n * Only available from the latest version (Scenario 3).\n */\n public async OnUpdateExistingQuery(): Promise<void> {\n this.ShowUpdateDropdown = false;\n if (!this.spec?.savedQueryId || !this.spec.metadata?.sql) return;\n\n this.IsSaving = true;\n this.SavingMessage = `Updating \"${this.SavedQueryDisplayName}\"...`;\n this.cdr.detectChanges();\n\n try {\n const md = new Metadata();\n const query = await md.GetEntityObject<import('@memberjunction/core-entities').MJQueryEntity>('MJ: Queries');\n const loaded = await query.Load(this.spec.savedQueryId);\n\n if (!loaded) {\n console.error('Failed to load saved query for update');\n return;\n }\n\n query.SQL = this.spec.metadata.sql;\n const saved = await query.Save();\n\n if (saved) {\n // Update spec with new version tracking\n this.spec.savedAtVersionNumber = this.CurrentVersionNumber;\n await this.PersistArtifactContent();\n\n // Refresh caches so future lookups see the updated data\n await QueryEngine.Instance.Config(true);\n await ArtifactMetadataEngine.Instance.Config(true);\n await md.Refresh();\n\n this.savedQuerySql = this.spec.metadata.sql;\n this.EffectiveSavedAtVersion = this.CurrentVersionNumber;\n this.QuerySyncState = 'synced';\n }\n } catch (error) {\n console.error('Failed to update saved query:', error);\n } finally {\n this.IsSaving = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Save as a new query (from the dropdown).\n * Opens the save dialog which creates a fresh query record.\n */\n public OnSaveAsNewQuery(): void {\n this.ShowUpdateDropdown = false;\n this.ShowSaveDialog = true;\n }\n\n /** Handle successful save from the dialog (both initial save and \"save as new\") */\n public async OnQuerySaved(event: SaveQueryResult): Promise<void> {\n this.ShowSaveDialog = false;\n this.IsSaving = true;\n this.SavingMessage = 'Saving query...';\n this.cdr.detectChanges();\n\n try {\n // Update spec with saved query info and version tracking\n this.spec!.savedQueryId = event.queryId;\n this.spec!.savedQueryName = event.queryName;\n this.spec!.savedAtVersionNumber = this.CurrentVersionNumber;\n\n // Persist and refresh caches\n await this.PersistArtifactContent();\n await QueryEngine.Instance.Config(true);\n await ArtifactMetadataEngine.Instance.Config(true);\n await new Metadata().Refresh();\n\n this.savedQuerySql = this.spec!.metadata?.sql ?? null;\n this.EffectiveSavedAtVersion = this.CurrentVersionNumber;\n this.QuerySyncState = 'synced';\n } catch (error) {\n console.error('Failed to save query:', error);\n } finally {\n this.IsSaving = false;\n this.cdr.detectChanges();\n }\n }\n\n /** Persist updated spec back to the artifact version entity */\n private async PersistArtifactContent(): Promise<void> {\n if (!this.artifactVersion || !this.spec) return;\n this.artifactVersion.Content = JSON.stringify(this.spec);\n await this.artifactVersion.Save();\n }\n\n // ─── Tabs ───────────────────────────────────────────────────────\n\n /**\n * Provide Plan tab (markdown) and SQL tab (code) when available\n */\n public GetAdditionalTabs(): ArtifactViewerTab[] {\n const tabs: ArtifactViewerTab[] = [];\n\n if (this.spec?.plan) {\n tabs.push({\n label: 'Plan',\n icon: 'fa-diagram-project',\n contentType: 'markdown',\n content: this.spec.plan\n });\n }\n\n if (this.spec?.metadata?.sql) {\n tabs.push({\n label: 'SQL',\n icon: 'fa-database',\n contentType: 'code',\n language: 'sql',\n content: this.spec.metadata.sql\n });\n }\n\n return tabs;\n }\n}\n","<div class=\"data-artifact-viewer\" [ngClass]=\"cssClass\">\n @if (spec) {\n @if (HasData || IsLoading) {\n <!-- Toolbar -->\n <div class=\"data-toolbar\">\n <div class=\"data-title\">\n <i class=\"fas fa-table\"></i>\n <span>{{ spec.title || 'Data Results' }}</span>\n @if (IsLive) {\n <span class=\"live-badge\">Live</span>\n }\n @if (DisplayRowCount != null) {\n <span class=\"row-count\">{{ DisplayRowCount }} rows</span>\n }\n @if (DisplayExecutionTime != null) {\n <span class=\"exec-time\">{{ DisplayExecutionTime }}ms</span>\n }\n </div>\n <div class=\"data-actions\">\n @if (IsLive) {\n <button class=\"btn-icon\" title=\"Refresh data\" (click)=\"OnRefresh()\" [disabled]=\"IsLoading\">\n <i class=\"fas fa-sync-alt\" [class.fa-spin]=\"IsLoading\"></i> Refresh\n </button>\n }\n\n @switch (QuerySyncState) {\n <!-- S1: No saved query, latest version → Save Query -->\n @case ('no-query-latest') {\n <button class=\"btn-icon btn-save\" title=\"Save as reusable query\"\n (click)=\"OnShowSaveDialog()\">\n <i class=\"fas fa-save\"></i> Save Query\n </button>\n }\n\n <!-- S2: SQL matches → green badge + Open -->\n @case ('synced') {\n <span class=\"query-badge query-badge-synced\">\n <i class=\"fas fa-check\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-open\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S3: SQL differs, latest version → amber badge + dropdown -->\n @case ('outdated-latest') {\n <span class=\"query-badge query-badge-outdated\">\n <i class=\"fas fa-circle-exclamation\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <div class=\"dropdown-wrapper\">\n <button class=\"btn-icon btn-warning\" title=\"Update or save query\"\n (click)=\"OnToggleUpdateDropdown()\">\n <i class=\"fas fa-save\"></i> Update Query <i class=\"fas fa-caret-down\"></i>\n </button>\n @if (ShowUpdateDropdown) {\n <div class=\"query-dropdown\" (click)=\"$event.stopPropagation()\">\n <div class=\"query-dropdown-item\" (click)=\"OnUpdateExistingQuery()\">\n <i class=\"fas fa-arrow-up-from-bracket\" style=\"color:#d97706\"></i>\n <div>\n <div class=\"dropdown-label\">Update \"{{ SavedQueryDisplayName }}\"</div>\n <div class=\"dropdown-desc\">Replace saved query SQL with this version's SQL</div>\n </div>\n </div>\n <div class=\"query-dropdown-item\" (click)=\"OnSaveAsNewQuery()\">\n <i class=\"fas fa-plus\" style=\"color:#16a34a\"></i>\n <div>\n <div class=\"dropdown-label\">Save as New Query</div>\n <div class=\"dropdown-desc\">Create a new query, keep the original unchanged</div>\n </div>\n </div>\n <div class=\"query-dropdown-item\" (click)=\"OnOpenSavedQuery(); OnCloseDropdown()\">\n <i class=\"fas fa-external-link-alt\" style=\"color:#6c757d\"></i>\n <div>\n <div class=\"dropdown-label\">Open Saved Query</div>\n <div class=\"dropdown-desc\">View \"{{ SavedQueryDisplayName }}\" (saved at v{{ SavedAtVersion }})</div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- S4: Older version, query was updated ahead -->\n @case ('query-ahead') {\n <span class=\"query-badge query-badge-muted\">\n <i class=\"fas fa-clock-rotate-left\"></i> Query updated at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-muted\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S5: Middle version, saved at older, not latest -->\n @case ('query-behind') {\n <span class=\"query-badge query-badge-muted\">\n <i class=\"fas fa-clock-rotate-left\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-muted\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S6: No saved query, older version → no actions -->\n @case ('no-query-older') {\n <!-- No query actions available on older versions -->\n }\n }\n </div>\n </div>\n\n <!-- Grid -->\n <div class=\"grid-container\">\n <!-- Saving overlay -->\n @if (IsSaving) {\n <div class=\"saving-overlay\">\n <mj-loading [text]=\"SavingMessage\"></mj-loading>\n </div>\n }\n @if (IsLoading) {\n <mj-loading text=\"Loading data...\"></mj-loading>\n } @else if (HasError && HasData) {\n <div class=\"error-banner\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ ErrorMessage }}</span>\n <span class=\"fallback-note\">(Showing cached data)</span>\n </div>\n <mj-query-data-grid\n [ColumnConfigs]=\"GridColumnConfigs\"\n [Data]=\"GridData\"\n [ShowToolbar]=\"false\"\n [ShowRefresh]=\"false\"\n [PersistState]=\"false\"\n [SelectionMode]=\"'none'\"\n (EntityLinkClick)=\"OnEntityLinkClick($event)\"\n Height=\"100%\">\n </mj-query-data-grid>\n } @else if (HasError) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ ErrorMessage }}</p>\n </div>\n } @else {\n <mj-query-data-grid\n [ColumnConfigs]=\"GridColumnConfigs\"\n [Data]=\"GridData\"\n [ShowToolbar]=\"false\"\n [ShowRefresh]=\"false\"\n [PersistState]=\"false\"\n [SelectionMode]=\"'none'\"\n (EntityLinkClick)=\"OnEntityLinkClick($event)\"\n Height=\"100%\">\n </mj-query-data-grid>\n }\n </div>\n } @else if (spec.plan) {\n <!-- Plan-only view (no results yet) -->\n <div class=\"data-toolbar\">\n <div class=\"data-title\">\n <i class=\"fas fa-diagram-project\"></i>\n <span>{{ spec.title || 'Query Plan' }}</span>\n </div>\n </div>\n <div class=\"plan-content\">\n <mj-markdown\n [data]=\"spec.plan\"\n [enableMermaid]=\"true\"\n [enableHighlight]=\"true\"\n [enableCollapsibleHeadings]=\"false\"\n [enableSmartypants]=\"true\">\n </mj-markdown>\n </div>\n } @else {\n <!-- No data and no plan -->\n <div class=\"empty-state\">\n <i class=\"fas fa-inbox\"></i>\n <p>No data to display</p>\n </div>\n }\n } @else if (HasError) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ ErrorMessage }}</p>\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fas fa-inbox\"></i>\n <p>No data to display</p>\n </div>\n }\n\n <!-- Save Query Panel (slide-in) -->\n @if (ShowSaveDialog) {\n <mj-save-query-panel\n [QueryName]=\"spec?.title || 'Untitled Query'\"\n [QueryDescription]=\"''\"\n [SQL]=\"spec?.metadata?.sql || ''\"\n (Saved)=\"OnQuerySaved($event)\"\n (Cancelled)=\"ShowSaveDialog = false\">\n </mj-save-query-panel>\n }\n</div>\n"]}
1
+ {"version":3,"file":"data-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/data-artifact-viewer.component.ts","../../../../src/lib/components/plugins/data-artifact-viewer.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ChangeDetectorRef, Output, EventEmitter } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { Metadata, RunQuery, CompositeKey, KeyValuePair } from '@memberjunction/core';\nimport { QueryEngine, ArtifactMetadataEngine } from '@memberjunction/core-entities';\nimport { QueryGridColumnConfig, QueryEntityLinkClickEvent, resolveTargetEntity } from '@memberjunction/ng-query-viewer';\nimport { BaseArtifactViewerPluginComponent, ArtifactViewerTab, NavigationRequest } from '../base-artifact-viewer.component';\nimport { SaveQueryResult } from './save-query-dialog.component';\n\n/**\n * JSON schema for Data artifact content.\n * The agent produces this structure when emitting query/view results.\n */\ninterface DataArtifactSpec {\n /** Data source type */\n source: 'query' | 'view';\n\n /** Display title for the data */\n title?: string;\n\n /** For query source: the query ID to render via mj-query-viewer */\n queryId?: string;\n\n /** For query source: parameter values to pass */\n parameters?: Record<string, string | number | boolean>;\n\n /** For view source: the entity name */\n entityName?: string;\n\n /** For view source: extra WHERE filter */\n extraFilter?: string;\n\n /** Column definitions for inline data display */\n columns?: DataArtifactColumn[];\n\n /** Inline row data (when results are embedded directly) */\n rows?: Record<string, unknown>[];\n\n /** Optional markdown plan/approach description (mermaid diagrams, explanations) */\n plan?: string;\n\n /** Query metadata */\n metadata?: {\n sql?: string;\n rowCount?: number;\n executionTimeMs?: number;\n };\n\n /** ID of saved query (set after user saves from artifact) */\n savedQueryId?: string;\n\n /** Name of saved query (for display) */\n savedQueryName?: string;\n\n /** Version number this query was saved/updated from */\n savedAtVersionNumber?: number;\n}\n\ninterface DataArtifactColumn {\n field: string;\n headerName?: string;\n width?: number;\n\n /** MJ entity name this column originates from (e.g., \"Members\") */\n sourceEntity?: string;\n\n /** Field name in that entity (e.g., \"ID\", \"FirstName\") */\n sourceFieldName?: string;\n\n /** True for calculated expressions (CASE, ROUND, CONCAT, etc.) */\n isComputed?: boolean;\n\n /** True for aggregate functions (SUM, COUNT, AVG, etc.) */\n isSummary?: boolean;\n\n /** SQL data type: int, nvarchar, uniqueidentifier, datetime, decimal, bit, money, etc. */\n sqlBaseType?: string;\n}\n\n/**\n * Describes the relationship between the current artifact version's SQL\n * and the saved query record. Drives the toolbar UI.\n */\ntype QuerySyncState =\n | 'no-query-latest' // No saved query, viewing latest version → show \"Save Query\"\n | 'no-query-older' // No saved query, viewing older version → no actions\n | 'synced' // SQL matches saved query → green badge + \"Open Query\"\n | 'outdated-latest' // SQL differs, viewing latest → amber badge + dropdown\n | 'query-ahead' // Viewing older version, query was updated at a newer version\n | 'query-behind'; // Viewing middle version, saved at older, not latest → muted\n\n/**\n * Viewer component for Data artifacts.\n *\n * Displays tabular data using AG Grid via mj-query-data-grid. Supports two modes:\n * 1. **Live data**: When metadata.sql is present, executes the query dynamically via RunQuery({ SQL })\n * to fetch fresh data on each view. Falls back to inline rows on error.\n * 2. **Inline data**: Rows embedded directly in the artifact JSON (backward compat with older artifacts)\n *\n * The Query Builder agent emits artifacts with metadata.sql for live execution.\n */\n@Component({\n standalone: false,\n selector: 'mj-data-artifact-viewer',\n templateUrl: './data-artifact-viewer.component.html',\n styleUrls: ['./data-artifact-viewer.component.css']\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'DataArtifactViewerPlugin')\nexport class DataArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit {\n @Output() openEntityRecord = new EventEmitter<{entityName: string; compositeKey: CompositeKey}>();\n @Output() override navigationRequest = new EventEmitter<NavigationRequest>();\n public override tabsChanged = new EventEmitter<void>();\n\n public spec: DataArtifactSpec | null = null;\n public GridData: Record<string, unknown>[] = [];\n public GridColumnConfigs: QueryGridColumnConfig[] | null = null;\n public IsLoading = false;\n public IsLive = false;\n public HasError = false;\n public ErrorMessage = '';\n public ShowSaveDialog = false;\n public ShowUpdateDropdown = false;\n public IsSaving = false;\n public SavingMessage = '';\n\n /** Query sync state — drives the toolbar UI for saved query actions */\n public QuerySyncState: QuerySyncState = 'no-query-latest';\n\n /** Latest version number for this artifact (from cache) */\n public LatestVersionNumber = 0;\n\n /** Metadata from live execution (overrides spec.metadata when live) */\n private liveRowCount: number | null = null;\n private liveExecutionTime: number | null = null;\n\n /** SQL from the saved query record (for comparison) */\n private savedQuerySql: string | null = null;\n\n constructor(private cdr: ChangeDetectorRef) {\n super();\n }\n\n public override get hasDisplayContent(): boolean {\n return this.spec != null && (this.HasData || this.IsLoading);\n }\n\n public override get parentShouldShowRawContent(): boolean {\n return true;\n }\n\n public get HasData(): boolean {\n return this.GridData.length > 0;\n }\n\n public get HasInlineData(): boolean {\n return !!(this.spec?.rows && this.spec.rows.length > 0);\n }\n\n public get DisplayRowCount(): number | null {\n return this.liveRowCount ?? this.spec?.metadata?.rowCount ?? null;\n }\n\n public get DisplayExecutionTime(): number | null {\n return this.liveExecutionTime ?? this.spec?.metadata?.executionTimeMs ?? null;\n }\n\n /** Current artifact version number */\n public get CurrentVersionNumber(): number {\n return this.artifactVersion?.VersionNumber || 1;\n }\n\n /** Whether this is the latest version of the artifact */\n public get IsLatestVersion(): boolean {\n return this.CurrentVersionNumber === this.LatestVersionNumber;\n }\n\n /**\n * The effective version number at which the query was last saved/updated.\n * When viewing an older version, this looks ahead through newer versions\n * to find the most recent savedAtVersionNumber for the same query,\n * giving the user accurate context (e.g., \"Query updated at v3\" instead\n * of the stale \"Saved at v1\" from this version's snapshot).\n */\n public EffectiveSavedAtVersion: number | null = null;\n\n /** Alias used by the template */\n public get SavedAtVersion(): number | null {\n return this.EffectiveSavedAtVersion;\n }\n\n /** Display name for the saved query */\n public get SavedQueryDisplayName(): string {\n return this.spec?.savedQueryName || 'Saved Query';\n }\n\n async ngOnInit(): Promise<void> {\n try {\n this.spec = this.parseJsonContent<DataArtifactSpec>();\n if (!this.spec) {\n this.HasError = true;\n this.ErrorMessage = 'Failed to parse data artifact content';\n return;\n }\n\n // Build enriched column configs from agent metadata (if available)\n this.GridColumnConfigs = this.BuildColumnConfigs();\n\n // Set loading early (synchronously) so hasDisplayContent is true immediately.\n // This ensures the Display tab is available when onPluginLoaded fires,\n // showing a loading indicator instead of briefly flashing the Plan tab.\n if (this.spec.metadata?.sql || this.HasInlineData) {\n this.IsLoading = true;\n }\n\n // Load cached metadata and resolve query sync state\n await this.InitQuerySyncState();\n\n // If SQL is available, execute it live\n if (this.spec.metadata?.sql) {\n await this.LoadLiveData();\n } else if (this.HasInlineData) {\n // Fall back to embedded rows\n this.GridData = this.spec.rows!;\n this.IsLoading = false;\n }\n\n // Signal parent that tabs/display content may have changed after async load\n this.tabsChanged.emit();\n } catch (error) {\n this.HasError = true;\n this.ErrorMessage = error instanceof Error ? error.message : 'Failed to load data';\n }\n }\n\n /**\n * Re-execute the live SQL query\n */\n public async OnRefresh(): Promise<void> {\n if (this.spec?.metadata?.sql) {\n await this.LoadLiveData();\n }\n }\n\n /**\n * Handle entity link click from the grid and bubble up as openEntityRecord.\n * Converts the grid's recordId string into a CompositeKey for the artifact viewer pipeline.\n */\n public OnEntityLinkClick(event: QueryEntityLinkClickEvent): void {\n const compositeKey = new CompositeKey([\n new KeyValuePair('ID', event.recordId)\n ]);\n this.openEntityRecord.emit({\n entityName: event.entityName,\n compositeKey\n });\n }\n\n /**\n * Execute the SQL query via RunQuery and populate the grid.\n * Falls back to inline data on error.\n */\n private async LoadLiveData(): Promise<void> {\n this.IsLoading = true;\n this.HasError = false;\n this.cdr.detectChanges();\n\n try {\n const rq = new RunQuery();\n const result = await rq.RunQuery({ SQL: this.spec!.metadata!.sql! });\n\n if (result.Success) {\n this.GridData = result.Results;\n this.liveRowCount = result.RowCount;\n this.liveExecutionTime = result.ExecutionTime;\n this.IsLive = true;\n } else {\n this.HandleQueryError(result.ErrorMessage || 'Query execution failed');\n }\n } catch (error) {\n this.HandleQueryError(error instanceof Error ? error.message : 'Query execution failed');\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Build QueryGridColumnConfig[] from enriched artifact column metadata.\n * Returns null if columns have no entity metadata (grid falls back to auto-inference).\n */\n private BuildColumnConfigs(): QueryGridColumnConfig[] | null {\n if (!this.spec?.columns?.length) return null;\n\n // Only build if at least one column has entity metadata or type info\n const hasMetadata = this.spec.columns.some(c => c.sourceEntity || c.sqlBaseType);\n if (!hasMetadata) return null;\n\n const md = new Metadata();\n return this.spec.columns.map((col, index) => {\n const target = resolveTargetEntity(col.sourceEntity, col.sourceFieldName, md);\n const isEntityLink = !!(target.targetEntityName && (target.isPrimaryKey || target.isForeignKey));\n const baseType = (col.sqlBaseType || 'nvarchar').toLowerCase();\n\n let align: 'left' | 'center' | 'right' = 'left';\n if (['int', 'bigint', 'decimal', 'numeric', 'float', 'money', 'smallmoney', 'real'].includes(baseType)) {\n align = 'right';\n } else if (baseType === 'bit') {\n align = 'center';\n }\n\n return {\n field: col.field,\n title: col.headerName || col.field,\n visible: true,\n sortable: true,\n resizable: true,\n reorderable: true,\n sqlBaseType: col.sqlBaseType || 'nvarchar',\n sqlFullType: col.sqlBaseType || 'nvarchar',\n align,\n order: index,\n sourceEntityName: col.sourceEntity,\n sourceFieldName: col.sourceFieldName,\n isEntityLink,\n targetEntityName: target.targetEntityName,\n targetEntityId: target.targetEntityId,\n targetEntityIcon: target.targetEntityIcon,\n isPrimaryKey: target.isPrimaryKey,\n isForeignKey: target.isForeignKey,\n pinned: null,\n } as QueryGridColumnConfig;\n });\n }\n\n /**\n * Handle a query error by setting error state and falling back to inline data\n */\n private HandleQueryError(message: string): void {\n this.HasError = true;\n this.ErrorMessage = message;\n if (this.HasInlineData) {\n this.GridData = this.spec!.rows!;\n }\n }\n\n // ─── Query Sync State ────────────────────────────────────────────\n\n /**\n * Initialize query sync state by loading cached metadata.\n * Resolves the latest version number and compares saved query SQL.\n */\n private async InitQuerySyncState(): Promise<void> {\n // Ensure artifact cache is loaded (not registered for startup)\n await ArtifactMetadataEngine.Instance.Config(false);\n\n this.LatestVersionNumber = this.resolveLatestVersionNumber();\n\n // If cache is stale (doesn't know about the version we're viewing),\n // force-refresh and re-resolve. This happens when new versions are\n // created during a conversation after the cache was first loaded.\n if (this.LatestVersionNumber < this.CurrentVersionNumber) {\n await ArtifactMetadataEngine.Instance.Config(true);\n this.LatestVersionNumber = this.resolveLatestVersionNumber();\n }\n\n this.EffectiveSavedAtVersion = this.resolveEffectiveSavedAtVersion();\n await this.resolveSavedQuerySql();\n this.QuerySyncState = this.computeQuerySyncState();\n }\n\n /**\n * Determine the latest version number for this artifact from cache.\n * Falls back to current version if cache miss.\n */\n private resolveLatestVersionNumber(): number {\n if (!this.artifactVersion?.ArtifactID) {\n return this.CurrentVersionNumber;\n }\n\n const versions = ArtifactMetadataEngine.Instance.GetVersionsForArtifact(this.artifactVersion.ArtifactID);\n if (versions.length > 0) {\n // GetVersionsForArtifact returns DESC sorted\n return versions[0].VersionNumber || 1;\n }\n\n // Cache miss — current version is our best guess\n return this.CurrentVersionNumber;\n }\n\n /**\n * Scan all versions of this artifact to find the most recent savedAtVersionNumber\n * for the same savedQueryId. When viewing an older version, this tells the user\n * where the query was *actually* last updated, not just what this version's\n * snapshot recorded at the time.\n */\n private resolveEffectiveSavedAtVersion(): number | null {\n const queryId = this.spec?.savedQueryId;\n if (!queryId) return null;\n\n // Start with this version's own value\n let effective = this.spec?.savedAtVersionNumber ?? null;\n\n if (!this.artifactVersion?.ArtifactID) return effective;\n\n // GetVersionsForArtifact returns DESC sorted — scan all versions\n const versions = ArtifactMetadataEngine.Instance.GetVersionsForArtifact(this.artifactVersion.ArtifactID);\n for (const v of versions) {\n try {\n if (!v.Content) continue;\n const content = typeof v.Content === 'string' ? JSON.parse(v.Content) : v.Content;\n if (content.savedQueryId === queryId && content.savedAtVersionNumber != null) {\n const vSavedAt = content.savedAtVersionNumber as number;\n if (effective == null || vSavedAt > effective) {\n effective = vSavedAt;\n }\n }\n } catch {\n // Skip versions with unparseable content\n }\n }\n\n return effective;\n }\n\n /**\n * Look up the saved query's SQL from QueryEngine cache for comparison.\n * Only fetches if savedQueryId is present.\n */\n private async resolveSavedQuerySql(): Promise<void> {\n if (!this.spec?.savedQueryId) {\n this.savedQuerySql = null;\n return;\n }\n\n // QueryEngine is registered for startup, should already be loaded\n let query = QueryEngine.Instance.FindQueryByID(this.spec.savedQueryId);\n\n if (!query) {\n // Cache miss — force refresh and retry\n await QueryEngine.Instance.Config(true);\n query = QueryEngine.Instance.FindQueryByID(this.spec.savedQueryId);\n }\n\n this.savedQuerySql = query?.SQL ?? null;\n }\n\n /**\n * Compute the query sync state from current spec, version, and saved query SQL.\n * Implements the decision tree from the UX design.\n */\n private computeQuerySyncState(): QuerySyncState {\n const hasSavedQuery = !!this.spec?.savedQueryId;\n const isLatest = this.IsLatestVersion;\n\n if (!hasSavedQuery) {\n return isLatest ? 'no-query-latest' : 'no-query-older';\n }\n\n // Compare SQL (normalize whitespace for reliable comparison)\n const specSql = this.normalizeSql(this.spec?.metadata?.sql);\n const querySql = this.normalizeSql(this.savedQuerySql);\n const sqlMatches = specSql != null && querySql != null && specSql === querySql;\n\n // Only truly synced if SQL matches AND this is the version it was saved at.\n // Even with identical SQL, a newer version should show the dropdown so the\n // user can update the version association (re-save at current version).\n const savedAtCurrent = this.EffectiveSavedAtVersion === this.CurrentVersionNumber;\n if (sqlMatches && savedAtCurrent) {\n return 'synced';\n }\n\n // SQL differs — determine position relative to saved version\n if (isLatest) {\n return 'outdated-latest';\n }\n\n // Use effective saved-at (looks ahead through newer versions)\n const savedAt = this.EffectiveSavedAtVersion;\n if (savedAt != null && this.CurrentVersionNumber < savedAt) {\n return 'query-ahead'; // query was updated at a newer version\n }\n\n return 'query-behind'; // ahead of saved but not latest\n }\n\n /** Normalize SQL for comparison: trim and collapse whitespace */\n private normalizeSql(sql: string | null | undefined): string | null {\n if (sql == null) return null;\n return sql.trim().replace(/\\s+/g, ' ');\n }\n\n // ─── Actions ────────────────────────────────────────────────────\n\n /** Navigate to the saved query in the Data Explorer's Queries browser */\n public OnOpenSavedQuery(): void {\n if (!this.spec?.savedQueryId) return;\n this.navigationRequest.emit({\n appName: 'Data Explorer',\n navItemName: 'Queries',\n queryParams: { queryId: this.spec.savedQueryId }\n });\n }\n\n /** Show the save panel for creating a brand-new query */\n public OnShowSaveDialog(): void {\n this.ShowSaveDialog = true;\n this.ShowUpdateDropdown = false;\n }\n\n /** Toggle the update query dropdown */\n public OnToggleUpdateDropdown(): void {\n this.ShowUpdateDropdown = !this.ShowUpdateDropdown;\n }\n\n /** Close the dropdown (e.g., on outside click) */\n public OnCloseDropdown(): void {\n this.ShowUpdateDropdown = false;\n }\n\n /**\n * Update the existing saved query's SQL to match this version.\n * Only available from the latest version (Scenario 3).\n */\n public async OnUpdateExistingQuery(): Promise<void> {\n this.ShowUpdateDropdown = false;\n if (!this.spec?.savedQueryId || !this.spec.metadata?.sql) return;\n\n this.IsSaving = true;\n this.SavingMessage = `Updating \"${this.SavedQueryDisplayName}\"...`;\n this.cdr.detectChanges();\n\n try {\n const md = new Metadata();\n const query = await md.GetEntityObject<import('@memberjunction/core-entities').MJQueryEntity>('MJ: Queries');\n const loaded = await query.Load(this.spec.savedQueryId);\n\n if (!loaded) {\n console.error('Failed to load saved query for update');\n return;\n }\n\n query.SQL = this.spec.metadata.sql;\n if (this.spec.plan?.trim()) {\n query.TechnicalDescription = this.spec.plan.trim();\n }\n const saved = await query.Save();\n\n if (saved) {\n // Update spec with new version tracking\n this.spec.savedAtVersionNumber = this.CurrentVersionNumber;\n await this.PersistArtifactContent();\n\n // Refresh caches so future lookups see the updated data\n await QueryEngine.Instance.Config(true);\n await ArtifactMetadataEngine.Instance.Config(true);\n await md.Refresh();\n\n this.savedQuerySql = this.spec.metadata.sql;\n this.EffectiveSavedAtVersion = this.CurrentVersionNumber;\n this.QuerySyncState = 'synced';\n }\n } catch (error) {\n console.error('Failed to update saved query:', error);\n } finally {\n this.IsSaving = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Save as a new query (from the dropdown).\n * Opens the save dialog which creates a fresh query record.\n */\n public OnSaveAsNewQuery(): void {\n this.ShowUpdateDropdown = false;\n this.ShowSaveDialog = true;\n }\n\n /** Handle successful save from the dialog (both initial save and \"save as new\") */\n public async OnQuerySaved(event: SaveQueryResult): Promise<void> {\n this.ShowSaveDialog = false;\n this.IsSaving = true;\n this.SavingMessage = 'Saving query...';\n this.cdr.detectChanges();\n\n try {\n // Update spec with saved query info and version tracking\n this.spec!.savedQueryId = event.queryId;\n this.spec!.savedQueryName = event.queryName;\n this.spec!.savedAtVersionNumber = this.CurrentVersionNumber;\n\n // Persist and refresh caches\n await this.PersistArtifactContent();\n await QueryEngine.Instance.Config(true);\n await ArtifactMetadataEngine.Instance.Config(true);\n await new Metadata().Refresh();\n\n this.savedQuerySql = this.spec!.metadata?.sql ?? null;\n this.EffectiveSavedAtVersion = this.CurrentVersionNumber;\n this.QuerySyncState = 'synced';\n } catch (error) {\n console.error('Failed to save query:', error);\n } finally {\n this.IsSaving = false;\n this.cdr.detectChanges();\n }\n }\n\n /** Persist updated spec back to the artifact version entity */\n private async PersistArtifactContent(): Promise<void> {\n if (!this.artifactVersion || !this.spec) return;\n this.artifactVersion.Content = JSON.stringify(this.spec);\n await this.artifactVersion.Save();\n }\n\n // ─── Tabs ───────────────────────────────────────────────────────\n\n /**\n * Provide Plan tab (markdown) and SQL tab (code) when available\n */\n public GetAdditionalTabs(): ArtifactViewerTab[] {\n const tabs: ArtifactViewerTab[] = [];\n\n if (this.spec?.plan) {\n tabs.push({\n label: 'Plan',\n icon: 'fa-diagram-project',\n contentType: 'markdown',\n content: this.spec.plan\n });\n }\n\n if (this.spec?.metadata?.sql) {\n tabs.push({\n label: 'SQL',\n icon: 'fa-database',\n contentType: 'code',\n language: 'sql',\n content: this.spec.metadata.sql\n });\n }\n\n return tabs;\n }\n}\n","<div class=\"data-artifact-viewer\" [ngClass]=\"cssClass\">\n @if (spec) {\n @if (HasData || IsLoading) {\n <!-- Toolbar -->\n <div class=\"data-toolbar\">\n <div class=\"data-title\">\n <i class=\"fas fa-table\"></i>\n <span>{{ spec.title || 'Data Results' }}</span>\n @if (IsLive) {\n <span class=\"live-badge\">Live</span>\n }\n @if (DisplayRowCount != null) {\n <span class=\"row-count\">{{ DisplayRowCount }} rows</span>\n }\n @if (DisplayExecutionTime != null) {\n <span class=\"exec-time\">{{ DisplayExecutionTime }}ms</span>\n }\n </div>\n <div class=\"data-actions\">\n @if (IsLive) {\n <button class=\"btn-icon\" title=\"Refresh data\" (click)=\"OnRefresh()\" [disabled]=\"IsLoading\">\n <i class=\"fas fa-sync-alt\" [class.fa-spin]=\"IsLoading\"></i> Refresh\n </button>\n }\n\n @switch (QuerySyncState) {\n <!-- S1: No saved query, latest version → Save Query -->\n @case ('no-query-latest') {\n <button class=\"btn-icon btn-save\" title=\"Save as reusable query\"\n (click)=\"OnShowSaveDialog()\">\n <i class=\"fas fa-save\"></i> Save Query\n </button>\n }\n\n <!-- S2: SQL matches → green badge + Open -->\n @case ('synced') {\n <span class=\"query-badge query-badge-synced\">\n <i class=\"fas fa-check\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-open\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S3: SQL differs, latest version → amber badge + dropdown -->\n @case ('outdated-latest') {\n <span class=\"query-badge query-badge-outdated\">\n <i class=\"fas fa-circle-exclamation\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <div class=\"dropdown-wrapper\">\n <button class=\"btn-icon btn-warning\" title=\"Update or save query\"\n (click)=\"OnToggleUpdateDropdown()\">\n <i class=\"fas fa-save\"></i> Update Query <i class=\"fas fa-caret-down\"></i>\n </button>\n @if (ShowUpdateDropdown) {\n <div class=\"query-dropdown\" (click)=\"$event.stopPropagation()\">\n <div class=\"query-dropdown-item\" (click)=\"OnUpdateExistingQuery()\">\n <i class=\"fas fa-arrow-up-from-bracket\" style=\"color:#d97706\"></i>\n <div>\n <div class=\"dropdown-label\">Update \"{{ SavedQueryDisplayName }}\"</div>\n <div class=\"dropdown-desc\">Replace saved query SQL with this version's SQL</div>\n </div>\n </div>\n <div class=\"query-dropdown-item\" (click)=\"OnSaveAsNewQuery()\">\n <i class=\"fas fa-plus\" style=\"color:#16a34a\"></i>\n <div>\n <div class=\"dropdown-label\">Save as New Query</div>\n <div class=\"dropdown-desc\">Create a new query, keep the original unchanged</div>\n </div>\n </div>\n <div class=\"query-dropdown-item\" (click)=\"OnOpenSavedQuery(); OnCloseDropdown()\">\n <i class=\"fas fa-external-link-alt\" style=\"color:#6c757d\"></i>\n <div>\n <div class=\"dropdown-label\">Open Saved Query</div>\n <div class=\"dropdown-desc\">View \"{{ SavedQueryDisplayName }}\" (saved at v{{ SavedAtVersion }})</div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- S4: Older version, query was updated ahead -->\n @case ('query-ahead') {\n <span class=\"query-badge query-badge-muted\">\n <i class=\"fas fa-clock-rotate-left\"></i> Query updated at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-muted\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S5: Middle version, saved at older, not latest -->\n @case ('query-behind') {\n <span class=\"query-badge query-badge-muted\">\n <i class=\"fas fa-clock-rotate-left\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-muted\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S6: No saved query, older version → no actions -->\n @case ('no-query-older') {\n <!-- No query actions available on older versions -->\n }\n }\n </div>\n </div>\n\n <!-- Grid -->\n <div class=\"grid-container\">\n <!-- Saving overlay -->\n @if (IsSaving) {\n <div class=\"saving-overlay\">\n <mj-loading [text]=\"SavingMessage\"></mj-loading>\n </div>\n }\n @if (IsLoading) {\n <mj-loading text=\"Loading data...\"></mj-loading>\n } @else if (HasError && HasData) {\n <div class=\"error-banner\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ ErrorMessage }}</span>\n <span class=\"fallback-note\">(Showing cached data)</span>\n </div>\n <mj-query-data-grid\n [ColumnConfigs]=\"GridColumnConfigs\"\n [Data]=\"GridData\"\n [ShowToolbar]=\"false\"\n [ShowRefresh]=\"false\"\n [PersistState]=\"false\"\n [SelectionMode]=\"'none'\"\n (EntityLinkClick)=\"OnEntityLinkClick($event)\"\n Height=\"100%\">\n </mj-query-data-grid>\n } @else if (HasError) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ ErrorMessage }}</p>\n </div>\n } @else {\n <mj-query-data-grid\n [ColumnConfigs]=\"GridColumnConfigs\"\n [Data]=\"GridData\"\n [ShowToolbar]=\"false\"\n [ShowRefresh]=\"false\"\n [PersistState]=\"false\"\n [SelectionMode]=\"'none'\"\n (EntityLinkClick)=\"OnEntityLinkClick($event)\"\n Height=\"100%\">\n </mj-query-data-grid>\n }\n </div>\n } @else if (spec.plan) {\n <!-- Plan-only view (no results yet) -->\n <div class=\"data-toolbar\">\n <div class=\"data-title\">\n <i class=\"fas fa-diagram-project\"></i>\n <span>{{ spec.title || 'Query Plan' }}</span>\n </div>\n </div>\n <div class=\"plan-content\">\n <mj-markdown\n [data]=\"spec.plan\"\n [enableMermaid]=\"true\"\n [enableHighlight]=\"true\"\n [enableCollapsibleHeadings]=\"false\"\n [enableSmartypants]=\"true\">\n </mj-markdown>\n </div>\n } @else {\n <!-- No data and no plan -->\n <div class=\"empty-state\">\n <i class=\"fas fa-inbox\"></i>\n <p>No data to display</p>\n </div>\n }\n } @else if (HasError) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ ErrorMessage }}</p>\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fas fa-inbox\"></i>\n <p>No data to display</p>\n </div>\n }\n\n <!-- Save Query Panel (slide-in) -->\n @if (ShowSaveDialog) {\n <mj-save-query-panel\n [QueryName]=\"spec?.title || 'Untitled Query'\"\n [QueryDescription]=\"''\"\n [SQL]=\"spec?.metadata?.sql || ''\"\n [Plan]=\"spec?.plan || ''\"\n (Saved)=\"OnQuerySaved($event)\"\n (Cancelled)=\"ShowSaveDialog = false\">\n </mj-save-query-panel>\n }\n</div>\n"]}
@@ -22,6 +22,7 @@ export declare class SaveQueryPanelComponent {
22
22
  QueryName: string;
23
23
  QueryDescription: string;
24
24
  SQL: string;
25
+ Plan: string;
25
26
  Saved: EventEmitter<SaveQueryResult>;
26
27
  Cancelled: EventEmitter<void>;
27
28
  categoryTree: TreeDropdownComponent;
@@ -52,6 +53,6 @@ export declare class SaveQueryPanelComponent {
52
53
  OnCancel(): void;
53
54
  private getEntityErrorMessage;
54
55
  static ɵfac: i0.ɵɵFactoryDeclaration<SaveQueryPanelComponent, never>;
55
- static ɵcmp: i0.ɵɵComponentDeclaration<SaveQueryPanelComponent, "mj-save-query-panel", never, { "QueryName": { "alias": "QueryName"; "required": false; }; "QueryDescription": { "alias": "QueryDescription"; "required": false; }; "SQL": { "alias": "SQL"; "required": false; }; }, { "Saved": "Saved"; "Cancelled": "Cancelled"; }, never, never, false, never>;
56
+ static ɵcmp: i0.ɵɵComponentDeclaration<SaveQueryPanelComponent, "mj-save-query-panel", never, { "QueryName": { "alias": "QueryName"; "required": false; }; "QueryDescription": { "alias": "QueryDescription"; "required": false; }; "SQL": { "alias": "SQL"; "required": false; }; "Plan": { "alias": "Plan"; "required": false; }; }, { "Saved": "Saved"; "Cancelled": "Cancelled"; }, never, never, false, never>;
56
57
  }
57
58
  //# sourceMappingURL=save-query-dialog.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"save-query-dialog.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/save-query-dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAsC,iBAAiB,EAAgB,MAAM,eAAe,CAAC;AAC5I,OAAO,EAAY,YAAY,EAA4B,MAAM,sBAAsB,CAAC;AAGxF,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;;AAEjE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,qBAwca,uBAAuB;IAsCtB,OAAO,CAAC,GAAG;IArCd,SAAS,SAAM;IACf,gBAAgB,SAAM;IACtB,GAAG,SAAM;IAER,KAAK,gCAAuC;IAC5C,SAAS,qBAA4B;IAEpB,YAAY,EAAG,qBAAqB,CAAC;IAGzD,IAAI,SAAM;IACV,WAAW,SAAM;IACjB,QAAQ,UAAS;IACjB,YAAY,SAAM;IAClB,SAAS,UAAS;IAGzB,OAAO,CAAC,kBAAkB,CAAuB;IAC1C,mBAAmB,EAAE,YAAY,GAAG,IAAI,CAAQ;IAGhD,kBAAkB,UAAS;IAC3B,wBAAwB,UAAS;IACjC,eAAe,SAAM;IACrB,mBAAmB,SAAM;IAChC,OAAO,CAAC,mBAAmB,CAAuB;IAElD,+CAA+C;IACxC,oBAAoB,EAAE,gBAAgB,CAO3C;gBAEkB,GAAG,EAAE,iBAAiB;IAE1C,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED,QAAQ,IAAI,IAAI;IAaT,WAAW,IAAI,IAAI;IAYnB,iBAAiB,CAAC,SAAS,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,IAAI,GAAG,IAAI;IAchE,mBAAmB,IAAI,IAAI;IAQ3B,oBAAoB,IAAI,IAAI;IAQ5B,0BAA0B,CAAC,SAAS,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,IAAI,GAAG,IAAI;IAUnE,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA6D/B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAoD7B,QAAQ,IAAI,IAAI;IAWvB,OAAO,CAAC,qBAAqB;yCAzOlB,uBAAuB;2CAAvB,uBAAuB;CAgPnC"}
1
+ {"version":3,"file":"save-query-dialog.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/save-query-dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAsC,iBAAiB,EAAgB,MAAM,eAAe,CAAC;AAC5I,OAAO,EAAY,YAAY,EAA4B,MAAM,sBAAsB,CAAC;AAGxF,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;;AAEjE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,qBAwca,uBAAuB;IAuCtB,OAAO,CAAC,GAAG;IAtCd,SAAS,SAAM;IACf,gBAAgB,SAAM;IACtB,GAAG,SAAM;IACT,IAAI,SAAM;IAET,KAAK,gCAAuC;IAC5C,SAAS,qBAA4B;IAEpB,YAAY,EAAG,qBAAqB,CAAC;IAGzD,IAAI,SAAM;IACV,WAAW,SAAM;IACjB,QAAQ,UAAS;IACjB,YAAY,SAAM;IAClB,SAAS,UAAS;IAGzB,OAAO,CAAC,kBAAkB,CAAuB;IAC1C,mBAAmB,EAAE,YAAY,GAAG,IAAI,CAAQ;IAGhD,kBAAkB,UAAS;IAC3B,wBAAwB,UAAS;IACjC,eAAe,SAAM;IACrB,mBAAmB,SAAM;IAChC,OAAO,CAAC,mBAAmB,CAAuB;IAElD,+CAA+C;IACxC,oBAAoB,EAAE,gBAAgB,CAO3C;gBAEkB,GAAG,EAAE,iBAAiB;IAE1C,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED,QAAQ,IAAI,IAAI;IAaT,WAAW,IAAI,IAAI;IAYnB,iBAAiB,CAAC,SAAS,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,IAAI,GAAG,IAAI;IAchE,mBAAmB,IAAI,IAAI;IAQ3B,oBAAoB,IAAI,IAAI;IAQ5B,0BAA0B,CAAC,SAAS,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,IAAI,GAAG,IAAI;IAUnE,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA6D/B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAuD7B,QAAQ,IAAI,IAAI;IAWvB,OAAO,CAAC,qBAAqB;yCA7OlB,uBAAuB;2CAAvB,uBAAuB;CAoPnC"}
@@ -103,6 +103,7 @@ export class SaveQueryPanelComponent {
103
103
  QueryName = '';
104
104
  QueryDescription = '';
105
105
  SQL = '';
106
+ Plan = '';
106
107
  Saved = new EventEmitter();
107
108
  Cancelled = new EventEmitter();
108
109
  categoryTree;
@@ -266,6 +267,9 @@ export class SaveQueryPanelComponent {
266
267
  if (this.Description?.trim()) {
267
268
  query.Description = this.Description.trim();
268
269
  }
270
+ if (this.Plan?.trim()) {
271
+ query.TechnicalDescription = this.Plan.trim();
272
+ }
269
273
  if (this.selectedCategoryId) {
270
274
  query.CategoryID = this.selectedCategoryId;
271
275
  }
@@ -325,7 +329,7 @@ export class SaveQueryPanelComponent {
325
329
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.categoryTree = _t.first);
326
330
  } }, hostBindings: function SaveQueryPanelComponent_HostBindings(rf, ctx) { if (rf & 1) {
327
331
  i0.ɵɵlistener("keydown.escape", function SaveQueryPanelComponent_keydown_escape_HostBindingHandler() { return ctx.OnEscapeKey(); }, i0.ɵɵresolveDocument);
328
- } }, inputs: { QueryName: "QueryName", QueryDescription: "QueryDescription", SQL: "SQL" }, outputs: { Saved: "Saved", Cancelled: "Cancelled" }, standalone: false, decls: 36, vars: 17, consts: [["categoryTree", ""], [1, "sqp-backdrop", 3, "click"], [1, "sqp-panel"], [1, "sqp-header"], [1, "sqp-title-group"], [1, "fa-solid", "fa-save", "sqp-title-icon"], [1, "sqp-title"], [1, "sqp-close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "sqp-body"], [1, "sqp-field"], [1, "sqp-label"], [1, "sqp-required"], ["type", "text", "placeholder", "Query name", 1, "sqp-input", 3, "ngModelChange", "keydown.enter", "ngModel"], [1, "sqp-label-row"], ["title", "Create new category", 1, "sqp-add-btn"], [3, "SelectionChange", "BranchConfig", "SelectionMode", "SelectableTypes", "Placeholder", "Value"], [1, "sqp-create-category"], ["placeholder", "Optional description", "rows", "3", 1, "sqp-textarea", 3, "ngModelChange", "ngModel"], [1, "sqp-error"], [1, "sqp-footer"], [1, "sqp-btn", "sqp-btn-save", 3, "click", "disabled"], [1, "sqp-btn", "sqp-btn-cancel", 3, "click", "disabled"], ["title", "Create new category", 1, "sqp-add-btn", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "sqp-create-header"], [1, "fa-solid", "fa-folder-plus"], [1, "sqp-create-fields"], ["type", "text", "placeholder", "Category name", 1, "sqp-input", 3, "ngModelChange", "keydown.enter", "keydown.escape", "ngModel"], [1, "sqp-create-parent"], [1, "sqp-sublabel"], [3, "SelectionChange", "BranchConfig", "SelectionMode", "SelectableTypes", "Placeholder"], [1, "sqp-create-actions"], [1, "sqp-btn", "sqp-btn-create", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-check"], [1, "sqp-btn", "sqp-btn-cancel-create", 3, "click", "disabled"], [1, "sqp-inline-error"], [1, "fa-solid", "fa-exclamation-circle"], [1, "fa-solid", "fa-save"]], template: function SaveQueryPanelComponent_Template(rf, ctx) { if (rf & 1) {
332
+ } }, inputs: { QueryName: "QueryName", QueryDescription: "QueryDescription", SQL: "SQL", Plan: "Plan" }, outputs: { Saved: "Saved", Cancelled: "Cancelled" }, standalone: false, decls: 36, vars: 17, consts: [["categoryTree", ""], [1, "sqp-backdrop", 3, "click"], [1, "sqp-panel"], [1, "sqp-header"], [1, "sqp-title-group"], [1, "fa-solid", "fa-save", "sqp-title-icon"], [1, "sqp-title"], [1, "sqp-close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "sqp-body"], [1, "sqp-field"], [1, "sqp-label"], [1, "sqp-required"], ["type", "text", "placeholder", "Query name", 1, "sqp-input", 3, "ngModelChange", "keydown.enter", "ngModel"], [1, "sqp-label-row"], ["title", "Create new category", 1, "sqp-add-btn"], [3, "SelectionChange", "BranchConfig", "SelectionMode", "SelectableTypes", "Placeholder", "Value"], [1, "sqp-create-category"], ["placeholder", "Optional description", "rows", "3", 1, "sqp-textarea", 3, "ngModelChange", "ngModel"], [1, "sqp-error"], [1, "sqp-footer"], [1, "sqp-btn", "sqp-btn-save", 3, "click", "disabled"], [1, "sqp-btn", "sqp-btn-cancel", 3, "click", "disabled"], ["title", "Create new category", 1, "sqp-add-btn", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "sqp-create-header"], [1, "fa-solid", "fa-folder-plus"], [1, "sqp-create-fields"], ["type", "text", "placeholder", "Category name", 1, "sqp-input", 3, "ngModelChange", "keydown.enter", "keydown.escape", "ngModel"], [1, "sqp-create-parent"], [1, "sqp-sublabel"], [3, "SelectionChange", "BranchConfig", "SelectionMode", "SelectableTypes", "Placeholder"], [1, "sqp-create-actions"], [1, "sqp-btn", "sqp-btn-create", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-check"], [1, "sqp-btn", "sqp-btn-cancel-create", 3, "click", "disabled"], [1, "sqp-inline-error"], [1, "fa-solid", "fa-exclamation-circle"], [1, "fa-solid", "fa-save"]], template: function SaveQueryPanelComponent_Template(rf, ctx) { if (rf & 1) {
329
333
  const _r1 = i0.ɵɵgetCurrentView();
330
334
  i0.ɵɵelementStart(0, "div", 1);
331
335
  i0.ɵɵlistener("click", function SaveQueryPanelComponent_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnCancel()); });
@@ -548,6 +552,8 @@ export class SaveQueryPanelComponent {
548
552
  type: Input
549
553
  }], SQL: [{
550
554
  type: Input
555
+ }], Plan: [{
556
+ type: Input
551
557
  }], Saved: [{
552
558
  type: Output
553
559
  }], Cancelled: [{
@@ -1 +1 @@
1
- {"version":3,"file":"save-query-dialog.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/save-query-dialog.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, ViewChild, ChangeDetectionStrategy, ChangeDetectorRef, HostListener } from '@angular/core';\nimport { Metadata, CompositeKey, KeyValuePair, BaseEntity } from '@memberjunction/core';\nimport { MJQueryEntity, MJQueryCategoryEntity } from '@memberjunction/core-entities';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\nimport { TreeBranchConfig, TreeNode } from '@memberjunction/ng-trees';\nimport { TreeDropdownComponent } from '@memberjunction/ng-trees';\n\n/**\n * Result emitted when a query is successfully saved\n */\nexport interface SaveQueryResult {\n queryId: string;\n queryName: string;\n}\n\n/**\n * Slide-in panel for saving an ad-hoc SQL query as a reusable MJ Query record.\n * Pre-populates name from the artifact title and provides a tree dropdown\n * for selecting a query category, with inline category creation.\n *\n * Follows the CreateAgentSlideInComponent pattern for slide-in UX.\n */\n@Component({\n standalone: false,\n selector: 'mj-save-query-panel',\n template: `\n <!-- Backdrop -->\n <div class=\"sqp-backdrop\" [class.sqp-visible]=\"IsVisible\" (click)=\"OnCancel()\"></div>\n\n <!-- Slide panel -->\n <div class=\"sqp-panel\" [class.sqp-visible]=\"IsVisible\">\n <!-- Header -->\n <div class=\"sqp-header\">\n <div class=\"sqp-title-group\">\n <i class=\"fa-solid fa-save sqp-title-icon\"></i>\n <h2 class=\"sqp-title\">Save Query</h2>\n </div>\n <button class=\"sqp-close-btn\" (click)=\"OnCancel()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"sqp-body\">\n <!-- Name -->\n <div class=\"sqp-field\">\n <label class=\"sqp-label\">\n Name <span class=\"sqp-required\">*</span>\n </label>\n <input\n type=\"text\"\n class=\"sqp-input\"\n [(ngModel)]=\"Name\"\n placeholder=\"Query name\"\n (keydown.enter)=\"OnSave()\">\n </div>\n\n <!-- Category -->\n <div class=\"sqp-field\">\n <div class=\"sqp-label-row\">\n <label class=\"sqp-label\">Category</label>\n @if (!IsCreatingCategory) {\n <button class=\"sqp-add-btn\" (click)=\"StartCreateCategory()\" title=\"Create new category\">\n <i class=\"fa-solid fa-plus\"></i> New\n </button>\n }\n </div>\n\n <mj-tree-dropdown\n #categoryTree\n [BranchConfig]=\"CategoryBranchConfig\"\n [SelectionMode]=\"'single'\"\n [SelectableTypes]=\"'branch'\"\n [Placeholder]=\"'Select a category (optional)'\"\n [Value]=\"SelectedCategoryKey\"\n (SelectionChange)=\"OnCategoryChanged($event)\">\n </mj-tree-dropdown>\n\n <!-- Inline create category form -->\n @if (IsCreatingCategory) {\n <div class=\"sqp-create-category\">\n <div class=\"sqp-create-header\">\n <i class=\"fa-solid fa-folder-plus\"></i>\n <span>New Category</span>\n </div>\n <div class=\"sqp-create-fields\">\n <input\n type=\"text\"\n class=\"sqp-input\"\n [(ngModel)]=\"NewCategoryName\"\n placeholder=\"Category name\"\n (keydown.enter)=\"CreateCategory()\"\n (keydown.escape)=\"CancelCreateCategory()\">\n <div class=\"sqp-create-parent\">\n <label class=\"sqp-sublabel\">Parent (optional)</label>\n <mj-tree-dropdown\n [BranchConfig]=\"CategoryBranchConfig\"\n [SelectionMode]=\"'single'\"\n [SelectableTypes]=\"'branch'\"\n [Placeholder]=\"'None (top level)'\"\n (SelectionChange)=\"OnNewCategoryParentChanged($event)\">\n </mj-tree-dropdown>\n </div>\n </div>\n <div class=\"sqp-create-actions\">\n <button class=\"sqp-btn sqp-btn-create\"\n (click)=\"CreateCategory()\"\n [disabled]=\"!NewCategoryName.trim() || IsCreatingCategorySaving\">\n @if (IsCreatingCategorySaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n }\n {{ IsCreatingCategorySaving ? 'Creating...' : 'Create' }}\n </button>\n <button class=\"sqp-btn sqp-btn-cancel-create\"\n (click)=\"CancelCreateCategory()\"\n [disabled]=\"IsCreatingCategorySaving\">\n Cancel\n </button>\n </div>\n @if (CreateCategoryError) {\n <div class=\"sqp-inline-error\">{{ CreateCategoryError }}</div>\n }\n </div>\n }\n </div>\n\n <!-- Description -->\n <div class=\"sqp-field\">\n <label class=\"sqp-label\">Description</label>\n <textarea\n class=\"sqp-textarea\"\n [(ngModel)]=\"Description\"\n placeholder=\"Optional description\"\n rows=\"3\">\n </textarea>\n </div>\n\n @if (ErrorMessage) {\n <div class=\"sqp-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ ErrorMessage }}\n </div>\n }\n </div>\n\n <!-- Footer -->\n <div class=\"sqp-footer\">\n <button class=\"sqp-btn sqp-btn-save\"\n (click)=\"OnSave()\"\n [disabled]=\"!CanSave || IsSaving\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else {\n <i class=\"fa-solid fa-save\"></i> Save Query\n }\n </button>\n <button class=\"sqp-btn sqp-btn-cancel\"\n (click)=\"OnCancel()\"\n [disabled]=\"IsSaving\">\n Cancel\n </button>\n </div>\n </div>\n `,\n styles: [`\n /* Backdrop */\n .sqp-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0);\n z-index: 1000;\n transition: background 0.3s ease;\n pointer-events: none;\n }\n .sqp-backdrop.sqp-visible {\n background: rgba(0, 0, 0, 0.3);\n pointer-events: auto;\n }\n\n /* Panel — uses right offset instead of transform to avoid creating\n a new containing block that breaks position:fixed children\n (e.g., the tree-dropdown popup). */\n .sqp-panel {\n position: fixed;\n top: 0;\n right: -440px;\n height: 100vh;\n width: 440px;\n background: var(--card-background, #ffffff);\n box-shadow: -8px 0 32px rgba(0, 0, 0, 0.12);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n transition: right 0.3s cubic-bezier(0.16, 1, 0.3, 1);\n }\n .sqp-panel.sqp-visible {\n right: 0;\n }\n\n /* Header */\n .sqp-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px 16px;\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n flex-shrink: 0;\n }\n .sqp-title-group {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n .sqp-title-icon {\n font-size: 20px;\n color: #5c6bc0;\n }\n .sqp-title {\n margin: 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n }\n .sqp-close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n background: none;\n border: none;\n border-radius: 8px;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.15s ease;\n font-size: 16px;\n flex-shrink: 0;\n }\n .sqp-close-btn:hover {\n background: var(--hover-background, #f3f4f6);\n color: var(--text-primary, #1f2937);\n }\n\n /* Body */\n .sqp-body {\n flex: 1;\n overflow-y: auto;\n padding: 24px;\n }\n\n /* Fields */\n .sqp-field {\n margin-bottom: 20px;\n }\n .sqp-label-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 6px;\n }\n .sqp-label {\n display: block;\n margin-bottom: 6px;\n font-weight: 600;\n font-size: 13px;\n color: var(--text-primary, #374151);\n }\n .sqp-label-row .sqp-label {\n margin-bottom: 0;\n }\n .sqp-sublabel {\n display: block;\n margin-bottom: 4px;\n font-weight: 500;\n font-size: 12px;\n color: #6b7280;\n }\n .sqp-required {\n color: #dc2626;\n }\n .sqp-input {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n font-size: 14px;\n color: #1f2937;\n background: #fff;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n box-sizing: border-box;\n }\n .sqp-input:focus {\n outline: none;\n border-color: #5c6bc0;\n box-shadow: 0 0 0 3px rgba(92, 107, 192, 0.15);\n }\n .sqp-input::placeholder {\n color: #9ca3af;\n }\n .sqp-textarea {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n font-size: 14px;\n color: #1f2937;\n background: #fff;\n resize: vertical;\n font-family: inherit;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n box-sizing: border-box;\n }\n .sqp-textarea:focus {\n outline: none;\n border-color: #5c6bc0;\n box-shadow: 0 0 0 3px rgba(92, 107, 192, 0.15);\n }\n .sqp-textarea::placeholder {\n color: #9ca3af;\n }\n\n /* Add category button */\n .sqp-add-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 10px;\n background: none;\n border: 1px solid #d1d5db;\n border-radius: 4px;\n font-size: 12px;\n color: #5c6bc0;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .sqp-add-btn:hover {\n background: #eef2ff;\n border-color: #5c6bc0;\n }\n\n /* Inline create category */\n .sqp-create-category {\n margin-top: 12px;\n padding: 14px;\n background: #f8fafc;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n }\n .sqp-create-header {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n font-weight: 600;\n color: #475569;\n margin-bottom: 10px;\n }\n .sqp-create-header i {\n color: #5c6bc0;\n }\n .sqp-create-fields {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n .sqp-create-parent {\n margin-top: 2px;\n }\n .sqp-create-actions {\n display: flex;\n gap: 8px;\n margin-top: 12px;\n }\n .sqp-inline-error {\n margin-top: 8px;\n font-size: 12px;\n color: #dc2626;\n }\n\n /* Buttons */\n .sqp-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .sqp-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n .sqp-btn-save {\n background: #5c6bc0;\n color: #fff;\n padding: 10px 20px;\n font-size: 14px;\n }\n .sqp-btn-save:hover:not(:disabled) {\n background: #3f51b5;\n }\n .sqp-btn-cancel {\n background: none;\n border: 1px solid #d1d5db;\n color: #6b7280;\n padding: 10px 20px;\n font-size: 14px;\n }\n .sqp-btn-cancel:hover:not(:disabled) {\n background: #f3f4f6;\n color: #374151;\n }\n .sqp-btn-create {\n background: #16a34a;\n color: #fff;\n }\n .sqp-btn-create:hover:not(:disabled) {\n background: #15803d;\n }\n .sqp-btn-cancel-create {\n background: none;\n color: #6b7280;\n }\n .sqp-btn-cancel-create:hover:not(:disabled) {\n color: #374151;\n background: #f1f5f9;\n }\n\n /* Footer */\n .sqp-footer {\n display: flex;\n gap: 10px;\n padding: 16px 24px;\n border-top: 1px solid var(--border-color, #e5e7eb);\n flex-shrink: 0;\n }\n\n /* Error */\n .sqp-error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 14px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 6px;\n color: #dc2626;\n font-size: 13px;\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .sqp-panel {\n width: 100% !important;\n right: -100%;\n }\n .sqp-panel.sqp-visible {\n right: 0;\n }\n .sqp-header {\n padding: 16px 20px 12px;\n }\n .sqp-body {\n padding: 16px;\n }\n .sqp-footer {\n padding: 12px 16px;\n }\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class SaveQueryPanelComponent {\n @Input() QueryName = '';\n @Input() QueryDescription = '';\n @Input() SQL = '';\n\n @Output() Saved = new EventEmitter<SaveQueryResult>();\n @Output() Cancelled = new EventEmitter<void>();\n\n @ViewChild('categoryTree') categoryTree!: TreeDropdownComponent;\n\n // Form state\n public Name = '';\n public Description = '';\n public IsSaving = false;\n public ErrorMessage = '';\n public IsVisible = false;\n\n // Category selection\n private selectedCategoryId: string | null = null;\n public SelectedCategoryKey: CompositeKey | null = null;\n\n // Inline category creation\n public IsCreatingCategory = false;\n public IsCreatingCategorySaving = false;\n public NewCategoryName = '';\n public CreateCategoryError = '';\n private newCategoryParentId: string | null = null;\n\n /** Tree config for query category hierarchy */\n public CategoryBranchConfig: TreeBranchConfig = {\n EntityName: 'MJ: Query Categories',\n DisplayField: 'Name',\n IDField: 'ID',\n ParentIDField: 'ParentID',\n DefaultIcon: 'fa-solid fa-folder',\n OrderBy: 'Name ASC'\n };\n\n constructor(private cdr: ChangeDetectorRef) {}\n\n public get CanSave(): boolean {\n return !!this.Name?.trim();\n }\n\n ngOnInit(): void {\n // Sync input values\n this.Name = this.QueryName;\n this.Description = this.QueryDescription;\n\n // Trigger slide-in on next microtask (ensures DOM is ready)\n Promise.resolve().then(() => {\n this.IsVisible = true;\n this.cdr.markForCheck();\n });\n }\n\n @HostListener('document:keydown.escape')\n public OnEscapeKey(): void {\n if (this.IsCreatingCategory) {\n this.CancelCreateCategory();\n } else if (!this.IsSaving) {\n this.OnCancel();\n }\n }\n\n // =========================================================================\n // Category Selection\n // =========================================================================\n\n public OnCategoryChanged(selection: TreeNode | TreeNode[] | null): void {\n if (!selection) {\n this.selectedCategoryId = null;\n } else if (Array.isArray(selection)) {\n this.selectedCategoryId = selection.length > 0 ? selection[0].ID : null;\n } else {\n this.selectedCategoryId = selection.ID;\n }\n }\n\n // =========================================================================\n // Inline Category Creation\n // =========================================================================\n\n public StartCreateCategory(): void {\n this.IsCreatingCategory = true;\n this.NewCategoryName = '';\n this.newCategoryParentId = null;\n this.CreateCategoryError = '';\n this.cdr.markForCheck();\n }\n\n public CancelCreateCategory(): void {\n this.IsCreatingCategory = false;\n this.NewCategoryName = '';\n this.newCategoryParentId = null;\n this.CreateCategoryError = '';\n this.cdr.markForCheck();\n }\n\n public OnNewCategoryParentChanged(selection: TreeNode | TreeNode[] | null): void {\n if (!selection) {\n this.newCategoryParentId = null;\n } else if (Array.isArray(selection)) {\n this.newCategoryParentId = selection.length > 0 ? selection[0].ID : null;\n } else {\n this.newCategoryParentId = selection.ID;\n }\n }\n\n public async CreateCategory(): Promise<void> {\n const name = this.NewCategoryName.trim();\n if (!name || this.IsCreatingCategorySaving) return;\n\n this.IsCreatingCategorySaving = true;\n this.CreateCategoryError = '';\n this.cdr.markForCheck();\n\n try {\n const md = new Metadata();\n const category = await md.GetEntityObject<MJQueryCategoryEntity>('MJ: Query Categories');\n\n category.Name = name;\n category.UserID = md.CurrentUser.ID;\n if (this.newCategoryParentId) {\n category.ParentID = this.newCategoryParentId;\n }\n\n const saved = await category.Save();\n if (saved) {\n MJNotificationService.Instance.CreateSimpleNotification(`Category \"${name}\" created`, 'success', 2500);\n\n // Refresh core metadata so Metadata.QueryCategories is up to date\n await md.Refresh();\n\n // Refresh tree to pick up the new category\n await this.categoryTree.Refresh();\n\n // Auto-select the newly created category.\n // Must use detectChanges() (not markForCheck) to immediately propagate\n // the new Value input to the tree dropdown, since this panel uses OnPush.\n const newKey = new CompositeKey([new KeyValuePair('ID', category.ID)]);\n this.SelectedCategoryKey = newKey;\n this.selectedCategoryId = category.ID;\n this.cdr.detectChanges();\n\n // Collapse the create form\n this.IsCreatingCategory = false;\n this.NewCategoryName = '';\n this.newCategoryParentId = null;\n } else {\n const errorMsg = this.getEntityErrorMessage(category, 'create category');\n this.CreateCategoryError = errorMsg;\n MJNotificationService.Instance.CreateSimpleNotification(errorMsg, 'error', 5000);\n console.error('Failed to create category:', category.LatestResult);\n }\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : 'Failed to create category';\n this.CreateCategoryError = errorMsg;\n MJNotificationService.Instance.CreateSimpleNotification(errorMsg, 'error', 5000);\n console.error('Error creating category:', error);\n } finally {\n this.IsCreatingCategorySaving = false;\n this.cdr.markForCheck();\n }\n }\n\n // =========================================================================\n // Save / Cancel\n // =========================================================================\n\n public async OnSave(): Promise<void> {\n if (!this.CanSave || this.IsSaving) return;\n\n this.IsSaving = true;\n this.ErrorMessage = '';\n this.cdr.markForCheck();\n\n try {\n const md = new Metadata();\n const query = await md.GetEntityObject<MJQueryEntity>('MJ: Queries');\n\n query.Name = this.Name.trim();\n query.SQL = this.SQL;\n query.Status = 'Approved';\n\n if (this.Description?.trim()) {\n query.Description = this.Description.trim();\n }\n if (this.selectedCategoryId) {\n query.CategoryID = this.selectedCategoryId;\n }\n\n const saved = await query.Save();\n if (saved) {\n MJNotificationService.Instance.CreateSimpleNotification(`Query \"${query.Name}\" saved`, 'success', 2500);\n\n // Animate out, then emit\n this.IsVisible = false;\n this.cdr.markForCheck();\n setTimeout(() => {\n this.Saved.emit({\n queryId: query.ID,\n queryName: query.Name\n });\n }, 300);\n } else {\n const errorMsg = this.getEntityErrorMessage(query, 'save query');\n this.ErrorMessage = errorMsg;\n MJNotificationService.Instance.CreateSimpleNotification(errorMsg, 'error', 5000);\n console.error('Failed to save query:', query.LatestResult);\n }\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : 'An unexpected error occurred';\n this.ErrorMessage = errorMsg;\n MJNotificationService.Instance.CreateSimpleNotification(errorMsg, 'error', 5000);\n console.error('Error saving query:', error);\n } finally {\n this.IsSaving = false;\n this.cdr.markForCheck();\n }\n }\n\n public OnCancel(): void {\n if (this.IsSaving) return;\n this.IsVisible = false;\n this.cdr.markForCheck();\n setTimeout(() => this.Cancelled.emit(), 300);\n }\n\n // =========================================================================\n // Helpers\n // =========================================================================\n\n private getEntityErrorMessage(entity: BaseEntity, operation: string): string {\n const result = entity.LatestResult;\n if (result?.Message) {\n return result.Message;\n }\n return `Failed to ${operation}. Please try again.`;\n }\n}\n"]}
1
+ {"version":3,"file":"save-query-dialog.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/save-query-dialog.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, ViewChild, ChangeDetectionStrategy, ChangeDetectorRef, HostListener } from '@angular/core';\nimport { Metadata, CompositeKey, KeyValuePair, BaseEntity } from '@memberjunction/core';\nimport { MJQueryEntity, MJQueryCategoryEntity } from '@memberjunction/core-entities';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\nimport { TreeBranchConfig, TreeNode } from '@memberjunction/ng-trees';\nimport { TreeDropdownComponent } from '@memberjunction/ng-trees';\n\n/**\n * Result emitted when a query is successfully saved\n */\nexport interface SaveQueryResult {\n queryId: string;\n queryName: string;\n}\n\n/**\n * Slide-in panel for saving an ad-hoc SQL query as a reusable MJ Query record.\n * Pre-populates name from the artifact title and provides a tree dropdown\n * for selecting a query category, with inline category creation.\n *\n * Follows the CreateAgentSlideInComponent pattern for slide-in UX.\n */\n@Component({\n standalone: false,\n selector: 'mj-save-query-panel',\n template: `\n <!-- Backdrop -->\n <div class=\"sqp-backdrop\" [class.sqp-visible]=\"IsVisible\" (click)=\"OnCancel()\"></div>\n\n <!-- Slide panel -->\n <div class=\"sqp-panel\" [class.sqp-visible]=\"IsVisible\">\n <!-- Header -->\n <div class=\"sqp-header\">\n <div class=\"sqp-title-group\">\n <i class=\"fa-solid fa-save sqp-title-icon\"></i>\n <h2 class=\"sqp-title\">Save Query</h2>\n </div>\n <button class=\"sqp-close-btn\" (click)=\"OnCancel()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"sqp-body\">\n <!-- Name -->\n <div class=\"sqp-field\">\n <label class=\"sqp-label\">\n Name <span class=\"sqp-required\">*</span>\n </label>\n <input\n type=\"text\"\n class=\"sqp-input\"\n [(ngModel)]=\"Name\"\n placeholder=\"Query name\"\n (keydown.enter)=\"OnSave()\">\n </div>\n\n <!-- Category -->\n <div class=\"sqp-field\">\n <div class=\"sqp-label-row\">\n <label class=\"sqp-label\">Category</label>\n @if (!IsCreatingCategory) {\n <button class=\"sqp-add-btn\" (click)=\"StartCreateCategory()\" title=\"Create new category\">\n <i class=\"fa-solid fa-plus\"></i> New\n </button>\n }\n </div>\n\n <mj-tree-dropdown\n #categoryTree\n [BranchConfig]=\"CategoryBranchConfig\"\n [SelectionMode]=\"'single'\"\n [SelectableTypes]=\"'branch'\"\n [Placeholder]=\"'Select a category (optional)'\"\n [Value]=\"SelectedCategoryKey\"\n (SelectionChange)=\"OnCategoryChanged($event)\">\n </mj-tree-dropdown>\n\n <!-- Inline create category form -->\n @if (IsCreatingCategory) {\n <div class=\"sqp-create-category\">\n <div class=\"sqp-create-header\">\n <i class=\"fa-solid fa-folder-plus\"></i>\n <span>New Category</span>\n </div>\n <div class=\"sqp-create-fields\">\n <input\n type=\"text\"\n class=\"sqp-input\"\n [(ngModel)]=\"NewCategoryName\"\n placeholder=\"Category name\"\n (keydown.enter)=\"CreateCategory()\"\n (keydown.escape)=\"CancelCreateCategory()\">\n <div class=\"sqp-create-parent\">\n <label class=\"sqp-sublabel\">Parent (optional)</label>\n <mj-tree-dropdown\n [BranchConfig]=\"CategoryBranchConfig\"\n [SelectionMode]=\"'single'\"\n [SelectableTypes]=\"'branch'\"\n [Placeholder]=\"'None (top level)'\"\n (SelectionChange)=\"OnNewCategoryParentChanged($event)\">\n </mj-tree-dropdown>\n </div>\n </div>\n <div class=\"sqp-create-actions\">\n <button class=\"sqp-btn sqp-btn-create\"\n (click)=\"CreateCategory()\"\n [disabled]=\"!NewCategoryName.trim() || IsCreatingCategorySaving\">\n @if (IsCreatingCategorySaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n }\n {{ IsCreatingCategorySaving ? 'Creating...' : 'Create' }}\n </button>\n <button class=\"sqp-btn sqp-btn-cancel-create\"\n (click)=\"CancelCreateCategory()\"\n [disabled]=\"IsCreatingCategorySaving\">\n Cancel\n </button>\n </div>\n @if (CreateCategoryError) {\n <div class=\"sqp-inline-error\">{{ CreateCategoryError }}</div>\n }\n </div>\n }\n </div>\n\n <!-- Description -->\n <div class=\"sqp-field\">\n <label class=\"sqp-label\">Description</label>\n <textarea\n class=\"sqp-textarea\"\n [(ngModel)]=\"Description\"\n placeholder=\"Optional description\"\n rows=\"3\">\n </textarea>\n </div>\n\n @if (ErrorMessage) {\n <div class=\"sqp-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ ErrorMessage }}\n </div>\n }\n </div>\n\n <!-- Footer -->\n <div class=\"sqp-footer\">\n <button class=\"sqp-btn sqp-btn-save\"\n (click)=\"OnSave()\"\n [disabled]=\"!CanSave || IsSaving\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else {\n <i class=\"fa-solid fa-save\"></i> Save Query\n }\n </button>\n <button class=\"sqp-btn sqp-btn-cancel\"\n (click)=\"OnCancel()\"\n [disabled]=\"IsSaving\">\n Cancel\n </button>\n </div>\n </div>\n `,\n styles: [`\n /* Backdrop */\n .sqp-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0);\n z-index: 1000;\n transition: background 0.3s ease;\n pointer-events: none;\n }\n .sqp-backdrop.sqp-visible {\n background: rgba(0, 0, 0, 0.3);\n pointer-events: auto;\n }\n\n /* Panel — uses right offset instead of transform to avoid creating\n a new containing block that breaks position:fixed children\n (e.g., the tree-dropdown popup). */\n .sqp-panel {\n position: fixed;\n top: 0;\n right: -440px;\n height: 100vh;\n width: 440px;\n background: var(--card-background, #ffffff);\n box-shadow: -8px 0 32px rgba(0, 0, 0, 0.12);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n transition: right 0.3s cubic-bezier(0.16, 1, 0.3, 1);\n }\n .sqp-panel.sqp-visible {\n right: 0;\n }\n\n /* Header */\n .sqp-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px 16px;\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n flex-shrink: 0;\n }\n .sqp-title-group {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n .sqp-title-icon {\n font-size: 20px;\n color: #5c6bc0;\n }\n .sqp-title {\n margin: 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n }\n .sqp-close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n background: none;\n border: none;\n border-radius: 8px;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.15s ease;\n font-size: 16px;\n flex-shrink: 0;\n }\n .sqp-close-btn:hover {\n background: var(--hover-background, #f3f4f6);\n color: var(--text-primary, #1f2937);\n }\n\n /* Body */\n .sqp-body {\n flex: 1;\n overflow-y: auto;\n padding: 24px;\n }\n\n /* Fields */\n .sqp-field {\n margin-bottom: 20px;\n }\n .sqp-label-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 6px;\n }\n .sqp-label {\n display: block;\n margin-bottom: 6px;\n font-weight: 600;\n font-size: 13px;\n color: var(--text-primary, #374151);\n }\n .sqp-label-row .sqp-label {\n margin-bottom: 0;\n }\n .sqp-sublabel {\n display: block;\n margin-bottom: 4px;\n font-weight: 500;\n font-size: 12px;\n color: #6b7280;\n }\n .sqp-required {\n color: #dc2626;\n }\n .sqp-input {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n font-size: 14px;\n color: #1f2937;\n background: #fff;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n box-sizing: border-box;\n }\n .sqp-input:focus {\n outline: none;\n border-color: #5c6bc0;\n box-shadow: 0 0 0 3px rgba(92, 107, 192, 0.15);\n }\n .sqp-input::placeholder {\n color: #9ca3af;\n }\n .sqp-textarea {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n font-size: 14px;\n color: #1f2937;\n background: #fff;\n resize: vertical;\n font-family: inherit;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n box-sizing: border-box;\n }\n .sqp-textarea:focus {\n outline: none;\n border-color: #5c6bc0;\n box-shadow: 0 0 0 3px rgba(92, 107, 192, 0.15);\n }\n .sqp-textarea::placeholder {\n color: #9ca3af;\n }\n\n /* Add category button */\n .sqp-add-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 10px;\n background: none;\n border: 1px solid #d1d5db;\n border-radius: 4px;\n font-size: 12px;\n color: #5c6bc0;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .sqp-add-btn:hover {\n background: #eef2ff;\n border-color: #5c6bc0;\n }\n\n /* Inline create category */\n .sqp-create-category {\n margin-top: 12px;\n padding: 14px;\n background: #f8fafc;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n }\n .sqp-create-header {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n font-weight: 600;\n color: #475569;\n margin-bottom: 10px;\n }\n .sqp-create-header i {\n color: #5c6bc0;\n }\n .sqp-create-fields {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n .sqp-create-parent {\n margin-top: 2px;\n }\n .sqp-create-actions {\n display: flex;\n gap: 8px;\n margin-top: 12px;\n }\n .sqp-inline-error {\n margin-top: 8px;\n font-size: 12px;\n color: #dc2626;\n }\n\n /* Buttons */\n .sqp-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .sqp-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n .sqp-btn-save {\n background: #5c6bc0;\n color: #fff;\n padding: 10px 20px;\n font-size: 14px;\n }\n .sqp-btn-save:hover:not(:disabled) {\n background: #3f51b5;\n }\n .sqp-btn-cancel {\n background: none;\n border: 1px solid #d1d5db;\n color: #6b7280;\n padding: 10px 20px;\n font-size: 14px;\n }\n .sqp-btn-cancel:hover:not(:disabled) {\n background: #f3f4f6;\n color: #374151;\n }\n .sqp-btn-create {\n background: #16a34a;\n color: #fff;\n }\n .sqp-btn-create:hover:not(:disabled) {\n background: #15803d;\n }\n .sqp-btn-cancel-create {\n background: none;\n color: #6b7280;\n }\n .sqp-btn-cancel-create:hover:not(:disabled) {\n color: #374151;\n background: #f1f5f9;\n }\n\n /* Footer */\n .sqp-footer {\n display: flex;\n gap: 10px;\n padding: 16px 24px;\n border-top: 1px solid var(--border-color, #e5e7eb);\n flex-shrink: 0;\n }\n\n /* Error */\n .sqp-error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 14px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 6px;\n color: #dc2626;\n font-size: 13px;\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .sqp-panel {\n width: 100% !important;\n right: -100%;\n }\n .sqp-panel.sqp-visible {\n right: 0;\n }\n .sqp-header {\n padding: 16px 20px 12px;\n }\n .sqp-body {\n padding: 16px;\n }\n .sqp-footer {\n padding: 12px 16px;\n }\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class SaveQueryPanelComponent {\n @Input() QueryName = '';\n @Input() QueryDescription = '';\n @Input() SQL = '';\n @Input() Plan = '';\n\n @Output() Saved = new EventEmitter<SaveQueryResult>();\n @Output() Cancelled = new EventEmitter<void>();\n\n @ViewChild('categoryTree') categoryTree!: TreeDropdownComponent;\n\n // Form state\n public Name = '';\n public Description = '';\n public IsSaving = false;\n public ErrorMessage = '';\n public IsVisible = false;\n\n // Category selection\n private selectedCategoryId: string | null = null;\n public SelectedCategoryKey: CompositeKey | null = null;\n\n // Inline category creation\n public IsCreatingCategory = false;\n public IsCreatingCategorySaving = false;\n public NewCategoryName = '';\n public CreateCategoryError = '';\n private newCategoryParentId: string | null = null;\n\n /** Tree config for query category hierarchy */\n public CategoryBranchConfig: TreeBranchConfig = {\n EntityName: 'MJ: Query Categories',\n DisplayField: 'Name',\n IDField: 'ID',\n ParentIDField: 'ParentID',\n DefaultIcon: 'fa-solid fa-folder',\n OrderBy: 'Name ASC'\n };\n\n constructor(private cdr: ChangeDetectorRef) {}\n\n public get CanSave(): boolean {\n return !!this.Name?.trim();\n }\n\n ngOnInit(): void {\n // Sync input values\n this.Name = this.QueryName;\n this.Description = this.QueryDescription;\n\n // Trigger slide-in on next microtask (ensures DOM is ready)\n Promise.resolve().then(() => {\n this.IsVisible = true;\n this.cdr.markForCheck();\n });\n }\n\n @HostListener('document:keydown.escape')\n public OnEscapeKey(): void {\n if (this.IsCreatingCategory) {\n this.CancelCreateCategory();\n } else if (!this.IsSaving) {\n this.OnCancel();\n }\n }\n\n // =========================================================================\n // Category Selection\n // =========================================================================\n\n public OnCategoryChanged(selection: TreeNode | TreeNode[] | null): void {\n if (!selection) {\n this.selectedCategoryId = null;\n } else if (Array.isArray(selection)) {\n this.selectedCategoryId = selection.length > 0 ? selection[0].ID : null;\n } else {\n this.selectedCategoryId = selection.ID;\n }\n }\n\n // =========================================================================\n // Inline Category Creation\n // =========================================================================\n\n public StartCreateCategory(): void {\n this.IsCreatingCategory = true;\n this.NewCategoryName = '';\n this.newCategoryParentId = null;\n this.CreateCategoryError = '';\n this.cdr.markForCheck();\n }\n\n public CancelCreateCategory(): void {\n this.IsCreatingCategory = false;\n this.NewCategoryName = '';\n this.newCategoryParentId = null;\n this.CreateCategoryError = '';\n this.cdr.markForCheck();\n }\n\n public OnNewCategoryParentChanged(selection: TreeNode | TreeNode[] | null): void {\n if (!selection) {\n this.newCategoryParentId = null;\n } else if (Array.isArray(selection)) {\n this.newCategoryParentId = selection.length > 0 ? selection[0].ID : null;\n } else {\n this.newCategoryParentId = selection.ID;\n }\n }\n\n public async CreateCategory(): Promise<void> {\n const name = this.NewCategoryName.trim();\n if (!name || this.IsCreatingCategorySaving) return;\n\n this.IsCreatingCategorySaving = true;\n this.CreateCategoryError = '';\n this.cdr.markForCheck();\n\n try {\n const md = new Metadata();\n const category = await md.GetEntityObject<MJQueryCategoryEntity>('MJ: Query Categories');\n\n category.Name = name;\n category.UserID = md.CurrentUser.ID;\n if (this.newCategoryParentId) {\n category.ParentID = this.newCategoryParentId;\n }\n\n const saved = await category.Save();\n if (saved) {\n MJNotificationService.Instance.CreateSimpleNotification(`Category \"${name}\" created`, 'success', 2500);\n\n // Refresh core metadata so Metadata.QueryCategories is up to date\n await md.Refresh();\n\n // Refresh tree to pick up the new category\n await this.categoryTree.Refresh();\n\n // Auto-select the newly created category.\n // Must use detectChanges() (not markForCheck) to immediately propagate\n // the new Value input to the tree dropdown, since this panel uses OnPush.\n const newKey = new CompositeKey([new KeyValuePair('ID', category.ID)]);\n this.SelectedCategoryKey = newKey;\n this.selectedCategoryId = category.ID;\n this.cdr.detectChanges();\n\n // Collapse the create form\n this.IsCreatingCategory = false;\n this.NewCategoryName = '';\n this.newCategoryParentId = null;\n } else {\n const errorMsg = this.getEntityErrorMessage(category, 'create category');\n this.CreateCategoryError = errorMsg;\n MJNotificationService.Instance.CreateSimpleNotification(errorMsg, 'error', 5000);\n console.error('Failed to create category:', category.LatestResult);\n }\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : 'Failed to create category';\n this.CreateCategoryError = errorMsg;\n MJNotificationService.Instance.CreateSimpleNotification(errorMsg, 'error', 5000);\n console.error('Error creating category:', error);\n } finally {\n this.IsCreatingCategorySaving = false;\n this.cdr.markForCheck();\n }\n }\n\n // =========================================================================\n // Save / Cancel\n // =========================================================================\n\n public async OnSave(): Promise<void> {\n if (!this.CanSave || this.IsSaving) return;\n\n this.IsSaving = true;\n this.ErrorMessage = '';\n this.cdr.markForCheck();\n\n try {\n const md = new Metadata();\n const query = await md.GetEntityObject<MJQueryEntity>('MJ: Queries');\n\n query.Name = this.Name.trim();\n query.SQL = this.SQL;\n query.Status = 'Approved';\n\n if (this.Description?.trim()) {\n query.Description = this.Description.trim();\n }\n if (this.Plan?.trim()) {\n query.TechnicalDescription = this.Plan.trim();\n }\n if (this.selectedCategoryId) {\n query.CategoryID = this.selectedCategoryId;\n }\n\n const saved = await query.Save();\n if (saved) {\n MJNotificationService.Instance.CreateSimpleNotification(`Query \"${query.Name}\" saved`, 'success', 2500);\n\n // Animate out, then emit\n this.IsVisible = false;\n this.cdr.markForCheck();\n setTimeout(() => {\n this.Saved.emit({\n queryId: query.ID,\n queryName: query.Name\n });\n }, 300);\n } else {\n const errorMsg = this.getEntityErrorMessage(query, 'save query');\n this.ErrorMessage = errorMsg;\n MJNotificationService.Instance.CreateSimpleNotification(errorMsg, 'error', 5000);\n console.error('Failed to save query:', query.LatestResult);\n }\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : 'An unexpected error occurred';\n this.ErrorMessage = errorMsg;\n MJNotificationService.Instance.CreateSimpleNotification(errorMsg, 'error', 5000);\n console.error('Error saving query:', error);\n } finally {\n this.IsSaving = false;\n this.cdr.markForCheck();\n }\n }\n\n public OnCancel(): void {\n if (this.IsSaving) return;\n this.IsVisible = false;\n this.cdr.markForCheck();\n setTimeout(() => this.Cancelled.emit(), 300);\n }\n\n // =========================================================================\n // Helpers\n // =========================================================================\n\n private getEntityErrorMessage(entity: BaseEntity, operation: string): string {\n const result = entity.LatestResult;\n if (result?.Message) {\n return result.Message;\n }\n return `Failed to ${operation}. Please try again.`;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-artifacts",
3
- "version": "5.9.0",
3
+ "version": "5.10.1",
4
4
  "description": "MemberJunction: Artifact viewer plugin system for rendering different artifact types (JSON, Code, Markdown, HTML, SVG, Components)",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -32,19 +32,19 @@
32
32
  "dependencies": {
33
33
  "@angular/cdk": "21.1.3",
34
34
  "@angular/forms": "21.1.3",
35
- "@memberjunction/core": "5.9.0",
36
- "@memberjunction/core-entities": "5.9.0",
37
- "@memberjunction/global": "5.9.0",
38
- "@memberjunction/interactive-component-types": "5.9.0",
39
- "@memberjunction/ng-base-types": "5.9.0",
40
- "@memberjunction/ng-code-editor": "5.9.0",
41
- "@memberjunction/ng-notifications": "5.9.0",
42
- "@memberjunction/ng-react": "5.9.0",
43
- "@memberjunction/ng-shared-generic": "5.9.0",
44
- "@memberjunction/ng-query-viewer": "5.9.0",
45
- "@memberjunction/ng-trees": "5.9.0",
46
- "@memberjunction/ng-export-service": "5.9.0",
47
- "@memberjunction/ng-markdown": "5.9.0",
35
+ "@memberjunction/core": "5.10.1",
36
+ "@memberjunction/core-entities": "5.10.1",
37
+ "@memberjunction/global": "5.10.1",
38
+ "@memberjunction/interactive-component-types": "5.10.1",
39
+ "@memberjunction/ng-base-types": "5.10.1",
40
+ "@memberjunction/ng-code-editor": "5.10.1",
41
+ "@memberjunction/ng-notifications": "5.10.1",
42
+ "@memberjunction/ng-react": "5.10.1",
43
+ "@memberjunction/ng-shared-generic": "5.10.1",
44
+ "@memberjunction/ng-query-viewer": "5.10.1",
45
+ "@memberjunction/ng-trees": "5.10.1",
46
+ "@memberjunction/ng-export-service": "5.10.1",
47
+ "@memberjunction/ng-markdown": "5.10.1",
48
48
  "marked": "^17.0.1",
49
49
  "rxjs": "^7.8.2",
50
50
  "tslib": "^2.8.1"