@memberjunction/ng-core-entity-forms 5.11.0 → 5.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.js +2 -2
  2. package/dist/lib/custom/AIAgents/add-action-dialog.component.js +2 -2
  3. package/dist/lib/custom/AIAgents/agent-prompt-advanced-settings-dialog.component.js +2 -2
  4. package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts +8 -0
  5. package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts.map +1 -1
  6. package/dist/lib/custom/AIAgents/ai-agent-form.component.js +199 -139
  7. package/dist/lib/custom/AIAgents/ai-agent-form.component.js.map +1 -1
  8. package/dist/lib/custom/AIAgents/create-prompt-dialog.component.js +2 -2
  9. package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.js +2 -2
  10. package/dist/lib/custom/AIAgents/new-agent-dialog.component.js +2 -2
  11. package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.js +6 -6
  12. package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.js.map +1 -1
  13. package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.js +2 -2
  14. package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.js +6 -6
  15. package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.js.map +1 -1
  16. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js +2 -2
  17. package/dist/lib/custom/AIPromptRuns/chat-message-viewer.component.js +2 -2
  18. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js +4 -4
  19. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js.map +1 -1
  20. package/dist/lib/custom/AIPrompts/template-selector-dialog.component.js +2 -2
  21. package/dist/lib/custom/Actions/action-execution-log-form.component.js +4 -4
  22. package/dist/lib/custom/Actions/action-execution-log-form.component.js.map +1 -1
  23. package/dist/lib/custom/Actions/action-form.component.js +22 -22
  24. package/dist/lib/custom/Actions/action-form.component.js.map +1 -1
  25. package/dist/lib/custom/Entities/entity-form.component.d.ts +11 -0
  26. package/dist/lib/custom/Entities/entity-form.component.d.ts.map +1 -1
  27. package/dist/lib/custom/Entities/entity-form.component.js +244 -217
  28. package/dist/lib/custom/Entities/entity-form.component.js.map +1 -1
  29. package/dist/lib/custom/EntityActions/entityaction.form.component.js +2 -2
  30. package/dist/lib/custom/Lists/list-form.component.js +3 -3
  31. package/dist/lib/custom/Lists/list-form.component.js.map +1 -1
  32. package/dist/lib/custom/Queries/query-category-dialog.component.js +3 -3
  33. package/dist/lib/custom/Queries/query-category-dialog.component.js.map +1 -1
  34. package/dist/lib/custom/Queries/query-form.component.js +2 -2
  35. package/dist/lib/custom/Queries/query-run-dialog.component.js +3 -3
  36. package/dist/lib/custom/Queries/query-run-dialog.component.js.map +1 -1
  37. package/dist/lib/custom/Templates/template-param-dialog.component.js +107 -111
  38. package/dist/lib/custom/Templates/template-param-dialog.component.js.map +1 -1
  39. package/dist/lib/custom/Templates/template-params-grid.component.js +2 -2
  40. package/dist/lib/custom/Templates/templates-form.component.js +40 -43
  41. package/dist/lib/custom/Templates/templates-form.component.js.map +1 -1
  42. package/dist/lib/custom/Tests/entity-link-pill.component.js +2 -2
  43. package/dist/lib/custom/Tests/entity-link-pill.component.js.map +1 -1
  44. package/dist/lib/custom/Tests/test-form.component.js +2 -2
  45. package/dist/lib/custom/Tests/test-rubric-form.component.js +2 -2
  46. package/dist/lib/custom/Tests/test-rubric-form.component.js.map +1 -1
  47. package/dist/lib/custom/Tests/test-run-feedback-form.component.js +2 -2
  48. package/dist/lib/custom/Tests/test-run-feedback-form.component.js.map +1 -1
  49. package/dist/lib/custom/Tests/test-run-form.component.js +2 -2
  50. package/dist/lib/custom/Tests/test-suite-form.component.js +2 -2
  51. package/dist/lib/custom/Tests/test-suite-run-form.component.js +2 -2
  52. package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.js +2 -2
  53. package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.js +2 -2
  54. package/dist/lib/custom/ai-agent-run/ai-agent-run-step-node.component.js +2 -2
  55. package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.js +2 -2
  56. package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.d.ts +1 -0
  57. package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.d.ts.map +1 -1
  58. package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.js +28 -18
  59. package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.js.map +1 -1
  60. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js +2 -2
  61. package/dist/lib/custom/custom-forms.module.d.ts +2 -1
  62. package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
  63. package/dist/lib/custom/custom-forms.module.js +7 -3
  64. package/dist/lib/custom/custom-forms.module.js.map +1 -1
  65. package/dist/lib/custom/shared/entity-selector-dialog.component.js +2 -2
  66. package/dist/lib/custom/shared/entity-selector-dialog.component.js.map +1 -1
  67. package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.js +155 -153
  68. package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.js.map +1 -1
  69. package/dist/lib/generated/Entities/MJAIAgentCategory/mjaiagentcategory.form.component.d.ts +10 -0
  70. package/dist/lib/generated/Entities/MJAIAgentCategory/mjaiagentcategory.form.component.d.ts.map +1 -0
  71. package/dist/lib/generated/Entities/MJAIAgentCategory/mjaiagentcategory.form.component.js +105 -0
  72. package/dist/lib/generated/Entities/MJAIAgentCategory/mjaiagentcategory.form.component.js.map +1 -0
  73. package/dist/lib/generated/Entities/MJAIAgentRequest/mjaiagentrequest.form.component.d.ts.map +1 -1
  74. package/dist/lib/generated/Entities/MJAIAgentRequest/mjaiagentrequest.form.component.js +31 -7
  75. package/dist/lib/generated/Entities/MJAIAgentRequest/mjaiagentrequest.form.component.js.map +1 -1
  76. package/dist/lib/generated/Entities/MJAIAgentRequestType/mjaiagentrequesttype.form.component.d.ts +10 -0
  77. package/dist/lib/generated/Entities/MJAIAgentRequestType/mjaiagentrequesttype.form.component.d.ts.map +1 -0
  78. package/dist/lib/generated/Entities/MJAIAgentRequestType/mjaiagentrequesttype.form.component.js +89 -0
  79. package/dist/lib/generated/Entities/MJAIAgentRequestType/mjaiagentrequesttype.form.component.js.map +1 -0
  80. package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.d.ts.map +1 -1
  81. package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js +50 -14
  82. package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js.map +1 -1
  83. package/dist/lib/generated/Entities/MJAIAgentRunStep/mjaiagentrunstep.form.component.d.ts.map +1 -1
  84. package/dist/lib/generated/Entities/MJAIAgentRunStep/mjaiagentrunstep.form.component.js +22 -4
  85. package/dist/lib/generated/Entities/MJAIAgentRunStep/mjaiagentrunstep.form.component.js.map +1 -1
  86. package/dist/lib/generated/Entities/MJAIAgentType/mjaiagenttype.form.component.js +13 -11
  87. package/dist/lib/generated/Entities/MJAIAgentType/mjaiagenttype.form.component.js.map +1 -1
  88. package/dist/lib/generated/Entities/MJAction/mjaction.form.component.js +83 -81
  89. package/dist/lib/generated/Entities/MJAction/mjaction.form.component.js.map +1 -1
  90. package/dist/lib/generated/Entities/MJIntegration/mjintegration.form.component.js +35 -33
  91. package/dist/lib/generated/Entities/MJIntegration/mjintegration.form.component.js.map +1 -1
  92. package/dist/lib/generated/Entities/MJIntegrationObject/mjintegrationobject.form.component.js +25 -19
  93. package/dist/lib/generated/Entities/MJIntegrationObject/mjintegrationobject.form.component.js.map +1 -1
  94. package/dist/lib/generated/generated-forms.module.d.ts +289 -287
  95. package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
  96. package/dist/lib/generated/generated-forms.module.js +102 -96
  97. package/dist/lib/generated/generated-forms.module.js.map +1 -1
  98. package/dist/lib/shared/components/template-editor.component.js +85 -89
  99. package/dist/lib/shared/components/template-editor.component.js.map +1 -1
  100. package/package.json +31 -31
