@memberjunction/ng-query-viewer 5.10.1 → 5.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -582,7 +582,7 @@ export class QueryParameterFormComponent {
582
582
  i0.ɵɵconditional(ctx.IsOpen && ctx.ShowOverlay ? 0 : -1);
583
583
  i0.ɵɵadvance();
584
584
  i0.ɵɵconditional(ctx.IsOpen ? 1 : -1);
585
- } }, styles: ["\n\n\n[_nghost-%COMP%] {\n display: block;\n}\n\n\n\n.param-form-overlay[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 1000;\n}\n\n\n\n.param-form-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n right: 0;\n height: 100%;\n background: #fff;\n box-shadow: -4px 0 20px rgba(0, 0, 0, 0.15);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: linear-gradient(135deg, #5c6bc0 0%, #3949ab 100%);\n color: #fff;\n flex-shrink: 0;\n}\n\n.header-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.header-icon[_ngcontent-%COMP%] {\n font-size: 24px;\n opacity: 0.9;\n}\n\n.header-text[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.header-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n}\n\n.header-subtitle[_ngcontent-%COMP%] {\n font-size: 12px;\n opacity: 0.8;\n margin-top: 2px;\n}\n\n.close-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: #fff;\n border-radius: 50%;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n}\n\n\n\n.no-params[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n text-align: center;\n}\n\n.no-params-icon[_ngcontent-%COMP%] {\n font-size: 48px;\n color: #4caf50;\n margin-bottom: 16px;\n}\n\n.no-params[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n color: #666;\n margin: 0 0 20px 0;\n}\n\n\n\n.param-fields[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.param-field[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.param-field.has-error[_ngcontent-%COMP%] .field-label[_ngcontent-%COMP%] {\n color: #d32f2f;\n}\n\n.param-field.has-error[_ngcontent-%COMP%] .form-input[_ngcontent-%COMP%] {\n border-color: #d32f2f;\n}\n\n\n\n.field-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.required-indicator[_ngcontent-%COMP%] {\n color: #d32f2f;\n font-weight: bold;\n}\n\n.field-type[_ngcontent-%COMP%] {\n font-weight: 400;\n color: #888;\n font-size: 11px;\n}\n\n\n\n.field-description[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #666;\n margin: 0;\n line-height: 1.4;\n}\n\n\n\n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 12px;\n font-size: 14px;\n border: 1px solid #ccc;\n border-radius: 4px;\n background: #fff;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n box-sizing: border-box;\n}\n\n.form-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #5c6bc0;\n box-shadow: 0 0 0 3px rgba(92, 107, 192, 0.15);\n}\n\n.form-input[_ngcontent-%COMP%]::placeholder {\n color: #999;\n}\n\n.form-input[type=\"number\"][_ngcontent-%COMP%] {\n -moz-appearance: textfield;\n}\n\n.form-input[type=\"number\"][_ngcontent-%COMP%]::-webkit-inner-spin-button, \n.form-input[type=\"number\"][_ngcontent-%COMP%]::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\n\n\n.checkbox-wrapper[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 0;\n}\n\n.checkbox-wrapper[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 18px;\n height: 18px;\n cursor: pointer;\n}\n\n.checkbox-label[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #333;\n cursor: pointer;\n}\n\n\n\n.field-hint[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #888;\n font-style: italic;\n}\n\n.field-error[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #d32f2f;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-error[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n.field-sample[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #888;\n}\n\n\n\n.panel-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: #f8f9fa;\n border-top: 1px solid #e0e0e0;\n flex-shrink: 0;\n}\n\n.footer-right[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.footer-right[_ngcontent-%COMP%] button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 6px;\n}\n\n\n\n@media (max-width: 480px) {\n .param-form-panel[_ngcontent-%COMP%] {\n width: 100% !important;\n }\n}\n\n\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: #f1f1f1;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: #ccc;\n border-radius: 3px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: #aaa;\n}\n\n\n\n.btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid transparent;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #5c6bc0 0%, #3949ab 100%);\n color: #fff;\n border-color: transparent;\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: linear-gradient(135deg, #7986cb 0%, #5c6bc0 100%);\n}\n\n.btn-primary[_ngcontent-%COMP%]:active:not(:disabled) {\n transform: translateY(1px);\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: #fff;\n color: #333;\n border-color: #ccc;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #f5f5f5;\n border-color: #bbb;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:active:not(:disabled) {\n background: #eee;\n transform: translateY(1px);\n}"], data: { animation: [
585
+ } }, styles: ["\n\n\n[_nghost-%COMP%] {\n display: block;\n}\n\n\n\n.param-form-overlay[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 1000;\n}\n\n\n\n.param-form-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n right: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n box-shadow: -4px 0 20px rgba(0, 0, 0, 0.15);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\n.header-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.header-icon[_ngcontent-%COMP%] {\n font-size: var(--mj-text-2xl);\n opacity: 0.9;\n}\n\n.header-text[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.header-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-base);\n font-weight: 600;\n}\n\n.header-subtitle[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n opacity: 0.8;\n margin-top: 2px;\n}\n\n.close-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: var(--mj-text-inverse);\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n}\n\n\n\n.no-params[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n text-align: center;\n}\n\n.no-params-icon[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--mj-status-success);\n margin-bottom: 16px;\n}\n\n.no-params[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n margin: 0 0 20px 0;\n}\n\n\n\n.param-fields[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.param-field[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.param-field.has-error[_ngcontent-%COMP%] .field-label[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.param-field.has-error[_ngcontent-%COMP%] .form-input[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n}\n\n\n\n.field-label[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.required-indicator[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n font-weight: bold;\n}\n\n.field-type[_ngcontent-%COMP%] {\n font-weight: 400;\n color: var(--mj-text-disabled);\n font-size: 11px;\n}\n\n\n\n.field-description[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n margin: 0;\n line-height: 1.4;\n}\n\n\n\n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 12px;\n font-size: var(--mj-text-sm);\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n box-sizing: border-box;\n}\n\n.form-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.form-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-disabled);\n}\n\n.form-input[type=\"number\"][_ngcontent-%COMP%] {\n -moz-appearance: textfield;\n}\n\n.form-input[type=\"number\"][_ngcontent-%COMP%]::-webkit-inner-spin-button, \n.form-input[type=\"number\"][_ngcontent-%COMP%]::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\n\n\n.checkbox-wrapper[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 0;\n}\n\n.checkbox-wrapper[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 18px;\n height: 18px;\n cursor: pointer;\n}\n\n.checkbox-label[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n cursor: pointer;\n}\n\n\n\n.field-hint[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n.field-error[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-error[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n.field-sample[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n}\n\n\n\n.panel-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.footer-right[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.footer-right[_ngcontent-%COMP%] button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 6px;\n}\n\n\n\n@media (max-width: 480px) {\n .param-form-panel[_ngcontent-%COMP%] {\n width: 100% !important;\n }\n}\n\n\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: var(--mj-radius-sm);\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n}\n\n\n\n.btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: var(--mj-text-sm);\n font-weight: 500;\n border: 1px solid transparent;\n border-radius: var(--mj-radius-sm);\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: transparent;\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.btn-primary[_ngcontent-%COMP%]:active:not(:disabled) {\n transform: translateY(1px);\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n}\n\n.btn-secondary[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n transform: translateY(1px);\n}"], data: { animation: [
586
586
  trigger('slideIn', [
587
587
  transition(':enter', [
588
588
  style({ transform: 'translateX(100%)', opacity: 0 }),
@@ -624,7 +624,7 @@ export class QueryParameterFormComponent {
624
624
  animate('100ms ease-in', style({ opacity: 0 }))
625
625
  ])
626
626
  ])
627
- ], template: "<!-- Query Parameter Form - Slide-in Panel -->\n@if (IsOpen && ShowOverlay) {\n <div class=\"param-form-overlay\"\n @fadeIn\n (click)=\"Cancel()\">\n </div>\n}\n\n@if (IsOpen) {\n <div class=\"param-form-panel\"\n @slideIn\n [style.width.px]=\"PanelWidth\">\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-content\">\n <i class=\"fa-solid fa-sliders header-icon\"></i>\n <div class=\"header-text\">\n <h3 class=\"header-title\">Query Parameters</h3>\n @if (QueryInfo) {\n <span class=\"header-subtitle\">{{ QueryInfo.Name }}</span>\n }\n </div>\n </div>\n <button class=\"close-btn\" (click)=\"Cancel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <!-- Form Content -->\n <div class=\"panel-content\">\n <!-- No parameters message -->\n @if (Fields.length === 0) {\n <div class=\"no-params\">\n <i class=\"fa-solid fa-check-circle no-params-icon\"></i>\n <p>This query has no parameters</p>\n <button class=\"btn btn-primary\" (click)=\"Submit()\">\n Run Query\n </button>\n </div>\n }\n <!-- Parameter fields -->\n @if (Fields.length > 0) {\n <div class=\"param-fields\">\n @for (field of Fields; track TrackByField($index, field)) {\n <div class=\"param-field\"\n [class.has-error]=\"field.error && field.touched\"\n [class.required]=\"field.info.IsRequired\">\n <!-- Label -->\n <label class=\"field-label\" [for]=\"'param-' + field.info.Name\">\n {{ field.info.Name }}\n @if (field.info.IsRequired) {\n <span class=\"required-indicator\">*</span>\n }\n <span class=\"field-type\">({{ field.info.Type }})</span>\n </label>\n <!-- Description -->\n @if (field.info.Description) {\n <p class=\"field-description\">\n {{ field.info.Description }}\n </p>\n }\n <!-- String input -->\n @if (field.info.Type === 'string') {\n <input type=\"text\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetStringValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info)\"\n (input)=\"OnInputChange(field, $event)\">\n }\n <!-- Number input -->\n @if (field.info.Type === 'number') {\n <input type=\"number\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetNumberValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info)\"\n (input)=\"OnNumberInputChange(field, $event)\">\n }\n <!-- Date input -->\n @if (field.info.Type === 'date') {\n <input type=\"date\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetDateValue(field.value)\"\n (input)=\"OnDateInputChange(field, $event)\">\n }\n <!-- Boolean input -->\n @if (field.info.Type === 'boolean') {\n <div class=\"checkbox-wrapper\">\n <input type=\"checkbox\"\n [id]=\"'param-' + field.info.Name\"\n [checked]=\"GetBooleanValue(field.value)\"\n (change)=\"OnCheckboxChange(field, $event)\">\n <label [for]=\"'param-' + field.info.Name\" class=\"checkbox-label\">\n {{ GetBooleanValue(field.value) ? 'Yes' : 'No' }}\n </label>\n </div>\n }\n <!-- Array input (comma-separated) -->\n @if (field.info.Type === 'array') {\n <input type=\"text\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetArrayDisplayValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info) || 'Enter values separated by commas'\"\n (input)=\"OnArrayInputChange(field, $event)\">\n <span class=\"field-hint\">Enter multiple values separated by commas</span>\n }\n <!-- Error message -->\n @if (field.error && field.touched) {\n <span class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ field.error }}\n </span>\n }\n <!-- Sample value hint -->\n @if (field.info.SampleValue && !field.error) {\n <span class=\"field-sample\">\n Example: {{ field.info.SampleValue }}\n </span>\n }\n </div>\n }\n </div>\n }\n </div>\n <!-- Footer -->\n @if (Fields.length > 0) {\n <div class=\"panel-footer\">\n <button class=\"btn btn-secondary\" (click)=\"Reset()\" title=\"Reset to defaults\">\n <i class=\"fa-solid fa-undo\"></i>\n Reset\n </button>\n <div class=\"footer-right\">\n <button class=\"btn btn-secondary\" (click)=\"Cancel()\">\n Cancel\n </button>\n <button class=\"btn btn-primary\"\n [disabled]=\"!CanSubmit\"\n (click)=\"Submit()\">\n <i class=\"fa-solid fa-play\"></i>\n Run Query\n </button>\n </div>\n </div>\n }\n </div>\n}\n", styles: ["/* Query Parameter Form - Slide-in Panel Styles */\n\n:host {\n display: block;\n}\n\n/* Overlay */\n.param-form-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 1000;\n}\n\n/* Panel */\n.param-form-panel {\n position: absolute;\n top: 0;\n right: 0;\n height: 100%;\n background: #fff;\n box-shadow: -4px 0 20px rgba(0, 0, 0, 0.15);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n/* Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: linear-gradient(135deg, #5c6bc0 0%, #3949ab 100%);\n color: #fff;\n flex-shrink: 0;\n}\n\n.header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.header-icon {\n font-size: 24px;\n opacity: 0.9;\n}\n\n.header-text {\n display: flex;\n flex-direction: column;\n}\n\n.header-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n}\n\n.header-subtitle {\n font-size: 12px;\n opacity: 0.8;\n margin-top: 2px;\n}\n\n.close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: #fff;\n border-radius: 50%;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.close-btn:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n/* Content */\n.panel-content {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n}\n\n/* No params message */\n.no-params {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n text-align: center;\n}\n\n.no-params-icon {\n font-size: 48px;\n color: #4caf50;\n margin-bottom: 16px;\n}\n\n.no-params p {\n color: #666;\n margin: 0 0 20px 0;\n}\n\n/* Parameter fields */\n.param-fields {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.param-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.param-field.has-error .field-label {\n color: #d32f2f;\n}\n\n.param-field.has-error .form-input {\n border-color: #d32f2f;\n}\n\n/* Field label */\n.field-label {\n font-size: 13px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.required-indicator {\n color: #d32f2f;\n font-weight: bold;\n}\n\n.field-type {\n font-weight: 400;\n color: #888;\n font-size: 11px;\n}\n\n/* Field description */\n.field-description {\n font-size: 12px;\n color: #666;\n margin: 0;\n line-height: 1.4;\n}\n\n/* Field inputs */\n.form-input {\n width: 100%;\n padding: 8px 12px;\n font-size: 14px;\n border: 1px solid #ccc;\n border-radius: 4px;\n background: #fff;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n box-sizing: border-box;\n}\n\n.form-input:focus {\n outline: none;\n border-color: #5c6bc0;\n box-shadow: 0 0 0 3px rgba(92, 107, 192, 0.15);\n}\n\n.form-input::placeholder {\n color: #999;\n}\n\n.form-input[type=\"number\"] {\n -moz-appearance: textfield;\n}\n\n.form-input[type=\"number\"]::-webkit-inner-spin-button,\n.form-input[type=\"number\"]::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\n/* Checkbox wrapper */\n.checkbox-wrapper {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 0;\n}\n\n.checkbox-wrapper input[type=\"checkbox\"] {\n width: 18px;\n height: 18px;\n cursor: pointer;\n}\n\n.checkbox-label {\n font-size: 14px;\n color: #333;\n cursor: pointer;\n}\n\n/* Field hints and errors */\n.field-hint {\n font-size: 11px;\n color: #888;\n font-style: italic;\n}\n\n.field-error {\n font-size: 12px;\n color: #d32f2f;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-error i {\n font-size: 11px;\n}\n\n.field-sample {\n font-size: 11px;\n color: #888;\n}\n\n/* Footer */\n.panel-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: #f8f9fa;\n border-top: 1px solid #e0e0e0;\n flex-shrink: 0;\n}\n\n.footer-right {\n display: flex;\n gap: 8px;\n}\n\n.footer-right button i {\n margin-right: 6px;\n}\n\n/* Responsive adjustments */\n@media (max-width: 480px) {\n .param-form-panel {\n width: 100% !important;\n }\n}\n\n/* Scrollbar styling */\n.panel-content::-webkit-scrollbar {\n width: 6px;\n}\n\n.panel-content::-webkit-scrollbar-track {\n background: #f1f1f1;\n}\n\n.panel-content::-webkit-scrollbar-thumb {\n background: #ccc;\n border-radius: 3px;\n}\n\n.panel-content::-webkit-scrollbar-thumb:hover {\n background: #aaa;\n}\n\n/* Buttons */\n.btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid transparent;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn i {\n font-size: 12px;\n}\n\n.btn-primary {\n background: linear-gradient(135deg, #5c6bc0 0%, #3949ab 100%);\n color: #fff;\n border-color: transparent;\n}\n\n.btn-primary:hover:not(:disabled) {\n background: linear-gradient(135deg, #7986cb 0%, #5c6bc0 100%);\n}\n\n.btn-primary:active:not(:disabled) {\n transform: translateY(1px);\n}\n\n.btn-secondary {\n background: #fff;\n color: #333;\n border-color: #ccc;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: #f5f5f5;\n border-color: #bbb;\n}\n\n.btn-secondary:active:not(:disabled) {\n background: #eee;\n transform: translateY(1px);\n}\n"] }]
627
+ ], template: "<!-- Query Parameter Form - Slide-in Panel -->\n@if (IsOpen && ShowOverlay) {\n <div class=\"param-form-overlay\"\n @fadeIn\n (click)=\"Cancel()\">\n </div>\n}\n\n@if (IsOpen) {\n <div class=\"param-form-panel\"\n @slideIn\n [style.width.px]=\"PanelWidth\">\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-content\">\n <i class=\"fa-solid fa-sliders header-icon\"></i>\n <div class=\"header-text\">\n <h3 class=\"header-title\">Query Parameters</h3>\n @if (QueryInfo) {\n <span class=\"header-subtitle\">{{ QueryInfo.Name }}</span>\n }\n </div>\n </div>\n <button class=\"close-btn\" (click)=\"Cancel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <!-- Form Content -->\n <div class=\"panel-content\">\n <!-- No parameters message -->\n @if (Fields.length === 0) {\n <div class=\"no-params\">\n <i class=\"fa-solid fa-check-circle no-params-icon\"></i>\n <p>This query has no parameters</p>\n <button class=\"btn btn-primary\" (click)=\"Submit()\">\n Run Query\n </button>\n </div>\n }\n <!-- Parameter fields -->\n @if (Fields.length > 0) {\n <div class=\"param-fields\">\n @for (field of Fields; track TrackByField($index, field)) {\n <div class=\"param-field\"\n [class.has-error]=\"field.error && field.touched\"\n [class.required]=\"field.info.IsRequired\">\n <!-- Label -->\n <label class=\"field-label\" [for]=\"'param-' + field.info.Name\">\n {{ field.info.Name }}\n @if (field.info.IsRequired) {\n <span class=\"required-indicator\">*</span>\n }\n <span class=\"field-type\">({{ field.info.Type }})</span>\n </label>\n <!-- Description -->\n @if (field.info.Description) {\n <p class=\"field-description\">\n {{ field.info.Description }}\n </p>\n }\n <!-- String input -->\n @if (field.info.Type === 'string') {\n <input type=\"text\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetStringValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info)\"\n (input)=\"OnInputChange(field, $event)\">\n }\n <!-- Number input -->\n @if (field.info.Type === 'number') {\n <input type=\"number\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetNumberValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info)\"\n (input)=\"OnNumberInputChange(field, $event)\">\n }\n <!-- Date input -->\n @if (field.info.Type === 'date') {\n <input type=\"date\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetDateValue(field.value)\"\n (input)=\"OnDateInputChange(field, $event)\">\n }\n <!-- Boolean input -->\n @if (field.info.Type === 'boolean') {\n <div class=\"checkbox-wrapper\">\n <input type=\"checkbox\"\n [id]=\"'param-' + field.info.Name\"\n [checked]=\"GetBooleanValue(field.value)\"\n (change)=\"OnCheckboxChange(field, $event)\">\n <label [for]=\"'param-' + field.info.Name\" class=\"checkbox-label\">\n {{ GetBooleanValue(field.value) ? 'Yes' : 'No' }}\n </label>\n </div>\n }\n <!-- Array input (comma-separated) -->\n @if (field.info.Type === 'array') {\n <input type=\"text\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetArrayDisplayValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info) || 'Enter values separated by commas'\"\n (input)=\"OnArrayInputChange(field, $event)\">\n <span class=\"field-hint\">Enter multiple values separated by commas</span>\n }\n <!-- Error message -->\n @if (field.error && field.touched) {\n <span class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ field.error }}\n </span>\n }\n <!-- Sample value hint -->\n @if (field.info.SampleValue && !field.error) {\n <span class=\"field-sample\">\n Example: {{ field.info.SampleValue }}\n </span>\n }\n </div>\n }\n </div>\n }\n </div>\n <!-- Footer -->\n @if (Fields.length > 0) {\n <div class=\"panel-footer\">\n <button class=\"btn btn-secondary\" (click)=\"Reset()\" title=\"Reset to defaults\">\n <i class=\"fa-solid fa-undo\"></i>\n Reset\n </button>\n <div class=\"footer-right\">\n <button class=\"btn btn-secondary\" (click)=\"Cancel()\">\n Cancel\n </button>\n <button class=\"btn btn-primary\"\n [disabled]=\"!CanSubmit\"\n (click)=\"Submit()\">\n <i class=\"fa-solid fa-play\"></i>\n Run Query\n </button>\n </div>\n </div>\n }\n </div>\n}\n", styles: ["/* Query Parameter Form - Slide-in Panel Styles */\n\n:host {\n display: block;\n}\n\n/* Overlay */\n.param-form-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 1000;\n}\n\n/* Panel */\n.param-form-panel {\n position: absolute;\n top: 0;\n right: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n box-shadow: -4px 0 20px rgba(0, 0, 0, 0.15);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n/* Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\n.header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.header-icon {\n font-size: var(--mj-text-2xl);\n opacity: 0.9;\n}\n\n.header-text {\n display: flex;\n flex-direction: column;\n}\n\n.header-title {\n margin: 0;\n font-size: var(--mj-text-base);\n font-weight: 600;\n}\n\n.header-subtitle {\n font-size: var(--mj-text-xs);\n opacity: 0.8;\n margin-top: 2px;\n}\n\n.close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: var(--mj-text-inverse);\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.close-btn:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n/* Content */\n.panel-content {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n}\n\n/* No params message */\n.no-params {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n text-align: center;\n}\n\n.no-params-icon {\n font-size: 48px;\n color: var(--mj-status-success);\n margin-bottom: 16px;\n}\n\n.no-params p {\n color: var(--mj-text-muted);\n margin: 0 0 20px 0;\n}\n\n/* Parameter fields */\n.param-fields {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.param-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.param-field.has-error .field-label {\n color: var(--mj-status-error);\n}\n\n.param-field.has-error .form-input {\n border-color: var(--mj-status-error);\n}\n\n/* Field label */\n.field-label {\n font-size: var(--mj-text-sm);\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.required-indicator {\n color: var(--mj-status-error);\n font-weight: bold;\n}\n\n.field-type {\n font-weight: 400;\n color: var(--mj-text-disabled);\n font-size: 11px;\n}\n\n/* Field description */\n.field-description {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n margin: 0;\n line-height: 1.4;\n}\n\n/* Field inputs */\n.form-input {\n width: 100%;\n padding: 8px 12px;\n font-size: var(--mj-text-sm);\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n box-sizing: border-box;\n}\n\n.form-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.form-input::placeholder {\n color: var(--mj-text-disabled);\n}\n\n.form-input[type=\"number\"] {\n -moz-appearance: textfield;\n}\n\n.form-input[type=\"number\"]::-webkit-inner-spin-button,\n.form-input[type=\"number\"]::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\n/* Checkbox wrapper */\n.checkbox-wrapper {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 0;\n}\n\n.checkbox-wrapper input[type=\"checkbox\"] {\n width: 18px;\n height: 18px;\n cursor: pointer;\n}\n\n.checkbox-label {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n cursor: pointer;\n}\n\n/* Field hints and errors */\n.field-hint {\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n.field-error {\n font-size: var(--mj-text-xs);\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.field-error i {\n font-size: 11px;\n}\n\n.field-sample {\n font-size: 11px;\n color: var(--mj-text-disabled);\n}\n\n/* Footer */\n.panel-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.footer-right {\n display: flex;\n gap: 8px;\n}\n\n.footer-right button i {\n margin-right: 6px;\n}\n\n/* Responsive adjustments */\n@media (max-width: 480px) {\n .param-form-panel {\n width: 100% !important;\n }\n}\n\n/* Scrollbar styling */\n.panel-content::-webkit-scrollbar {\n width: 6px;\n}\n\n.panel-content::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n}\n\n.panel-content::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: var(--mj-radius-sm);\n}\n\n.panel-content::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n}\n\n/* Buttons */\n.btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: var(--mj-text-sm);\n font-weight: 500;\n border: 1px solid transparent;\n border-radius: var(--mj-radius-sm);\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn i {\n font-size: var(--mj-text-xs);\n}\n\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: transparent;\n}\n\n.btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.btn-primary:active:not(:disabled) {\n transform: translateY(1px);\n}\n\n.btn-secondary {\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n}\n\n.btn-secondary:active:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n transform: translateY(1px);\n}\n"] }]
628
628
  }], () => [{ type: i0.ChangeDetectorRef }], { QueryInfo: [{
629
629
  type: Input
630
630
  }], InitialValues: [{
@@ -1 +1 @@
1
- {"version":3,"file":"query-parameter-form.component.js","sourceRoot":"","sources":["../../../src/lib/query-parameter-form/query-parameter-form.component.ts","../../../src/lib/query-parameter-form/query-parameter-form.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit,\n OnDestroy,\n OnChanges,\n SimpleChanges,\n ChangeDetectorRef,\n ChangeDetectionStrategy\n} from '@angular/core';\nimport { trigger, transition, style, animate } from '@angular/animations';\nimport { QueryInfo, QueryParameterInfo } from '@memberjunction/core';\nimport { QueryParameterValues } from '../query-data-grid/models/query-grid-types';\n\n/**\n * A single parameter field in the form\n */\ninterface ParameterField {\n info: QueryParameterInfo;\n value: string | number | boolean | Date | string[] | null;\n error: string | null;\n touched: boolean;\n}\n\n/**\n * A slide-in form for entering query parameters before execution.\n * Features:\n * - Dynamic form generation from QueryParameterInfo metadata\n * - Type-appropriate input controls (text, number, date, checkbox, multi-select)\n * - Validation with helpful error messages\n * - Sample values as placeholders\n * - Description tooltips\n *\n * @example\n * ```html\n * <mj-query-parameter-form\n * [QueryInfo]=\"query\"\n * [InitialValues]=\"savedParams\"\n * [IsOpen]=\"showParams\"\n * (ParametersSubmit)=\"onRunQuery($event)\"\n * (Close)=\"showParams = false\">\n * </mj-query-parameter-form>\n * ```\n */\n@Component({\n standalone: false,\n selector: 'mj-query-parameter-form',\n templateUrl: './query-parameter-form.component.html',\n styleUrls: ['./query-parameter-form.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n animations: [\n trigger('slideIn', [\n transition(':enter', [\n style({ transform: 'translateX(100%)', opacity: 0 }),\n animate('250ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))\n ]),\n transition(':leave', [\n animate('200ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))\n ])\n ]),\n trigger('fadeIn', [\n transition(':enter', [\n style({ opacity: 0 }),\n animate('150ms ease-out', style({ opacity: 1 }))\n ]),\n transition(':leave', [\n animate('100ms ease-in', style({ opacity: 0 }))\n ])\n ])\n ]\n})\nexport class QueryParameterFormComponent implements OnInit, OnChanges, OnDestroy {\n // ========================================\n // Inputs\n // ========================================\n\n /**\n * The query metadata containing parameter definitions\n */\n @Input() QueryInfo: QueryInfo | null = null;\n\n /**\n * Initial values to populate the form (e.g., from saved state)\n */\n @Input() InitialValues: QueryParameterValues = {};\n\n /**\n * Whether the panel is open/visible\n */\n @Input() IsOpen: boolean = false;\n\n /**\n * Panel width in pixels\n */\n @Input() PanelWidth: number = 400;\n\n /**\n * Whether to show the overlay backdrop\n */\n @Input() ShowOverlay: boolean = true;\n\n // ========================================\n // Outputs\n // ========================================\n\n /**\n * Fired when user submits the form with valid parameters\n */\n @Output() ParametersSubmit = new EventEmitter<QueryParameterValues>();\n\n /**\n * Fired when panel is closed\n */\n @Output() Close = new EventEmitter<void>();\n\n // ========================================\n // Internal State\n // ========================================\n\n public Fields: ParameterField[] = [];\n public HasRequiredParams: boolean = false;\n public AllRequiredFilled: boolean = false;\n\n constructor(private cdr: ChangeDetectorRef) {}\n\n ngOnInit(): void {\n this.buildForm();\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['QueryInfo'] || changes['InitialValues']) {\n this.buildForm();\n }\n }\n\n ngOnDestroy(): void {}\n\n // ========================================\n // Form Building\n // ========================================\n\n private buildForm(): void {\n if (!this.QueryInfo) {\n this.Fields = [];\n this.HasRequiredParams = false;\n return;\n }\n\n const parameters = this.QueryInfo.Parameters || [];\n\n this.Fields = parameters.map(param => {\n const initialValue = this.getInitialValue(param);\n\n return {\n info: param,\n value: initialValue,\n error: null,\n touched: false\n };\n });\n\n this.HasRequiredParams = this.Fields.some(f => f.info.IsRequired);\n this.validateAllFields();\n this.cdr.markForCheck();\n }\n\n private getInitialValue(param: QueryParameterInfo): string | number | boolean | Date | string[] | null {\n // Check initial values first\n if (this.InitialValues && this.InitialValues[param.Name] !== undefined) {\n return this.InitialValues[param.Name];\n }\n\n // Fall back to default value\n if (param.DefaultValue !== null && param.DefaultValue !== undefined) {\n return this.parseDefaultValue(param);\n }\n\n // Type-specific defaults\n switch (param.Type) {\n case 'boolean':\n return false;\n case 'array':\n return [];\n default:\n return null;\n }\n }\n\n private parseDefaultValue(param: QueryParameterInfo): string | number | boolean | Date | string[] | null {\n const defaultValue = param.DefaultValue;\n if (defaultValue === null || defaultValue === undefined) return null;\n\n try {\n switch (param.Type) {\n case 'number':\n return Number(defaultValue);\n case 'boolean':\n return defaultValue.toLowerCase() === 'true' || defaultValue === '1';\n case 'date':\n return new Date(defaultValue);\n case 'array':\n return JSON.parse(defaultValue);\n default:\n return defaultValue;\n }\n } catch {\n return defaultValue;\n }\n }\n\n // ========================================\n // Value Handling\n // ========================================\n\n public OnValueChange(field: ParameterField, value: unknown): void {\n field.value = value as ParameterField['value'];\n field.touched = true;\n this.validateField(field);\n this.updateAllRequiredFilled();\n this.cdr.markForCheck();\n }\n\n public OnDateChange(field: ParameterField, value: Date | null): void {\n field.value = value;\n field.touched = true;\n this.validateField(field);\n this.updateAllRequiredFilled();\n this.cdr.markForCheck();\n }\n\n public OnCheckboxChange(field: ParameterField, event: Event): void {\n const input = event.target as HTMLInputElement;\n field.value = input.checked;\n field.touched = true;\n this.validateField(field);\n this.updateAllRequiredFilled();\n this.cdr.markForCheck();\n }\n\n // ========================================\n // Validation\n // ========================================\n\n private validateField(field: ParameterField): void {\n field.error = null;\n\n const value = field.value;\n const param = field.info;\n\n // Required check\n if (param.IsRequired) {\n if (value === null || value === undefined || value === '') {\n field.error = 'This field is required';\n return;\n }\n if (param.Type === 'array' && Array.isArray(value) && value.length === 0) {\n field.error = 'At least one value is required';\n return;\n }\n }\n\n // Type validation\n if (value !== null && value !== undefined && value !== '') {\n switch (param.Type) {\n case 'number':\n if (isNaN(Number(value))) {\n field.error = 'Must be a valid number';\n }\n break;\n case 'date':\n if (value instanceof Date && isNaN(value.getTime())) {\n field.error = 'Must be a valid date';\n }\n break;\n }\n }\n }\n\n private validateAllFields(): void {\n for (const field of this.Fields) {\n this.validateField(field);\n }\n this.updateAllRequiredFilled();\n }\n\n private updateAllRequiredFilled(): void {\n this.AllRequiredFilled = this.Fields\n .filter(f => f.info.IsRequired)\n .every(f => {\n const value = f.value;\n if (value === null || value === undefined || value === '') return false;\n if (f.info.Type === 'array' && Array.isArray(value) && value.length === 0) return false;\n return f.error === null;\n });\n }\n\n public get HasErrors(): boolean {\n return this.Fields.some(f => f.error !== null);\n }\n\n public get CanSubmit(): boolean {\n return !this.HasErrors && this.AllRequiredFilled;\n }\n\n // ========================================\n // Form Submission\n // ========================================\n\n public Submit(): void {\n // Mark all fields as touched\n for (const field of this.Fields) {\n field.touched = true;\n }\n this.validateAllFields();\n\n if (!this.CanSubmit) {\n this.cdr.markForCheck();\n return;\n }\n\n // Build parameter values object\n const values: QueryParameterValues = {};\n for (const field of this.Fields) {\n if (field.value !== null && field.value !== undefined) {\n values[field.info.Name] = field.value;\n }\n }\n\n this.ParametersSubmit.emit(values);\n }\n\n public Cancel(): void {\n this.Close.emit();\n }\n\n public Reset(): void {\n this.buildForm();\n }\n\n // ========================================\n // UI Helpers\n // ========================================\n\n public GetInputType(param: QueryParameterInfo): string {\n switch (param.Type) {\n case 'number':\n return 'number';\n case 'boolean':\n return 'checkbox';\n case 'date':\n return 'date';\n default:\n return 'text';\n }\n }\n\n public GetPlaceholder(param: QueryParameterInfo): string {\n if (param.SampleValue) {\n return `e.g., ${param.SampleValue}`;\n }\n return param.Description || '';\n }\n\n public TrackByField(index: number, field: ParameterField): string {\n return field.info.Name;\n }\n\n // ========================================\n // Type-Safe Value Getters for Template\n // ========================================\n\n public GetStringValue(value: ParameterField['value']): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n return String(value);\n }\n\n public GetNumberValue(value: ParameterField['value']): number | null {\n if (value === null || value === undefined) return null;\n if (typeof value === 'number') return value;\n const num = Number(value);\n return isNaN(num) ? null : num;\n }\n\n public GetDateValue(value: ParameterField['value']): string {\n if (value === null || value === undefined) return '';\n if (value instanceof Date) {\n // Format as YYYY-MM-DD for HTML date input\n return value.toISOString().split('T')[0];\n }\n if (typeof value === 'string') {\n // Try to parse and format\n const date = new Date(value);\n if (!isNaN(date.getTime())) {\n return date.toISOString().split('T')[0];\n }\n }\n return '';\n }\n\n public GetBooleanValue(value: ParameterField['value']): boolean {\n if (value === null || value === undefined) return false;\n return Boolean(value);\n }\n\n public GetArrayDisplayValue(value: ParameterField['value']): string {\n if (value === null || value === undefined) return '';\n if (Array.isArray(value)) {\n return value.join(', ');\n }\n return String(value);\n }\n\n // ========================================\n // Input Event Handlers\n // ========================================\n\n public OnInputChange(field: ParameterField, event: Event): void {\n const input = event.target as HTMLInputElement;\n this.OnValueChange(field, input.value);\n }\n\n public OnNumberInputChange(field: ParameterField, event: Event): void {\n const input = event.target as HTMLInputElement;\n const value = input.value === '' ? null : Number(input.value);\n this.OnValueChange(field, value);\n }\n\n public OnDateInputChange(field: ParameterField, event: Event): void {\n const input = event.target as HTMLInputElement;\n const value = input.value ? new Date(input.value) : null;\n this.OnDateChange(field, value);\n }\n\n public OnArrayInputChange(field: ParameterField, event: Event): void {\n const input = event.target as HTMLInputElement;\n const value = input.value\n ? input.value.split(',').map(s => s.trim()).filter(s => s)\n : [];\n this.OnValueChange(field, value);\n }\n}\n","<!-- Query Parameter Form - Slide-in Panel -->\n@if (IsOpen && ShowOverlay) {\n <div class=\"param-form-overlay\"\n @fadeIn\n (click)=\"Cancel()\">\n </div>\n}\n\n@if (IsOpen) {\n <div class=\"param-form-panel\"\n @slideIn\n [style.width.px]=\"PanelWidth\">\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-content\">\n <i class=\"fa-solid fa-sliders header-icon\"></i>\n <div class=\"header-text\">\n <h3 class=\"header-title\">Query Parameters</h3>\n @if (QueryInfo) {\n <span class=\"header-subtitle\">{{ QueryInfo.Name }}</span>\n }\n </div>\n </div>\n <button class=\"close-btn\" (click)=\"Cancel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <!-- Form Content -->\n <div class=\"panel-content\">\n <!-- No parameters message -->\n @if (Fields.length === 0) {\n <div class=\"no-params\">\n <i class=\"fa-solid fa-check-circle no-params-icon\"></i>\n <p>This query has no parameters</p>\n <button class=\"btn btn-primary\" (click)=\"Submit()\">\n Run Query\n </button>\n </div>\n }\n <!-- Parameter fields -->\n @if (Fields.length > 0) {\n <div class=\"param-fields\">\n @for (field of Fields; track TrackByField($index, field)) {\n <div class=\"param-field\"\n [class.has-error]=\"field.error && field.touched\"\n [class.required]=\"field.info.IsRequired\">\n <!-- Label -->\n <label class=\"field-label\" [for]=\"'param-' + field.info.Name\">\n {{ field.info.Name }}\n @if (field.info.IsRequired) {\n <span class=\"required-indicator\">*</span>\n }\n <span class=\"field-type\">({{ field.info.Type }})</span>\n </label>\n <!-- Description -->\n @if (field.info.Description) {\n <p class=\"field-description\">\n {{ field.info.Description }}\n </p>\n }\n <!-- String input -->\n @if (field.info.Type === 'string') {\n <input type=\"text\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetStringValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info)\"\n (input)=\"OnInputChange(field, $event)\">\n }\n <!-- Number input -->\n @if (field.info.Type === 'number') {\n <input type=\"number\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetNumberValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info)\"\n (input)=\"OnNumberInputChange(field, $event)\">\n }\n <!-- Date input -->\n @if (field.info.Type === 'date') {\n <input type=\"date\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetDateValue(field.value)\"\n (input)=\"OnDateInputChange(field, $event)\">\n }\n <!-- Boolean input -->\n @if (field.info.Type === 'boolean') {\n <div class=\"checkbox-wrapper\">\n <input type=\"checkbox\"\n [id]=\"'param-' + field.info.Name\"\n [checked]=\"GetBooleanValue(field.value)\"\n (change)=\"OnCheckboxChange(field, $event)\">\n <label [for]=\"'param-' + field.info.Name\" class=\"checkbox-label\">\n {{ GetBooleanValue(field.value) ? 'Yes' : 'No' }}\n </label>\n </div>\n }\n <!-- Array input (comma-separated) -->\n @if (field.info.Type === 'array') {\n <input type=\"text\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetArrayDisplayValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info) || 'Enter values separated by commas'\"\n (input)=\"OnArrayInputChange(field, $event)\">\n <span class=\"field-hint\">Enter multiple values separated by commas</span>\n }\n <!-- Error message -->\n @if (field.error && field.touched) {\n <span class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ field.error }}\n </span>\n }\n <!-- Sample value hint -->\n @if (field.info.SampleValue && !field.error) {\n <span class=\"field-sample\">\n Example: {{ field.info.SampleValue }}\n </span>\n }\n </div>\n }\n </div>\n }\n </div>\n <!-- Footer -->\n @if (Fields.length > 0) {\n <div class=\"panel-footer\">\n <button class=\"btn btn-secondary\" (click)=\"Reset()\" title=\"Reset to defaults\">\n <i class=\"fa-solid fa-undo\"></i>\n Reset\n </button>\n <div class=\"footer-right\">\n <button class=\"btn btn-secondary\" (click)=\"Cancel()\">\n Cancel\n </button>\n <button class=\"btn btn-primary\"\n [disabled]=\"!CanSubmit\"\n (click)=\"Submit()\">\n <i class=\"fa-solid fa-play\"></i>\n Run Query\n </button>\n </div>\n </div>\n }\n </div>\n}\n"]}
1
+ {"version":3,"file":"query-parameter-form.component.js","sourceRoot":"","sources":["../../../src/lib/query-parameter-form/query-parameter-form.component.ts","../../../src/lib/query-parameter-form/query-parameter-form.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit,\n OnDestroy,\n OnChanges,\n SimpleChanges,\n ChangeDetectorRef,\n ChangeDetectionStrategy\n} from '@angular/core';\nimport { trigger, transition, style, animate } from '@angular/animations';\nimport { QueryInfo, QueryParameterInfo } from '@memberjunction/core';\nimport { QueryParameterValues } from '../query-data-grid/models/query-grid-types';\n\n/**\n * A single parameter field in the form\n */\ninterface ParameterField {\n info: QueryParameterInfo;\n value: string | number | boolean | Date | string[] | null;\n error: string | null;\n touched: boolean;\n}\n\n/**\n * A slide-in form for entering query parameters before execution.\n * Features:\n * - Dynamic form generation from QueryParameterInfo metadata\n * - Type-appropriate input controls (text, number, date, checkbox, multi-select)\n * - Validation with helpful error messages\n * - Sample values as placeholders\n * - Description tooltips\n *\n * @example\n * ```html\n * <mj-query-parameter-form\n * [QueryInfo]=\"query\"\n * [InitialValues]=\"savedParams\"\n * [IsOpen]=\"showParams\"\n * (ParametersSubmit)=\"onRunQuery($event)\"\n * (Close)=\"showParams = false\">\n * </mj-query-parameter-form>\n * ```\n */\n@Component({\n standalone: false,\n selector: 'mj-query-parameter-form',\n templateUrl: './query-parameter-form.component.html',\n styleUrls: ['./query-parameter-form.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n animations: [\n trigger('slideIn', [\n transition(':enter', [\n style({ transform: 'translateX(100%)', opacity: 0 }),\n animate('250ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))\n ]),\n transition(':leave', [\n animate('200ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))\n ])\n ]),\n trigger('fadeIn', [\n transition(':enter', [\n style({ opacity: 0 }),\n animate('150ms ease-out', style({ opacity: 1 }))\n ]),\n transition(':leave', [\n animate('100ms ease-in', style({ opacity: 0 }))\n ])\n ])\n ]\n})\nexport class QueryParameterFormComponent implements OnInit, OnChanges, OnDestroy {\n // ========================================\n // Inputs\n // ========================================\n\n /**\n * The query metadata containing parameter definitions\n */\n @Input() QueryInfo: QueryInfo | null = null;\n\n /**\n * Initial values to populate the form (e.g., from saved state)\n */\n @Input() InitialValues: QueryParameterValues = {};\n\n /**\n * Whether the panel is open/visible\n */\n @Input() IsOpen: boolean = false;\n\n /**\n * Panel width in pixels\n */\n @Input() PanelWidth: number = 400;\n\n /**\n * Whether to show the overlay backdrop\n */\n @Input() ShowOverlay: boolean = true;\n\n // ========================================\n // Outputs\n // ========================================\n\n /**\n * Fired when user submits the form with valid parameters\n */\n @Output() ParametersSubmit = new EventEmitter<QueryParameterValues>();\n\n /**\n * Fired when panel is closed\n */\n @Output() Close = new EventEmitter<void>();\n\n // ========================================\n // Internal State\n // ========================================\n\n public Fields: ParameterField[] = [];\n public HasRequiredParams: boolean = false;\n public AllRequiredFilled: boolean = false;\n\n constructor(private cdr: ChangeDetectorRef) {}\n\n ngOnInit(): void {\n this.buildForm();\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['QueryInfo'] || changes['InitialValues']) {\n this.buildForm();\n }\n }\n\n ngOnDestroy(): void {}\n\n // ========================================\n // Form Building\n // ========================================\n\n private buildForm(): void {\n if (!this.QueryInfo) {\n this.Fields = [];\n this.HasRequiredParams = false;\n return;\n }\n\n const parameters = this.QueryInfo.Parameters || [];\n\n this.Fields = parameters.map(param => {\n const initialValue = this.getInitialValue(param);\n\n return {\n info: param,\n value: initialValue,\n error: null,\n touched: false\n };\n });\n\n this.HasRequiredParams = this.Fields.some(f => f.info.IsRequired);\n this.validateAllFields();\n this.cdr.markForCheck();\n }\n\n private getInitialValue(param: QueryParameterInfo): string | number | boolean | Date | string[] | null {\n // Check initial values first\n if (this.InitialValues && this.InitialValues[param.Name] !== undefined) {\n return this.InitialValues[param.Name];\n }\n\n // Fall back to default value\n if (param.DefaultValue !== null && param.DefaultValue !== undefined) {\n return this.parseDefaultValue(param);\n }\n\n // Type-specific defaults\n switch (param.Type) {\n case 'boolean':\n return false;\n case 'array':\n return [];\n default:\n return null;\n }\n }\n\n private parseDefaultValue(param: QueryParameterInfo): string | number | boolean | Date | string[] | null {\n const defaultValue = param.DefaultValue;\n if (defaultValue === null || defaultValue === undefined) return null;\n\n try {\n switch (param.Type) {\n case 'number':\n return Number(defaultValue);\n case 'boolean':\n return defaultValue.toLowerCase() === 'true' || defaultValue === '1';\n case 'date':\n return new Date(defaultValue);\n case 'array':\n return JSON.parse(defaultValue);\n default:\n return defaultValue;\n }\n } catch {\n return defaultValue;\n }\n }\n\n // ========================================\n // Value Handling\n // ========================================\n\n public OnValueChange(field: ParameterField, value: unknown): void {\n field.value = value as ParameterField['value'];\n field.touched = true;\n this.validateField(field);\n this.updateAllRequiredFilled();\n this.cdr.markForCheck();\n }\n\n public OnDateChange(field: ParameterField, value: Date | null): void {\n field.value = value;\n field.touched = true;\n this.validateField(field);\n this.updateAllRequiredFilled();\n this.cdr.markForCheck();\n }\n\n public OnCheckboxChange(field: ParameterField, event: Event): void {\n const input = event.target as HTMLInputElement;\n field.value = input.checked;\n field.touched = true;\n this.validateField(field);\n this.updateAllRequiredFilled();\n this.cdr.markForCheck();\n }\n\n // ========================================\n // Validation\n // ========================================\n\n private validateField(field: ParameterField): void {\n field.error = null;\n\n const value = field.value;\n const param = field.info;\n\n // Required check\n if (param.IsRequired) {\n if (value === null || value === undefined || value === '') {\n field.error = 'This field is required';\n return;\n }\n if (param.Type === 'array' && Array.isArray(value) && value.length === 0) {\n field.error = 'At least one value is required';\n return;\n }\n }\n\n // Type validation\n if (value !== null && value !== undefined && value !== '') {\n switch (param.Type) {\n case 'number':\n if (isNaN(Number(value))) {\n field.error = 'Must be a valid number';\n }\n break;\n case 'date':\n if (value instanceof Date && isNaN(value.getTime())) {\n field.error = 'Must be a valid date';\n }\n break;\n }\n }\n }\n\n private validateAllFields(): void {\n for (const field of this.Fields) {\n this.validateField(field);\n }\n this.updateAllRequiredFilled();\n }\n\n private updateAllRequiredFilled(): void {\n this.AllRequiredFilled = this.Fields\n .filter(f => f.info.IsRequired)\n .every(f => {\n const value = f.value;\n if (value === null || value === undefined || value === '') return false;\n if (f.info.Type === 'array' && Array.isArray(value) && value.length === 0) return false;\n return f.error === null;\n });\n }\n\n public get HasErrors(): boolean {\n return this.Fields.some(f => f.error !== null);\n }\n\n public get CanSubmit(): boolean {\n return !this.HasErrors && this.AllRequiredFilled;\n }\n\n // ========================================\n // Form Submission\n // ========================================\n\n public Submit(): void {\n // Mark all fields as touched\n for (const field of this.Fields) {\n field.touched = true;\n }\n this.validateAllFields();\n\n if (!this.CanSubmit) {\n this.cdr.markForCheck();\n return;\n }\n\n // Build parameter values object\n const values: QueryParameterValues = {};\n for (const field of this.Fields) {\n if (field.value !== null && field.value !== undefined) {\n values[field.info.Name] = field.value;\n }\n }\n\n this.ParametersSubmit.emit(values);\n }\n\n public Cancel(): void {\n this.Close.emit();\n }\n\n public Reset(): void {\n this.buildForm();\n }\n\n // ========================================\n // UI Helpers\n // ========================================\n\n public GetInputType(param: QueryParameterInfo): string {\n switch (param.Type) {\n case 'number':\n return 'number';\n case 'boolean':\n return 'checkbox';\n case 'date':\n return 'date';\n default:\n return 'text';\n }\n }\n\n public GetPlaceholder(param: QueryParameterInfo): string {\n if (param.SampleValue) {\n return `e.g., ${param.SampleValue}`;\n }\n return param.Description || '';\n }\n\n public TrackByField(index: number, field: ParameterField): string {\n return field.info.Name;\n }\n\n // ========================================\n // Type-Safe Value Getters for Template\n // ========================================\n\n public GetStringValue(value: ParameterField['value']): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n return String(value);\n }\n\n public GetNumberValue(value: ParameterField['value']): number | null {\n if (value === null || value === undefined) return null;\n if (typeof value === 'number') return value;\n const num = Number(value);\n return isNaN(num) ? null : num;\n }\n\n public GetDateValue(value: ParameterField['value']): string {\n if (value === null || value === undefined) return '';\n if (value instanceof Date) {\n // Format as YYYY-MM-DD for HTML date input\n return value.toISOString().split('T')[0];\n }\n if (typeof value === 'string') {\n // Try to parse and format\n const date = new Date(value);\n if (!isNaN(date.getTime())) {\n return date.toISOString().split('T')[0];\n }\n }\n return '';\n }\n\n public GetBooleanValue(value: ParameterField['value']): boolean {\n if (value === null || value === undefined) return false;\n return Boolean(value);\n }\n\n public GetArrayDisplayValue(value: ParameterField['value']): string {\n if (value === null || value === undefined) return '';\n if (Array.isArray(value)) {\n return value.join(', ');\n }\n return String(value);\n }\n\n // ========================================\n // Input Event Handlers\n // ========================================\n\n public OnInputChange(field: ParameterField, event: Event): void {\n const input = event.target as HTMLInputElement;\n this.OnValueChange(field, input.value);\n }\n\n public OnNumberInputChange(field: ParameterField, event: Event): void {\n const input = event.target as HTMLInputElement;\n const value = input.value === '' ? null : Number(input.value);\n this.OnValueChange(field, value);\n }\n\n public OnDateInputChange(field: ParameterField, event: Event): void {\n const input = event.target as HTMLInputElement;\n const value = input.value ? new Date(input.value) : null;\n this.OnDateChange(field, value);\n }\n\n public OnArrayInputChange(field: ParameterField, event: Event): void {\n const input = event.target as HTMLInputElement;\n const value = input.value\n ? input.value.split(',').map(s => s.trim()).filter(s => s)\n : [];\n this.OnValueChange(field, value);\n }\n}\n","<!-- Query Parameter Form - Slide-in Panel -->\n@if (IsOpen && ShowOverlay) {\n <div class=\"param-form-overlay\"\n @fadeIn\n (click)=\"Cancel()\">\n </div>\n}\n\n@if (IsOpen) {\n <div class=\"param-form-panel\"\n @slideIn\n [style.width.px]=\"PanelWidth\">\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-content\">\n <i class=\"fa-solid fa-sliders header-icon\"></i>\n <div class=\"header-text\">\n <h3 class=\"header-title\">Query Parameters</h3>\n @if (QueryInfo) {\n <span class=\"header-subtitle\">{{ QueryInfo.Name }}</span>\n }\n </div>\n </div>\n <button class=\"close-btn\" (click)=\"Cancel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <!-- Form Content -->\n <div class=\"panel-content\">\n <!-- No parameters message -->\n @if (Fields.length === 0) {\n <div class=\"no-params\">\n <i class=\"fa-solid fa-check-circle no-params-icon\"></i>\n <p>This query has no parameters</p>\n <button class=\"btn btn-primary\" (click)=\"Submit()\">\n Run Query\n </button>\n </div>\n }\n <!-- Parameter fields -->\n @if (Fields.length > 0) {\n <div class=\"param-fields\">\n @for (field of Fields; track TrackByField($index, field)) {\n <div class=\"param-field\"\n [class.has-error]=\"field.error && field.touched\"\n [class.required]=\"field.info.IsRequired\">\n <!-- Label -->\n <label class=\"field-label\" [for]=\"'param-' + field.info.Name\">\n {{ field.info.Name }}\n @if (field.info.IsRequired) {\n <span class=\"required-indicator\">*</span>\n }\n <span class=\"field-type\">({{ field.info.Type }})</span>\n </label>\n <!-- Description -->\n @if (field.info.Description) {\n <p class=\"field-description\">\n {{ field.info.Description }}\n </p>\n }\n <!-- String input -->\n @if (field.info.Type === 'string') {\n <input type=\"text\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetStringValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info)\"\n (input)=\"OnInputChange(field, $event)\">\n }\n <!-- Number input -->\n @if (field.info.Type === 'number') {\n <input type=\"number\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetNumberValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info)\"\n (input)=\"OnNumberInputChange(field, $event)\">\n }\n <!-- Date input -->\n @if (field.info.Type === 'date') {\n <input type=\"date\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetDateValue(field.value)\"\n (input)=\"OnDateInputChange(field, $event)\">\n }\n <!-- Boolean input -->\n @if (field.info.Type === 'boolean') {\n <div class=\"checkbox-wrapper\">\n <input type=\"checkbox\"\n [id]=\"'param-' + field.info.Name\"\n [checked]=\"GetBooleanValue(field.value)\"\n (change)=\"OnCheckboxChange(field, $event)\">\n <label [for]=\"'param-' + field.info.Name\" class=\"checkbox-label\">\n {{ GetBooleanValue(field.value) ? 'Yes' : 'No' }}\n </label>\n </div>\n }\n <!-- Array input (comma-separated) -->\n @if (field.info.Type === 'array') {\n <input type=\"text\"\n class=\"form-input\"\n [id]=\"'param-' + field.info.Name\"\n [value]=\"GetArrayDisplayValue(field.value)\"\n [placeholder]=\"GetPlaceholder(field.info) || 'Enter values separated by commas'\"\n (input)=\"OnArrayInputChange(field, $event)\">\n <span class=\"field-hint\">Enter multiple values separated by commas</span>\n }\n <!-- Error message -->\n @if (field.error && field.touched) {\n <span class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ field.error }}\n </span>\n }\n <!-- Sample value hint -->\n @if (field.info.SampleValue && !field.error) {\n <span class=\"field-sample\">\n Example: {{ field.info.SampleValue }}\n </span>\n }\n </div>\n }\n </div>\n }\n </div>\n <!-- Footer -->\n @if (Fields.length > 0) {\n <div class=\"panel-footer\">\n <button class=\"btn btn-secondary\" (click)=\"Reset()\" title=\"Reset to defaults\">\n <i class=\"fa-solid fa-undo\"></i>\n Reset\n </button>\n <div class=\"footer-right\">\n <button class=\"btn btn-secondary\" (click)=\"Cancel()\">\n Cancel\n </button>\n <button class=\"btn btn-primary\"\n [disabled]=\"!CanSubmit\"\n (click)=\"Submit()\">\n <i class=\"fa-solid fa-play\"></i>\n Run Query\n </button>\n </div>\n </div>\n }\n </div>\n}\n"]}
@@ -700,7 +700,7 @@ export class QueryRowDetailComponent {
700
700
  i0.ɵɵconditional(ctx.Visible ? 0 : -1);
701
701
  i0.ɵɵadvance();
702
702
  i0.ɵɵconditional(ctx.Visible ? 1 : -1);
703
- } }, styles: ["\n\n\n[_nghost-%COMP%] {\n display: block;\n}\n\n\n\n\n\n\n.row-detail-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n right: 0;\n height: 100%;\n background: #fff;\n box-shadow: -4px 0 20px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n\n\n\n\n\n.resize-handle[_ngcontent-%COMP%] {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: ew-resize;\n background: transparent;\n transition: background 0.15s ease;\n z-index: 10;\n}\n\n.resize-handle[_ngcontent-%COMP%]:hover, \n.resize-handle.resizing[_ngcontent-%COMP%] {\n background: rgba(33, 150, 243, 0.3);\n}\n\n.resize-handle[_ngcontent-%COMP%]::before {\n content: '';\n position: absolute;\n left: 2px;\n top: 50%;\n transform: translateY(-50%);\n width: 2px;\n height: 40px;\n background: #ccc;\n border-radius: 1px;\n transition: background 0.15s ease;\n}\n\n.resize-handle[_ngcontent-%COMP%]:hover::before, \n.resize-handle.resizing[_ngcontent-%COMP%]::before {\n background: #2196F3;\n}\n\n\n\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: linear-gradient(135deg, #5c6bc0 0%, #3949ab 100%);\n color: #fff;\n flex-shrink: 0;\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.header-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n opacity: 0.9;\n}\n\n.close-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: #fff;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n.panel-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: #fff;\n}\n\n.header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n\n\n\n\n\n.row-nav[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 8px;\n background: rgba(255, 255, 255, 0.15);\n border-radius: 4px;\n}\n\n.nav-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n background: transparent;\n color: #fff;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s ease;\n}\n\n.nav-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.15);\n}\n\n.nav-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.row-indicator[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: #fff;\n padding: 0 4px;\n min-width: 50px;\n text-align: center;\n}\n\n\n\n\n\n\n.action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: #fff;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.action-btn[_ngcontent-%COMP%]:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n.action-btn.active[_ngcontent-%COMP%] {\n background: rgba(255, 255, 255, 0.3);\n}\n\n.hidden-count[_ngcontent-%COMP%] {\n font-weight: 400;\n font-size: 11px;\n color: rgba(255, 255, 255, 0.7);\n margin-left: auto;\n}\n\n\n\n\n\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n}\n\n\n\n\n\n\n.field-section[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n\n.field-section[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.section-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 0 12px 0;\n font-size: 14px;\n font-weight: 600;\n color: #333;\n padding-bottom: 8px;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.section-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.pk-icon[_ngcontent-%COMP%] {\n color: #f9a825;\n}\n\n.fk-icon[_ngcontent-%COMP%] {\n color: #2196F3;\n}\n\n\n\n\n\n\n.field-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.field-item[_ngcontent-%COMP%] {\n padding: 10px 12px;\n background: #f8f9fa;\n border-radius: 6px;\n border-left: 3px solid #5c6bc0;\n}\n\n.field-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n}\n\n.field-name[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: #333;\n flex-shrink: 0;\n}\n\n.field-type[_ngcontent-%COMP%] {\n font-size: 11px;\n font-family: 'Consolas', 'Monaco', monospace;\n color: #666;\n background: #e8eaf6;\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.target-entity[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: #2196F3;\n margin-left: auto;\n}\n\n.target-entity[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 8px;\n}\n\n.copy-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: none;\n background: transparent;\n color: #aaa;\n cursor: pointer;\n border-radius: 4px;\n margin-left: auto;\n opacity: 0;\n transition: all 0.15s ease;\n}\n\n.field-item[_ngcontent-%COMP%]:hover .copy-btn[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.copy-btn[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.08);\n color: #666;\n}\n\n\n\n\n\n\n.field-value[_ngcontent-%COMP%] {\n font-size: 13px;\n color: #333;\n line-height: 1.5;\n word-break: break-word;\n}\n\n.field-value.empty[_ngcontent-%COMP%] {\n color: #999;\n font-style: italic;\n}\n\n.field-value.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n margin: -2px -4px;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.field-value.clickable[_ngcontent-%COMP%]:hover {\n background: rgba(33, 150, 243, 0.1);\n}\n\n.entity-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #2196F3;\n flex-shrink: 0;\n}\n\n.link-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n color: #aaa;\n margin-left: auto;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.field-value.clickable[_ngcontent-%COMP%]:hover .link-icon[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.value-text[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.value-text.monospace[_ngcontent-%COMP%] {\n font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;\n font-size: 12px;\n}\n\n\n\n\n\n\n.boolean-value[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.bool-true[_ngcontent-%COMP%] {\n color: #4caf50;\n}\n\n.bool-false[_ngcontent-%COMP%] {\n color: #9e9e9e;\n}\n\n\n\n\n\n\n.json-value[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.json-content[_ngcontent-%COMP%] {\n margin: 0;\n padding: 8px;\n background: #f5f5f5;\n border-radius: 4px;\n font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;\n font-size: 11px;\n line-height: 1.4;\n overflow: hidden;\n max-height: 100px;\n white-space: pre-wrap;\n word-break: break-all;\n}\n\n.json-value.expanded[_ngcontent-%COMP%] .json-content[_ngcontent-%COMP%] {\n max-height: none;\n}\n\n\n\n\n\n\n.long-text[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.long-text[_ngcontent-%COMP%] .value-text[_ngcontent-%COMP%] {\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.long-text.expanded[_ngcontent-%COMP%] .value-text[_ngcontent-%COMP%] {\n display: block;\n -webkit-line-clamp: unset;\n}\n\n\n\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n display: inline-block;\n margin-top: 6px;\n padding: 4px 8px;\n border: none;\n background: transparent;\n color: #2196F3;\n font-size: 11px;\n font-weight: 500;\n cursor: pointer;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: rgba(33, 150, 243, 0.1);\n}\n\n\n\n\n\n\n.panel-backdrop[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 999;\n}\n\n\n\n\n\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: #ccc;\n border-radius: 3px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: #aaa;\n}\n\n\n\n\n\n\n@media (max-width: 600px) {\n .row-detail-panel[_ngcontent-%COMP%] {\n width: 100% !important;\n }\n\n .resize-handle[_ngcontent-%COMP%] {\n display: none;\n }\n}"], data: { animation: [
703
+ } }, styles: ["\n\n\n[_nghost-%COMP%] {\n display: block;\n}\n\n\n\n\n\n\n.row-detail-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n right: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n box-shadow: -4px 0 20px var(--mj-bg-overlay);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n\n\n\n\n\n.resize-handle[_ngcontent-%COMP%] {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: ew-resize;\n background: transparent;\n transition: background 0.15s ease;\n z-index: 10;\n}\n\n.resize-handle[_ngcontent-%COMP%]:hover, \n.resize-handle.resizing[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n.resize-handle[_ngcontent-%COMP%]::before {\n content: '';\n position: absolute;\n left: 2px;\n top: 50%;\n transform: translateY(-50%);\n width: 2px;\n height: 40px;\n background: var(--mj-border-strong);\n border-radius: 1px;\n transition: background 0.15s ease;\n}\n\n.resize-handle[_ngcontent-%COMP%]:hover::before, \n.resize-handle.resizing[_ngcontent-%COMP%]::before {\n background: var(--mj-brand-primary);\n}\n\n\n\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.header-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n opacity: 0.9;\n}\n\n.close-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: var(--mj-text-inverse);\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n.panel-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n}\n\n.header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n\n\n\n\n\n.row-nav[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 8px;\n background: rgba(255, 255, 255, 0.15);\n border-radius: 4px;\n}\n\n.nav-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--mj-text-inverse);\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s ease;\n}\n\n.nav-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.15);\n}\n\n.nav-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.row-indicator[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-inverse);\n padding: 0 4px;\n min-width: 50px;\n text-align: center;\n}\n\n\n\n\n\n\n.action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: var(--mj-text-inverse);\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.action-btn[_ngcontent-%COMP%]:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n.action-btn.active[_ngcontent-%COMP%] {\n background: rgba(255, 255, 255, 0.3);\n}\n\n.hidden-count[_ngcontent-%COMP%] {\n font-weight: 400;\n font-size: 11px;\n color: rgba(255, 255, 255, 0.7);\n margin-left: auto;\n}\n\n\n\n\n\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n}\n\n\n\n\n\n\n.field-section[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n\n.field-section[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.section-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 0 12px 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n padding-bottom: 8px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.section-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.pk-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n.fk-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n\n\n\n.field-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.field-item[_ngcontent-%COMP%] {\n padding: 10px 12px;\n background: var(--mj-bg-surface-card);\n border-radius: 6px;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.field-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n}\n\n.field-name[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n flex-shrink: 0;\n}\n\n.field-type[_ngcontent-%COMP%] {\n font-size: 11px;\n font-family: 'Consolas', 'Monaco', monospace;\n color: var(--mj-text-secondary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.target-entity[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: var(--mj-brand-primary);\n margin-left: auto;\n}\n\n.target-entity[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 8px;\n}\n\n.copy-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--mj-text-disabled);\n cursor: pointer;\n border-radius: 4px;\n margin-left: auto;\n opacity: 0;\n transition: all 0.15s ease;\n}\n\n.field-item[_ngcontent-%COMP%]:hover .copy-btn[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.copy-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n\n.field-value[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-primary);\n line-height: 1.5;\n word-break: break-word;\n}\n\n.field-value.empty[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n.field-value.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n margin: -2px -4px;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.field-value.clickable[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.entity-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.link-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-disabled);\n margin-left: auto;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.field-value.clickable[_ngcontent-%COMP%]:hover .link-icon[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.value-text[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.value-text.monospace[_ngcontent-%COMP%] {\n font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;\n font-size: 12px;\n}\n\n\n\n\n\n\n.boolean-value[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.bool-true[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.bool-false[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n}\n\n\n\n\n\n\n.json-value[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.json-content[_ngcontent-%COMP%] {\n margin: 0;\n padding: 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 4px;\n font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;\n font-size: 11px;\n line-height: 1.4;\n overflow: hidden;\n max-height: 100px;\n white-space: pre-wrap;\n word-break: break-all;\n}\n\n.json-value.expanded[_ngcontent-%COMP%] .json-content[_ngcontent-%COMP%] {\n max-height: none;\n}\n\n\n\n\n\n\n.long-text[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.long-text[_ngcontent-%COMP%] .value-text[_ngcontent-%COMP%] {\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.long-text.expanded[_ngcontent-%COMP%] .value-text[_ngcontent-%COMP%] {\n display: block;\n -webkit-line-clamp: unset;\n}\n\n\n\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n display: inline-block;\n margin-top: 6px;\n padding: 4px 8px;\n border: none;\n background: transparent;\n color: var(--mj-brand-primary);\n font-size: 11px;\n font-weight: 500;\n cursor: pointer;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n\n\n\n\n\n.panel-backdrop[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 999;\n}\n\n\n\n\n\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 3px;\n}\n\n.panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n}\n\n\n\n\n\n\n@media (max-width: 600px) {\n .row-detail-panel[_ngcontent-%COMP%] {\n width: 100% !important;\n }\n\n .resize-handle[_ngcontent-%COMP%] {\n display: none;\n }\n}"], data: { animation: [
704
704
  trigger('slideIn', [
705
705
  transition(':enter', [
706
706
  style({ transform: 'translateX(100%)', opacity: 0 }),
@@ -724,7 +724,7 @@ export class QueryRowDetailComponent {
724
724
  animate('150ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))
725
725
  ])
726
726
  ])
727
- ], template: "<!-- Row Detail Slide-in Panel -->\n@if (Visible) {\n <div class=\"row-detail-panel\"\n @slideIn\n [style.width.px]=\"PanelWidth\">\n <!-- Resize handle -->\n <div class=\"resize-handle\"\n (mousedown)=\"onResizeStart($event)\"\n [class.resizing]=\"IsResizing\">\n </div>\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-left\">\n <i class=\"fa-solid fa-table-cells-large header-icon\"></i>\n <h3 class=\"panel-title\">Row Details</h3>\n </div>\n <div class=\"header-right\">\n <!-- Row navigation -->\n @if (TotalRows > 1) {\n <div class=\"row-nav\">\n <button class=\"nav-btn\"\n [disabled]=\"RowIndex === 0\"\n (click)=\"onNavigatePrev()\"\n title=\"Previous row (\u2191 or K)\">\n <i class=\"fa-solid fa-chevron-up\"></i>\n </button>\n <span class=\"row-indicator\">{{ RowIndex + 1 }} / {{ TotalRows }}</span>\n <button class=\"nav-btn\"\n [disabled]=\"RowIndex >= TotalRows - 1\"\n (click)=\"onNavigateNext()\"\n title=\"Next row (\u2193 or J)\">\n <i class=\"fa-solid fa-chevron-down\"></i>\n </button>\n </div>\n }\n <!-- Toggle empty fields -->\n <button class=\"action-btn\"\n (click)=\"toggleHideEmptyFields()\"\n [class.active]=\"HideEmptyFields\"\n [title]=\"HideEmptyFields ? 'Show empty fields' : 'Hide empty fields'\">\n <i class=\"fa-solid\" [class.fa-eye]=\"!HideEmptyFields\" [class.fa-eye-slash]=\"HideEmptyFields\"></i>\n </button>\n <!-- Copy JSON button -->\n <button class=\"action-btn\" (click)=\"copyRowAsJson()\" title=\"Copy row as JSON\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n <!-- Close button -->\n <button class=\"close-btn\" (click)=\"onClose()\" title=\"Close (Esc)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n <!-- Content -->\n <div class=\"panel-content\">\n <!-- Primary Keys Section -->\n @if (getVisibleFields(PrimaryKeyFields).length > 0) {\n <div class=\"field-section\">\n <h4 class=\"section-title\">\n <i class=\"fa-solid fa-key section-icon pk-icon\"></i>\n Primary Key\n </h4>\n <div class=\"field-list\">\n @for (field of getVisibleFields(PrimaryKeyFields); track field) {\n <div class=\"field-item\">\n <div class=\"field-header\">\n <span class=\"field-name\">{{ field.displayName }}</span>\n <button class=\"copy-btn\" (click)=\"copyValue(field)\" title=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n <div class=\"field-value\"\n [class.clickable]=\"field.targetEntityName\"\n (click)=\"field.targetEntityName && onEntityLinkClick(field)\">\n @if (field.targetEntityIcon) {\n <i\n [class]=\"field.targetEntityIcon\"\n class=\"entity-icon\"></i>\n }\n <span class=\"value-text monospace\">{{ field.formattedValue }}</span>\n @if (field.targetEntityName) {\n <i\n class=\"fa-solid fa-arrow-up-right-from-square link-icon\"></i>\n }\n </div>\n </div>\n }\n </div>\n </div>\n }\n <!-- Foreign Keys Section -->\n @if (getVisibleFields(ForeignKeyFields).length > 0) {\n <div class=\"field-section\">\n <h4 class=\"section-title\">\n <i class=\"fa-solid fa-link section-icon fk-icon\"></i>\n Related Records\n </h4>\n <div class=\"field-list\">\n @for (field of getVisibleFields(ForeignKeyFields); track field) {\n <div class=\"field-item\">\n <div class=\"field-header\">\n <span class=\"field-name\">{{ field.displayName }}</span>\n @if (field.targetEntityName) {\n <span class=\"target-entity\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n {{ field.targetEntityName }}\n </span>\n }\n <button class=\"copy-btn\" (click)=\"copyValue(field)\" title=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n @if (field.value != null) {\n <div class=\"field-value clickable\"\n (click)=\"onEntityLinkClick(field)\">\n @if (field.targetEntityIcon) {\n <i\n [class]=\"field.targetEntityIcon\"\n class=\"entity-icon\"></i>\n }\n <span class=\"value-text monospace\">{{ field.formattedValue }}</span>\n <i class=\"fa-solid fa-arrow-up-right-from-square link-icon\"></i>\n </div>\n }\n @if (field.value == null) {\n <div class=\"field-value empty\">\n <span class=\"value-text\">(empty)</span>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n <!-- Regular Fields Section -->\n @if (getVisibleFields(RegularFields).length > 0) {\n <div class=\"field-section\">\n <h4 class=\"section-title\">\n <i class=\"fa-solid fa-list section-icon\"></i>\n Fields\n @if (HideEmptyFields && getEmptyFieldCount(RegularFields) > 0) {\n <span class=\"hidden-count\">\n ({{ getEmptyFieldCount(RegularFields) }} empty hidden)\n </span>\n }\n </h4>\n <div class=\"field-list\">\n @for (field of getVisibleFields(RegularFields); track field) {\n <div class=\"field-item\">\n <div class=\"field-header\">\n <span class=\"field-name\">{{ field.displayName }}</span>\n <span class=\"field-type\">{{ field.sqlType }}</span>\n <button class=\"copy-btn\" (click)=\"copyValue(field)\" title=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n <!-- JSON value -->\n @if (isJson(field.formattedValue)) {\n <div class=\"field-value json-value\"\n [class.expanded]=\"field.isExpanded\">\n <pre class=\"json-content\">{{ formatJson(field.formattedValue) }}</pre>\n <button class=\"expand-btn\" (click)=\"toggleFieldExpand(field)\">\n {{ field.isExpanded ? 'Collapse' : 'Expand' }}\n </button>\n </div>\n }\n <!-- Long text value -->\n @if (!isJson(field.formattedValue) && field.isLongText) {\n <div class=\"field-value long-text\"\n [class.expanded]=\"field.isExpanded\">\n <span class=\"value-text\">{{ field.formattedValue }}</span>\n <button class=\"expand-btn\" (click)=\"toggleFieldExpand(field)\">\n {{ field.isExpanded ? 'Show less' : 'Show more' }}\n </button>\n </div>\n }\n <!-- Boolean value -->\n @if (field.sqlType.toLowerCase() === 'bit' && !isJson(field.formattedValue)) {\n <div class=\"field-value boolean-value\"\n >\n <i [class]=\"field.value ? 'fa-solid fa-check-circle bool-true' : 'fa-solid fa-times-circle bool-false'\"></i>\n <span class=\"value-text\">{{ field.formattedValue }}</span>\n </div>\n }\n <!-- Empty value -->\n @if (field.value == null && !isJson(field.formattedValue)) {\n <div class=\"field-value empty\"\n >\n <span class=\"value-text\">(empty)</span>\n </div>\n }\n <!-- Regular value -->\n @if (field.value != null && !isJson(field.formattedValue) && !field.isLongText && field.sqlType.toLowerCase() !== 'bit') {\n <div class=\"field-value\"\n >\n <span class=\"value-text\"\n [class.monospace]=\"field.sqlType.toLowerCase().includes('uniqueidentifier') || field.name.toLowerCase().includes('id')\">\n {{ field.formattedValue }}\n </span>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n}\n\n<!-- Backdrop -->\n@if (Visible) {\n <div class=\"panel-backdrop\"\n (click)=\"onClose()\">\n </div>\n}\n", styles: ["/* Query Row Detail Panel Styles */\n\n:host {\n display: block;\n}\n\n/* ========================================\n Panel Container\n ======================================== */\n\n.row-detail-panel {\n position: absolute;\n top: 0;\n right: 0;\n height: 100%;\n background: #fff;\n box-shadow: -4px 0 20px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n/* ========================================\n Resize Handle\n ======================================== */\n\n.resize-handle {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: ew-resize;\n background: transparent;\n transition: background 0.15s ease;\n z-index: 10;\n}\n\n.resize-handle:hover,\n.resize-handle.resizing {\n background: rgba(33, 150, 243, 0.3);\n}\n\n.resize-handle::before {\n content: '';\n position: absolute;\n left: 2px;\n top: 50%;\n transform: translateY(-50%);\n width: 2px;\n height: 40px;\n background: #ccc;\n border-radius: 1px;\n transition: background 0.15s ease;\n}\n\n.resize-handle:hover::before,\n.resize-handle.resizing::before {\n background: #2196F3;\n}\n\n/* ========================================\n Header\n ======================================== */\n\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: linear-gradient(135deg, #5c6bc0 0%, #3949ab 100%);\n color: #fff;\n flex-shrink: 0;\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.header-icon {\n font-size: 20px;\n opacity: 0.9;\n}\n\n.close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: #fff;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.close-btn:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n.panel-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: #fff;\n}\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* ========================================\n Row Navigation\n ======================================== */\n\n.row-nav {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 8px;\n background: rgba(255, 255, 255, 0.15);\n border-radius: 4px;\n}\n\n.nav-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n background: transparent;\n color: #fff;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s ease;\n}\n\n.nav-btn:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.15);\n}\n\n.nav-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.row-indicator {\n font-size: 12px;\n font-weight: 500;\n color: #fff;\n padding: 0 4px;\n min-width: 50px;\n text-align: center;\n}\n\n/* ========================================\n Action Buttons\n ======================================== */\n\n.action-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: #fff;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.action-btn:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n.action-btn.active {\n background: rgba(255, 255, 255, 0.3);\n}\n\n.hidden-count {\n font-weight: 400;\n font-size: 11px;\n color: rgba(255, 255, 255, 0.7);\n margin-left: auto;\n}\n\n/* ========================================\n Content\n ======================================== */\n\n.panel-content {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n}\n\n/* ========================================\n Field Sections\n ======================================== */\n\n.field-section {\n margin-bottom: 24px;\n}\n\n.field-section:last-child {\n margin-bottom: 0;\n}\n\n.section-title {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 0 12px 0;\n font-size: 14px;\n font-weight: 600;\n color: #333;\n padding-bottom: 8px;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.section-icon {\n font-size: 12px;\n}\n\n.pk-icon {\n color: #f9a825;\n}\n\n.fk-icon {\n color: #2196F3;\n}\n\n/* ========================================\n Field Items\n ======================================== */\n\n.field-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.field-item {\n padding: 10px 12px;\n background: #f8f9fa;\n border-radius: 6px;\n border-left: 3px solid #5c6bc0;\n}\n\n.field-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n}\n\n.field-name {\n font-size: 12px;\n font-weight: 600;\n color: #333;\n flex-shrink: 0;\n}\n\n.field-type {\n font-size: 11px;\n font-family: 'Consolas', 'Monaco', monospace;\n color: #666;\n background: #e8eaf6;\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.target-entity {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: #2196F3;\n margin-left: auto;\n}\n\n.target-entity i {\n font-size: 8px;\n}\n\n.copy-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: none;\n background: transparent;\n color: #aaa;\n cursor: pointer;\n border-radius: 4px;\n margin-left: auto;\n opacity: 0;\n transition: all 0.15s ease;\n}\n\n.field-item:hover .copy-btn {\n opacity: 1;\n}\n\n.copy-btn:hover {\n background: rgba(0, 0, 0, 0.08);\n color: #666;\n}\n\n/* ========================================\n Field Values\n ======================================== */\n\n.field-value {\n font-size: 13px;\n color: #333;\n line-height: 1.5;\n word-break: break-word;\n}\n\n.field-value.empty {\n color: #999;\n font-style: italic;\n}\n\n.field-value.clickable {\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n margin: -2px -4px;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.field-value.clickable:hover {\n background: rgba(33, 150, 243, 0.1);\n}\n\n.entity-icon {\n font-size: 12px;\n color: #2196F3;\n flex-shrink: 0;\n}\n\n.link-icon {\n font-size: 10px;\n color: #aaa;\n margin-left: auto;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.field-value.clickable:hover .link-icon {\n opacity: 1;\n}\n\n.value-text {\n flex: 1;\n}\n\n.value-text.monospace {\n font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;\n font-size: 12px;\n}\n\n/* ========================================\n Boolean Values\n ======================================== */\n\n.boolean-value {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.bool-true {\n color: #4caf50;\n}\n\n.bool-false {\n color: #9e9e9e;\n}\n\n/* ========================================\n JSON Values\n ======================================== */\n\n.json-value {\n position: relative;\n}\n\n.json-content {\n margin: 0;\n padding: 8px;\n background: #f5f5f5;\n border-radius: 4px;\n font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;\n font-size: 11px;\n line-height: 1.4;\n overflow: hidden;\n max-height: 100px;\n white-space: pre-wrap;\n word-break: break-all;\n}\n\n.json-value.expanded .json-content {\n max-height: none;\n}\n\n/* ========================================\n Long Text Values\n ======================================== */\n\n.long-text {\n position: relative;\n}\n\n.long-text .value-text {\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.long-text.expanded .value-text {\n display: block;\n -webkit-line-clamp: unset;\n}\n\n/* ========================================\n Expand Button\n ======================================== */\n\n.expand-btn {\n display: inline-block;\n margin-top: 6px;\n padding: 4px 8px;\n border: none;\n background: transparent;\n color: #2196F3;\n font-size: 11px;\n font-weight: 500;\n cursor: pointer;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.expand-btn:hover {\n background: rgba(33, 150, 243, 0.1);\n}\n\n/* ========================================\n Backdrop\n ======================================== */\n\n.panel-backdrop {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 999;\n}\n\n/* ========================================\n Scrollbar\n ======================================== */\n\n.panel-content::-webkit-scrollbar {\n width: 6px;\n}\n\n.panel-content::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.panel-content::-webkit-scrollbar-thumb {\n background: #ccc;\n border-radius: 3px;\n}\n\n.panel-content::-webkit-scrollbar-thumb:hover {\n background: #aaa;\n}\n\n/* ========================================\n Responsive\n ======================================== */\n\n@media (max-width: 600px) {\n .row-detail-panel {\n width: 100% !important;\n }\n\n .resize-handle {\n display: none;\n }\n}\n"] }]
727
+ ], template: "<!-- Row Detail Slide-in Panel -->\n@if (Visible) {\n <div class=\"row-detail-panel\"\n @slideIn\n [style.width.px]=\"PanelWidth\">\n <!-- Resize handle -->\n <div class=\"resize-handle\"\n (mousedown)=\"onResizeStart($event)\"\n [class.resizing]=\"IsResizing\">\n </div>\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-left\">\n <i class=\"fa-solid fa-table-cells-large header-icon\"></i>\n <h3 class=\"panel-title\">Row Details</h3>\n </div>\n <div class=\"header-right\">\n <!-- Row navigation -->\n @if (TotalRows > 1) {\n <div class=\"row-nav\">\n <button class=\"nav-btn\"\n [disabled]=\"RowIndex === 0\"\n (click)=\"onNavigatePrev()\"\n title=\"Previous row (\u2191 or K)\">\n <i class=\"fa-solid fa-chevron-up\"></i>\n </button>\n <span class=\"row-indicator\">{{ RowIndex + 1 }} / {{ TotalRows }}</span>\n <button class=\"nav-btn\"\n [disabled]=\"RowIndex >= TotalRows - 1\"\n (click)=\"onNavigateNext()\"\n title=\"Next row (\u2193 or J)\">\n <i class=\"fa-solid fa-chevron-down\"></i>\n </button>\n </div>\n }\n <!-- Toggle empty fields -->\n <button class=\"action-btn\"\n (click)=\"toggleHideEmptyFields()\"\n [class.active]=\"HideEmptyFields\"\n [title]=\"HideEmptyFields ? 'Show empty fields' : 'Hide empty fields'\">\n <i class=\"fa-solid\" [class.fa-eye]=\"!HideEmptyFields\" [class.fa-eye-slash]=\"HideEmptyFields\"></i>\n </button>\n <!-- Copy JSON button -->\n <button class=\"action-btn\" (click)=\"copyRowAsJson()\" title=\"Copy row as JSON\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n <!-- Close button -->\n <button class=\"close-btn\" (click)=\"onClose()\" title=\"Close (Esc)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n <!-- Content -->\n <div class=\"panel-content\">\n <!-- Primary Keys Section -->\n @if (getVisibleFields(PrimaryKeyFields).length > 0) {\n <div class=\"field-section\">\n <h4 class=\"section-title\">\n <i class=\"fa-solid fa-key section-icon pk-icon\"></i>\n Primary Key\n </h4>\n <div class=\"field-list\">\n @for (field of getVisibleFields(PrimaryKeyFields); track field) {\n <div class=\"field-item\">\n <div class=\"field-header\">\n <span class=\"field-name\">{{ field.displayName }}</span>\n <button class=\"copy-btn\" (click)=\"copyValue(field)\" title=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n <div class=\"field-value\"\n [class.clickable]=\"field.targetEntityName\"\n (click)=\"field.targetEntityName && onEntityLinkClick(field)\">\n @if (field.targetEntityIcon) {\n <i\n [class]=\"field.targetEntityIcon\"\n class=\"entity-icon\"></i>\n }\n <span class=\"value-text monospace\">{{ field.formattedValue }}</span>\n @if (field.targetEntityName) {\n <i\n class=\"fa-solid fa-arrow-up-right-from-square link-icon\"></i>\n }\n </div>\n </div>\n }\n </div>\n </div>\n }\n <!-- Foreign Keys Section -->\n @if (getVisibleFields(ForeignKeyFields).length > 0) {\n <div class=\"field-section\">\n <h4 class=\"section-title\">\n <i class=\"fa-solid fa-link section-icon fk-icon\"></i>\n Related Records\n </h4>\n <div class=\"field-list\">\n @for (field of getVisibleFields(ForeignKeyFields); track field) {\n <div class=\"field-item\">\n <div class=\"field-header\">\n <span class=\"field-name\">{{ field.displayName }}</span>\n @if (field.targetEntityName) {\n <span class=\"target-entity\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n {{ field.targetEntityName }}\n </span>\n }\n <button class=\"copy-btn\" (click)=\"copyValue(field)\" title=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n @if (field.value != null) {\n <div class=\"field-value clickable\"\n (click)=\"onEntityLinkClick(field)\">\n @if (field.targetEntityIcon) {\n <i\n [class]=\"field.targetEntityIcon\"\n class=\"entity-icon\"></i>\n }\n <span class=\"value-text monospace\">{{ field.formattedValue }}</span>\n <i class=\"fa-solid fa-arrow-up-right-from-square link-icon\"></i>\n </div>\n }\n @if (field.value == null) {\n <div class=\"field-value empty\">\n <span class=\"value-text\">(empty)</span>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n <!-- Regular Fields Section -->\n @if (getVisibleFields(RegularFields).length > 0) {\n <div class=\"field-section\">\n <h4 class=\"section-title\">\n <i class=\"fa-solid fa-list section-icon\"></i>\n Fields\n @if (HideEmptyFields && getEmptyFieldCount(RegularFields) > 0) {\n <span class=\"hidden-count\">\n ({{ getEmptyFieldCount(RegularFields) }} empty hidden)\n </span>\n }\n </h4>\n <div class=\"field-list\">\n @for (field of getVisibleFields(RegularFields); track field) {\n <div class=\"field-item\">\n <div class=\"field-header\">\n <span class=\"field-name\">{{ field.displayName }}</span>\n <span class=\"field-type\">{{ field.sqlType }}</span>\n <button class=\"copy-btn\" (click)=\"copyValue(field)\" title=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n <!-- JSON value -->\n @if (isJson(field.formattedValue)) {\n <div class=\"field-value json-value\"\n [class.expanded]=\"field.isExpanded\">\n <pre class=\"json-content\">{{ formatJson(field.formattedValue) }}</pre>\n <button class=\"expand-btn\" (click)=\"toggleFieldExpand(field)\">\n {{ field.isExpanded ? 'Collapse' : 'Expand' }}\n </button>\n </div>\n }\n <!-- Long text value -->\n @if (!isJson(field.formattedValue) && field.isLongText) {\n <div class=\"field-value long-text\"\n [class.expanded]=\"field.isExpanded\">\n <span class=\"value-text\">{{ field.formattedValue }}</span>\n <button class=\"expand-btn\" (click)=\"toggleFieldExpand(field)\">\n {{ field.isExpanded ? 'Show less' : 'Show more' }}\n </button>\n </div>\n }\n <!-- Boolean value -->\n @if (field.sqlType.toLowerCase() === 'bit' && !isJson(field.formattedValue)) {\n <div class=\"field-value boolean-value\"\n >\n <i [class]=\"field.value ? 'fa-solid fa-check-circle bool-true' : 'fa-solid fa-times-circle bool-false'\"></i>\n <span class=\"value-text\">{{ field.formattedValue }}</span>\n </div>\n }\n <!-- Empty value -->\n @if (field.value == null && !isJson(field.formattedValue)) {\n <div class=\"field-value empty\"\n >\n <span class=\"value-text\">(empty)</span>\n </div>\n }\n <!-- Regular value -->\n @if (field.value != null && !isJson(field.formattedValue) && !field.isLongText && field.sqlType.toLowerCase() !== 'bit') {\n <div class=\"field-value\"\n >\n <span class=\"value-text\"\n [class.monospace]=\"field.sqlType.toLowerCase().includes('uniqueidentifier') || field.name.toLowerCase().includes('id')\">\n {{ field.formattedValue }}\n </span>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n}\n\n<!-- Backdrop -->\n@if (Visible) {\n <div class=\"panel-backdrop\"\n (click)=\"onClose()\">\n </div>\n}\n", styles: ["/* Query Row Detail Panel Styles */\n\n:host {\n display: block;\n}\n\n/* ========================================\n Panel Container\n ======================================== */\n\n.row-detail-panel {\n position: absolute;\n top: 0;\n right: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n box-shadow: -4px 0 20px var(--mj-bg-overlay);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n/* ========================================\n Resize Handle\n ======================================== */\n\n.resize-handle {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: ew-resize;\n background: transparent;\n transition: background 0.15s ease;\n z-index: 10;\n}\n\n.resize-handle:hover,\n.resize-handle.resizing {\n background: color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n.resize-handle::before {\n content: '';\n position: absolute;\n left: 2px;\n top: 50%;\n transform: translateY(-50%);\n width: 2px;\n height: 40px;\n background: var(--mj-border-strong);\n border-radius: 1px;\n transition: background 0.15s ease;\n}\n\n.resize-handle:hover::before,\n.resize-handle.resizing::before {\n background: var(--mj-brand-primary);\n}\n\n/* ========================================\n Header\n ======================================== */\n\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.header-icon {\n font-size: 20px;\n opacity: 0.9;\n}\n\n.close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: var(--mj-text-inverse);\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.close-btn:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n.panel-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n}\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* ========================================\n Row Navigation\n ======================================== */\n\n.row-nav {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 8px;\n background: rgba(255, 255, 255, 0.15);\n border-radius: 4px;\n}\n\n.nav-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--mj-text-inverse);\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s ease;\n}\n\n.nav-btn:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.15);\n}\n\n.nav-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.row-indicator {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-inverse);\n padding: 0 4px;\n min-width: 50px;\n text-align: center;\n}\n\n/* ========================================\n Action Buttons\n ======================================== */\n\n.action-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n color: var(--mj-text-inverse);\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.action-btn:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n.action-btn.active {\n background: rgba(255, 255, 255, 0.3);\n}\n\n.hidden-count {\n font-weight: 400;\n font-size: 11px;\n color: rgba(255, 255, 255, 0.7);\n margin-left: auto;\n}\n\n/* ========================================\n Content\n ======================================== */\n\n.panel-content {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n}\n\n/* ========================================\n Field Sections\n ======================================== */\n\n.field-section {\n margin-bottom: 24px;\n}\n\n.field-section:last-child {\n margin-bottom: 0;\n}\n\n.section-title {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 0 12px 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n padding-bottom: 8px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.section-icon {\n font-size: 12px;\n}\n\n.pk-icon {\n color: var(--mj-status-warning);\n}\n\n.fk-icon {\n color: var(--mj-brand-primary);\n}\n\n/* ========================================\n Field Items\n ======================================== */\n\n.field-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.field-item {\n padding: 10px 12px;\n background: var(--mj-bg-surface-card);\n border-radius: 6px;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.field-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n}\n\n.field-name {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n flex-shrink: 0;\n}\n\n.field-type {\n font-size: 11px;\n font-family: 'Consolas', 'Monaco', monospace;\n color: var(--mj-text-secondary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.target-entity {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: var(--mj-brand-primary);\n margin-left: auto;\n}\n\n.target-entity i {\n font-size: 8px;\n}\n\n.copy-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--mj-text-disabled);\n cursor: pointer;\n border-radius: 4px;\n margin-left: auto;\n opacity: 0;\n transition: all 0.15s ease;\n}\n\n.field-item:hover .copy-btn {\n opacity: 1;\n}\n\n.copy-btn:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n color: var(--mj-text-secondary);\n}\n\n/* ========================================\n Field Values\n ======================================== */\n\n.field-value {\n font-size: 13px;\n color: var(--mj-text-primary);\n line-height: 1.5;\n word-break: break-word;\n}\n\n.field-value.empty {\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n.field-value.clickable {\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n margin: -2px -4px;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.field-value.clickable:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.entity-icon {\n font-size: 12px;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.link-icon {\n font-size: 10px;\n color: var(--mj-text-disabled);\n margin-left: auto;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.field-value.clickable:hover .link-icon {\n opacity: 1;\n}\n\n.value-text {\n flex: 1;\n}\n\n.value-text.monospace {\n font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;\n font-size: 12px;\n}\n\n/* ========================================\n Boolean Values\n ======================================== */\n\n.boolean-value {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.bool-true {\n color: var(--mj-status-success);\n}\n\n.bool-false {\n color: var(--mj-text-disabled);\n}\n\n/* ========================================\n JSON Values\n ======================================== */\n\n.json-value {\n position: relative;\n}\n\n.json-content {\n margin: 0;\n padding: 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 4px;\n font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;\n font-size: 11px;\n line-height: 1.4;\n overflow: hidden;\n max-height: 100px;\n white-space: pre-wrap;\n word-break: break-all;\n}\n\n.json-value.expanded .json-content {\n max-height: none;\n}\n\n/* ========================================\n Long Text Values\n ======================================== */\n\n.long-text {\n position: relative;\n}\n\n.long-text .value-text {\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.long-text.expanded .value-text {\n display: block;\n -webkit-line-clamp: unset;\n}\n\n/* ========================================\n Expand Button\n ======================================== */\n\n.expand-btn {\n display: inline-block;\n margin-top: 6px;\n padding: 4px 8px;\n border: none;\n background: transparent;\n color: var(--mj-brand-primary);\n font-size: 11px;\n font-weight: 500;\n cursor: pointer;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.expand-btn:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n/* ========================================\n Backdrop\n ======================================== */\n\n.panel-backdrop {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 999;\n}\n\n/* ========================================\n Scrollbar\n ======================================== */\n\n.panel-content::-webkit-scrollbar {\n width: 6px;\n}\n\n.panel-content::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.panel-content::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 3px;\n}\n\n.panel-content::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n}\n\n/* ========================================\n Responsive\n ======================================== */\n\n@media (max-width: 600px) {\n .row-detail-panel {\n width: 100% !important;\n }\n\n .resize-handle {\n display: none;\n }\n}\n"] }]
728
728
  }], () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }], { RowData: [{
729
729
  type: Input
730
730
  }], Columns: [{