@@ -1 +1 @@
1
- {"version":3,"file":"query-category-dialog.component.js","sourceRoot":"","sources":["../../../../src/lib/custom/Queries/query-category-dialog.component.ts","../../../../src/lib/custom/Queries/query-category-dialog.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';\nimport { MJQueryCategoryEntity } from '@memberjunction/core-entities';\nimport { Metadata, RunView } from '@memberjunction/core';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\n\ninterface CategoryNode {\n id: string;\n name: string;\n fullPath: string;\n children: CategoryNode[];\n level: number;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-query-category-dialog',\n templateUrl: './query-category-dialog.component.html',\n styleUrls: ['./query-category-dialog.component.css']\n})\nexport class QueryCategoryDialogComponent implements OnInit {\n @Input() isVisible = false;\n @Output() isVisibleChange = new EventEmitter<boolean>();\n @Output() onCategoryCreated = new EventEmitter<MJQueryCategoryEntity>();\n \n public categoryName = '';\n public selectedParentId: string | null = null;\n public categories: MJQueryCategoryEntity[] = [];\n public categoryTree: CategoryNode[] = [];\n public flattenedCategories: CategoryNode[] = [];\n public isCreating = false;\n \n async ngOnInit() {\n await this.loadCategories();\n }\n \n async loadCategories() {\n try {\n const rv = new RunView();\n const result = await rv.RunView<MJQueryCategoryEntity>({\n EntityName: 'MJ: Query Categories',\n OrderBy: 'Name',\n ResultType: 'entity_object'\n });\n \n if (result.Success && result.Results) {\n this.categories = result.Results;\n this.categoryTree = this.buildCategoryTree(this.categories);\n this.flattenedCategories = this.flattenCategories(this.categoryTree, 0);\n }\n } catch (error) {\n console.error('Error loading categories:', error);\n }\n }\n \n private buildCategoryTree(categories: MJQueryCategoryEntity[]): CategoryNode[] {\n const categoryMap = new Map<string, CategoryNode>();\n const rootCategories: CategoryNode[] = [];\n \n // Create nodes for all categories\n categories.forEach(cat => {\n categoryMap.set(cat.ID, {\n id: cat.ID,\n name: cat.Name,\n fullPath: cat.Name,\n children: [],\n level: 0\n });\n });\n \n // Build the tree structure\n categories.forEach(cat => {\n const node = categoryMap.get(cat.ID)!;\n if (cat.ParentID && categoryMap.has(cat.ParentID)) {\n const parent = categoryMap.get(cat.ParentID)!;\n parent.children.push(node);\n node.fullPath = `${parent.fullPath} / ${node.name}`;\n } else {\n rootCategories.push(node);\n }\n });\n \n // Sort children alphabetically\n const sortNodes = (nodes: CategoryNode[]) => {\n nodes.sort((a, b) => a.name.localeCompare(b.name));\n nodes.forEach(node => sortNodes(node.children));\n };\n sortNodes(rootCategories);\n \n return rootCategories;\n }\n \n private flattenCategories(nodes: CategoryNode[], level: number): CategoryNode[] {\n const result: CategoryNode[] = [];\n nodes.forEach(node => {\n node.level = level;\n result.push(node);\n if (node.children.length > 0) {\n result.push(...this.flattenCategories(node.children, level + 1));\n }\n });\n return result;\n }\n \n async createCategory() {\n if (!this.categoryName.trim()) {\n MJNotificationService.Instance.CreateSimpleNotification(\n 'Please enter a category name',\n 'warning'\n );\n return;\n }\n \n this.isCreating = true;\n \n try {\n const md = new Metadata();\n const newCategory = await md.GetEntityObject<MJQueryCategoryEntity>('MJ: Query Categories');\n newCategory.Name = this.categoryName.trim();\n newCategory.ParentID = this.selectedParentId;\n newCategory.UserID = md.CurrentUser.ID;\n \n const saved = await newCategory.Save();\n \n if (saved) {\n MJNotificationService.Instance.CreateSimpleNotification(\n 'Category created successfully',\n 'success'\n );\n this.onCategoryCreated.emit(newCategory);\n this.close();\n } else {\n MJNotificationService.Instance.CreateSimpleNotification(\n `Failed to create category: ${newCategory.LatestResult?.Message || 'Unknown error'}`,\n 'error'\n );\n }\n } catch (error) {\n console.error('Error creating category:', error);\n MJNotificationService.Instance.CreateSimpleNotification(\n 'Error creating category',\n 'error'\n );\n } finally {\n this.isCreating = false;\n }\n }\n \n close() {\n this.categoryName = '';\n this.selectedParentId = null;\n this.isVisible = false;\n this.isVisibleChange.emit(false);\n }\n \n getCategoryIndent(category: CategoryNode): string {\n return `${category.level * 20}px`;\n }\n \n getFullPath(): string {\n const parent = this.flattenedCategories.find(c => c.id === this.selectedParentId);\n const name = this.categoryName || 'New Category';\n return parent ? `${parent.fullPath} / ${name}` : name;\n }\n}","@if (isVisible) {\n <kendo-dialog\n [width]=\"500\"\n [height]=\"400\"\n (close)=\"close()\">\n <kendo-dialog-titlebar>\n <div style=\"display: flex; align-items: center; gap: 8px;\">\n <i class=\"fa-solid fa-folder-plus\" style=\"color: #28a745;\"></i>\n Create New Query Category\n </div>\n </kendo-dialog-titlebar>\n <div style=\"padding: 20px;\">\n <div class=\"form-group\" style=\"margin-bottom: 20px;\">\n <label for=\"categoryName\" style=\"display: block; margin-bottom: 8px; font-weight: 600; color: #495057;\">\n <i class=\"fa-solid fa-tag\"></i> Category Name <span style=\"color: #dc3545;\">*</span>\n </label>\n <kendo-textbox\n [(ngModel)]=\"categoryName\"\n name=\"categoryName\"\n placeholder=\"Enter category name...\"\n style=\"width: 100%;\">\n </kendo-textbox>\n </div>\n <div class=\"form-group\">\n <label for=\"parentCategory\" style=\"display: block; margin-bottom: 8px; font-weight: 600; color: #495057;\">\n <i class=\"fa-solid fa-folder-tree\"></i> Parent Category (Optional)\n </label>\n <kendo-dropdownlist\n [(ngModel)]=\"selectedParentId\"\n name=\"parentCategory\"\n [data]=\"flattenedCategories\"\n [textField]=\"'name'\"\n [valueField]=\"'id'\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"{id: null, name: '-- No Parent (Top Level) --'}\"\n style=\"width: 100%;\">\n <ng-template kendoDropDownListItemTemplate let-dataItem>\n <div style=\"padding-left: {{getCategoryIndent(dataItem)}}; display: flex; align-items: center; gap: 6px;\">\n @if (dataItem.children && dataItem.children.length > 0) {\n <i class=\"fa-solid fa-folder\" style=\"color: #ffc107; font-size: 0.9em;\"></i>\n } @else {\n <i class=\"fa-solid fa-folder-open\" style=\"color: #6c757d; font-size: 0.9em;\"></i>\n }\n <span>{{ dataItem.name }}</span>\n </div>\n </ng-template>\n </kendo-dropdownlist>\n @if (selectedParentId) {\n <div style=\"margin-top: 8px; padding: 8px; background: #f8f9fa; border-radius: 4px; font-size: 0.85em; color: #6c757d;\">\n <i class=\"fa-solid fa-info-circle\"></i>\n Full path: {{ getFullPath() }}\n </div>\n }\n </div>\n </div>\n <kendo-dialog-actions>\n <button kendoButton (click)=\"close()\">\n <i class=\"fa-solid fa-times\"></i> Cancel\n </button>\n <button kendoButton\n [themeColor]=\"'primary'\"\n [disabled]=\"!categoryName.trim() || isCreating\"\n (click)=\"createCategory()\">\n @if (isCreating) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Creating...\n } @else {\n <i class=\"fa-solid fa-check\"></i> Create Category\n }\n </button>\n </kendo-dialog-actions>\n </kendo-dialog>\n}"]}
1
+ {"version":3,"file":"query-category-dialog.component.js","sourceRoot":"","sources":["../../../../src/lib/custom/Queries/query-category-dialog.component.ts","../../../../src/lib/custom/Queries/query-category-dialog.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';\nimport { MJQueryCategoryEntity } from '@memberjunction/core-entities';\nimport { Metadata, RunView } from '@memberjunction/core';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\n\ninterface CategoryNode {\n id: string;\n name: string;\n fullPath: string;\n children: CategoryNode[];\n level: number;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-query-category-dialog',\n templateUrl: './query-category-dialog.component.html',\n styleUrls: ['./query-category-dialog.component.css']\n})\nexport class QueryCategoryDialogComponent implements OnInit {\n @Input() isVisible = false;\n @Output() isVisibleChange = new EventEmitter<boolean>();\n @Output() onCategoryCreated = new EventEmitter<MJQueryCategoryEntity>();\n \n public categoryName = '';\n public selectedParentId: string | null = null;\n public categories: MJQueryCategoryEntity[] = [];\n public categoryTree: CategoryNode[] = [];\n public flattenedCategories: CategoryNode[] = [];\n public isCreating = false;\n \n async ngOnInit() {\n await this.loadCategories();\n }\n \n async loadCategories() {\n try {\n const rv = new RunView();\n const result = await rv.RunView<MJQueryCategoryEntity>({\n EntityName: 'MJ: Query Categories',\n OrderBy: 'Name',\n ResultType: 'entity_object'\n });\n \n if (result.Success && result.Results) {\n this.categories = result.Results;\n this.categoryTree = this.buildCategoryTree(this.categories);\n this.flattenedCategories = this.flattenCategories(this.categoryTree, 0);\n }\n } catch (error) {\n console.error('Error loading categories:', error);\n }\n }\n \n private buildCategoryTree(categories: MJQueryCategoryEntity[]): CategoryNode[] {\n const categoryMap = new Map<string, CategoryNode>();\n const rootCategories: CategoryNode[] = [];\n \n // Create nodes for all categories\n categories.forEach(cat => {\n categoryMap.set(cat.ID, {\n id: cat.ID,\n name: cat.Name,\n fullPath: cat.Name,\n children: [],\n level: 0\n });\n });\n \n // Build the tree structure\n categories.forEach(cat => {\n const node = categoryMap.get(cat.ID)!;\n if (cat.ParentID && categoryMap.has(cat.ParentID)) {\n const parent = categoryMap.get(cat.ParentID)!;\n parent.children.push(node);\n node.fullPath = `${parent.fullPath} / ${node.name}`;\n } else {\n rootCategories.push(node);\n }\n });\n \n // Sort children alphabetically\n const sortNodes = (nodes: CategoryNode[]) => {\n nodes.sort((a, b) => a.name.localeCompare(b.name));\n nodes.forEach(node => sortNodes(node.children));\n };\n sortNodes(rootCategories);\n \n return rootCategories;\n }\n \n private flattenCategories(nodes: CategoryNode[], level: number): CategoryNode[] {\n const result: CategoryNode[] = [];\n nodes.forEach(node => {\n node.level = level;\n result.push(node);\n if (node.children.length > 0) {\n result.push(...this.flattenCategories(node.children, level + 1));\n }\n });\n return result;\n }\n \n async createCategory() {\n if (!this.categoryName.trim()) {\n MJNotificationService.Instance.CreateSimpleNotification(\n 'Please enter a category name',\n 'warning'\n );\n return;\n }\n \n this.isCreating = true;\n \n try {\n const md = new Metadata();\n const newCategory = await md.GetEntityObject<MJQueryCategoryEntity>('MJ: Query Categories');\n newCategory.Name = this.categoryName.trim();\n newCategory.ParentID = this.selectedParentId;\n newCategory.UserID = md.CurrentUser.ID;\n \n const saved = await newCategory.Save();\n \n if (saved) {\n MJNotificationService.Instance.CreateSimpleNotification(\n 'Category created successfully',\n 'success'\n );\n this.onCategoryCreated.emit(newCategory);\n this.close();\n } else {\n MJNotificationService.Instance.CreateSimpleNotification(\n `Failed to create category: ${newCategory.LatestResult?.Message || 'Unknown error'}`,\n 'error'\n );\n }\n } catch (error) {\n console.error('Error creating category:', error);\n MJNotificationService.Instance.CreateSimpleNotification(\n 'Error creating category',\n 'error'\n );\n } finally {\n this.isCreating = false;\n }\n }\n \n close() {\n this.categoryName = '';\n this.selectedParentId = null;\n this.isVisible = false;\n this.isVisibleChange.emit(false);\n }\n \n getCategoryIndent(category: CategoryNode): string {\n return `${category.level * 20}px`;\n }\n \n getFullPath(): string {\n const parent = this.flattenedCategories.find(c => c.id === this.selectedParentId);\n const name = this.categoryName || 'New Category';\n return parent ? `${parent.fullPath} / ${name}` : name;\n }\n}","@if (isVisible) {\n <kendo-dialog\n [width]=\"500\"\n [height]=\"400\"\n (close)=\"close()\">\n <kendo-dialog-titlebar>\n <div style=\"display: flex; align-items: center; gap: 8px;\">\n <i class=\"fa-solid fa-folder-plus\" style=\"color: #28a745;\"></i>\n Create New Query Category\n </div>\n </kendo-dialog-titlebar>\n <div style=\"padding: 20px;\">\n <div class=\"form-group\" style=\"margin-bottom: 20px;\">\n <label for=\"categoryName\" style=\"display: block; margin-bottom: 8px; font-weight: 600; color: var(--mj-text-secondary);\">\n <i class=\"fa-solid fa-tag\"></i> Category Name <span style=\"color: #dc3545;\">*</span>\n </label>\n <kendo-textbox\n [(ngModel)]=\"categoryName\"\n name=\"categoryName\"\n placeholder=\"Enter category name...\"\n style=\"width: 100%;\">\n </kendo-textbox>\n </div>\n <div class=\"form-group\">\n <label for=\"parentCategory\" style=\"display: block; margin-bottom: 8px; font-weight: 600; color: var(--mj-text-secondary);\">\n <i class=\"fa-solid fa-folder-tree\"></i> Parent Category (Optional)\n </label>\n <kendo-dropdownlist\n [(ngModel)]=\"selectedParentId\"\n name=\"parentCategory\"\n [data]=\"flattenedCategories\"\n [textField]=\"'name'\"\n [valueField]=\"'id'\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"{id: null, name: '-- No Parent (Top Level) --'}\"\n style=\"width: 100%;\">\n <ng-template kendoDropDownListItemTemplate let-dataItem>\n <div style=\"padding-left: {{getCategoryIndent(dataItem)}}; display: flex; align-items: center; gap: 6px;\">\n @if (dataItem.children && dataItem.children.length > 0) {\n <i class=\"fa-solid fa-folder\" style=\"color: #ffc107; font-size: 0.9em;\"></i>\n } @else {\n <i class=\"fa-solid fa-folder-open\" style=\"color: var(--mj-text-muted); font-size: 0.9em;\"></i>\n }\n <span>{{ dataItem.name }}</span>\n </div>\n </ng-template>\n </kendo-dropdownlist>\n @if (selectedParentId) {\n <div style=\"margin-top: 8px; padding: 8px; background: var(--mj-bg-surface-sunken); border-radius: 4px; font-size: 0.85em; color: var(--mj-text-muted);\">\n <i class=\"fa-solid fa-info-circle\"></i>\n Full path: {{ getFullPath() }}\n </div>\n }\n </div>\n </div>\n <kendo-dialog-actions>\n <button kendoButton (click)=\"close()\">\n <i class=\"fa-solid fa-times\"></i> Cancel\n </button>\n <button kendoButton\n [themeColor]=\"'primary'\"\n [disabled]=\"!categoryName.trim() || isCreating\"\n (click)=\"createCategory()\">\n @if (isCreating) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Creating...\n } @else {\n <i class=\"fa-solid fa-check\"></i> Create Category\n }\n </button>\n </kendo-dialog-actions>\n </kendo-dialog>\n}"]}
@@ -1805,7 +1805,7 @@ let MJQueryFormComponentExtended = class MJQueryFormComponentExtended extends MJ
1805
1805
  } if (rf & 2) {
1806
1806
  i0.ɵɵadvance();
1807
1807
  i0.ɵɵconditional(ctx.record ? 1 : -1);
1808
- } }, dependencies: [i1.NgClass, i2.ɵNgNoValidate, i2.NgControlStatus, i2.NgControlStatusGroup, i2.NgModel, i2.NgForm, i3.ExpansionPanelComponent, i3.ExpansionPanelTitleDirective, i4.TextBoxComponent, i4.TextAreaComponent, i4.SwitchComponent, i5.DropDownListComponent, i6.ButtonComponent, i7.MjFormToolbarComponent, i7.ExplorerEntityDataGridComponent, i8.CodeEditorComponent, i9.LoadingComponent, i10.MarkdownComponent, i11.QueryRunDialogComponent, i12.QueryCategoryDialogComponent], styles: [".k-pane[_ngcontent-%COMP%] {\n background-color: #F5F6FA;\n}\n\n.content-margin[_ngcontent-%COMP%] {\n margin: 10px;\n} \n\n\na[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: bolder;\n}\n\n.tab-header-icon[_ngcontent-%COMP%] {\n margin-right: 5px;\n}\n\n.record-form[_ngcontent-%COMP%] {\n display: block;\n flex-direction: column;\n background-color: #F5F6FA;\n padding: 0;\n min-height: 100vh;\n}\n\n.record-form-group[_ngcontent-%COMP%] {\n margin-top: 0px;\n background-color: #F5F6FA;\n}\n\nbutton[_ngcontent-%COMP%] {\n margin-right: 5px;\n}\n\n.record-form[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin-bottom: 10px;\n}\n\n.k-splitter[_ngcontent-%COMP%] {\n border-width: 0px;\n}\n\n.record-form-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: auto 1fr;\n align-items: start;\n gap: 10px;\n margin-bottom: 12px;\n padding-top: 5px;\n padding-bottom: 5px;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n.record-form[_ngcontent-%COMP%] .record-form-row[_ngcontent-%COMP%] > [_ngcontent-%COMP%]:first-child {\n font-weight: bold;\n padding-right: 10px;\n} \n\n.record-form[_ngcontent-%COMP%] .record-form-row[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n \n\n@media (min-width: 768px) {\n .record-form-row[_ngcontent-%COMP%] {\n flex-direction: row;\n align-items: center;\n }\n\n .record-form-row[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n width: 240px;\n margin-bottom: 0;\n }\n}\n\n\n\n.form-panels-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 16px;\n background-color: #F5F6FA;\n}\n\n\n\n.form-panels-container[_ngcontent-%COMP%] > .form-card[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n\n\n.form-panels-container[_ngcontent-%COMP%] .related-entity-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr;\n gap: 16px;\n width: 100%;\n}\n\n\n\n@media (min-width: 1400px) {\n .form-panels-container[_ngcontent-%COMP%] .related-entity-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(auto-fit, minmax(600px, 1fr));\n }\n}\n\n.form-card[_ngcontent-%COMP%] {\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n}\n\n.collapsible-card[_ngcontent-%COMP%] {\n overflow: hidden;\n}\n\n.collapsible-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n background: linear-gradient(135deg, #f9fafb 0%, #ffffff 100%);\n border-bottom: 2px solid #e5e7eb;\n cursor: pointer;\n user-select: none;\n transition: all 0.3s ease;\n}\n\n.collapsible-header[_ngcontent-%COMP%]:hover {\n background: linear-gradient(135deg, #f3f4f6 0%, #f9fafb 100%);\n border-bottom-color: #667eea;\n}\n\n.collapsible-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n}\n\n.collapsible-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: #667eea;\n}\n\n.collapsible-title[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #1f2937;\n}\n\n.collapsible-header[_ngcontent-%COMP%] .collapse-icon[_ngcontent-%COMP%] {\n color: #6b7280;\n transition: transform 0.3s ease;\n}\n\n.collapsible-body[_ngcontent-%COMP%] {\n max-height: 2000px;\n overflow: hidden;\n transition: max-height 0.4s ease, padding 0.4s ease, opacity 0.3s ease;\n opacity: 1;\n}\n\n.collapsible-body.collapsed[_ngcontent-%COMP%] {\n max-height: 0;\n padding: 0;\n opacity: 0;\n}\n\n.form-body[_ngcontent-%COMP%] {\n padding: 24px;\n}\n\n\n\n.form-card.related-entity[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f0f9ff 0%, #ffffff 100%);\n border-left: 3px solid #3b82f6;\n}\n\n.form-card.related-entity[_ngcontent-%COMP%] .collapsible-header[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #e0f2fe 0%, #f0f9ff 100%);\n}\n\n.form-card.related-entity[_ngcontent-%COMP%] .collapsible-header[_ngcontent-%COMP%]:hover {\n background: linear-gradient(135deg, #bfdbfe 0%, #e0f2fe 100%);\n border-bottom-color: #3b82f6;\n}\n\n.form-card.related-entity[_ngcontent-%COMP%] .collapsible-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #3b82f6;\n}\n\n\n\n.form-section-controls[_ngcontent-%COMP%] {\n display: flex;\n gap: 10px;\n padding: 14px 18px;\n background: linear-gradient(135deg, #f9fafb 0%, #ffffff 100%);\n border-bottom: 2px solid #e5e7eb;\n align-items: center;\n flex-wrap: wrap;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n}\n\n.form-section-controls[_ngcontent-%COMP%] .control-group[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.form-section-controls[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n padding: 8px 14px;\n font-size: 13px;\n border: 1px solid #d1d5db;\n background: white;\n color: #374151;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n margin-right: 0;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 500;\n}\n\n.form-section-controls[_ngcontent-%COMP%] button[_ngcontent-%COMP%]:hover {\n background: #667eea;\n color: white;\n border-color: #667eea;\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(102, 126, 234, 0.2);\n}\n\n.form-section-controls[_ngcontent-%COMP%] button[_ngcontent-%COMP%]:active {\n transform: translateY(0);\n}\n\n.form-section-controls[_ngcontent-%COMP%] button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 0;\n font-size: 14px;\n}\n\n.form-section-controls[_ngcontent-%COMP%] .section-search[_ngcontent-%COMP%] {\n padding: 8px 14px;\n font-size: 13px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n width: 240px;\n transition: all 0.2s;\n background: white;\n}\n\n.form-section-controls[_ngcontent-%COMP%] .section-search[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #667eea;\n box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);\n}\n\n.form-section-controls[_ngcontent-%COMP%] .section-search[_ngcontent-%COMP%]::placeholder {\n color: #9ca3af;\n font-style: italic;\n}\n\n.form-section-controls[_ngcontent-%COMP%] .section-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: #6b7280;\n margin-left: auto;\n font-weight: 500;\n}\n\n\n\n.form-card.search-hidden[_ngcontent-%COMP%] {\n display: none;\n}\n\n\n\n.section-count-badge[_ngcontent-%COMP%] {\n background: #667eea;\n color: white;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n}\n\n\n\n.collapsible-title[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] .search-highlight[_ngcontent-%COMP%] {\n background-color: #fef08a;\n color: #854d0e;\n padding: 2px 4px;\n border-radius: 3px;\n font-weight: 700;\n}\n\n\n\n.collapsible-title[_ngcontent-%COMP%] .row-count-badge[_ngcontent-%COMP%] {\n background: #10b981;\n color: white;\n padding: 3px 6px 2px 6px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n margin-left: 8px;\n vertical-align: middle;\n position: relative;\n top: -2px;\n display: inline-block;\n line-height: 1;\n}\n\n\n\n.collapsible-title[_ngcontent-%COMP%] .row-count-badge.zero-rows[_ngcontent-%COMP%] {\n background: #9ca3af;\n}", "\n\n[_nghost-%COMP%] {\n display: block;\n height: 100%;\n}\n\n\n\n.record-form[_ngcontent-%COMP%] {\n min-height: 0 !important;\n}\n\n\n\n\n\n\n.query-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: linear-gradient(135deg, #5c6bc0 0%, #3949ab 100%);\n border-bottom: none;\n padding: 0;\n}\n\n.query-header-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px 20px;\n}\n\n.query-header-top[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 20px;\n}\n\n.query-name-section[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.query-title-icon[_ngcontent-%COMP%] {\n color: rgba(255, 255, 255, 0.85);\n font-size: 1.3em;\n flex-shrink: 0;\n}\n\n.query-name-input[_ngcontent-%COMP%] {\n font-size: 1.2em;\n font-weight: 600;\n min-width: 300px;\n flex: 1;\n}\n\n.query-name-display[_ngcontent-%COMP%] {\n margin: 0;\n color: #fff;\n font-weight: 600;\n font-size: 1.2em;\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.query-header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.run-query-btn[_ngcontent-%COMP%] {\n white-space: nowrap;\n}\n\n\n\n.query-meta-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 24px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.query-meta-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.meta-label[_ngcontent-%COMP%] {\n font-weight: 500;\n color: rgba(255, 255, 255, 0.75);\n font-size: 13px;\n min-width: 60px;\n}\n\n.meta-value[_ngcontent-%COMP%] {\n color: rgba(255, 255, 255, 0.95);\n font-size: 14px;\n}\n\n.meta-dropdown[_ngcontent-%COMP%] {\n min-width: 200px;\n}\n\n.status-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: 14px;\n color: #fff;\n font-size: 13px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.status-pill[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n.query-description-row[_ngcontent-%COMP%] {\n margin-top: 2px;\n}\n\n.query-description-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.query-description-text[_ngcontent-%COMP%] {\n margin: 0;\n color: rgba(255, 255, 255, 0.8);\n font-size: 13px;\n line-height: 1.4;\n}\n\n\n\n\n\n\n.status-warning-banner[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 16px;\n margin: 0;\n background: #fff8e1;\n border-left: 4px solid #f59e0b;\n font-size: 13px;\n color: #5d4037;\n flex-shrink: 0;\n}\n\n.status-warning-banner[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n flex-shrink: 0;\n}\n\n.status-warning-banner[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n font-weight: 600;\n}\n\n\n\n\n\n\n.query-content[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n padding: 16px;\n overflow-y: auto;\n background: #f5f5f5;\n}\n\n\n\n\n\n\n.query-panel[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n}\n\n .query-content kendo-expansionpanel {\n border: none !important;\n border-radius: 8px !important;\n margin-bottom: 12px !important;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08) !important;\n background: white !important;\n overflow: hidden !important;\n}\n\n .query-content .k-expander-header {\n background: white !important;\n border: none !important;\n padding: 14px 18px !important;\n border-radius: 8px !important;\n color: #333 !important;\n font-weight: 600 !important;\n font-size: 14px !important;\n transition: background 0.15s ease !important;\n}\n\n .query-content .k-expander-header:hover {\n background: #f8f9fa !important;\n}\n\n .query-content kendo-expansionpanel[aria-expanded=\"true\"] .k-expander-header {\n background: #5c6bc0 !important;\n color: white !important;\n border-radius: 8px 8px 0 0 !important;\n}\n\n .query-content .k-expander-content {\n padding: 0 !important;\n border: none !important;\n background: white !important;\n border-radius: 0 0 8px 8px !important;\n}\n\n\n\n\n\n\n.panel-title-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n}\n\n.panel-icon[_ngcontent-%COMP%] {\n font-size: 14px;\n opacity: 0.7;\n}\n\n.sql-icon[_ngcontent-%COMP%] {\n color: #5c6bc0;\n}\n\n kendo-expansionpanel[aria-expanded=\"true\"] .panel-icon {\n color: rgba(255, 255, 255, 0.85) !important;\n opacity: 1;\n}\n\n.panel-badge[_ngcontent-%COMP%] {\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.panel-badge.defined[_ngcontent-%COMP%] {\n background: #28a745;\n color: white;\n}\n\n.panel-badge.count[_ngcontent-%COMP%] {\n background: #5c6bc0;\n color: white;\n}\n\n kendo-expansionpanel[aria-expanded=\"true\"] .panel-badge.count {\n background: rgba(255, 255, 255, 0.25) !important;\n}\n\n kendo-expansionpanel[aria-expanded=\"true\"] .panel-badge.defined {\n background: rgba(255, 255, 255, 0.25) !important;\n}\n\n.filters-help-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-right: 8px;\n font-size: 12px;\n}\n\n\n\n\n\n\n.panel-body[_ngcontent-%COMP%] {\n padding: 16px 0;\n}\n\n.panel-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 40px;\n}\n\n.panel-toolbar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n padding: 0 20px 12px;\n}\n\n\n\n\n\n\n.sql-panel-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.sql-editor[_ngcontent-%COMP%] {\n flex: 1;\n height: 400px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n margin: 16px;\n}\n\n\n\n.filters-help[_ngcontent-%COMP%] {\n background: #fafafa;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n padding: 16px;\n margin: 0 16px 16px;\n}\n\n.filters-help-title[_ngcontent-%COMP%] {\n margin: 0 0 12px 0;\n color: #333;\n font-weight: 600;\n font-size: 14px;\n}\n\n.filters-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n gap: 10px;\n}\n\n.filter-card[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n padding: 12px;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n}\n\n.filter-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n.filter-name[_ngcontent-%COMP%] {\n font-family: 'Courier New', monospace;\n font-weight: bold;\n color: #5c6bc0;\n margin-bottom: 4px;\n}\n\n.filter-description[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #555;\n margin-bottom: 6px;\n}\n\n.filter-syntax[_ngcontent-%COMP%] {\n font-family: 'Courier New', monospace;\n font-size: 11px;\n background: #f5f5f5;\n padding: 6px;\n border-radius: 4px;\n margin-bottom: 4px;\n}\n\n.filter-notes[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #888;\n font-style: italic;\n}\n\n\n\n\n\n\n.card-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));\n gap: 12px;\n padding: 0 20px 20px;\n}\n\n.item-card[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n padding: 14px;\n transition: all 0.15s ease;\n cursor: pointer;\n position: relative;\n}\n\n.item-card[_ngcontent-%COMP%]:hover {\n border-color: #5c6bc0;\n box-shadow: 0 2px 8px rgba(92, 107, 192, 0.12);\n}\n\n.item-card.required[_ngcontent-%COMP%] {\n border-left: 3px solid #f59e0b;\n}\n\n.item-card-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 10px;\n}\n\n.item-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: #333;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.item-name-icon[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.item-name-icon.param-icon[_ngcontent-%COMP%] {\n color: #5c6bc0;\n}\n\n.item-name-icon.field-icon[_ngcontent-%COMP%] {\n color: #5c6bc0;\n}\n\n.item-name-icon.entity-icon[_ngcontent-%COMP%] {\n color: #28a745;\n}\n\n.item-badges[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n}\n\n.item-badge[_ngcontent-%COMP%] {\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n color: white;\n}\n\n.item-badge.required[_ngcontent-%COMP%] {\n background: #f59e0b;\n}\n\n.item-badge.type[_ngcontent-%COMP%] {\n background: #e8eaf6;\n color: #3949ab;\n}\n\n.item-badge.sequence[_ngcontent-%COMP%] {\n background: #f3e5f5;\n color: #7b1fa2;\n}\n\n.item-card-body[_ngcontent-%COMP%] {\n color: #666;\n font-size: 13px;\n}\n\n.item-description[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n}\n\n.item-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n font-size: 12px;\n}\n\n.meta-tag[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.meta-code[_ngcontent-%COMP%] {\n background: #f5f5f5;\n padding: 1px 4px;\n border-radius: 3px;\n font-size: 11px;\n}\n\n\n\n.item-actions[_ngcontent-%COMP%] {\n position: absolute;\n top: 10px;\n right: 10px;\n display: flex;\n gap: 4px;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.item-card[_ngcontent-%COMP%]:hover .item-actions[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.item-card-actions[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n margin-top: 8px;\n}\n\n.item-action-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px 8px;\n border-radius: 4px;\n cursor: pointer;\n color: #888;\n transition: all 0.15s ease;\n}\n\n.item-action-btn[_ngcontent-%COMP%]:hover {\n background: #f0f0f0;\n color: #5c6bc0;\n}\n\n.item-action-btn.delete[_ngcontent-%COMP%]:hover {\n background: #fff5f5;\n color: #dc3545;\n}\n\n\n\n.entity-dropdown-wrapper[_ngcontent-%COMP%] {\n flex: 1;\n margin-left: 12px;\n}\n\n.entity-dropdown[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n\n\n\n\n\n.details-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));\n gap: 16px;\n padding: 16px 20px;\n}\n\n.detail-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.detail-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: #888;\n display: flex;\n align-items: center;\n gap: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.detail-value[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #333;\n}\n\n.detail-tag[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 13px;\n}\n\n.detail-tag.positive[_ngcontent-%COMP%] {\n color: #28a745;\n}\n\n.detail-tag.neutral[_ngcontent-%COMP%] {\n color: #888;\n}\n\n\n\n\n\n\n.permissions-list[_ngcontent-%COMP%] {\n padding: 0 20px;\n}\n\n.permission-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n background: #fafafa;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n padding: 14px 16px;\n margin-bottom: 8px;\n}\n\n.permission-icon[_ngcontent-%COMP%] {\n font-size: 1.3em;\n color: #5c6bc0;\n}\n\n.permission-info[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.permission-role[_ngcontent-%COMP%] {\n font-weight: 600;\n color: #333;\n font-size: 14px;\n}\n\n.permission-type[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #888;\n}\n\n.permission-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n background: #5c6bc0;\n color: white;\n padding: 4px 10px;\n border-radius: 6px;\n font-size: 12px;\n font-weight: 500;\n}\n\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 20px;\n text-align: center;\n color: #888;\n}\n\n.empty-state-icon[_ngcontent-%COMP%] {\n font-size: 40px;\n margin-bottom: 14px;\n opacity: 0.25;\n color: #333;\n}\n\n.empty-state-title[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 600;\n margin-bottom: 6px;\n color: #555;\n}\n\n.empty-state-text[_ngcontent-%COMP%] {\n font-size: 13px;\n margin-bottom: 16px;\n color: #888;\n}\n\n\n\n\n\n\n.add-item-btn[_ngcontent-%COMP%] {\n background: #5c6bc0;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 500;\n font-size: 13px;\n}\n\n.add-item-btn[_ngcontent-%COMP%]:hover {\n background: #3949ab;\n box-shadow: 0 2px 6px rgba(92, 107, 192, 0.3);\n}\n\n\n\n\n\n\n.badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n\n\n\n\n\n.technical-description-textarea[_ngcontent-%COMP%] {\n width: 100%;\n font-family: 'Consolas', 'Monaco', 'Courier New', monospace;\n font-size: 13px;\n}\n\n.technical-description-preview[_ngcontent-%COMP%] {\n margin-top: 16px;\n border-top: 1px solid #e0e0e0;\n padding-top: 12px;\n}\n\n.preview-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: #666;\n margin-bottom: 8px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.technical-description-view[_ngcontent-%COMP%] {\n max-height: 500px;\n overflow-y: auto;\n padding: 12px 16px;\n}\n\n\n\n.dependents-icon[_ngcontent-%COMP%] {\n color: #ef6c00;\n}\n\n.dependents-description[_ngcontent-%COMP%] {\n padding: 0 20px 12px;\n font-size: 13px;\n color: #666;\n}\n\n.dependents-description[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: #f0f0f0;\n padding: 1px 5px;\n border-radius: 3px;\n font-size: 12px;\n}\n\n.dependent-card[_ngcontent-%COMP%] {\n cursor: pointer;\n border-left: 3px solid #ef6c00 !important;\n}\n\n.dependent-card[_ngcontent-%COMP%]:hover {\n border-left-color: #e65100 !important;\n background: #fff8f0 !important;\n}\n\n.dependent-query-icon[_ngcontent-%COMP%] {\n color: #ef6c00 !important;\n}\n\n.item-card-footer[_ngcontent-%COMP%] {\n padding-top: 8px;\n border-top: 1px solid #f0f0f0;\n margin-top: 8px;\n}\n\n.open-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: #5c6bc0;\n font-weight: 500;\n}\n\n.dependent-card[_ngcontent-%COMP%]:hover .open-link[_ngcontent-%COMP%] {\n color: #3949ab;\n}"] }); }
1808
+ } }, dependencies: [i1.NgClass, i2.ɵNgNoValidate, i2.NgControlStatus, i2.NgControlStatusGroup, i2.NgModel, i2.NgForm, i3.ExpansionPanelComponent, i3.ExpansionPanelTitleDirective, i4.TextBoxComponent, i4.TextAreaComponent, i4.SwitchComponent, i5.DropDownListComponent, i6.ButtonComponent, i7.MjFormToolbarComponent, i7.ExplorerEntityDataGridComponent, i8.CodeEditorComponent, i9.LoadingComponent, i10.MarkdownComponent, i11.QueryRunDialogComponent, i12.QueryCategoryDialogComponent], styles: [".k-pane[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface);\n}\n\n.content-margin[_ngcontent-%COMP%] {\n margin: 10px;\n}\n\n\na[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: bolder;\n}\n\n.tab-header-icon[_ngcontent-%COMP%] {\n margin-right: 5px;\n}\n\n.record-form[_ngcontent-%COMP%] {\n display: block;\n flex-direction: column;\n background-color: var(--mj-bg-surface);\n padding: 0;\n min-height: 100vh;\n}\n\n.record-form-group[_ngcontent-%COMP%] {\n margin-top: 0px;\n background-color: var(--mj-bg-surface);\n}\n\nbutton[_ngcontent-%COMP%] {\n margin-right: 5px;\n}\n\n.record-form[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin-bottom: 10px;\n}\n\n.k-splitter[_ngcontent-%COMP%] {\n border-width: 0px;\n}\n\n.record-form-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: auto 1fr;\n align-items: start;\n gap: 10px;\n margin-bottom: 12px;\n padding-top: 5px;\n padding-bottom: 5px;\n}\n\n.record-form[_ngcontent-%COMP%] .record-form-row[_ngcontent-%COMP%] > [_ngcontent-%COMP%]:first-child {\n font-weight: bold;\n padding-right: 10px;\n}\n\n.record-form[_ngcontent-%COMP%] .record-form-row[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n@media (min-width: 768px) {\n .record-form-row[_ngcontent-%COMP%] {\n flex-direction: row;\n align-items: center;\n }\n\n .record-form-row[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n width: 240px;\n margin-bottom: 0;\n }\n}\n\n\n\n.form-panels-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 16px;\n background-color: var(--mj-bg-surface);\n}\n\n\n\n.form-panels-container[_ngcontent-%COMP%] > .form-card[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n\n\n.form-panels-container[_ngcontent-%COMP%] .related-entity-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr;\n gap: 16px;\n width: 100%;\n}\n\n\n\n@media (min-width: 1400px) {\n .form-panels-container[_ngcontent-%COMP%] .related-entity-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(auto-fit, minmax(600px, 1fr));\n }\n}\n\n.form-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n box-shadow: 0 2px 4px var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n.collapsible-card[_ngcontent-%COMP%] {\n overflow: hidden;\n}\n\n.collapsible-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n background: var(--mj-bg-surface-card);\n border-bottom: 2px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n transition: all 0.3s ease;\n}\n\n.collapsible-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-bottom-color: var(--mj-brand-primary);\n}\n\n.collapsible-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n}\n\n.collapsible-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.collapsible-title[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.collapsible-header[_ngcontent-%COMP%] .collapse-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n transition: transform 0.3s ease;\n}\n\n.collapsible-body[_ngcontent-%COMP%] {\n max-height: 2000px;\n overflow: hidden;\n transition: max-height 0.4s ease, padding 0.4s ease, opacity 0.3s ease;\n opacity: 1;\n}\n\n.collapsible-body.collapsed[_ngcontent-%COMP%] {\n max-height: 0;\n padding: 0;\n opacity: 0;\n}\n\n.form-body[_ngcontent-%COMP%] {\n padding: 24px;\n}\n\n\n\n.form-card.related-entity[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.form-card.related-entity[_ngcontent-%COMP%] .collapsible-header[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n}\n\n.form-card.related-entity[_ngcontent-%COMP%] .collapsible-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n border-bottom-color: var(--mj-brand-primary);\n}\n\n.form-card.related-entity[_ngcontent-%COMP%] .collapsible-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n.form-section-controls[_ngcontent-%COMP%] {\n display: flex;\n gap: 10px;\n padding: 14px 18px;\n background: var(--mj-bg-surface-card);\n border-bottom: 2px solid var(--mj-border-default);\n align-items: center;\n flex-wrap: wrap;\n box-shadow: 0 1px 3px var(--mj-shadow-sm);\n}\n\n.form-section-controls[_ngcontent-%COMP%] .control-group[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.form-section-controls[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n padding: 8px 14px;\n font-size: 13px;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n margin-right: 0;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 500;\n}\n\n.form-section-controls[_ngcontent-%COMP%] button[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px var(--mj-shadow-md);\n}\n\n.form-section-controls[_ngcontent-%COMP%] button[_ngcontent-%COMP%]:active {\n transform: translateY(0);\n}\n\n.form-section-controls[_ngcontent-%COMP%] button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 0;\n font-size: 14px;\n}\n\n.form-section-controls[_ngcontent-%COMP%] .section-search[_ngcontent-%COMP%] {\n padding: 8px 14px;\n font-size: 13px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n width: 240px;\n transition: all 0.2s;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.form-section-controls[_ngcontent-%COMP%] .section-search[_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) 10%, transparent);\n}\n\n.form-section-controls[_ngcontent-%COMP%] .section-search[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.form-section-controls[_ngcontent-%COMP%] .section-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin-left: auto;\n font-weight: 500;\n}\n\n\n\n.form-card.search-hidden[_ngcontent-%COMP%] {\n display: none;\n}\n\n\n\n.section-count-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n}\n\n\n\n.collapsible-title[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] .search-highlight[_ngcontent-%COMP%] {\n background-color: var(--mj-status-warning);\n color: var(--mj-text-primary);\n padding: 2px 4px;\n border-radius: 3px;\n font-weight: 700;\n}\n\n\n\n.collapsible-title[_ngcontent-%COMP%] .row-count-badge[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n color: var(--mj-text-inverse);\n padding: 3px 6px 2px 6px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n margin-left: 8px;\n vertical-align: middle;\n position: relative;\n top: -2px;\n display: inline-block;\n line-height: 1;\n}\n\n\n\n.collapsible-title[_ngcontent-%COMP%] .row-count-badge.zero-rows[_ngcontent-%COMP%] {\n background: var(--mj-text-muted);\n}", "\n\n[_nghost-%COMP%] {\n display: block;\n height: 100%;\n}\n\n\n\n.record-form[_ngcontent-%COMP%] {\n min-height: 0 !important;\n}\n\n\n\n\n\n\n.query-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-brand-primary);\n border-bottom: none;\n padding: 0;\n}\n\n.query-header-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px 20px;\n}\n\n.query-header-top[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 20px;\n}\n\n.query-name-section[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.query-title-icon[_ngcontent-%COMP%] {\n color: rgba(255, 255, 255, 0.85);\n font-size: 1.3em;\n flex-shrink: 0;\n}\n\n.query-name-input[_ngcontent-%COMP%] {\n font-size: 1.2em;\n font-weight: 600;\n min-width: 300px;\n flex: 1;\n}\n\n.query-name-display[_ngcontent-%COMP%] {\n margin: 0;\n color: var(--mj-text-inverse, white);\n font-weight: 600;\n font-size: 1.2em;\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.query-header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.run-query-btn[_ngcontent-%COMP%] {\n white-space: nowrap;\n}\n\n\n\n.query-meta-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 24px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.query-meta-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.meta-label[_ngcontent-%COMP%] {\n font-weight: 500;\n color: rgba(255, 255, 255, 0.75);\n font-size: var(--mj-text-sm);\n min-width: 60px;\n}\n\n.meta-value[_ngcontent-%COMP%] {\n color: rgba(255, 255, 255, 0.95);\n font-size: var(--mj-text-sm);\n}\n\n.meta-dropdown[_ngcontent-%COMP%] {\n min-width: 200px;\n}\n\n.status-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: var(--mj-radius-xl);\n color: var(--mj-text-inverse, white);\n font-size: var(--mj-text-sm);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.status-pill[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n}\n\n\n\n.query-description-row[_ngcontent-%COMP%] {\n margin-top: 2px;\n}\n\n.query-description-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.query-description-text[_ngcontent-%COMP%] {\n margin: 0;\n color: rgba(255, 255, 255, 0.8);\n font-size: var(--mj-text-sm);\n line-height: 1.4;\n}\n\n\n\n\n\n\n.status-warning-banner[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 16px;\n margin: 0;\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n border-left: 4px solid var(--mj-status-warning);\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.status-warning-banner[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-base);\n flex-shrink: 0;\n}\n\n.status-warning-banner[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n font-weight: 600;\n}\n\n\n\n\n\n\n.query-content[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n padding: 16px;\n overflow-y: auto;\n background: var(--mj-bg-surface-card);\n}\n\n\n\n\n\n\n.query-panel[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n}\n\n .query-content kendo-expansionpanel {\n border: none !important;\n border-radius: var(--mj-radius-md) !important;\n margin-bottom: 12px !important;\n box-shadow: var(--mj-shadow-sm) !important;\n background: var(--mj-bg-surface) !important;\n overflow: hidden !important;\n}\n\n .query-content .k-expander-header {\n background: var(--mj-bg-surface) !important;\n border: none !important;\n padding: 14px 18px !important;\n border-radius: var(--mj-radius-md) !important;\n color: var(--mj-text-primary) !important;\n font-weight: 600 !important;\n font-size: var(--mj-text-sm) !important;\n transition: background 0.15s ease !important;\n}\n\n .query-content .k-expander-header:hover {\n background: var(--mj-bg-surface-card) !important;\n}\n\n .query-content kendo-expansionpanel[aria-expanded=\"true\"] .k-expander-header {\n background: var(--mj-brand-primary) !important;\n color: white !important;\n border-radius: var(--mj-radius-md) var(--mj-radius-md) 0 0 !important;\n}\n\n .query-content .k-expander-content {\n padding: 0 !important;\n border: none !important;\n background: var(--mj-bg-surface) !important;\n border-radius: 0 0 var(--mj-radius-md) var(--mj-radius-md) !important;\n}\n\n\n\n\n\n\n.panel-title-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n}\n\n.panel-icon[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n opacity: 0.7;\n}\n\n.sql-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n kendo-expansionpanel[aria-expanded=\"true\"] .panel-icon {\n color: rgba(255, 255, 255, 0.85) !important;\n opacity: 1;\n}\n\n.panel-badge[_ngcontent-%COMP%] {\n padding: 2px 8px;\n border-radius: var(--mj-radius-lg);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n}\n\n.panel-badge.defined[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n color: white;\n}\n\n.panel-badge.count[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: white;\n}\n\n kendo-expansionpanel[aria-expanded=\"true\"] .panel-badge.count {\n background: rgba(255, 255, 255, 0.25) !important;\n}\n\n kendo-expansionpanel[aria-expanded=\"true\"] .panel-badge.defined {\n background: rgba(255, 255, 255, 0.25) !important;\n}\n\n.filters-help-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-right: 8px;\n font-size: var(--mj-text-xs);\n}\n\n\n\n\n\n\n.panel-body[_ngcontent-%COMP%] {\n padding: 16px 0;\n}\n\n.panel-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 40px;\n}\n\n.panel-toolbar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n padding: 0 20px 12px;\n}\n\n\n\n\n\n\n.sql-panel-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.sql-editor[_ngcontent-%COMP%] {\n flex: 1;\n height: 400px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n margin: 16px;\n}\n\n\n\n.filters-help[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 16px;\n margin: 0 16px 16px;\n}\n\n.filters-help-title[_ngcontent-%COMP%] {\n margin: 0 0 12px 0;\n color: var(--mj-text-primary);\n font-weight: 600;\n font-size: var(--mj-text-sm);\n}\n\n.filters-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n gap: 10px;\n}\n\n.filter-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 12px;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n}\n\n.filter-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.filter-name[_ngcontent-%COMP%] {\n font-family: 'Courier New', monospace;\n font-weight: bold;\n color: var(--mj-brand-primary);\n margin-bottom: 4px;\n}\n\n.filter-description[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n margin-bottom: 6px;\n}\n\n.filter-syntax[_ngcontent-%COMP%] {\n font-family: 'Courier New', monospace;\n font-size: var(--mj-text-xs);\n background: var(--mj-bg-surface-card);\n padding: 6px;\n border-radius: var(--mj-radius-sm);\n margin-bottom: 4px;\n}\n\n.filter-notes[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n\n\n\n\n\n.card-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));\n gap: 12px;\n padding: 0 20px 20px;\n}\n\n.item-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px;\n transition: all 0.15s ease;\n cursor: pointer;\n position: relative;\n}\n\n.item-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.item-card.required[_ngcontent-%COMP%] {\n border-left: 3px solid var(--mj-status-warning);\n}\n\n.item-card-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 10px;\n}\n\n.item-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.item-name-icon[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n}\n\n.item-name-icon.param-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.item-name-icon.field-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.item-name-icon.entity-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.item-badges[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n}\n\n.item-badge[_ngcontent-%COMP%] {\n padding: 2px 8px;\n border-radius: var(--mj-radius-lg);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: white;\n}\n\n.item-badge.required[_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n}\n\n.item-badge.type[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.item-badge.sequence[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: color-mix(in srgb, var(--mj-brand-primary) 80%, purple);\n}\n\n.item-card-body[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n}\n\n.item-description[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n}\n\n.item-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n font-size: var(--mj-text-xs);\n}\n\n.meta-tag[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.meta-code[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n padding: 1px 4px;\n border-radius: var(--mj-radius-sm);\n font-size: var(--mj-text-xs);\n}\n\n\n\n.item-actions[_ngcontent-%COMP%] {\n position: absolute;\n top: 10px;\n right: 10px;\n display: flex;\n gap: 4px;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.item-card[_ngcontent-%COMP%]:hover .item-actions[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.item-card-actions[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n margin-top: 8px;\n}\n\n.item-action-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n cursor: pointer;\n color: var(--mj-text-disabled);\n transition: all 0.15s ease;\n}\n\n.item-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.item-action-btn.delete[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n\n\n.entity-dropdown-wrapper[_ngcontent-%COMP%] {\n flex: 1;\n margin-left: 12px;\n}\n\n.entity-dropdown[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n\n\n\n\n\n.details-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));\n gap: 16px;\n padding: 16px 20px;\n}\n\n.detail-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.detail-label[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-disabled);\n display: flex;\n align-items: center;\n gap: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.detail-value[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.detail-tag[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: var(--mj-text-sm);\n}\n\n.detail-tag.positive[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.detail-tag.neutral[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n}\n\n\n\n\n\n\n.permissions-list[_ngcontent-%COMP%] {\n padding: 0 20px;\n}\n\n.permission-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px 16px;\n margin-bottom: 8px;\n}\n\n.permission-icon[_ngcontent-%COMP%] {\n font-size: 1.3em;\n color: var(--mj-brand-primary);\n}\n\n.permission-info[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.permission-role[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n font-size: var(--mj-text-sm);\n}\n\n.permission-type[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-disabled);\n}\n\n.permission-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n background: var(--mj-brand-primary);\n color: white;\n padding: 4px 10px;\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-xs);\n font-weight: 500;\n}\n\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 20px;\n text-align: center;\n color: var(--mj-text-disabled);\n}\n\n.empty-state-icon[_ngcontent-%COMP%] {\n font-size: 40px;\n margin-bottom: 14px;\n opacity: 0.25;\n color: var(--mj-text-primary);\n}\n\n.empty-state-title[_ngcontent-%COMP%] {\n font-size: var(--mj-text-base);\n font-weight: 600;\n margin-bottom: 6px;\n color: var(--mj-text-secondary);\n}\n\n.empty-state-text[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n margin-bottom: 16px;\n color: var(--mj-text-disabled);\n}\n\n\n\n\n\n\n.add-item-btn[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: all 0.15s ease;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 500;\n font-size: var(--mj-text-sm);\n}\n\n.add-item-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 85%, black);\n box-shadow: 0 2px 6px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n\n\n\n\n\n.badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n\n\n\n\n\n.technical-description-textarea[_ngcontent-%COMP%] {\n width: 100%;\n font-family: 'Consolas', 'Monaco', 'Courier New', monospace;\n font-size: 13px;\n}\n\n.technical-description-preview[_ngcontent-%COMP%] {\n margin-top: 16px;\n border-top: 1px solid var(--mj-border-default);\n padding-top: 12px;\n}\n\n.preview-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n margin-bottom: 8px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.technical-description-view[_ngcontent-%COMP%] {\n max-height: 500px;\n overflow-y: auto;\n padding: 12px 16px;\n}\n\n\n\n.dependents-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n.dependents-description[_ngcontent-%COMP%] {\n padding: 0 20px 12px;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.dependents-description[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n padding: 1px 5px;\n border-radius: 3px;\n font-size: 12px;\n}\n\n.dependent-card[_ngcontent-%COMP%] {\n cursor: pointer;\n border-left: 3px solid var(--mj-status-warning) !important;\n}\n\n.dependent-card[_ngcontent-%COMP%]:hover {\n border-left-color: var(--mj-status-warning-text) !important;\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface)) !important;\n}\n\n.dependent-query-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-warning) !important;\n}\n\n.item-card-footer[_ngcontent-%COMP%] {\n padding-top: 8px;\n border-top: 1px solid var(--mj-bg-surface-sunken);\n margin-top: 8px;\n}\n\n.open-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-brand-primary);\n font-weight: 500;\n}\n\n.dependent-card[_ngcontent-%COMP%]:hover .open-link[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary-hover);\n}"] }); }
1809
1809
  };
1810
1810
  MJQueryFormComponentExtended = __decorate([
1811
1811
  RegisterClass(BaseFormComponent, 'MJ: Queries')
@@ -1813,7 +1813,7 @@ MJQueryFormComponentExtended = __decorate([
1813
1813
  export { MJQueryFormComponentExtended };
1814
1814
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJQueryFormComponentExtended, [{
1815
1815
  type: Component,
1816
- args: [{ standalone: false, selector: 'mj-query-form', template: "<div class=\"record-form-container\" style=\"height: 100%; display: flex; flex-direction: column;\">\n @if (record) {\n <form class=\"record-form\" #form=\"ngForm\" style=\"display: flex; flex-direction: column; height: 100%; overflow: hidden;\">\n <mj-form-toolbar [Form]=\"this\" [Config]=\"ToolbarConfig\"></mj-form-toolbar>\n\n <!-- Header Section -->\n <div class=\"query-header\">\n <div class=\"query-header-content\">\n <!-- Top Row: Name and Run Button -->\n <div class=\"query-header-top\">\n <!-- Left: Query Name -->\n <div class=\"query-name-section\">\n <i class=\"fa-solid fa-database query-title-icon\"></i>\n @if (EditMode) {\n <kendo-textbox [(ngModel)]=\"record.Name\"\n name=\"queryName\"\n placeholder=\"Enter query name...\"\n class=\"query-name-input\">\n </kendo-textbox>\n } @else {\n <h4 class=\"query-name-display\">{{ record.Name || 'Untitled Query' }}</h4>\n }\n </div>\n\n <!-- Right: Action Buttons -->\n <div class=\"query-header-actions\">\n @if (record.ID) {\n <button kendoButton\n [themeColor]=\"'primary'\"\n [size]=\"'large'\"\n [disabled]=\"EditMode || !record.SQL || record.SQL.trim().length === 0\"\n (click)=\"runQuery()\"\n title=\"Run Query\"\n class=\"run-query-btn\">\n <i class=\"fa-solid fa-play\"></i> Run\n </button>\n }\n </div>\n </div>\n\n <!-- Second Row: Category and Status -->\n <div class=\"query-meta-row\">\n <!-- Category -->\n <div class=\"query-meta-item\">\n <label class=\"meta-label\">Category</label>\n @if (EditMode) {\n <kendo-dropdownlist\n [(ngModel)]=\"record.CategoryID\"\n name=\"categoryId\"\n [data]=\"categoryOptions\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n placeholder=\"Select category...\"\n class=\"meta-dropdown\">\n </kendo-dropdownlist>\n } @else {\n <span class=\"meta-value\">{{ categoryPathDisplay || 'Uncategorized' }}</span>\n }\n </div>\n\n <!-- Status -->\n <div class=\"query-meta-item\">\n <label class=\"meta-label\">Status</label>\n @if (EditMode) {\n <kendo-dropdownlist\n [(ngModel)]=\"record.Status\"\n name=\"status\"\n [data]=\"statusOptions\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n class=\"meta-dropdown status-dropdown\">\n </kendo-dropdownlist>\n } @else {\n <span class=\"status-pill\"\n [style.background]=\"getStatusBadgeColor()\">\n <i class=\"fa-solid\" [class]=\"getStatusBannerIcon()\"></i>\n {{ record.Status || 'Unknown' }}\n </span>\n }\n </div>\n </div>\n\n <!-- Third Row: Description -->\n @if (EditMode || record.Description) {\n <div class=\"query-description-row\">\n @if (EditMode) {\n <kendo-textarea [(ngModel)]=\"record.Description\"\n name=\"description\"\n [rows]=\"2\"\n placeholder=\"Enter query description...\"\n class=\"query-description-input\">\n </kendo-textarea>\n } @else {\n <p class=\"query-description-text\">{{ record.Description }}</p>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Status Warning Banner for Non-Approved Queries -->\n @if (record.Status && record.Status !== 'Approved' && !EditMode) {\n <div class=\"status-warning-banner\" [style.border-left-color]=\"getStatusBadgeColor()\">\n <i class=\"fa-solid\" [class]=\"getStatusBannerIcon()\"\n [style.color]=\"getStatusBadgeColor()\"></i>\n <span>\n This query has status <strong>{{ record.Status }}</strong>. {{ getStatusBannerMessage() }}\n </span>\n </div>\n }\n\n <!-- Main Content Area with Expansion Panels -->\n <div class=\"query-content\">\n\n <!-- SQL Query Panel -->\n <kendo-expansionpanel\n [(expanded)]=\"sqlPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title-row\">\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-code panel-icon sql-icon\"></i>\n SQL\n @if (record.SQL) {\n <span class=\"panel-badge defined\">\n <i class=\"fa-solid fa-check\"></i> Defined\n </span>\n }\n </span>\n <button type=\"button\"\n kendoButton\n fillMode=\"flat\"\n size=\"small\"\n (click)=\"toggleFiltersHelp(); $event.stopPropagation()\"\n title=\"Show/hide SQL filters help\"\n class=\"filters-help-btn\">\n <i class=\"fa-solid fa-question-circle\"></i>\n <span>Filters Help</span>\n <i class=\"fa-solid\" [ngClass]=\"showFiltersHelp ? 'fa-chevron-up' : 'fa-chevron-down'\"></i>\n </button>\n </span>\n </ng-template>\n\n <div class=\"sql-panel-content\">\n <!-- Code Editor -->\n <mj-code-editor #sqlEditor\n (change)=\"onSQLChange($event)\"\n (CompositionTokenClick)=\"onCompositionTokenClick($event)\"\n [language]=\"'sql'\"\n class=\"sql-editor\">\n </mj-code-editor>\n\n <!-- SQL Filters Help (Below Editor) -->\n @if (showFiltersHelp) {\n <div class=\"filters-help\">\n <h6 class=\"filters-help-title\">\n <i class=\"fa-solid fa-filter\"></i> Available SQL Filters for Parameterized Queries\n </h6>\n <div class=\"filters-grid\">\n @for (filter of sqlFilters; track filter.name) {\n <div class=\"filter-card\">\n <div class=\"filter-name\">{{ filter.name }}</div>\n <div class=\"filter-description\">{{ filter.description }}</div>\n <div class=\"filter-syntax\">{{ filter.exampleSyntax }}</div>\n @if (filter.notes) {\n <div class=\"filter-notes\">{{ filter.notes }}</div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n </kendo-expansionpanel>\n\n <!-- Technical Description Panel -->\n @if (record.TechnicalDescription || EditMode) {\n <kendo-expansionpanel\n [(expanded)]=\"technicalDescriptionPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-book panel-icon\"></i>\n Technical Description\n @if (record.TechnicalDescription) {\n <span class=\"panel-badge defined\">\n <i class=\"fa-solid fa-check\"></i> Documented\n </span>\n }\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n @if (EditMode) {\n <kendo-textarea [(ngModel)]=\"record.TechnicalDescription\"\n name=\"technicalDescription\"\n [rows]=\"8\"\n placeholder=\"Technical documentation of the query logic, performance considerations, and parameter usage. Supports markdown and mermaid diagrams.\"\n class=\"technical-description-textarea\">\n </kendo-textarea>\n @if (record.TechnicalDescription) {\n <div class=\"technical-description-preview\">\n <div class=\"preview-label\">\n <i class=\"fa-solid fa-eye\"></i> Preview\n </div>\n <mj-markdown\n [data]=\"record.TechnicalDescription || ''\"\n [enableMermaid]=\"true\"\n [enableHighlight]=\"true\"\n [enableCollapsibleHeadings]=\"false\"\n [enableSmartypants]=\"true\">\n </mj-markdown>\n </div>\n }\n } @else {\n <div class=\"technical-description-view\">\n <mj-markdown\n [data]=\"record.TechnicalDescription || ''\"\n [enableMermaid]=\"true\"\n [enableHighlight]=\"true\"\n [enableCollapsibleHeadings]=\"false\"\n [enableSmartypants]=\"true\">\n </mj-markdown>\n </div>\n }\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Parameters Panel -->\n @if (record.IsSaved) {\n <kendo-expansionpanel\n [(expanded)]=\"parametersPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-sliders panel-icon\"></i>\n Parameters\n @if (queryParameters.length > 0) {\n <span class=\"panel-badge count\">{{ queryParameters.length }}</span>\n }\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n @if (isLoadingParameters) {\n <div class=\"panel-loading\">\n <mj-loading text=\"Loading parameters...\"></mj-loading>\n </div>\n } @else {\n @if (queryParameters.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-sliders empty-state-icon\"></i>\n <div class=\"empty-state-title\">No Parameters Defined</div>\n <div class=\"empty-state-text\">\n Add parameters to make your query dynamic and reusable.\n </div>\n @if (EditMode) {\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addParameter()\">\n <i class=\"fa-solid fa-plus\"></i> Add First Parameter\n </button>\n }\n </div>\n } @else {\n @if (EditMode) {\n <div class=\"panel-toolbar\">\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addParameter()\">\n <i class=\"fa-solid fa-plus\"></i> Add Parameter\n </button>\n </div>\n }\n <div class=\"card-grid\">\n @for (param of queryParameters; track param.ID || $index) {\n <div class=\"item-card\" [class.required]=\"param.IsRequired\" (click)=\"editParameter(param)\">\n <div class=\"item-card-header\">\n <div class=\"item-name\">\n <i class=\"fa-solid fa-at item-name-icon param-icon\"></i>\n {{ param.Name }}\n </div>\n <div class=\"item-badges\">\n @if (param.IsRequired) {\n <span class=\"item-badge required\">Required</span>\n }\n </div>\n </div>\n <div class=\"item-card-body\">\n @if (param.Description) {\n <div class=\"item-description\">{{ param.Description }}</div>\n }\n <div class=\"item-meta\">\n <span class=\"meta-tag\">\n <strong>Type:</strong> {{ param.Type || 'Text' }}\n </span>\n @if (param.DefaultValue) {\n <span class=\"meta-tag\">\n <strong>Default:</strong>\n <code class=\"meta-code\">{{ param.DefaultValue }}</code>\n </span>\n }\n </div>\n </div>\n @if (EditMode) {\n <div class=\"item-actions\" (click)=\"$event.stopPropagation()\">\n <button type=\"button\" class=\"item-action-btn\" (click)=\"editParameter(param)\" title=\"Edit parameter\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n <button type=\"button\" class=\"item-action-btn delete\" (click)=\"deleteParameter(param)\" title=\"Delete parameter\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Query Fields Panel -->\n @if (record.IsSaved) {\n <kendo-expansionpanel\n [(expanded)]=\"fieldsPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-table panel-icon\"></i>\n Fields\n @if (queryFields.length > 0) {\n <span class=\"panel-badge count\">{{ queryFields.length }}</span>\n }\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n @if (isLoadingFields) {\n <div class=\"panel-loading\">\n <mj-loading text=\"Loading fields...\"></mj-loading>\n </div>\n } @else {\n @if (queryFields.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-table empty-state-icon\"></i>\n <div class=\"empty-state-title\">No Fields Defined</div>\n <div class=\"empty-state-text\">\n Define output fields for your query results.\n </div>\n @if (EditMode) {\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addField()\">\n <i class=\"fa-solid fa-plus\"></i> Add First Field\n </button>\n }\n </div>\n } @else {\n @if (EditMode) {\n <div class=\"panel-toolbar\">\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addField()\">\n <i class=\"fa-solid fa-plus\"></i> Add Field\n </button>\n </div>\n }\n <div class=\"card-grid\">\n @for (field of queryFields; track field.ID) {\n <div class=\"item-card\">\n <div class=\"item-card-header\">\n <div class=\"item-name\">\n <i class=\"fa-solid fa-columns item-name-icon field-icon\"></i>\n {{ field.Name }}\n </div>\n <div class=\"item-badges\">\n <span class=\"item-badge type\">{{ field.SQLBaseType }}</span>\n @if (field.Sequence) {\n <span class=\"item-badge sequence\">#{{ field.Sequence }}</span>\n }\n </div>\n </div>\n <div class=\"item-card-body\">\n @if (field.Description) {\n <div class=\"item-description\">{{ field.Description }}</div>\n }\n <div class=\"item-meta\">\n <span class=\"meta-tag\">\n <i class=\"fa-solid fa-code\"></i> {{ field.SQLFullType || field.SQLBaseType }}\n </span>\n </div>\n </div>\n @if (EditMode) {\n <div class=\"item-card-actions\">\n <button type=\"button\" class=\"item-action-btn delete\" (click)=\"deleteField(field)\" title=\"Delete field\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Dependent Queries Panel -->\n @if (record.IsSaved && DependentQueries.length > 0) {\n <kendo-expansionpanel\n [(expanded)]=\"dependentsPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-arrow-left panel-icon dependents-icon\"></i>\n Dependent Queries\n <span class=\"panel-badge count\">{{ DependentQueries.length }}</span>\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n <div class=\"dependents-description\">\n These queries reference this query via <code>{{\"{{query:\\\"...\\\"}}\"}} </code> composition syntax.\n </div>\n <div class=\"card-grid\">\n @for (dep of DependentQueries; track dep.ID) {\n <div class=\"item-card dependent-card\" (click)=\"onDependentQueryClick(dep)\">\n <div class=\"item-card-header\">\n <div class=\"item-name\">\n <i class=\"fa-solid fa-arrow-left item-name-icon dependent-query-icon\"></i>\n {{ dep.Query }}\n </div>\n </div>\n <div class=\"item-card-body\">\n @if (dep.ReferencePath) {\n <div class=\"item-meta\">\n <span class=\"meta-tag\">\n <i class=\"fa-solid fa-link\"></i> {{ dep.ReferencePath }}\n </span>\n </div>\n }\n @if (dep.Alias) {\n <div class=\"item-meta\">\n <span class=\"meta-tag\">\n <strong>Alias:</strong> <code class=\"meta-code\">{{ dep.Alias }}</code>\n </span>\n </div>\n }\n </div>\n <div class=\"item-card-footer\">\n <span class=\"open-link\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Query Entities Panel -->\n @if (record.IsSaved) {\n <kendo-expansionpanel\n [(expanded)]=\"entitiesPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-database panel-icon\"></i>\n Entities\n @if (queryEntities.length > 0) {\n <span class=\"panel-badge count\">{{ queryEntities.length }}</span>\n }\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n @if (isLoadingEntities) {\n <div class=\"panel-loading\">\n <mj-loading text=\"Loading entities...\"></mj-loading>\n </div>\n } @else {\n @if (queryEntities.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-database empty-state-icon\"></i>\n <div class=\"empty-state-title\">No Entities Tracked</div>\n <div class=\"empty-state-text\">\n Track which entities this query uses for documentation.\n </div>\n @if (EditMode) {\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addEntity()\">\n <i class=\"fa-solid fa-plus\"></i> Add First Entity\n </button>\n }\n </div>\n } @else {\n @if (EditMode) {\n <div class=\"panel-toolbar\">\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addEntity()\">\n <i class=\"fa-solid fa-plus\"></i> Add Entity\n </button>\n </div>\n }\n <div class=\"card-grid\">\n @for (entity of queryEntities; track entity.ID) {\n <div class=\"item-card\">\n <div class=\"item-card-header\">\n <div class=\"item-name\">\n <i class=\"fa-solid fa-table item-name-icon entity-icon\"></i>\n {{ entity.Entity || 'Select Entity...' }}\n </div>\n @if (EditMode) {\n <div class=\"entity-dropdown-wrapper\">\n <kendo-dropdownlist\n [(ngModel)]=\"entity.EntityID\"\n [name]=\"'entity_' + entity.ID\"\n [data]=\"getEntityOptions()\"\n textField=\"text\"\n valueField=\"id\"\n [valuePrimitive]=\"true\"\n placeholder=\"Select entity...\"\n class=\"entity-dropdown\">\n </kendo-dropdownlist>\n </div>\n }\n </div>\n @if (!EditMode && entity.Entity) {\n <div class=\"item-card-body\">\n <div class=\"item-meta\">\n <span class=\"meta-tag\">\n <i class=\"fa-solid fa-database\"></i> Data Source\n </span>\n </div>\n </div>\n }\n @if (EditMode) {\n <div class=\"item-card-actions\">\n <button type=\"button\" class=\"item-action-btn delete\" (click)=\"deleteEntity(entity)\" title=\"Delete entity\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Details Panel -->\n <kendo-expansionpanel\n [(expanded)]=\"detailsPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-info-circle panel-icon\"></i>\n Details\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n <div class=\"details-grid\">\n <!-- Uses Template -->\n <div class=\"detail-item\">\n <label class=\"detail-label\">\n <i class=\"fa-solid fa-file-code\"></i> Template Usage\n </label>\n @if (EditMode) {\n <kendo-switch [(ngModel)]=\"record.UsesTemplate\" name=\"usesTemplate\"></kendo-switch>\n } @else {\n <div class=\"detail-value\">\n @if (record.UsesTemplate) {\n <span class=\"detail-tag positive\"><i class=\"fa-solid fa-check\"></i> Uses Templates</span>\n } @else {\n <span class=\"detail-tag neutral\"><i class=\"fa-solid fa-times\"></i> No Templates</span>\n }\n </div>\n }\n </div>\n\n <!-- Created Date -->\n <div class=\"detail-item\">\n <label class=\"detail-label\">\n <i class=\"fa-solid fa-calendar-plus\"></i> Created\n </label>\n <div class=\"detail-value\">{{ formatDate(record.__mj_CreatedAt) }}</div>\n </div>\n\n <!-- Updated Date -->\n <div class=\"detail-item\">\n <label class=\"detail-label\">\n <i class=\"fa-solid fa-calendar-check\"></i> Last Updated\n </label>\n <div class=\"detail-value\">{{ formatDate(record.__mj_UpdatedAt) }}</div>\n </div>\n\n <!-- Quality Rank -->\n @if (record.QualityRank != null) {\n <div class=\"detail-item\">\n <label class=\"detail-label\">\n <i class=\"fa-solid fa-star\"></i> Quality Rank\n </label>\n <div class=\"detail-value\">{{ record.QualityRank }}/10</div>\n </div>\n }\n </div>\n </div>\n </kendo-expansionpanel>\n\n <!-- Permissions Panel -->\n @if (record.IsSaved) {\n <kendo-expansionpanel\n [(expanded)]=\"permissionsPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-shield-alt panel-icon\"></i>\n Permissions\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n @if (isLoadingPermissions) {\n <div class=\"panel-loading\">\n <mj-loading text=\"Loading permissions...\"></mj-loading>\n </div>\n } @else {\n @if (queryPermissions.length === 0 && !EditMode) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shield-alt empty-state-icon\"></i>\n <div class=\"empty-state-title\">No Permissions Set</div>\n <div class=\"empty-state-text\">\n This query uses default permissions.\n </div>\n </div>\n } @else {\n @if (EditMode) {\n <mj-explorer-entity-data-grid\n [Params]=\"BuildRelationshipViewParamsByEntityName('MJ: Query Permissions','QueryID')\"\n [NewRecordValues]=\"NewRecordValues('MJ: Query Permissions')\"\n [AllowLoad]=\"true\"\n [ShowToolbar]=\"false\">\n </mj-explorer-entity-data-grid>\n } @else {\n <div class=\"permissions-list\">\n @for (permission of queryPermissions; track permission.ID) {\n <div class=\"permission-card\">\n <i class=\"fa-solid fa-users permission-icon\"></i>\n <div class=\"permission-info\">\n <div class=\"permission-role\">{{ permission.Role }}</div>\n <div class=\"permission-type\">Role Permission</div>\n </div>\n <span class=\"permission-badge\">\n <i class=\"fa-solid fa-play\"></i> Can Execute\n </span>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n </kendo-expansionpanel>\n }\n\n </div>\n </form>\n\n <!-- Query Run Dialog -->\n <mj-query-run-dialog\n [query]=\"record\"\n [parameters]=\"queryParameters\"\n [(isVisible)]=\"showRunDialog\"\n (onClose)=\"onRunDialogClose()\">\n </mj-query-run-dialog>\n\n <!-- Category Creation Dialog -->\n <mj-query-category-dialog\n [(isVisible)]=\"showCategoryDialog\"\n (onCategoryCreated)=\"onCategoryCreated($event)\">\n </mj-query-category-dialog>\n }\n</div>\n", styles: [".k-pane {\n background-color: #F5F6FA;\n}\n\n.content-margin {\n margin: 10px;\n} \n\n\na {\n font-size: 14px;\n font-weight: bolder;\n}\n\n.tab-header-icon {\n margin-right: 5px;\n}\n\n.record-form {\n display: block;\n flex-direction: column;\n background-color: #F5F6FA;\n padding: 0;\n min-height: 100vh;\n}\n\n.record-form-group {\n margin-top: 0px;\n background-color: #F5F6FA;\n}\n\nbutton {\n margin-right: 5px;\n}\n\n.record-form h2 {\n margin-bottom: 10px;\n}\n\n.k-splitter {\n border-width: 0px;\n}\n\n.record-form-row {\n display: grid;\n grid-template-columns: auto 1fr;\n align-items: start;\n gap: 10px;\n margin-bottom: 12px;\n padding-top: 5px;\n padding-bottom: 5px;\n}\n\n\n/* .record-form .record-form-row:nth-child(odd) {\n background-color: #f2f2f2; \n} */\n\n/* \n.record-form .record-form-row:nth-child(even) {\n background-color: #ffffff; \n} */\n\n.record-form .record-form-row > :first-child {\n font-weight: bold;\n padding-right: 10px;\n} \n\n.record-form .record-form-row > span {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n \n\n@media (min-width: 768px) {\n .record-form-row {\n flex-direction: row;\n align-items: center;\n }\n\n .record-form-row label {\n width: 240px;\n margin-bottom: 0;\n }\n}\n\n/* Collapsible Panel Styles */\n.form-panels-container {\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 16px;\n background-color: #F5F6FA;\n}\n\n/* All field sections take full width */\n.form-panels-container > .form-card {\n width: 100%;\n}\n\n/* Related entity grid container - responsive layout */\n.form-panels-container .related-entity-grid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 16px;\n width: 100%;\n}\n\n/* Responsive multi-column layout for related entities on wider screens */\n@media (min-width: 1400px) {\n .form-panels-container .related-entity-grid {\n grid-template-columns: repeat(auto-fit, minmax(600px, 1fr));\n }\n}\n\n.form-card {\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n}\n\n.collapsible-card {\n overflow: hidden;\n}\n\n.collapsible-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n background: linear-gradient(135deg, #f9fafb 0%, #ffffff 100%);\n border-bottom: 2px solid #e5e7eb;\n cursor: pointer;\n user-select: none;\n transition: all 0.3s ease;\n}\n\n.collapsible-header:hover {\n background: linear-gradient(135deg, #f3f4f6 0%, #f9fafb 100%);\n border-bottom-color: #667eea;\n}\n\n.collapsible-title {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n}\n\n.collapsible-title i {\n font-size: 20px;\n color: #667eea;\n}\n\n.collapsible-title h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #1f2937;\n}\n\n.collapsible-header .collapse-icon {\n color: #6b7280;\n transition: transform 0.3s ease;\n}\n\n.collapsible-body {\n max-height: 2000px;\n overflow: hidden;\n transition: max-height 0.4s ease, padding 0.4s ease, opacity 0.3s ease;\n opacity: 1;\n}\n\n.collapsible-body.collapsed {\n max-height: 0;\n padding: 0;\n opacity: 0;\n}\n\n.form-body {\n padding: 24px;\n}\n\n/* Related Entity Sections - Visual Distinction */\n.form-card.related-entity {\n background: linear-gradient(135deg, #f0f9ff 0%, #ffffff 100%);\n border-left: 3px solid #3b82f6;\n}\n\n.form-card.related-entity .collapsible-header {\n background: linear-gradient(135deg, #e0f2fe 0%, #f0f9ff 100%);\n}\n\n.form-card.related-entity .collapsible-header:hover {\n background: linear-gradient(135deg, #bfdbfe 0%, #e0f2fe 100%);\n border-bottom-color: #3b82f6;\n}\n\n.form-card.related-entity .collapsible-title i {\n color: #3b82f6;\n}\n\n/* Section Controls */\n.form-section-controls {\n display: flex;\n gap: 10px;\n padding: 14px 18px;\n background: linear-gradient(135deg, #f9fafb 0%, #ffffff 100%);\n border-bottom: 2px solid #e5e7eb;\n align-items: center;\n flex-wrap: wrap;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n}\n\n.form-section-controls .control-group {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.form-section-controls button {\n padding: 8px 14px;\n font-size: 13px;\n border: 1px solid #d1d5db;\n background: white;\n color: #374151;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n margin-right: 0;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 500;\n}\n\n.form-section-controls button:hover {\n background: #667eea;\n color: white;\n border-color: #667eea;\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(102, 126, 234, 0.2);\n}\n\n.form-section-controls button:active {\n transform: translateY(0);\n}\n\n.form-section-controls button i {\n margin-right: 0;\n font-size: 14px;\n}\n\n.form-section-controls .section-search {\n padding: 8px 14px;\n font-size: 13px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n width: 240px;\n transition: all 0.2s;\n background: white;\n}\n\n.form-section-controls .section-search:focus {\n outline: none;\n border-color: #667eea;\n box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);\n}\n\n.form-section-controls .section-search::placeholder {\n color: #9ca3af;\n font-style: italic;\n}\n\n.form-section-controls .section-count {\n font-size: 13px;\n color: #6b7280;\n margin-left: auto;\n font-weight: 500;\n}\n\n/* Hidden sections for search filter */\n.form-card.search-hidden {\n display: none;\n}\n\n/* Section count badge */\n.section-count-badge {\n background: #667eea;\n color: white;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n}\n\n/* Search highlighting in section names */\n.collapsible-title h3 .search-highlight {\n background-color: #fef08a;\n color: #854d0e;\n padding: 2px 4px;\n border-radius: 3px;\n font-weight: 700;\n}\n\n/* Row count badge in section headers */\n.collapsible-title .row-count-badge {\n background: #10b981;\n color: white;\n padding: 3px 6px 2px 6px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n margin-left: 8px;\n vertical-align: middle;\n position: relative;\n top: -2px;\n display: inline-block;\n line-height: 1;\n}\n\n/* Gray badge for zero rows (loaded but empty) */\n.collapsible-title .row-count-badge.zero-rows {\n background: #9ca3af;\n}\n", "/* Override shared form-styles to enable flex layout */\n:host {\n display: block;\n height: 100%;\n}\n\n/* Override the shared record-form min-height so flex layout works properly */\n.record-form {\n min-height: 0 !important;\n}\n\n/* ========================================\n Header Section \u2014 matches Query Browser gradient\n ======================================== */\n\n.query-header {\n flex-shrink: 0;\n background: linear-gradient(135deg, #5c6bc0 0%, #3949ab 100%);\n border-bottom: none;\n padding: 0;\n}\n\n.query-header-content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px 20px;\n}\n\n.query-header-top {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 20px;\n}\n\n.query-name-section {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.query-title-icon {\n color: rgba(255, 255, 255, 0.85);\n font-size: 1.3em;\n flex-shrink: 0;\n}\n\n.query-name-input {\n font-size: 1.2em;\n font-weight: 600;\n min-width: 300px;\n flex: 1;\n}\n\n.query-name-display {\n margin: 0;\n color: #fff;\n font-weight: 600;\n font-size: 1.2em;\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.query-header-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.run-query-btn {\n white-space: nowrap;\n}\n\n/* Meta row (category + status) */\n.query-meta-row {\n display: flex;\n gap: 24px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.query-meta-item {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.meta-label {\n font-weight: 500;\n color: rgba(255, 255, 255, 0.75);\n font-size: 13px;\n min-width: 60px;\n}\n\n.meta-value {\n color: rgba(255, 255, 255, 0.95);\n font-size: 14px;\n}\n\n.meta-dropdown {\n min-width: 200px;\n}\n\n.status-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: 14px;\n color: #fff;\n font-size: 13px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.status-pill i {\n font-size: 12px;\n}\n\n/* Description row */\n.query-description-row {\n margin-top: 2px;\n}\n\n.query-description-input {\n width: 100%;\n}\n\n.query-description-text {\n margin: 0;\n color: rgba(255, 255, 255, 0.8);\n font-size: 13px;\n line-height: 1.4;\n}\n\n/* ========================================\n Status Warning Banner\n ======================================== */\n\n.status-warning-banner {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 16px;\n margin: 0;\n background: #fff8e1;\n border-left: 4px solid #f59e0b;\n font-size: 13px;\n color: #5d4037;\n flex-shrink: 0;\n}\n\n.status-warning-banner i {\n font-size: 16px;\n flex-shrink: 0;\n}\n\n.status-warning-banner strong {\n font-weight: 600;\n}\n\n/* ========================================\n Main Content Area\n ======================================== */\n\n.query-content {\n flex: 1;\n min-height: 0;\n padding: 16px;\n overflow-y: auto;\n background: #f5f5f5;\n}\n\n/* ========================================\n Expansion Panel Overrides \u2014 Modern Style\n ======================================== */\n\n.query-panel {\n margin-bottom: 12px;\n}\n\n::ng-deep .query-content kendo-expansionpanel {\n border: none !important;\n border-radius: 8px !important;\n margin-bottom: 12px !important;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08) !important;\n background: white !important;\n overflow: hidden !important;\n}\n\n::ng-deep .query-content .k-expander-header {\n background: white !important;\n border: none !important;\n padding: 14px 18px !important;\n border-radius: 8px !important;\n color: #333 !important;\n font-weight: 600 !important;\n font-size: 14px !important;\n transition: background 0.15s ease !important;\n}\n\n::ng-deep .query-content .k-expander-header:hover {\n background: #f8f9fa !important;\n}\n\n::ng-deep .query-content kendo-expansionpanel[aria-expanded=\"true\"] .k-expander-header {\n background: #5c6bc0 !important;\n color: white !important;\n border-radius: 8px 8px 0 0 !important;\n}\n\n::ng-deep .query-content .k-expander-content {\n padding: 0 !important;\n border: none !important;\n background: white !important;\n border-radius: 0 0 8px 8px !important;\n}\n\n/* ========================================\n Panel Title & Badges\n ======================================== */\n\n.panel-title-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n}\n\n.panel-icon {\n font-size: 14px;\n opacity: 0.7;\n}\n\n.sql-icon {\n color: #5c6bc0;\n}\n\n::ng-deep kendo-expansionpanel[aria-expanded=\"true\"] .panel-icon {\n color: rgba(255, 255, 255, 0.85) !important;\n opacity: 1;\n}\n\n.panel-badge {\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.panel-badge.defined {\n background: #28a745;\n color: white;\n}\n\n.panel-badge.count {\n background: #5c6bc0;\n color: white;\n}\n\n::ng-deep kendo-expansionpanel[aria-expanded=\"true\"] .panel-badge.count {\n background: rgba(255, 255, 255, 0.25) !important;\n}\n\n::ng-deep kendo-expansionpanel[aria-expanded=\"true\"] .panel-badge.defined {\n background: rgba(255, 255, 255, 0.25) !important;\n}\n\n.filters-help-btn {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-right: 8px;\n font-size: 12px;\n}\n\n/* ========================================\n Panel Body & Loading\n ======================================== */\n\n.panel-body {\n padding: 16px 0;\n}\n\n.panel-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 40px;\n}\n\n.panel-toolbar {\n display: flex;\n justify-content: flex-end;\n padding: 0 20px 12px;\n}\n\n/* ========================================\n SQL Panel\n ======================================== */\n\n.sql-panel-content {\n display: flex;\n flex-direction: column;\n}\n\n.sql-editor {\n flex: 1;\n height: 400px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n margin: 16px;\n}\n\n/* Filters Help */\n.filters-help {\n background: #fafafa;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n padding: 16px;\n margin: 0 16px 16px;\n}\n\n.filters-help-title {\n margin: 0 0 12px 0;\n color: #333;\n font-weight: 600;\n font-size: 14px;\n}\n\n.filters-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n gap: 10px;\n}\n\n.filter-card {\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n padding: 12px;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n}\n\n.filter-card:hover {\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n.filter-name {\n font-family: 'Courier New', monospace;\n font-weight: bold;\n color: #5c6bc0;\n margin-bottom: 4px;\n}\n\n.filter-description {\n font-size: 12px;\n color: #555;\n margin-bottom: 6px;\n}\n\n.filter-syntax {\n font-family: 'Courier New', monospace;\n font-size: 11px;\n background: #f5f5f5;\n padding: 6px;\n border-radius: 4px;\n margin-bottom: 4px;\n}\n\n.filter-notes {\n font-size: 11px;\n color: #888;\n font-style: italic;\n}\n\n/* ========================================\n Card Grid (Parameters, Fields, Entities)\n ======================================== */\n\n.card-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));\n gap: 12px;\n padding: 0 20px 20px;\n}\n\n.item-card {\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n padding: 14px;\n transition: all 0.15s ease;\n cursor: pointer;\n position: relative;\n}\n\n.item-card:hover {\n border-color: #5c6bc0;\n box-shadow: 0 2px 8px rgba(92, 107, 192, 0.12);\n}\n\n.item-card.required {\n border-left: 3px solid #f59e0b;\n}\n\n.item-card-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 10px;\n}\n\n.item-name {\n font-weight: 600;\n font-size: 14px;\n color: #333;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.item-name-icon {\n font-size: 14px;\n}\n\n.item-name-icon.param-icon {\n color: #5c6bc0;\n}\n\n.item-name-icon.field-icon {\n color: #5c6bc0;\n}\n\n.item-name-icon.entity-icon {\n color: #28a745;\n}\n\n.item-badges {\n display: flex;\n gap: 6px;\n}\n\n.item-badge {\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n color: white;\n}\n\n.item-badge.required {\n background: #f59e0b;\n}\n\n.item-badge.type {\n background: #e8eaf6;\n color: #3949ab;\n}\n\n.item-badge.sequence {\n background: #f3e5f5;\n color: #7b1fa2;\n}\n\n.item-card-body {\n color: #666;\n font-size: 13px;\n}\n\n.item-description {\n margin-bottom: 8px;\n}\n\n.item-meta {\n display: flex;\n gap: 16px;\n font-size: 12px;\n}\n\n.meta-tag {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.meta-code {\n background: #f5f5f5;\n padding: 1px 4px;\n border-radius: 3px;\n font-size: 11px;\n}\n\n/* Card actions (edit/delete) */\n.item-actions {\n position: absolute;\n top: 10px;\n right: 10px;\n display: flex;\n gap: 4px;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.item-card:hover .item-actions {\n opacity: 1;\n}\n\n.item-card-actions {\n display: flex;\n justify-content: flex-end;\n margin-top: 8px;\n}\n\n.item-action-btn {\n background: none;\n border: none;\n padding: 4px 8px;\n border-radius: 4px;\n cursor: pointer;\n color: #888;\n transition: all 0.15s ease;\n}\n\n.item-action-btn:hover {\n background: #f0f0f0;\n color: #5c6bc0;\n}\n\n.item-action-btn.delete:hover {\n background: #fff5f5;\n color: #dc3545;\n}\n\n/* Entity dropdown in card */\n.entity-dropdown-wrapper {\n flex: 1;\n margin-left: 12px;\n}\n\n.entity-dropdown {\n width: 100%;\n}\n\n/* ========================================\n Details Grid\n ======================================== */\n\n.details-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));\n gap: 16px;\n padding: 16px 20px;\n}\n\n.detail-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.detail-label {\n font-size: 12px;\n font-weight: 600;\n color: #888;\n display: flex;\n align-items: center;\n gap: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.detail-value {\n font-size: 14px;\n color: #333;\n}\n\n.detail-tag {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 13px;\n}\n\n.detail-tag.positive {\n color: #28a745;\n}\n\n.detail-tag.neutral {\n color: #888;\n}\n\n/* ========================================\n Permissions\n ======================================== */\n\n.permissions-list {\n padding: 0 20px;\n}\n\n.permission-card {\n display: flex;\n align-items: center;\n gap: 14px;\n background: #fafafa;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n padding: 14px 16px;\n margin-bottom: 8px;\n}\n\n.permission-icon {\n font-size: 1.3em;\n color: #5c6bc0;\n}\n\n.permission-info {\n flex: 1;\n}\n\n.permission-role {\n font-weight: 600;\n color: #333;\n font-size: 14px;\n}\n\n.permission-type {\n font-size: 12px;\n color: #888;\n}\n\n.permission-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n background: #5c6bc0;\n color: white;\n padding: 4px 10px;\n border-radius: 6px;\n font-size: 12px;\n font-weight: 500;\n}\n\n/* ========================================\n Empty State\n ======================================== */\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 20px;\n text-align: center;\n color: #888;\n}\n\n.empty-state-icon {\n font-size: 40px;\n margin-bottom: 14px;\n opacity: 0.25;\n color: #333;\n}\n\n.empty-state-title {\n font-size: 15px;\n font-weight: 600;\n margin-bottom: 6px;\n color: #555;\n}\n\n.empty-state-text {\n font-size: 13px;\n margin-bottom: 16px;\n color: #888;\n}\n\n/* ========================================\n Buttons\n ======================================== */\n\n.add-item-btn {\n background: #5c6bc0;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 500;\n font-size: 13px;\n}\n\n.add-item-btn:hover {\n background: #3949ab;\n box-shadow: 0 2px 6px rgba(92, 107, 192, 0.3);\n}\n\n/* ========================================\n Badge (reused across components)\n ======================================== */\n\n.badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n/* ========================================\n Technical Description Panel\n ======================================== */\n\n.technical-description-textarea {\n width: 100%;\n font-family: 'Consolas', 'Monaco', 'Courier New', monospace;\n font-size: 13px;\n}\n\n.technical-description-preview {\n margin-top: 16px;\n border-top: 1px solid #e0e0e0;\n padding-top: 12px;\n}\n\n.preview-label {\n font-size: 12px;\n font-weight: 600;\n color: #666;\n margin-bottom: 8px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.technical-description-view {\n max-height: 500px;\n overflow-y: auto;\n padding: 12px 16px;\n}\n\n/* Dependent Queries */\n.dependents-icon {\n color: #ef6c00;\n}\n\n.dependents-description {\n padding: 0 20px 12px;\n font-size: 13px;\n color: #666;\n}\n\n.dependents-description code {\n background: #f0f0f0;\n padding: 1px 5px;\n border-radius: 3px;\n font-size: 12px;\n}\n\n.dependent-card {\n cursor: pointer;\n border-left: 3px solid #ef6c00 !important;\n}\n\n.dependent-card:hover {\n border-left-color: #e65100 !important;\n background: #fff8f0 !important;\n}\n\n.dependent-query-icon {\n color: #ef6c00 !important;\n}\n\n.item-card-footer {\n padding-top: 8px;\n border-top: 1px solid #f0f0f0;\n margin-top: 8px;\n}\n\n.open-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: #5c6bc0;\n font-weight: 500;\n}\n\n.dependent-card:hover .open-link {\n color: #3949ab;\n}\n"] }]
1816
+ args: [{ standalone: false, selector: 'mj-query-form', template: "<div class=\"record-form-container\" style=\"height: 100%; display: flex; flex-direction: column;\">\n @if (record) {\n <form class=\"record-form\" #form=\"ngForm\" style=\"display: flex; flex-direction: column; height: 100%; overflow: hidden;\">\n <mj-form-toolbar [Form]=\"this\" [Config]=\"ToolbarConfig\"></mj-form-toolbar>\n\n <!-- Header Section -->\n <div class=\"query-header\">\n <div class=\"query-header-content\">\n <!-- Top Row: Name and Run Button -->\n <div class=\"query-header-top\">\n <!-- Left: Query Name -->\n <div class=\"query-name-section\">\n <i class=\"fa-solid fa-database query-title-icon\"></i>\n @if (EditMode) {\n <kendo-textbox [(ngModel)]=\"record.Name\"\n name=\"queryName\"\n placeholder=\"Enter query name...\"\n class=\"query-name-input\">\n </kendo-textbox>\n } @else {\n <h4 class=\"query-name-display\">{{ record.Name || 'Untitled Query' }}</h4>\n }\n </div>\n\n <!-- Right: Action Buttons -->\n <div class=\"query-header-actions\">\n @if (record.ID) {\n <button kendoButton\n [themeColor]=\"'primary'\"\n [size]=\"'large'\"\n [disabled]=\"EditMode || !record.SQL || record.SQL.trim().length === 0\"\n (click)=\"runQuery()\"\n title=\"Run Query\"\n class=\"run-query-btn\">\n <i class=\"fa-solid fa-play\"></i> Run\n </button>\n }\n </div>\n </div>\n\n <!-- Second Row: Category and Status -->\n <div class=\"query-meta-row\">\n <!-- Category -->\n <div class=\"query-meta-item\">\n <label class=\"meta-label\">Category</label>\n @if (EditMode) {\n <kendo-dropdownlist\n [(ngModel)]=\"record.CategoryID\"\n name=\"categoryId\"\n [data]=\"categoryOptions\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n placeholder=\"Select category...\"\n class=\"meta-dropdown\">\n </kendo-dropdownlist>\n } @else {\n <span class=\"meta-value\">{{ categoryPathDisplay || 'Uncategorized' }}</span>\n }\n </div>\n\n <!-- Status -->\n <div class=\"query-meta-item\">\n <label class=\"meta-label\">Status</label>\n @if (EditMode) {\n <kendo-dropdownlist\n [(ngModel)]=\"record.Status\"\n name=\"status\"\n [data]=\"statusOptions\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n class=\"meta-dropdown status-dropdown\">\n </kendo-dropdownlist>\n } @else {\n <span class=\"status-pill\"\n [style.background]=\"getStatusBadgeColor()\">\n <i class=\"fa-solid\" [class]=\"getStatusBannerIcon()\"></i>\n {{ record.Status || 'Unknown' }}\n </span>\n }\n </div>\n </div>\n\n <!-- Third Row: Description -->\n @if (EditMode || record.Description) {\n <div class=\"query-description-row\">\n @if (EditMode) {\n <kendo-textarea [(ngModel)]=\"record.Description\"\n name=\"description\"\n [rows]=\"2\"\n placeholder=\"Enter query description...\"\n class=\"query-description-input\">\n </kendo-textarea>\n } @else {\n <p class=\"query-description-text\">{{ record.Description }}</p>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Status Warning Banner for Non-Approved Queries -->\n @if (record.Status && record.Status !== 'Approved' && !EditMode) {\n <div class=\"status-warning-banner\" [style.border-left-color]=\"getStatusBadgeColor()\">\n <i class=\"fa-solid\" [class]=\"getStatusBannerIcon()\"\n [style.color]=\"getStatusBadgeColor()\"></i>\n <span>\n This query has status <strong>{{ record.Status }}</strong>. {{ getStatusBannerMessage() }}\n </span>\n </div>\n }\n\n <!-- Main Content Area with Expansion Panels -->\n <div class=\"query-content\">\n\n <!-- SQL Query Panel -->\n <kendo-expansionpanel\n [(expanded)]=\"sqlPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title-row\">\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-code panel-icon sql-icon\"></i>\n SQL\n @if (record.SQL) {\n <span class=\"panel-badge defined\">\n <i class=\"fa-solid fa-check\"></i> Defined\n </span>\n }\n </span>\n <button type=\"button\"\n kendoButton\n fillMode=\"flat\"\n size=\"small\"\n (click)=\"toggleFiltersHelp(); $event.stopPropagation()\"\n title=\"Show/hide SQL filters help\"\n class=\"filters-help-btn\">\n <i class=\"fa-solid fa-question-circle\"></i>\n <span>Filters Help</span>\n <i class=\"fa-solid\" [ngClass]=\"showFiltersHelp ? 'fa-chevron-up' : 'fa-chevron-down'\"></i>\n </button>\n </span>\n </ng-template>\n\n <div class=\"sql-panel-content\">\n <!-- Code Editor -->\n <mj-code-editor #sqlEditor\n (change)=\"onSQLChange($event)\"\n (CompositionTokenClick)=\"onCompositionTokenClick($event)\"\n [language]=\"'sql'\"\n class=\"sql-editor\">\n </mj-code-editor>\n\n <!-- SQL Filters Help (Below Editor) -->\n @if (showFiltersHelp) {\n <div class=\"filters-help\">\n <h6 class=\"filters-help-title\">\n <i class=\"fa-solid fa-filter\"></i> Available SQL Filters for Parameterized Queries\n </h6>\n <div class=\"filters-grid\">\n @for (filter of sqlFilters; track filter.name) {\n <div class=\"filter-card\">\n <div class=\"filter-name\">{{ filter.name }}</div>\n <div class=\"filter-description\">{{ filter.description }}</div>\n <div class=\"filter-syntax\">{{ filter.exampleSyntax }}</div>\n @if (filter.notes) {\n <div class=\"filter-notes\">{{ filter.notes }}</div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n </kendo-expansionpanel>\n\n <!-- Technical Description Panel -->\n @if (record.TechnicalDescription || EditMode) {\n <kendo-expansionpanel\n [(expanded)]=\"technicalDescriptionPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-book panel-icon\"></i>\n Technical Description\n @if (record.TechnicalDescription) {\n <span class=\"panel-badge defined\">\n <i class=\"fa-solid fa-check\"></i> Documented\n </span>\n }\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n @if (EditMode) {\n <kendo-textarea [(ngModel)]=\"record.TechnicalDescription\"\n name=\"technicalDescription\"\n [rows]=\"8\"\n placeholder=\"Technical documentation of the query logic, performance considerations, and parameter usage. Supports markdown and mermaid diagrams.\"\n class=\"technical-description-textarea\">\n </kendo-textarea>\n @if (record.TechnicalDescription) {\n <div class=\"technical-description-preview\">\n <div class=\"preview-label\">\n <i class=\"fa-solid fa-eye\"></i> Preview\n </div>\n <mj-markdown\n [data]=\"record.TechnicalDescription || ''\"\n [enableMermaid]=\"true\"\n [enableHighlight]=\"true\"\n [enableCollapsibleHeadings]=\"false\"\n [enableSmartypants]=\"true\">\n </mj-markdown>\n </div>\n }\n } @else {\n <div class=\"technical-description-view\">\n <mj-markdown\n [data]=\"record.TechnicalDescription || ''\"\n [enableMermaid]=\"true\"\n [enableHighlight]=\"true\"\n [enableCollapsibleHeadings]=\"false\"\n [enableSmartypants]=\"true\">\n </mj-markdown>\n </div>\n }\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Parameters Panel -->\n @if (record.IsSaved) {\n <kendo-expansionpanel\n [(expanded)]=\"parametersPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-sliders panel-icon\"></i>\n Parameters\n @if (queryParameters.length > 0) {\n <span class=\"panel-badge count\">{{ queryParameters.length }}</span>\n }\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n @if (isLoadingParameters) {\n <div class=\"panel-loading\">\n <mj-loading text=\"Loading parameters...\"></mj-loading>\n </div>\n } @else {\n @if (queryParameters.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-sliders empty-state-icon\"></i>\n <div class=\"empty-state-title\">No Parameters Defined</div>\n <div class=\"empty-state-text\">\n Add parameters to make your query dynamic and reusable.\n </div>\n @if (EditMode) {\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addParameter()\">\n <i class=\"fa-solid fa-plus\"></i> Add First Parameter\n </button>\n }\n </div>\n } @else {\n @if (EditMode) {\n <div class=\"panel-toolbar\">\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addParameter()\">\n <i class=\"fa-solid fa-plus\"></i> Add Parameter\n </button>\n </div>\n }\n <div class=\"card-grid\">\n @for (param of queryParameters; track param.ID || $index) {\n <div class=\"item-card\" [class.required]=\"param.IsRequired\" (click)=\"editParameter(param)\">\n <div class=\"item-card-header\">\n <div class=\"item-name\">\n <i class=\"fa-solid fa-at item-name-icon param-icon\"></i>\n {{ param.Name }}\n </div>\n <div class=\"item-badges\">\n @if (param.IsRequired) {\n <span class=\"item-badge required\">Required</span>\n }\n </div>\n </div>\n <div class=\"item-card-body\">\n @if (param.Description) {\n <div class=\"item-description\">{{ param.Description }}</div>\n }\n <div class=\"item-meta\">\n <span class=\"meta-tag\">\n <strong>Type:</strong> {{ param.Type || 'Text' }}\n </span>\n @if (param.DefaultValue) {\n <span class=\"meta-tag\">\n <strong>Default:</strong>\n <code class=\"meta-code\">{{ param.DefaultValue }}</code>\n </span>\n }\n </div>\n </div>\n @if (EditMode) {\n <div class=\"item-actions\" (click)=\"$event.stopPropagation()\">\n <button type=\"button\" class=\"item-action-btn\" (click)=\"editParameter(param)\" title=\"Edit parameter\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n <button type=\"button\" class=\"item-action-btn delete\" (click)=\"deleteParameter(param)\" title=\"Delete parameter\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Query Fields Panel -->\n @if (record.IsSaved) {\n <kendo-expansionpanel\n [(expanded)]=\"fieldsPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-table panel-icon\"></i>\n Fields\n @if (queryFields.length > 0) {\n <span class=\"panel-badge count\">{{ queryFields.length }}</span>\n }\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n @if (isLoadingFields) {\n <div class=\"panel-loading\">\n <mj-loading text=\"Loading fields...\"></mj-loading>\n </div>\n } @else {\n @if (queryFields.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-table empty-state-icon\"></i>\n <div class=\"empty-state-title\">No Fields Defined</div>\n <div class=\"empty-state-text\">\n Define output fields for your query results.\n </div>\n @if (EditMode) {\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addField()\">\n <i class=\"fa-solid fa-plus\"></i> Add First Field\n </button>\n }\n </div>\n } @else {\n @if (EditMode) {\n <div class=\"panel-toolbar\">\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addField()\">\n <i class=\"fa-solid fa-plus\"></i> Add Field\n </button>\n </div>\n }\n <div class=\"card-grid\">\n @for (field of queryFields; track field.ID) {\n <div class=\"item-card\">\n <div class=\"item-card-header\">\n <div class=\"item-name\">\n <i class=\"fa-solid fa-columns item-name-icon field-icon\"></i>\n {{ field.Name }}\n </div>\n <div class=\"item-badges\">\n <span class=\"item-badge type\">{{ field.SQLBaseType }}</span>\n @if (field.Sequence) {\n <span class=\"item-badge sequence\">#{{ field.Sequence }}</span>\n }\n </div>\n </div>\n <div class=\"item-card-body\">\n @if (field.Description) {\n <div class=\"item-description\">{{ field.Description }}</div>\n }\n <div class=\"item-meta\">\n <span class=\"meta-tag\">\n <i class=\"fa-solid fa-code\"></i> {{ field.SQLFullType || field.SQLBaseType }}\n </span>\n </div>\n </div>\n @if (EditMode) {\n <div class=\"item-card-actions\">\n <button type=\"button\" class=\"item-action-btn delete\" (click)=\"deleteField(field)\" title=\"Delete field\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Dependent Queries Panel -->\n @if (record.IsSaved && DependentQueries.length > 0) {\n <kendo-expansionpanel\n [(expanded)]=\"dependentsPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-arrow-left panel-icon dependents-icon\"></i>\n Dependent Queries\n <span class=\"panel-badge count\">{{ DependentQueries.length }}</span>\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n <div class=\"dependents-description\">\n These queries reference this query via <code>{{\"{{query:\\\"...\\\"}}\"}} </code> composition syntax.\n </div>\n <div class=\"card-grid\">\n @for (dep of DependentQueries; track dep.ID) {\n <div class=\"item-card dependent-card\" (click)=\"onDependentQueryClick(dep)\">\n <div class=\"item-card-header\">\n <div class=\"item-name\">\n <i class=\"fa-solid fa-arrow-left item-name-icon dependent-query-icon\"></i>\n {{ dep.Query }}\n </div>\n </div>\n <div class=\"item-card-body\">\n @if (dep.ReferencePath) {\n <div class=\"item-meta\">\n <span class=\"meta-tag\">\n <i class=\"fa-solid fa-link\"></i> {{ dep.ReferencePath }}\n </span>\n </div>\n }\n @if (dep.Alias) {\n <div class=\"item-meta\">\n <span class=\"meta-tag\">\n <strong>Alias:</strong> <code class=\"meta-code\">{{ dep.Alias }}</code>\n </span>\n </div>\n }\n </div>\n <div class=\"item-card-footer\">\n <span class=\"open-link\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Query Entities Panel -->\n @if (record.IsSaved) {\n <kendo-expansionpanel\n [(expanded)]=\"entitiesPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-database panel-icon\"></i>\n Entities\n @if (queryEntities.length > 0) {\n <span class=\"panel-badge count\">{{ queryEntities.length }}</span>\n }\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n @if (isLoadingEntities) {\n <div class=\"panel-loading\">\n <mj-loading text=\"Loading entities...\"></mj-loading>\n </div>\n } @else {\n @if (queryEntities.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-database empty-state-icon\"></i>\n <div class=\"empty-state-title\">No Entities Tracked</div>\n <div class=\"empty-state-text\">\n Track which entities this query uses for documentation.\n </div>\n @if (EditMode) {\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addEntity()\">\n <i class=\"fa-solid fa-plus\"></i> Add First Entity\n </button>\n }\n </div>\n } @else {\n @if (EditMode) {\n <div class=\"panel-toolbar\">\n <button type=\"button\" class=\"add-item-btn\" (click)=\"addEntity()\">\n <i class=\"fa-solid fa-plus\"></i> Add Entity\n </button>\n </div>\n }\n <div class=\"card-grid\">\n @for (entity of queryEntities; track entity.ID) {\n <div class=\"item-card\">\n <div class=\"item-card-header\">\n <div class=\"item-name\">\n <i class=\"fa-solid fa-table item-name-icon entity-icon\"></i>\n {{ entity.Entity || 'Select Entity...' }}\n </div>\n @if (EditMode) {\n <div class=\"entity-dropdown-wrapper\">\n <kendo-dropdownlist\n [(ngModel)]=\"entity.EntityID\"\n [name]=\"'entity_' + entity.ID\"\n [data]=\"getEntityOptions()\"\n textField=\"text\"\n valueField=\"id\"\n [valuePrimitive]=\"true\"\n placeholder=\"Select entity...\"\n class=\"entity-dropdown\">\n </kendo-dropdownlist>\n </div>\n }\n </div>\n @if (!EditMode && entity.Entity) {\n <div class=\"item-card-body\">\n <div class=\"item-meta\">\n <span class=\"meta-tag\">\n <i class=\"fa-solid fa-database\"></i> Data Source\n </span>\n </div>\n </div>\n }\n @if (EditMode) {\n <div class=\"item-card-actions\">\n <button type=\"button\" class=\"item-action-btn delete\" (click)=\"deleteEntity(entity)\" title=\"Delete entity\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Details Panel -->\n <kendo-expansionpanel\n [(expanded)]=\"detailsPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-info-circle panel-icon\"></i>\n Details\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n <div class=\"details-grid\">\n <!-- Uses Template -->\n <div class=\"detail-item\">\n <label class=\"detail-label\">\n <i class=\"fa-solid fa-file-code\"></i> Template Usage\n </label>\n @if (EditMode) {\n <kendo-switch [(ngModel)]=\"record.UsesTemplate\" name=\"usesTemplate\"></kendo-switch>\n } @else {\n <div class=\"detail-value\">\n @if (record.UsesTemplate) {\n <span class=\"detail-tag positive\"><i class=\"fa-solid fa-check\"></i> Uses Templates</span>\n } @else {\n <span class=\"detail-tag neutral\"><i class=\"fa-solid fa-times\"></i> No Templates</span>\n }\n </div>\n }\n </div>\n\n <!-- Created Date -->\n <div class=\"detail-item\">\n <label class=\"detail-label\">\n <i class=\"fa-solid fa-calendar-plus\"></i> Created\n </label>\n <div class=\"detail-value\">{{ formatDate(record.__mj_CreatedAt) }}</div>\n </div>\n\n <!-- Updated Date -->\n <div class=\"detail-item\">\n <label class=\"detail-label\">\n <i class=\"fa-solid fa-calendar-check\"></i> Last Updated\n </label>\n <div class=\"detail-value\">{{ formatDate(record.__mj_UpdatedAt) }}</div>\n </div>\n\n <!-- Quality Rank -->\n @if (record.QualityRank != null) {\n <div class=\"detail-item\">\n <label class=\"detail-label\">\n <i class=\"fa-solid fa-star\"></i> Quality Rank\n </label>\n <div class=\"detail-value\">{{ record.QualityRank }}/10</div>\n </div>\n }\n </div>\n </div>\n </kendo-expansionpanel>\n\n <!-- Permissions Panel -->\n @if (record.IsSaved) {\n <kendo-expansionpanel\n [(expanded)]=\"permissionsPanelExpanded\"\n class=\"query-panel\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span class=\"panel-title\">\n <i class=\"fa-solid fa-shield-alt panel-icon\"></i>\n Permissions\n </span>\n </ng-template>\n\n <div class=\"panel-body\">\n @if (isLoadingPermissions) {\n <div class=\"panel-loading\">\n <mj-loading text=\"Loading permissions...\"></mj-loading>\n </div>\n } @else {\n @if (queryPermissions.length === 0 && !EditMode) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shield-alt empty-state-icon\"></i>\n <div class=\"empty-state-title\">No Permissions Set</div>\n <div class=\"empty-state-text\">\n This query uses default permissions.\n </div>\n </div>\n } @else {\n @if (EditMode) {\n <mj-explorer-entity-data-grid\n [Params]=\"BuildRelationshipViewParamsByEntityName('MJ: Query Permissions','QueryID')\"\n [NewRecordValues]=\"NewRecordValues('MJ: Query Permissions')\"\n [AllowLoad]=\"true\"\n [ShowToolbar]=\"false\">\n </mj-explorer-entity-data-grid>\n } @else {\n <div class=\"permissions-list\">\n @for (permission of queryPermissions; track permission.ID) {\n <div class=\"permission-card\">\n <i class=\"fa-solid fa-users permission-icon\"></i>\n <div class=\"permission-info\">\n <div class=\"permission-role\">{{ permission.Role }}</div>\n <div class=\"permission-type\">Role Permission</div>\n </div>\n <span class=\"permission-badge\">\n <i class=\"fa-solid fa-play\"></i> Can Execute\n </span>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n </kendo-expansionpanel>\n }\n\n </div>\n </form>\n\n <!-- Query Run Dialog -->\n <mj-query-run-dialog\n [query]=\"record\"\n [parameters]=\"queryParameters\"\n [(isVisible)]=\"showRunDialog\"\n (onClose)=\"onRunDialogClose()\">\n </mj-query-run-dialog>\n\n <!-- Category Creation Dialog -->\n <mj-query-category-dialog\n [(isVisible)]=\"showCategoryDialog\"\n (onCategoryCreated)=\"onCategoryCreated($event)\">\n </mj-query-category-dialog>\n }\n</div>\n", styles: [".k-pane {\n background-color: var(--mj-bg-surface);\n}\n\n.content-margin {\n margin: 10px;\n}\n\n\na {\n font-size: 14px;\n font-weight: bolder;\n}\n\n.tab-header-icon {\n margin-right: 5px;\n}\n\n.record-form {\n display: block;\n flex-direction: column;\n background-color: var(--mj-bg-surface);\n padding: 0;\n min-height: 100vh;\n}\n\n.record-form-group {\n margin-top: 0px;\n background-color: var(--mj-bg-surface);\n}\n\nbutton {\n margin-right: 5px;\n}\n\n.record-form h2 {\n margin-bottom: 10px;\n}\n\n.k-splitter {\n border-width: 0px;\n}\n\n.record-form-row {\n display: grid;\n grid-template-columns: auto 1fr;\n align-items: start;\n gap: 10px;\n margin-bottom: 12px;\n padding-top: 5px;\n padding-bottom: 5px;\n}\n\n.record-form .record-form-row > :first-child {\n font-weight: bold;\n padding-right: 10px;\n}\n\n.record-form .record-form-row > span {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n@media (min-width: 768px) {\n .record-form-row {\n flex-direction: row;\n align-items: center;\n }\n\n .record-form-row label {\n width: 240px;\n margin-bottom: 0;\n }\n}\n\n/* Collapsible Panel Styles */\n.form-panels-container {\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 16px;\n background-color: var(--mj-bg-surface);\n}\n\n/* All field sections take full width */\n.form-panels-container > .form-card {\n width: 100%;\n}\n\n/* Related entity grid container - responsive layout */\n.form-panels-container .related-entity-grid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 16px;\n width: 100%;\n}\n\n/* Responsive multi-column layout for related entities on wider screens */\n@media (min-width: 1400px) {\n .form-panels-container .related-entity-grid {\n grid-template-columns: repeat(auto-fit, minmax(600px, 1fr));\n }\n}\n\n.form-card {\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n box-shadow: 0 2px 4px var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n.collapsible-card {\n overflow: hidden;\n}\n\n.collapsible-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n background: var(--mj-bg-surface-card);\n border-bottom: 2px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n transition: all 0.3s ease;\n}\n\n.collapsible-header:hover {\n background: var(--mj-bg-surface-sunken);\n border-bottom-color: var(--mj-brand-primary);\n}\n\n.collapsible-title {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n}\n\n.collapsible-title i {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.collapsible-title h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.collapsible-header .collapse-icon {\n color: var(--mj-text-muted);\n transition: transform 0.3s ease;\n}\n\n.collapsible-body {\n max-height: 2000px;\n overflow: hidden;\n transition: max-height 0.4s ease, padding 0.4s ease, opacity 0.3s ease;\n opacity: 1;\n}\n\n.collapsible-body.collapsed {\n max-height: 0;\n padding: 0;\n opacity: 0;\n}\n\n.form-body {\n padding: 24px;\n}\n\n/* Related Entity Sections - Visual Distinction */\n.form-card.related-entity {\n background: var(--mj-bg-surface-card);\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.form-card.related-entity .collapsible-header {\n background: var(--mj-bg-surface-sunken);\n}\n\n.form-card.related-entity .collapsible-header:hover {\n background: var(--mj-bg-surface-card);\n border-bottom-color: var(--mj-brand-primary);\n}\n\n.form-card.related-entity .collapsible-title i {\n color: var(--mj-brand-primary);\n}\n\n/* Section Controls */\n.form-section-controls {\n display: flex;\n gap: 10px;\n padding: 14px 18px;\n background: var(--mj-bg-surface-card);\n border-bottom: 2px solid var(--mj-border-default);\n align-items: center;\n flex-wrap: wrap;\n box-shadow: 0 1px 3px var(--mj-shadow-sm);\n}\n\n.form-section-controls .control-group {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.form-section-controls button {\n padding: 8px 14px;\n font-size: 13px;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n margin-right: 0;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 500;\n}\n\n.form-section-controls button:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px var(--mj-shadow-md);\n}\n\n.form-section-controls button:active {\n transform: translateY(0);\n}\n\n.form-section-controls button i {\n margin-right: 0;\n font-size: 14px;\n}\n\n.form-section-controls .section-search {\n padding: 8px 14px;\n font-size: 13px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n width: 240px;\n transition: all 0.2s;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.form-section-controls .section-search: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) 10%, transparent);\n}\n\n.form-section-controls .section-search::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.form-section-controls .section-count {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin-left: auto;\n font-weight: 500;\n}\n\n/* Hidden sections for search filter */\n.form-card.search-hidden {\n display: none;\n}\n\n/* Section count badge */\n.section-count-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n}\n\n/* Search highlighting in section names */\n.collapsible-title h3 .search-highlight {\n background-color: var(--mj-status-warning);\n color: var(--mj-text-primary);\n padding: 2px 4px;\n border-radius: 3px;\n font-weight: 700;\n}\n\n/* Row count badge in section headers */\n.collapsible-title .row-count-badge {\n background: var(--mj-status-success);\n color: var(--mj-text-inverse);\n padding: 3px 6px 2px 6px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n margin-left: 8px;\n vertical-align: middle;\n position: relative;\n top: -2px;\n display: inline-block;\n line-height: 1;\n}\n\n/* Gray badge for zero rows (loaded but empty) */\n.collapsible-title .row-count-badge.zero-rows {\n background: var(--mj-text-muted);\n}\n", "/* Override shared form-styles to enable flex layout */\n:host {\n display: block;\n height: 100%;\n}\n\n/* Override the shared record-form min-height so flex layout works properly */\n.record-form {\n min-height: 0 !important;\n}\n\n/* ========================================\n Header Section \u2014 matches Query Browser gradient\n ======================================== */\n\n.query-header {\n flex-shrink: 0;\n background: var(--mj-brand-primary);\n border-bottom: none;\n padding: 0;\n}\n\n.query-header-content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px 20px;\n}\n\n.query-header-top {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 20px;\n}\n\n.query-name-section {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.query-title-icon {\n color: rgba(255, 255, 255, 0.85);\n font-size: 1.3em;\n flex-shrink: 0;\n}\n\n.query-name-input {\n font-size: 1.2em;\n font-weight: 600;\n min-width: 300px;\n flex: 1;\n}\n\n.query-name-display {\n margin: 0;\n color: var(--mj-text-inverse, white);\n font-weight: 600;\n font-size: 1.2em;\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.query-header-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.run-query-btn {\n white-space: nowrap;\n}\n\n/* Meta row (category + status) */\n.query-meta-row {\n display: flex;\n gap: 24px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.query-meta-item {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.meta-label {\n font-weight: 500;\n color: rgba(255, 255, 255, 0.75);\n font-size: var(--mj-text-sm);\n min-width: 60px;\n}\n\n.meta-value {\n color: rgba(255, 255, 255, 0.95);\n font-size: var(--mj-text-sm);\n}\n\n.meta-dropdown {\n min-width: 200px;\n}\n\n.status-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: var(--mj-radius-xl);\n color: var(--mj-text-inverse, white);\n font-size: var(--mj-text-sm);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.status-pill i {\n font-size: var(--mj-text-xs);\n}\n\n/* Description row */\n.query-description-row {\n margin-top: 2px;\n}\n\n.query-description-input {\n width: 100%;\n}\n\n.query-description-text {\n margin: 0;\n color: rgba(255, 255, 255, 0.8);\n font-size: var(--mj-text-sm);\n line-height: 1.4;\n}\n\n/* ========================================\n Status Warning Banner\n ======================================== */\n\n.status-warning-banner {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 16px;\n margin: 0;\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n border-left: 4px solid var(--mj-status-warning);\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.status-warning-banner i {\n font-size: var(--mj-text-base);\n flex-shrink: 0;\n}\n\n.status-warning-banner strong {\n font-weight: 600;\n}\n\n/* ========================================\n Main Content Area\n ======================================== */\n\n.query-content {\n flex: 1;\n min-height: 0;\n padding: 16px;\n overflow-y: auto;\n background: var(--mj-bg-surface-card);\n}\n\n/* ========================================\n Expansion Panel Overrides \u2014 Modern Style\n ======================================== */\n\n.query-panel {\n margin-bottom: 12px;\n}\n\n::ng-deep .query-content kendo-expansionpanel {\n border: none !important;\n border-radius: var(--mj-radius-md) !important;\n margin-bottom: 12px !important;\n box-shadow: var(--mj-shadow-sm) !important;\n background: var(--mj-bg-surface) !important;\n overflow: hidden !important;\n}\n\n::ng-deep .query-content .k-expander-header {\n background: var(--mj-bg-surface) !important;\n border: none !important;\n padding: 14px 18px !important;\n border-radius: var(--mj-radius-md) !important;\n color: var(--mj-text-primary) !important;\n font-weight: 600 !important;\n font-size: var(--mj-text-sm) !important;\n transition: background 0.15s ease !important;\n}\n\n::ng-deep .query-content .k-expander-header:hover {\n background: var(--mj-bg-surface-card) !important;\n}\n\n::ng-deep .query-content kendo-expansionpanel[aria-expanded=\"true\"] .k-expander-header {\n background: var(--mj-brand-primary) !important;\n color: white !important;\n border-radius: var(--mj-radius-md) var(--mj-radius-md) 0 0 !important;\n}\n\n::ng-deep .query-content .k-expander-content {\n padding: 0 !important;\n border: none !important;\n background: var(--mj-bg-surface) !important;\n border-radius: 0 0 var(--mj-radius-md) var(--mj-radius-md) !important;\n}\n\n/* ========================================\n Panel Title & Badges\n ======================================== */\n\n.panel-title-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n}\n\n.panel-icon {\n font-size: var(--mj-text-sm);\n opacity: 0.7;\n}\n\n.sql-icon {\n color: var(--mj-brand-primary);\n}\n\n::ng-deep kendo-expansionpanel[aria-expanded=\"true\"] .panel-icon {\n color: rgba(255, 255, 255, 0.85) !important;\n opacity: 1;\n}\n\n.panel-badge {\n padding: 2px 8px;\n border-radius: var(--mj-radius-lg);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n}\n\n.panel-badge.defined {\n background: var(--mj-status-success);\n color: white;\n}\n\n.panel-badge.count {\n background: var(--mj-brand-primary);\n color: white;\n}\n\n::ng-deep kendo-expansionpanel[aria-expanded=\"true\"] .panel-badge.count {\n background: rgba(255, 255, 255, 0.25) !important;\n}\n\n::ng-deep kendo-expansionpanel[aria-expanded=\"true\"] .panel-badge.defined {\n background: rgba(255, 255, 255, 0.25) !important;\n}\n\n.filters-help-btn {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-right: 8px;\n font-size: var(--mj-text-xs);\n}\n\n/* ========================================\n Panel Body & Loading\n ======================================== */\n\n.panel-body {\n padding: 16px 0;\n}\n\n.panel-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 40px;\n}\n\n.panel-toolbar {\n display: flex;\n justify-content: flex-end;\n padding: 0 20px 12px;\n}\n\n/* ========================================\n SQL Panel\n ======================================== */\n\n.sql-panel-content {\n display: flex;\n flex-direction: column;\n}\n\n.sql-editor {\n flex: 1;\n height: 400px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n margin: 16px;\n}\n\n/* Filters Help */\n.filters-help {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 16px;\n margin: 0 16px 16px;\n}\n\n.filters-help-title {\n margin: 0 0 12px 0;\n color: var(--mj-text-primary);\n font-weight: 600;\n font-size: var(--mj-text-sm);\n}\n\n.filters-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n gap: 10px;\n}\n\n.filter-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 12px;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n}\n\n.filter-card:hover {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.filter-name {\n font-family: 'Courier New', monospace;\n font-weight: bold;\n color: var(--mj-brand-primary);\n margin-bottom: 4px;\n}\n\n.filter-description {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n margin-bottom: 6px;\n}\n\n.filter-syntax {\n font-family: 'Courier New', monospace;\n font-size: var(--mj-text-xs);\n background: var(--mj-bg-surface-card);\n padding: 6px;\n border-radius: var(--mj-radius-sm);\n margin-bottom: 4px;\n}\n\n.filter-notes {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-disabled);\n font-style: italic;\n}\n\n/* ========================================\n Card Grid (Parameters, Fields, Entities)\n ======================================== */\n\n.card-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));\n gap: 12px;\n padding: 0 20px 20px;\n}\n\n.item-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px;\n transition: all 0.15s ease;\n cursor: pointer;\n position: relative;\n}\n\n.item-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.item-card.required {\n border-left: 3px solid var(--mj-status-warning);\n}\n\n.item-card-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 10px;\n}\n\n.item-name {\n font-weight: 600;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.item-name-icon {\n font-size: var(--mj-text-sm);\n}\n\n.item-name-icon.param-icon {\n color: var(--mj-brand-primary);\n}\n\n.item-name-icon.field-icon {\n color: var(--mj-brand-primary);\n}\n\n.item-name-icon.entity-icon {\n color: var(--mj-status-success);\n}\n\n.item-badges {\n display: flex;\n gap: 6px;\n}\n\n.item-badge {\n padding: 2px 8px;\n border-radius: var(--mj-radius-lg);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: white;\n}\n\n.item-badge.required {\n background: var(--mj-status-warning);\n}\n\n.item-badge.type {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.item-badge.sequence {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: color-mix(in srgb, var(--mj-brand-primary) 80%, purple);\n}\n\n.item-card-body {\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n}\n\n.item-description {\n margin-bottom: 8px;\n}\n\n.item-meta {\n display: flex;\n gap: 16px;\n font-size: var(--mj-text-xs);\n}\n\n.meta-tag {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.meta-code {\n background: var(--mj-bg-surface-card);\n padding: 1px 4px;\n border-radius: var(--mj-radius-sm);\n font-size: var(--mj-text-xs);\n}\n\n/* Card actions (edit/delete) */\n.item-actions {\n position: absolute;\n top: 10px;\n right: 10px;\n display: flex;\n gap: 4px;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.item-card:hover .item-actions {\n opacity: 1;\n}\n\n.item-card-actions {\n display: flex;\n justify-content: flex-end;\n margin-top: 8px;\n}\n\n.item-action-btn {\n background: none;\n border: none;\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n cursor: pointer;\n color: var(--mj-text-disabled);\n transition: all 0.15s ease;\n}\n\n.item-action-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.item-action-btn.delete:hover {\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n/* Entity dropdown in card */\n.entity-dropdown-wrapper {\n flex: 1;\n margin-left: 12px;\n}\n\n.entity-dropdown {\n width: 100%;\n}\n\n/* ========================================\n Details Grid\n ======================================== */\n\n.details-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));\n gap: 16px;\n padding: 16px 20px;\n}\n\n.detail-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.detail-label {\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-disabled);\n display: flex;\n align-items: center;\n gap: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.detail-value {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.detail-tag {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: var(--mj-text-sm);\n}\n\n.detail-tag.positive {\n color: var(--mj-status-success);\n}\n\n.detail-tag.neutral {\n color: var(--mj-text-disabled);\n}\n\n/* ========================================\n Permissions\n ======================================== */\n\n.permissions-list {\n padding: 0 20px;\n}\n\n.permission-card {\n display: flex;\n align-items: center;\n gap: 14px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px 16px;\n margin-bottom: 8px;\n}\n\n.permission-icon {\n font-size: 1.3em;\n color: var(--mj-brand-primary);\n}\n\n.permission-info {\n flex: 1;\n}\n\n.permission-role {\n font-weight: 600;\n color: var(--mj-text-primary);\n font-size: var(--mj-text-sm);\n}\n\n.permission-type {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-disabled);\n}\n\n.permission-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n background: var(--mj-brand-primary);\n color: white;\n padding: 4px 10px;\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-xs);\n font-weight: 500;\n}\n\n/* ========================================\n Empty State\n ======================================== */\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 20px;\n text-align: center;\n color: var(--mj-text-disabled);\n}\n\n.empty-state-icon {\n font-size: 40px;\n margin-bottom: 14px;\n opacity: 0.25;\n color: var(--mj-text-primary);\n}\n\n.empty-state-title {\n font-size: var(--mj-text-base);\n font-weight: 600;\n margin-bottom: 6px;\n color: var(--mj-text-secondary);\n}\n\n.empty-state-text {\n font-size: var(--mj-text-sm);\n margin-bottom: 16px;\n color: var(--mj-text-disabled);\n}\n\n/* ========================================\n Buttons\n ======================================== */\n\n.add-item-btn {\n background: var(--mj-brand-primary);\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: all 0.15s ease;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 500;\n font-size: var(--mj-text-sm);\n}\n\n.add-item-btn:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 85%, black);\n box-shadow: 0 2px 6px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n/* ========================================\n Badge (reused across components)\n ======================================== */\n\n.badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n/* ========================================\n Technical Description Panel\n ======================================== */\n\n.technical-description-textarea {\n width: 100%;\n font-family: 'Consolas', 'Monaco', 'Courier New', monospace;\n font-size: 13px;\n}\n\n.technical-description-preview {\n margin-top: 16px;\n border-top: 1px solid var(--mj-border-default);\n padding-top: 12px;\n}\n\n.preview-label {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n margin-bottom: 8px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.technical-description-view {\n max-height: 500px;\n overflow-y: auto;\n padding: 12px 16px;\n}\n\n/* Dependent Queries */\n.dependents-icon {\n color: var(--mj-status-warning);\n}\n\n.dependents-description {\n padding: 0 20px 12px;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.dependents-description code {\n background: var(--mj-bg-surface-sunken);\n padding: 1px 5px;\n border-radius: 3px;\n font-size: 12px;\n}\n\n.dependent-card {\n cursor: pointer;\n border-left: 3px solid var(--mj-status-warning) !important;\n}\n\n.dependent-card:hover {\n border-left-color: var(--mj-status-warning-text) !important;\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface)) !important;\n}\n\n.dependent-query-icon {\n color: var(--mj-status-warning) !important;\n}\n\n.item-card-footer {\n padding-top: 8px;\n border-top: 1px solid var(--mj-bg-surface-sunken);\n margin-top: 8px;\n}\n\n.open-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-brand-primary);\n font-weight: 500;\n}\n\n.dependent-card:hover .open-link {\n color: var(--mj-brand-primary-hover);\n}\n"] }]
1817
1817
  }], null, { sqlEditor: [{
1818
1818
  type: ViewChild,
1819
1819
  args: ['sqlEditor']