@memberjunction/ng-dashboards 5.11.0 → 5.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AI/components/agents/agent-configuration.component.d.ts +34 -2
- package/dist/AI/components/agents/agent-configuration.component.d.ts.map +1 -1
- package/dist/AI/components/agents/agent-configuration.component.js +586 -223
- package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.js +2 -2
- package/dist/AI/components/agents/agent-filter-panel.component.d.ts +8 -0
- package/dist/AI/components/agents/agent-filter-panel.component.d.ts.map +1 -1
- package/dist/AI/components/agents/agent-filter-panel.component.js +85 -52
- package/dist/AI/components/agents/agent-filter-panel.component.js.map +1 -1
- package/dist/AI/components/charts/performance-heatmap.component.d.ts +1 -0
- package/dist/AI/components/charts/performance-heatmap.component.d.ts.map +1 -1
- package/dist/AI/components/charts/performance-heatmap.component.js +27 -5
- package/dist/AI/components/charts/performance-heatmap.component.js.map +1 -1
- package/dist/AI/components/charts/time-series-chart.component.d.ts +5 -0
- package/dist/AI/components/charts/time-series-chart.component.d.ts.map +1 -1
- package/dist/AI/components/charts/time-series-chart.component.js +23 -8
- package/dist/AI/components/charts/time-series-chart.component.js.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +2 -2
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/models/model-management.component.js +2 -2
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +2 -2
- package/dist/AI/components/prompts/prompt-filter-panel.component.js +2 -2
- package/dist/AI/components/prompts/prompt-management.component.js +3 -3
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-version-control.component.js +2 -2
- package/dist/AI/components/requests/agent-requests-resource.component.d.ts +83 -0
- package/dist/AI/components/requests/agent-requests-resource.component.d.ts.map +1 -0
- package/dist/AI/components/requests/agent-requests-resource.component.js +547 -0
- package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -0
- package/dist/AI/components/system/system-config-filter-panel.component.js +2 -2
- package/dist/AI/components/system/system-configuration.component.js +2 -2
- package/dist/AI/components/widgets/kpi-card.component.js +7 -7
- package/dist/AI/components/widgets/kpi-card.component.js.map +1 -1
- package/dist/AI/components/widgets/live-execution-widget.component.d.ts.map +1 -1
- package/dist/AI/components/widgets/live-execution-widget.component.js +6 -6
- package/dist/AI/components/widgets/live-execution-widget.component.js.map +1 -1
- package/dist/AI/index.d.ts +1 -0
- package/dist/AI/index.d.ts.map +1 -1
- package/dist/AI/index.js +2 -0
- package/dist/AI/index.js.map +1 -1
- package/dist/APIKeys/api-applications-panel.component.js +3 -3
- package/dist/APIKeys/api-applications-panel.component.js.map +1 -1
- package/dist/APIKeys/api-key-create-dialog.component.js +3 -3
- package/dist/APIKeys/api-key-create-dialog.component.js.map +1 -1
- package/dist/APIKeys/api-key-edit-panel.component.js +1 -1
- package/dist/APIKeys/api-key-edit-panel.component.js.map +1 -1
- package/dist/APIKeys/api-key-list.component.js +3 -3
- package/dist/APIKeys/api-key-list.component.js.map +1 -1
- package/dist/APIKeys/api-keys-resource.component.js +1 -1
- package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
- package/dist/APIKeys/api-scopes-panel.component.js +2 -2
- package/dist/APIKeys/api-usage-panel.component.js +2 -2
- package/dist/Actions/components/actions-overview.component.js +2 -2
- package/dist/Actions/components/execution-monitoring.component.js +2 -2
- package/dist/Actions/components/explorer/action-breadcrumb.component.js +2 -2
- package/dist/Actions/components/explorer/action-card.component.js +2 -2
- package/dist/Actions/components/explorer/action-explorer.component.js +2 -2
- package/dist/Actions/components/explorer/action-list-item.component.js +2 -2
- package/dist/Actions/components/explorer/action-toolbar.component.js +2 -2
- package/dist/Actions/components/explorer/action-tree-panel.component.js +2 -2
- package/dist/Actions/components/explorer/new-action-panel.component.js +2 -2
- package/dist/Actions/components/explorer/new-action-panel.component.js.map +1 -1
- package/dist/Actions/components/explorer/new-category-panel.component.js +2 -2
- package/dist/Actions/components/explorer/new-category-panel.component.js.map +1 -1
- package/dist/Communication/communication-dashboard.component.js +2 -2
- package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-logs-resource.component.js +3 -3
- package/dist/Communication/communication-logs-resource.component.js.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.js +5 -5
- package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
- package/dist/Communication/communication-providers-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-providers-resource.component.js +3 -3
- package/dist/Communication/communication-providers-resource.component.js.map +1 -1
- package/dist/Communication/communication-runs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-runs-resource.component.js +3 -3
- package/dist/Communication/communication-runs-resource.component.js.map +1 -1
- package/dist/Communication/communication-templates-resource.component.js +2 -2
- package/dist/Communication/communication-templates-resource.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +2 -2
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +2 -2
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js +2 -2
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +2 -2
- package/dist/ComponentStudio/components/browser/component-browser.component.js +2 -2
- package/dist/ComponentStudio/components/editors/code-editor-panel.component.js +2 -2
- package/dist/ComponentStudio/components/editors/code-editor-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js +2 -2
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/requirements-editor.component.js +2 -2
- package/dist/ComponentStudio/components/editors/requirements-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/spec-editor.component.js +2 -2
- package/dist/ComponentStudio/components/editors/spec-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/new-component-dialog/new-component-dialog.component.js +2 -2
- package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js +2 -2
- package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/text-import-dialog.component.js +2 -2
- package/dist/ComponentStudio/components/text-import-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.js +2 -2
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +2 -2
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
- package/dist/Credentials/components/credentials-audit-resource.component.js +9 -9
- package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.js +11 -3
- package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.js +2 -2
- package/dist/Credentials/components/credentials-overview-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-overview-resource.component.js +12 -11
- package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.js +9 -9
- package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
- package/dist/Credentials/credentials-dashboard.component.js +2 -2
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js +2 -2
- package/dist/DashboardBrowser/dashboard-share-dialog.component.js +2 -2
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js +2 -2
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js +2 -2
- package/dist/DataExplorer/components/view-selector/view-selector.component.js +2 -2
- package/dist/DataExplorer/data-explorer-dashboard.component.js +4 -4
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/Home/home-dashboard.component.js +2 -2
- package/dist/Integration/components/activity/activity.component.d.ts +1 -1
- package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
- package/dist/Integration/components/activity/activity.component.js +5 -5
- package/dist/Integration/components/activity/activity.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.d.ts +31 -2
- package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +753 -412
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +3 -3
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
- package/dist/Integration/components/overview/overview.component.d.ts +0 -1
- package/dist/Integration/components/overview/overview.component.d.ts.map +1 -1
- package/dist/Integration/components/overview/overview.component.js +3 -6
- package/dist/Integration/components/overview/overview.component.js.map +1 -1
- package/dist/Integration/components/pipelines/pipelines.component.js +3 -3
- package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.d.ts +20 -0
- package/dist/Integration/components/schedules/schedules.component.d.ts.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.js +97 -5
- package/dist/Integration/components/schedules/schedules.component.js.map +1 -1
- package/dist/Integration/components/visual-editor/visual-editor.component.js +2 -2
- package/dist/Integration/components/widgets/integration-card.component.d.ts.map +1 -1
- package/dist/Integration/components/widgets/integration-card.component.js +5 -1
- package/dist/Integration/components/widgets/integration-card.component.js.map +1 -1
- package/dist/Integration/components/widgets/run-history-panel.component.js +2 -2
- package/dist/Integration/components/widgets/run-history-panel.component.js.map +1 -1
- package/dist/Integration/integration.module.d.ts +2 -1
- package/dist/Integration/integration.module.d.ts.map +1 -1
- package/dist/Integration/integration.module.js +7 -3
- package/dist/Integration/integration.module.js.map +1 -1
- package/dist/Integration/services/integration-data.service.d.ts +27 -2
- package/dist/Integration/services/integration-data.service.d.ts.map +1 -1
- package/dist/Integration/services/integration-data.service.js +107 -4
- package/dist/Integration/services/integration-data.service.js.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.js +25 -24
- package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-categories-resource.component.js +2 -2
- package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.js +26 -25
- package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-operations-resource.component.js +2 -2
- package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
- package/dist/Lists/components/venn-diagram/venn-diagram.component.js +3 -3
- package/dist/Lists/components/venn-diagram/venn-diagram.component.js.map +1 -1
- package/dist/MCP/components/mcp-connection-dialog.component.js +2 -2
- package/dist/MCP/components/mcp-log-detail-panel.component.js +2 -2
- package/dist/MCP/components/mcp-log-detail-panel.component.js.map +1 -1
- package/dist/MCP/components/mcp-server-dialog.component.js +2 -2
- package/dist/MCP/components/mcp-test-tool-dialog.component.js +2 -2
- package/dist/MCP/components/mcp-test-tool-dialog.component.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +2 -2
- package/dist/MCP/mcp-filter-panel.component.js +2 -2
- package/dist/QueryBrowser/query-browser-resource.component.js +7 -7
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/Scheduling/components/index.d.ts +0 -1
- package/dist/Scheduling/components/index.d.ts.map +1 -1
- package/dist/Scheduling/components/index.js +0 -1
- package/dist/Scheduling/components/index.js.map +1 -1
- package/dist/Scheduling/components/scheduling-activity.component.js +2 -2
- package/dist/Scheduling/components/scheduling-jobs.component.d.ts +6 -9
- package/dist/Scheduling/components/scheduling-jobs.component.d.ts.map +1 -1
- package/dist/Scheduling/components/scheduling-jobs.component.js +118 -110
- package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-overview.component.js +3 -3
- package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
- package/dist/Scheduling/scheduling-dashboard.component.js +2 -2
- package/dist/SystemDiagnostics/system-diagnostics.component.js +4 -4
- package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
- package/dist/Testing/components/testing-analytics.component.js +2 -2
- package/dist/Testing/components/testing-analytics.component.js.map +1 -1
- package/dist/Testing/components/testing-dashboard-tab.component.js +4 -4
- package/dist/Testing/components/testing-dashboard-tab.component.js.map +1 -1
- package/dist/Testing/components/testing-explorer.component.js +2 -2
- package/dist/Testing/components/testing-explorer.component.js.map +1 -1
- package/dist/Testing/components/testing-review.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-review.component.js +5 -5
- package/dist/Testing/components/testing-review.component.js.map +1 -1
- package/dist/Testing/components/testing-runs.component.js +2 -2
- package/dist/Testing/components/testing-runs.component.js.map +1 -1
- package/dist/Testing/components/widgets/oracle-breakdown-table.component.js +2 -2
- package/dist/Testing/components/widgets/oracle-breakdown-table.component.js.map +1 -1
- package/dist/Testing/components/widgets/suite-tree.component.js +4 -4
- package/dist/Testing/components/widgets/suite-tree.component.js.map +1 -1
- package/dist/Testing/components/widgets/test-run-detail-panel.component.js +2 -2
- package/dist/Testing/components/widgets/test-run-detail-panel.component.js.map +1 -1
- package/dist/Testing/testing-dashboard.component.js +2 -2
- package/dist/VersionHistory/components/diff-resource.component.js +2 -2
- package/dist/VersionHistory/components/graph-resource.component.js +2 -2
- package/dist/VersionHistory/components/labels-resource.component.js +3 -3
- package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
- package/dist/VersionHistory/components/restore-resource.component.js +3 -3
- package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
- package/dist/__tests__/integration-data-service.test.js +1 -0
- package/dist/__tests__/integration-data-service.test.js.map +1 -1
- package/dist/module.d.ts +52 -49
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +25 -6
- package/dist/module.js.map +1 -1
- package/dist/public-api.d.ts +1 -1
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -1
- package/dist/public-api.js.map +1 -1
- package/package.json +42 -40
- package/dist/Scheduling/components/job-slideout.component.d.ts +0 -45
- package/dist/Scheduling/components/job-slideout.component.d.ts.map +0 -1
- package/dist/Scheduling/components/job-slideout.component.js +0 -459
- package/dist/Scheduling/components/job-slideout.component.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials-overview-resource.component.js","sourceRoot":"","sources":["../../../src/Credentials/components/credentials-overview-resource.component.ts","../../../src/Credentials/components/credentials-overview-resource.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { ResourceData, MJCredentialEntity, MJCredentialTypeEntity, MJCredentialCategoryEntity, MJAuditLogEntity } from '@memberjunction/core-entities';\nimport { RegisterClass , UUIDsEqual } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { RunView, Metadata, CompositeKey } from '@memberjunction/core';\ninterface CategoryStat {\n category: string;\n categoryId: string;\n count: number;\n iconClass: string;\n color: string;\n percentage: number;\n}\n\ninterface TypeStat {\n typeId: string;\n typeName: string;\n category: string;\n credentialCount: number;\n activeCount: number;\n expiringCount: number;\n}\n\ninterface ActivityItem {\n id: string;\n credentialName: string;\n credentialId: string;\n typeName: string;\n action: 'Created' | 'Updated' | 'Accessed' | 'Rotated';\n date: Date;\n user?: string;\n}\n\ninterface UsageTrendPoint {\n timestamp: Date;\n accessCount: number;\n uniqueCredentials: number;\n successRate: number;\n}\n\n@RegisterClass(BaseResourceComponent, 'CredentialsOverviewResource')\n@Component({\n standalone: false,\n selector: 'mj-credentials-overview-resource',\n templateUrl: './credentials-overview-resource.component.html',\n styleUrls: ['./credentials-overview-resource.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class CredentialsOverviewResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public isLoading = true;\n\n // Summary stats\n public totalCredentials = 0;\n public activeCredentials = 0;\n public expiredCredentials = 0;\n public expiringSoonCount = 0;\n public credentialTypes = 0;\n public categories = 0;\n\n // Grouped data\n public categoryStats: CategoryStat[] = [];\n public typeStats: TypeStat[] = [];\n public recentActivity: ActivityItem[] = [];\n public usageTrend: UsageTrendPoint[] = [];\n\n // Raw data\n private credentials: MJCredentialEntity[] = [];\n private types: MJCredentialTypeEntity[] = [];\n private categoryList: MJCredentialCategoryEntity[] = [];\n private auditLogs: MJAuditLogEntity[] = [];\n\n // Permissions\n private _metadata = new Metadata();\n private _permissionCache = new Map<string, boolean>();\n\n // Category colors for charts\n private categoryColors: Record<string, string> = {\n 'AI': '#8b5cf6',\n 'Communication': '#3b82f6',\n 'Storage': '#10b981',\n 'Database': '#f59e0b',\n 'Authentication': '#ef4444',\n 'Integration': '#6366f1'\n };\n\n private destroy$ = new Subject<void>();\n\n constructor(\n private cdr: ChangeDetectorRef,\n private navigationService: NavigationService\n ) {\n super();\n }\n\n ngOnInit(): void {\n this.loadData();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Overview';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-chart-pie';\n }\n\n // === Permission Checks ===\n public get UserCanCreateCredentials(): boolean {\n return this.checkEntityPermission('MJ: Credentials', 'Create');\n }\n\n public get UserCanUpdateCredentials(): boolean {\n return this.checkEntityPermission('MJ: Credentials', 'Update');\n }\n\n private checkEntityPermission(entityName: string, permissionType: 'Create' | 'Read' | 'Update' | 'Delete'): boolean {\n const cacheKey = `${entityName}_${permissionType}`;\n\n if (this._permissionCache.has(cacheKey)) {\n return this._permissionCache.get(cacheKey)!;\n }\n\n try {\n const entityInfo = this._metadata.Entities.find(e => e.Name === entityName);\n if (!entityInfo) {\n this._permissionCache.set(cacheKey, false);\n return false;\n }\n\n const userPermissions = entityInfo.GetUserPermisions(this._metadata.CurrentUser);\n let hasPermission = false;\n\n switch (permissionType) {\n case 'Create': hasPermission = userPermissions.CanCreate; break;\n case 'Read': hasPermission = userPermissions.CanRead; break;\n case 'Update': hasPermission = userPermissions.CanUpdate; break;\n case 'Delete': hasPermission = userPermissions.CanDelete; break;\n }\n\n this._permissionCache.set(cacheKey, hasPermission);\n return hasPermission;\n } catch (error) {\n this._permissionCache.set(cacheKey, false);\n return false;\n }\n }\n\n private async loadData(): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.markForCheck();\n\n const rv = new RunView();\n\n // Calculate date range for audit logs (last 30 days)\n const thirtyDaysAgo = new Date();\n thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);\n const dateFilter = `__mj_CreatedAt >= '${thirtyDaysAgo.toISOString()}'`;\n\n // Load all data in parallel using RunViews\n const [credResult, typeResult, categoryResult, auditResult] = await rv.RunViews([\n {\n EntityName: 'MJ: Credentials',\n ResultType: 'entity_object'\n },\n {\n EntityName: 'MJ: Credential Types',\n ResultType: 'entity_object'\n },\n {\n EntityName: 'MJ: Credential Categories',\n ResultType: 'entity_object'\n },\n {\n EntityName: 'MJ: Audit Logs',\n ExtraFilter: `AuditLogType LIKE '%Credential%' AND ${dateFilter}`,\n OrderBy: '__mj_CreatedAt DESC',\n MaxRows: 100,\n ResultType: 'entity_object'\n }\n ]);\n\n if (credResult.Success) {\n this.credentials = credResult.Results as MJCredentialEntity[];\n this.processCredentialStats();\n }\n\n if (typeResult.Success) {\n this.types = typeResult.Results as MJCredentialTypeEntity[];\n this.credentialTypes = this.types.length;\n this.processTypeStats();\n }\n\n if (categoryResult.Success) {\n this.categoryList = categoryResult.Results as MJCredentialCategoryEntity[];\n this.categories = this.categoryList.length;\n this.processCategoryStats();\n }\n\n if (auditResult.Success) {\n this.auditLogs = auditResult.Results as MJAuditLogEntity[];\n this.processActivityAndTrends();\n }\n\n // Build recent activity from credentials if no audit logs\n if (this.recentActivity.length === 0) {\n this.buildActivityFromCredentials();\n }\n\n } catch (error) {\n console.error('Error loading credentials overview:', error);\n } finally {\n this.isLoading = false;\n this.NotifyLoadComplete();\n this.cdr.markForCheck();\n }\n }\n\n private processCredentialStats(): void {\n this.totalCredentials = this.credentials.length;\n this.activeCredentials = this.credentials.filter(c => c.IsActive).length;\n\n const now = new Date();\n const thirtyDaysFromNow = new Date();\n thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30);\n\n this.expiredCredentials = this.credentials.filter(c =>\n c.ExpiresAt && new Date(c.ExpiresAt) < now\n ).length;\n\n this.expiringSoonCount = this.credentials.filter(c =>\n c.ExpiresAt &&\n new Date(c.ExpiresAt) >= now &&\n new Date(c.ExpiresAt) <= thirtyDaysFromNow &&\n c.IsActive\n ).length;\n }\n\n private processTypeStats(): void {\n const now = new Date();\n const thirtyDaysFromNow = new Date();\n thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30);\n\n this.typeStats = this.types.map(type => {\n const typeCredentials = this.credentials.filter(c => UUIDsEqual(c.CredentialTypeID, type.ID));\n\n return {\n typeId: type.ID,\n typeName: type.Name,\n category: type.Category,\n credentialCount: typeCredentials.length,\n activeCount: typeCredentials.filter(c => c.IsActive).length,\n expiringCount: typeCredentials.filter(c =>\n c.ExpiresAt &&\n new Date(c.ExpiresAt) >= now &&\n new Date(c.ExpiresAt) <= thirtyDaysFromNow\n ).length\n };\n }).sort((a, b) => b.credentialCount - a.credentialCount);\n }\n\n private processCategoryStats(): void {\n const categoryMap = new Map<string, CategoryStat>();\n\n // Initialize from credential types\n for (const type of this.types) {\n const category = type.Category;\n const existing = categoryMap.get(category);\n const categoryCredentials = this.credentials.filter(c => UUIDsEqual(c.CredentialTypeID, type.ID));\n\n if (existing) {\n existing.count += categoryCredentials.length;\n } else {\n categoryMap.set(category, {\n category: category,\n categoryId: category, // Use category name as ID for filtering\n count: categoryCredentials.length,\n iconClass: this.getCategoryIcon(category),\n color: this.categoryColors[category] || '#64748b',\n percentage: 0\n });\n }\n }\n\n // Calculate percentages\n const total = this.totalCredentials || 1;\n categoryMap.forEach(stat => {\n stat.percentage = Math.round((stat.count / total) * 100);\n });\n\n this.categoryStats = Array.from(categoryMap.values())\n .sort((a, b) => b.count - a.count);\n }\n\n private processActivityAndTrends(): void {\n // Process recent activity from audit logs\n this.recentActivity = this.auditLogs\n .slice(0, 10)\n .map(log => ({\n id: log.ID,\n credentialName: this.extractCredentialName(log.Description || ''),\n credentialId: '', // Would need to parse from log\n typeName: 'Credential',\n action: this.extractAction(log.Description || '') as ActivityItem['action'],\n date: new Date(log.__mj_CreatedAt),\n user: log.User\n }));\n\n // Build usage trend data (group by day)\n const trendMap = new Map<string, UsageTrendPoint>();\n const uniqueCredentialsPerDay = new Map<string, Set<string>>();\n\n for (const log of this.auditLogs) {\n const dateKey = new Date(log.__mj_CreatedAt).toISOString().split('T')[0];\n\n if (!trendMap.has(dateKey)) {\n trendMap.set(dateKey, {\n timestamp: new Date(dateKey),\n accessCount: 0,\n uniqueCredentials: 0,\n successRate: 100\n });\n uniqueCredentialsPerDay.set(dateKey, new Set());\n }\n\n const point = trendMap.get(dateKey)!;\n point.accessCount++;\n\n // Track unique credentials (would need proper parsing)\n const credId = this.extractCredentialId(log.Description || '');\n if (credId) {\n uniqueCredentialsPerDay.get(dateKey)!.add(credId);\n }\n }\n\n // Finalize unique counts\n trendMap.forEach((point, dateKey) => {\n point.uniqueCredentials = uniqueCredentialsPerDay.get(dateKey)?.size || 0;\n });\n\n this.usageTrend = Array.from(trendMap.values())\n .sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());\n }\n\n private buildActivityFromCredentials(): void {\n this.recentActivity = this.credentials\n .filter(c => c.__mj_UpdatedAt)\n .sort((a, b) => new Date(b.__mj_UpdatedAt).getTime() - new Date(a.__mj_UpdatedAt).getTime())\n .slice(0, 10)\n .map(c => ({\n id: c.ID,\n credentialName: c.Name,\n credentialId: c.ID,\n typeName: c.CredentialType || 'Unknown',\n action: 'Updated' as const,\n date: new Date(c.__mj_UpdatedAt),\n user: undefined\n }));\n }\n\n private extractCredentialName(description: string): string {\n // Try to extract credential name from audit log description\n const match = description.match(/credential[:\\s]+['\"]?([^'\"]+)['\"]?/i);\n return match ? match[1] : 'Unknown Credential';\n }\n\n private extractAction(description: string): string {\n if (description.toLowerCase().includes('creat')) return 'Created';\n if (description.toLowerCase().includes('rotat')) return 'Rotated';\n if (description.toLowerCase().includes('access')) return 'Accessed';\n return 'Updated';\n }\n\n private extractCredentialId(description: string): string {\n const match = description.match(/[a-f0-9-]{36}/i);\n return match ? match[0] : '';\n }\n\n private getCategoryIcon(category: string): string {\n const iconMap: Record<string, string> = {\n 'AI': 'fa-solid fa-brain',\n 'Communication': 'fa-solid fa-envelope',\n 'Storage': 'fa-solid fa-cloud',\n 'Database': 'fa-solid fa-database',\n 'Authentication': 'fa-solid fa-shield-halved',\n 'Integration': 'fa-solid fa-plug'\n };\n return iconMap[category] || 'fa-solid fa-key';\n }\n\n // === Navigation Actions ===\n\n public createNewCredential(): void {\n // Navigate to Credentials tab with openCreatePanel flag to show the slide-in editor\n this.navigationService.OpenNavItemByName('Credentials', {\n openCreatePanel: true\n });\n }\n\n public openCredential(credentialId: string): void {\n const key = new CompositeKey([{ FieldName: 'ID', Value: credentialId }]);\n this.navigationService.OpenEntityRecord('MJ: Credentials', key);\n }\n\n public onCategoryClick(category: CategoryStat): void {\n // Navigate to types nav item with category filter\n this.navigationService.OpenNavItemByName('Types', {\n categoryFilter: category.category\n });\n }\n\n public onTypeClick(typeStat: TypeStat): void {\n // Navigate to credentials nav item with type filter\n this.navigationService.OpenNavItemByName('Credentials', {\n typeId: typeStat.typeId\n });\n }\n\n public onActivityClick(activity: ActivityItem): void {\n if (activity.credentialId) {\n this.openCredential(activity.credentialId);\n }\n }\n\n public viewAllCredentials(): void {\n this.navigationService.OpenNavItemByName('Credentials');\n }\n\n public viewAuditLog(): void {\n this.navigationService.OpenNavItemByName('Audit Log');\n }\n\n public viewAllTypes(): void {\n this.navigationService.OpenNavItemByName('Types');\n }\n\n public viewAllCategories(): void {\n this.navigationService.OpenNavItemByName('Categories');\n }\n\n public viewExpiringCredentials(): void {\n this.navigationService.OpenNavItemByName('Credentials', {\n filter: 'expiring'\n });\n }\n\n // === Formatting Helpers ===\n\n public formatDate(date: Date): string {\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMins = Math.floor(diffMs / 60000);\n const diffHours = Math.floor(diffMs / 3600000);\n const diffDays = Math.floor(diffMs / 86400000);\n\n if (diffMins < 1) return 'Just now';\n if (diffMins < 60) return `${diffMins}m ago`;\n if (diffHours < 24) return `${diffHours}h ago`;\n if (diffDays < 7) return `${diffDays}d ago`;\n\n return date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n });\n }\n\n public getActionIcon(action: string): string {\n const iconMap: Record<string, string> = {\n 'Created': 'fa-solid fa-plus',\n 'Updated': 'fa-solid fa-pen',\n 'Accessed': 'fa-solid fa-eye',\n 'Rotated': 'fa-solid fa-rotate'\n };\n return iconMap[action] || 'fa-solid fa-circle';\n }\n\n public getActionClass(action: string): string {\n const classMap: Record<string, string> = {\n 'Created': 'action-created',\n 'Updated': 'action-updated',\n 'Accessed': 'action-accessed',\n 'Rotated': 'action-rotated'\n };\n return classMap[action] || '';\n }\n\n public refresh(): void {\n this.loadData();\n }\n\n public getHealthScore(): number {\n if (this.totalCredentials === 0) return 100;\n\n const activeRatio = this.activeCredentials / this.totalCredentials;\n const expiredPenalty = (this.expiredCredentials / this.totalCredentials) * 30;\n const expiringPenalty = (this.expiringSoonCount / this.totalCredentials) * 15;\n\n return Math.max(0, Math.min(100, Math.round((activeRatio * 100) - expiredPenalty - expiringPenalty)));\n }\n\n public getHealthClass(): string {\n const score = this.getHealthScore();\n if (score >= 80) return 'health-good';\n if (score >= 60) return 'health-warning';\n return 'health-critical';\n }\n\n public getHealthLabel(): string {\n const score = this.getHealthScore();\n if (score >= 80) return 'Healthy';\n if (score >= 60) return 'Needs Attention';\n return 'Critical';\n }\n\n public getDonutOffset(index: number): number {\n // Calculate cumulative offset for donut chart segments\n // Each segment starts where the previous one ended\n // The circumference is 251 (2 * PI * 40)\n let offset = 63; // Start at top (25% of circumference = 90 degrees rotation)\n\n for (let i = 0; i < index; i++) {\n offset -= this.categoryStats[i].percentage * 2.51;\n }\n\n return offset;\n }\n}\n","<div class=\"overview-container\">\n @if (isLoading) {\n <mj-loading text=\"Loading overview...\"></mj-loading>\n }\n\n @if (!isLoading) {\n <!-- Header with Actions -->\n <div class=\"overview-header\">\n <div class=\"header-left\">\n <h2 class=\"overview-title\">Credential Overview</h2>\n <p class=\"overview-subtitle\">Monitor and manage your organization's credentials</p>\n </div>\n <div class=\"header-actions\">\n <button class=\"btn-refresh\" (click)=\"refresh()\" title=\"Refresh\">\n <i class=\"fa-solid fa-refresh\"></i>\n </button>\n @if (UserCanCreateCredentials) {\n <button class=\"btn-primary\" (click)=\"createNewCredential()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New Credential</span>\n </button>\n }\n </div>\n </div>\n <!-- Health Score Banner -->\n <div class=\"health-banner\" [ngClass]=\"getHealthClass()\">\n <div class=\"health-score-container\">\n <div class=\"health-score-ring\">\n <svg viewBox=\"0 0 36 36\" class=\"circular-chart\">\n <path class=\"circle-bg\"\n d=\"M18 2.0845\n a 15.9155 15.9155 0 0 1 0 31.831\n a 15.9155 15.9155 0 0 1 0 -31.831\"\n />\n <path class=\"circle\"\n [attr.stroke-dasharray]=\"getHealthScore() + ', 100'\"\n d=\"M18 2.0845\n a 15.9155 15.9155 0 0 1 0 31.831\n a 15.9155 15.9155 0 0 1 0 -31.831\"\n />\n </svg>\n <div class=\"health-score-value\">{{getHealthScore()}}</div>\n </div>\n </div>\n <div class=\"health-info\">\n <div class=\"health-label\">{{getHealthLabel()}}</div>\n <div class=\"health-details\">\n @if (expiredCredentials > 0) {\n <span class=\"health-alert\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{expiredCredentials}} expired\n </span>\n }\n @if (expiringSoonCount > 0) {\n <span class=\"health-warning-text\" (click)=\"viewExpiringCredentials()\">\n <i class=\"fa-solid fa-clock\"></i>\n {{expiringSoonCount}} expiring soon\n </span>\n }\n @if (expiredCredentials === 0 && expiringSoonCount === 0) {\n <span class=\"health-ok\">\n <i class=\"fa-solid fa-check-circle\"></i>\n All credentials healthy\n </span>\n }\n </div>\n </div>\n </div>\n <!-- KPI Cards Row -->\n <div class=\"kpi-row\">\n <div class=\"kpi-card clickable\" (click)=\"viewAllCredentials()\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-key\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{totalCredentials}}</div>\n <div class=\"kpi-label\">Total Credentials</div>\n </div>\n <div class=\"kpi-trend\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n </div>\n </div>\n <div class=\"kpi-card active clickable\" (click)=\"viewAllCredentials()\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-check-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{activeCredentials}}</div>\n <div class=\"kpi-label\">Active</div>\n </div>\n <div class=\"kpi-trend success\">\n <span class=\"percentage\">{{totalCredentials > 0 ? (activeCredentials / totalCredentials * 100).toFixed(0) : 0}}%</span>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-cubes\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{credentialTypes}}</div>\n <div class=\"kpi-label\">Types</div>\n </div>\n </div>\n <div class=\"kpi-card clickable\" [class.warning]=\"expiringSoonCount > 0\" (click)=\"viewExpiringCredentials()\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-clock\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{expiringSoonCount}}</div>\n <div class=\"kpi-label\">Expiring Soon</div>\n </div>\n @if (expiringSoonCount > 0) {\n <div class=\"kpi-trend warning\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n </div>\n }\n </div>\n <div class=\"kpi-card\" [class.danger]=\"expiredCredentials > 0\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-circle-xmark\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{expiredCredentials}}</div>\n <div class=\"kpi-label\">Expired</div>\n </div>\n </div>\n </div>\n <!-- Content Grid -->\n <div class=\"content-grid\">\n <!-- Category Distribution Chart -->\n <div class=\"panel category-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-chart-pie\"></i>\n <span>Credentials by Category</span>\n </div>\n <span class=\"panel-subtitle\">Click to filter by category</span>\n </div>\n <div class=\"panel-body\">\n @if (categoryStats.length > 0) {\n <div class=\"category-chart\">\n <!-- Visual Donut Chart -->\n <div class=\"donut-chart-container\">\n <svg viewBox=\"0 0 100 100\" class=\"donut-chart\">\n <circle cx=\"50\" cy=\"50\" r=\"40\" fill=\"none\" stroke=\"#e5e7eb\" stroke-width=\"12\"/>\n @for (stat of categoryStats; track stat; let i = $index) {\n <ng-container>\n <circle\n cx=\"50\" cy=\"50\" r=\"40\"\n fill=\"none\"\n [attr.stroke]=\"stat.color\"\n stroke-width=\"12\"\n [attr.stroke-dasharray]=\"stat.percentage * 2.51 + ' ' + (251 - stat.percentage * 2.51)\"\n [attr.stroke-dashoffset]=\"getDonutOffset(i)\"\n class=\"donut-segment\"\n (click)=\"onCategoryClick(stat)\"\n />\n </ng-container>\n }\n </svg>\n <div class=\"donut-center\">\n <div class=\"donut-total\">{{totalCredentials}}</div>\n <div class=\"donut-label\">Total</div>\n </div>\n </div>\n <!-- Legend -->\n <div class=\"category-legend\">\n @for (stat of categoryStats; track stat) {\n <div class=\"legend-item\" (click)=\"onCategoryClick(stat)\">\n <div class=\"legend-color\" [style.backgroundColor]=\"stat.color\"></div>\n <div class=\"legend-info\">\n <div class=\"legend-name\">\n <i [class]=\"stat.iconClass\"></i>\n {{stat.category}}\n </div>\n <div class=\"legend-value\">{{stat.count}} ({{stat.percentage}}%)</div>\n </div>\n <i class=\"fa-solid fa-chevron-right legend-arrow\"></i>\n </div>\n }\n </div>\n </div>\n }\n @if (categoryStats.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-folder-open\"></i>\n <span>No credentials configured</span>\n </div>\n }\n </div>\n </div>\n <!-- Types Breakdown -->\n <div class=\"panel types-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-cubes\"></i>\n <span>Top Credential Types</span>\n </div>\n <button class=\"panel-action\" (click)=\"viewAllTypes()\">\n View All <i class=\"fa-solid fa-arrow-right\"></i>\n </button>\n </div>\n <div class=\"panel-body\">\n @if (typeStats.length > 0) {\n <div class=\"type-list\">\n @for (type of typeStats.slice(0, 6); track type) {\n <div class=\"type-item\" (click)=\"onTypeClick(type)\">\n <div class=\"type-info\">\n <div class=\"type-name\">{{type.typeName}}</div>\n <div class=\"type-category\">{{type.category}}</div>\n </div>\n <div class=\"type-stats\">\n <div class=\"type-count\">\n <span class=\"count-value\">{{type.credentialCount}}</span>\n <span class=\"count-label\">credentials</span>\n </div>\n <div class=\"type-bar\">\n <div class=\"type-bar-fill\"\n [style.width.%]=\"totalCredentials > 0 ? (type.credentialCount / totalCredentials * 100) : 0\">\n </div>\n </div>\n <div class=\"type-indicators\">\n @if (type.activeCount > 0) {\n <span class=\"indicator active\" title=\"Active\">\n <i class=\"fa-solid fa-circle\"></i> {{type.activeCount}}\n </span>\n }\n @if (type.expiringCount > 0) {\n <span class=\"indicator warning\" title=\"Expiring Soon\">\n <i class=\"fa-solid fa-clock\"></i> {{type.expiringCount}}\n </span>\n }\n </div>\n </div>\n </div>\n }\n </div>\n }\n @if (typeStats.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shapes\"></i>\n <span>No credential types configured</span>\n </div>\n }\n </div>\n </div>\n <!-- Recent Activity -->\n <div class=\"panel activity-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n <span>Recent Activity</span>\n </div>\n <button class=\"panel-action\" (click)=\"viewAuditLog()\">\n View All <i class=\"fa-solid fa-arrow-right\"></i>\n </button>\n </div>\n <div class=\"panel-body\">\n @if (recentActivity.length > 0) {\n <div class=\"activity-list\">\n @for (activity of recentActivity; track activity) {\n <div class=\"activity-item\" (click)=\"onActivityClick(activity)\">\n <div class=\"activity-icon\" [ngClass]=\"getActionClass(activity.action)\">\n <i [class]=\"getActionIcon(activity.action)\"></i>\n </div>\n <div class=\"activity-info\">\n <div class=\"activity-name\">{{activity.credentialName}}</div>\n <div class=\"activity-meta\">\n <span class=\"activity-type\">{{activity.typeName}}</span>\n <span class=\"activity-action\">{{activity.action}}</span>\n @if (activity.user) {\n <span class=\"activity-user\">by {{activity.user}}</span>\n }\n </div>\n </div>\n <div class=\"activity-time\">\n {{formatDate(activity.date)}}\n </div>\n </div>\n }\n </div>\n }\n @if (recentActivity.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No recent activity</span>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Quick Actions -->\n @if (UserCanCreateCredentials) {\n <div class=\"quick-actions\">\n <div class=\"quick-actions-title\">Quick Actions</div>\n <div class=\"quick-actions-grid\">\n <button class=\"quick-action\" (click)=\"createNewCredential()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>Add Credential</span>\n </button>\n <button class=\"quick-action\" (click)=\"viewAllTypes()\">\n <i class=\"fa-solid fa-shapes\"></i>\n <span>Manage Types</span>\n </button>\n <button class=\"quick-action\" (click)=\"viewAllCategories()\">\n <i class=\"fa-solid fa-folder-tree\"></i>\n <span>Categories</span>\n </button>\n <button class=\"quick-action\" (click)=\"viewAuditLog()\">\n <i class=\"fa-solid fa-clipboard-list\"></i>\n <span>Audit Log</span>\n </button>\n </div>\n </div>\n }\n <!-- Security Notice -->\n <div class=\"security-notice\">\n <i class=\"fa-solid fa-shield-check\"></i>\n <div class=\"notice-content\">\n <strong>Security Note:</strong> All credential values are encrypted.\n Access to credentials is logged in the audit trail for compliance and security monitoring.\n </div>\n </div>\n }\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"credentials-overview-resource.component.js","sourceRoot":"","sources":["../../../src/Credentials/components/credentials-overview-resource.component.ts","../../../src/Credentials/components/credentials-overview-resource.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { ResourceData, MJCredentialEntity, MJCredentialTypeEntity, MJCredentialCategoryEntity, MJAuditLogEntity } from '@memberjunction/core-entities';\nimport { RegisterClass , UUIDsEqual } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { RunView, Metadata, CompositeKey } from '@memberjunction/core';\ninterface CategoryStat {\n category: string;\n categoryId: string;\n count: number;\n iconClass: string;\n color: string;\n percentage: number;\n}\n\ninterface TypeStat {\n typeId: string;\n typeName: string;\n category: string;\n credentialCount: number;\n activeCount: number;\n expiringCount: number;\n}\n\ninterface ActivityItem {\n id: string;\n credentialName: string;\n credentialId: string;\n typeName: string;\n action: 'Created' | 'Updated' | 'Accessed' | 'Rotated';\n date: Date;\n user?: string;\n}\n\ninterface UsageTrendPoint {\n timestamp: Date;\n accessCount: number;\n uniqueCredentials: number;\n successRate: number;\n}\n\n@RegisterClass(BaseResourceComponent, 'CredentialsOverviewResource')\n@Component({\n standalone: false,\n selector: 'mj-credentials-overview-resource',\n templateUrl: './credentials-overview-resource.component.html',\n styleUrls: ['./credentials-overview-resource.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class CredentialsOverviewResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public isLoading = true;\n\n // Summary stats\n public totalCredentials = 0;\n public activeCredentials = 0;\n public expiredCredentials = 0;\n public expiringSoonCount = 0;\n public credentialTypes = 0;\n public categories = 0;\n\n // Grouped data\n public categoryStats: CategoryStat[] = [];\n public typeStats: TypeStat[] = [];\n public recentActivity: ActivityItem[] = [];\n public usageTrend: UsageTrendPoint[] = [];\n\n // Raw data\n private credentials: MJCredentialEntity[] = [];\n private types: MJCredentialTypeEntity[] = [];\n private categoryList: MJCredentialCategoryEntity[] = [];\n private auditLogs: MJAuditLogEntity[] = [];\n\n // Permissions\n private _metadata = new Metadata();\n private _permissionCache = new Map<string, boolean>();\n\n // Category colors for charts - using CSS custom properties via getComputedStyle at runtime\n // These are semantic fallback values; the actual tokens are resolved from the theme\n private categoryColors: Record<string, string> = {\n 'AI': 'var(--mj-brand-primary)',\n 'Communication': 'var(--mj-brand-primary)',\n 'Storage': 'var(--mj-status-success)',\n 'Database': 'var(--mj-status-warning)',\n 'Authentication': 'var(--mj-status-error)',\n 'Integration': 'var(--mj-brand-primary)'\n };\n\n private destroy$ = new Subject<void>();\n\n constructor(\n private cdr: ChangeDetectorRef,\n private navigationService: NavigationService\n ) {\n super();\n }\n\n ngOnInit(): void {\n this.loadData();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Overview';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-chart-pie';\n }\n\n // === Permission Checks ===\n public get UserCanCreateCredentials(): boolean {\n return this.checkEntityPermission('MJ: Credentials', 'Create');\n }\n\n public get UserCanUpdateCredentials(): boolean {\n return this.checkEntityPermission('MJ: Credentials', 'Update');\n }\n\n private checkEntityPermission(entityName: string, permissionType: 'Create' | 'Read' | 'Update' | 'Delete'): boolean {\n const cacheKey = `${entityName}_${permissionType}`;\n\n if (this._permissionCache.has(cacheKey)) {\n return this._permissionCache.get(cacheKey)!;\n }\n\n try {\n const entityInfo = this._metadata.Entities.find(e => e.Name === entityName);\n if (!entityInfo) {\n this._permissionCache.set(cacheKey, false);\n return false;\n }\n\n const userPermissions = entityInfo.GetUserPermisions(this._metadata.CurrentUser);\n let hasPermission = false;\n\n switch (permissionType) {\n case 'Create': hasPermission = userPermissions.CanCreate; break;\n case 'Read': hasPermission = userPermissions.CanRead; break;\n case 'Update': hasPermission = userPermissions.CanUpdate; break;\n case 'Delete': hasPermission = userPermissions.CanDelete; break;\n }\n\n this._permissionCache.set(cacheKey, hasPermission);\n return hasPermission;\n } catch (error) {\n this._permissionCache.set(cacheKey, false);\n return false;\n }\n }\n\n private async loadData(): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.markForCheck();\n\n const rv = new RunView();\n\n // Calculate date range for audit logs (last 30 days)\n const thirtyDaysAgo = new Date();\n thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);\n const dateFilter = `__mj_CreatedAt >= '${thirtyDaysAgo.toISOString()}'`;\n\n // Load all data in parallel using RunViews\n const [credResult, typeResult, categoryResult, auditResult] = await rv.RunViews([\n {\n EntityName: 'MJ: Credentials',\n ResultType: 'entity_object'\n },\n {\n EntityName: 'MJ: Credential Types',\n ResultType: 'entity_object'\n },\n {\n EntityName: 'MJ: Credential Categories',\n ResultType: 'entity_object'\n },\n {\n EntityName: 'MJ: Audit Logs',\n ExtraFilter: `AuditLogType LIKE '%Credential%' AND ${dateFilter}`,\n OrderBy: '__mj_CreatedAt DESC',\n MaxRows: 100,\n ResultType: 'entity_object'\n }\n ]);\n\n if (credResult.Success) {\n this.credentials = credResult.Results as MJCredentialEntity[];\n this.processCredentialStats();\n }\n\n if (typeResult.Success) {\n this.types = typeResult.Results as MJCredentialTypeEntity[];\n this.credentialTypes = this.types.length;\n this.processTypeStats();\n }\n\n if (categoryResult.Success) {\n this.categoryList = categoryResult.Results as MJCredentialCategoryEntity[];\n this.categories = this.categoryList.length;\n this.processCategoryStats();\n }\n\n if (auditResult.Success) {\n this.auditLogs = auditResult.Results as MJAuditLogEntity[];\n this.processActivityAndTrends();\n }\n\n // Build recent activity from credentials if no audit logs\n if (this.recentActivity.length === 0) {\n this.buildActivityFromCredentials();\n }\n\n } catch (error) {\n console.error('Error loading credentials overview:', error);\n } finally {\n this.isLoading = false;\n this.NotifyLoadComplete();\n this.cdr.markForCheck();\n }\n }\n\n private processCredentialStats(): void {\n this.totalCredentials = this.credentials.length;\n this.activeCredentials = this.credentials.filter(c => c.IsActive).length;\n\n const now = new Date();\n const thirtyDaysFromNow = new Date();\n thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30);\n\n this.expiredCredentials = this.credentials.filter(c =>\n c.ExpiresAt && new Date(c.ExpiresAt) < now\n ).length;\n\n this.expiringSoonCount = this.credentials.filter(c =>\n c.ExpiresAt &&\n new Date(c.ExpiresAt) >= now &&\n new Date(c.ExpiresAt) <= thirtyDaysFromNow &&\n c.IsActive\n ).length;\n }\n\n private processTypeStats(): void {\n const now = new Date();\n const thirtyDaysFromNow = new Date();\n thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30);\n\n this.typeStats = this.types.map(type => {\n const typeCredentials = this.credentials.filter(c => UUIDsEqual(c.CredentialTypeID, type.ID));\n\n return {\n typeId: type.ID,\n typeName: type.Name,\n category: type.Category,\n credentialCount: typeCredentials.length,\n activeCount: typeCredentials.filter(c => c.IsActive).length,\n expiringCount: typeCredentials.filter(c =>\n c.ExpiresAt &&\n new Date(c.ExpiresAt) >= now &&\n new Date(c.ExpiresAt) <= thirtyDaysFromNow\n ).length\n };\n }).sort((a, b) => b.credentialCount - a.credentialCount);\n }\n\n private processCategoryStats(): void {\n const categoryMap = new Map<string, CategoryStat>();\n\n // Initialize from credential types\n for (const type of this.types) {\n const category = type.Category;\n const existing = categoryMap.get(category);\n const categoryCredentials = this.credentials.filter(c => UUIDsEqual(c.CredentialTypeID, type.ID));\n\n if (existing) {\n existing.count += categoryCredentials.length;\n } else {\n categoryMap.set(category, {\n category: category,\n categoryId: category, // Use category name as ID for filtering\n count: categoryCredentials.length,\n iconClass: this.getCategoryIcon(category),\n color: this.categoryColors[category] || 'var(--mj-text-muted)',\n percentage: 0\n });\n }\n }\n\n // Calculate percentages\n const total = this.totalCredentials || 1;\n categoryMap.forEach(stat => {\n stat.percentage = Math.round((stat.count / total) * 100);\n });\n\n this.categoryStats = Array.from(categoryMap.values())\n .sort((a, b) => b.count - a.count);\n }\n\n private processActivityAndTrends(): void {\n // Process recent activity from audit logs\n this.recentActivity = this.auditLogs\n .slice(0, 10)\n .map(log => ({\n id: log.ID,\n credentialName: this.extractCredentialName(log.Description || ''),\n credentialId: '', // Would need to parse from log\n typeName: 'Credential',\n action: this.extractAction(log.Description || '') as ActivityItem['action'],\n date: new Date(log.__mj_CreatedAt),\n user: log.User\n }));\n\n // Build usage trend data (group by day)\n const trendMap = new Map<string, UsageTrendPoint>();\n const uniqueCredentialsPerDay = new Map<string, Set<string>>();\n\n for (const log of this.auditLogs) {\n const dateKey = new Date(log.__mj_CreatedAt).toISOString().split('T')[0];\n\n if (!trendMap.has(dateKey)) {\n trendMap.set(dateKey, {\n timestamp: new Date(dateKey),\n accessCount: 0,\n uniqueCredentials: 0,\n successRate: 100\n });\n uniqueCredentialsPerDay.set(dateKey, new Set());\n }\n\n const point = trendMap.get(dateKey)!;\n point.accessCount++;\n\n // Track unique credentials (would need proper parsing)\n const credId = this.extractCredentialId(log.Description || '');\n if (credId) {\n uniqueCredentialsPerDay.get(dateKey)!.add(credId);\n }\n }\n\n // Finalize unique counts\n trendMap.forEach((point, dateKey) => {\n point.uniqueCredentials = uniqueCredentialsPerDay.get(dateKey)?.size || 0;\n });\n\n this.usageTrend = Array.from(trendMap.values())\n .sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());\n }\n\n private buildActivityFromCredentials(): void {\n this.recentActivity = this.credentials\n .filter(c => c.__mj_UpdatedAt)\n .sort((a, b) => new Date(b.__mj_UpdatedAt).getTime() - new Date(a.__mj_UpdatedAt).getTime())\n .slice(0, 10)\n .map(c => ({\n id: c.ID,\n credentialName: c.Name,\n credentialId: c.ID,\n typeName: c.CredentialType || 'Unknown',\n action: 'Updated' as const,\n date: new Date(c.__mj_UpdatedAt),\n user: undefined\n }));\n }\n\n private extractCredentialName(description: string): string {\n // Try to extract credential name from audit log description\n const match = description.match(/credential[:\\s]+['\"]?([^'\"]+)['\"]?/i);\n return match ? match[1] : 'Unknown Credential';\n }\n\n private extractAction(description: string): string {\n if (description.toLowerCase().includes('creat')) return 'Created';\n if (description.toLowerCase().includes('rotat')) return 'Rotated';\n if (description.toLowerCase().includes('access')) return 'Accessed';\n return 'Updated';\n }\n\n private extractCredentialId(description: string): string {\n const match = description.match(/[a-f0-9-]{36}/i);\n return match ? match[0] : '';\n }\n\n private getCategoryIcon(category: string): string {\n const iconMap: Record<string, string> = {\n 'AI': 'fa-solid fa-brain',\n 'Communication': 'fa-solid fa-envelope',\n 'Storage': 'fa-solid fa-cloud',\n 'Database': 'fa-solid fa-database',\n 'Authentication': 'fa-solid fa-shield-halved',\n 'Integration': 'fa-solid fa-plug'\n };\n return iconMap[category] || 'fa-solid fa-key';\n }\n\n // === Navigation Actions ===\n\n public createNewCredential(): void {\n // Navigate to Credentials tab with openCreatePanel flag to show the slide-in editor\n this.navigationService.OpenNavItemByName('Credentials', {\n openCreatePanel: true\n });\n }\n\n public openCredential(credentialId: string): void {\n const key = new CompositeKey([{ FieldName: 'ID', Value: credentialId }]);\n this.navigationService.OpenEntityRecord('MJ: Credentials', key);\n }\n\n public onCategoryClick(category: CategoryStat): void {\n // Navigate to types nav item with category filter\n this.navigationService.OpenNavItemByName('Types', {\n categoryFilter: category.category\n });\n }\n\n public onTypeClick(typeStat: TypeStat): void {\n // Navigate to credentials nav item with type filter\n this.navigationService.OpenNavItemByName('Credentials', {\n typeId: typeStat.typeId\n });\n }\n\n public onActivityClick(activity: ActivityItem): void {\n if (activity.credentialId) {\n this.openCredential(activity.credentialId);\n }\n }\n\n public viewAllCredentials(): void {\n this.navigationService.OpenNavItemByName('Credentials');\n }\n\n public viewAuditLog(): void {\n this.navigationService.OpenNavItemByName('Audit Log');\n }\n\n public viewAllTypes(): void {\n this.navigationService.OpenNavItemByName('Types');\n }\n\n public viewAllCategories(): void {\n this.navigationService.OpenNavItemByName('Categories');\n }\n\n public viewExpiringCredentials(): void {\n this.navigationService.OpenNavItemByName('Credentials', {\n filter: 'expiring'\n });\n }\n\n // === Formatting Helpers ===\n\n public formatDate(date: Date): string {\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMins = Math.floor(diffMs / 60000);\n const diffHours = Math.floor(diffMs / 3600000);\n const diffDays = Math.floor(diffMs / 86400000);\n\n if (diffMins < 1) return 'Just now';\n if (diffMins < 60) return `${diffMins}m ago`;\n if (diffHours < 24) return `${diffHours}h ago`;\n if (diffDays < 7) return `${diffDays}d ago`;\n\n return date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n });\n }\n\n public getActionIcon(action: string): string {\n const iconMap: Record<string, string> = {\n 'Created': 'fa-solid fa-plus',\n 'Updated': 'fa-solid fa-pen',\n 'Accessed': 'fa-solid fa-eye',\n 'Rotated': 'fa-solid fa-rotate'\n };\n return iconMap[action] || 'fa-solid fa-circle';\n }\n\n public getActionClass(action: string): string {\n const classMap: Record<string, string> = {\n 'Created': 'action-created',\n 'Updated': 'action-updated',\n 'Accessed': 'action-accessed',\n 'Rotated': 'action-rotated'\n };\n return classMap[action] || '';\n }\n\n public refresh(): void {\n this.loadData();\n }\n\n public getHealthScore(): number {\n if (this.totalCredentials === 0) return 100;\n\n const activeRatio = this.activeCredentials / this.totalCredentials;\n const expiredPenalty = (this.expiredCredentials / this.totalCredentials) * 30;\n const expiringPenalty = (this.expiringSoonCount / this.totalCredentials) * 15;\n\n return Math.max(0, Math.min(100, Math.round((activeRatio * 100) - expiredPenalty - expiringPenalty)));\n }\n\n public getHealthClass(): string {\n const score = this.getHealthScore();\n if (score >= 80) return 'health-good';\n if (score >= 60) return 'health-warning';\n return 'health-critical';\n }\n\n public getHealthLabel(): string {\n const score = this.getHealthScore();\n if (score >= 80) return 'Healthy';\n if (score >= 60) return 'Needs Attention';\n return 'Critical';\n }\n\n public getDonutOffset(index: number): number {\n // Calculate cumulative offset for donut chart segments\n // Each segment starts where the previous one ended\n // The circumference is 251 (2 * PI * 40)\n let offset = 63; // Start at top (25% of circumference = 90 degrees rotation)\n\n for (let i = 0; i < index; i++) {\n offset -= this.categoryStats[i].percentage * 2.51;\n }\n\n return offset;\n }\n}\n","<div class=\"overview-container\">\n @if (isLoading) {\n <mj-loading text=\"Loading overview...\"></mj-loading>\n }\n\n @if (!isLoading) {\n <!-- Header with Actions -->\n <div class=\"overview-header\">\n <div class=\"header-left\">\n <h2 class=\"overview-title\">Credential Overview</h2>\n <p class=\"overview-subtitle\">Monitor and manage your organization's credentials</p>\n </div>\n <div class=\"header-actions\">\n <button class=\"btn-refresh\" (click)=\"refresh()\" title=\"Refresh\">\n <i class=\"fa-solid fa-refresh\"></i>\n </button>\n @if (UserCanCreateCredentials) {\n <button class=\"btn-primary\" (click)=\"createNewCredential()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New Credential</span>\n </button>\n }\n </div>\n </div>\n <!-- Health Score Banner -->\n <div class=\"health-banner\" [ngClass]=\"getHealthClass()\">\n <div class=\"health-score-container\">\n <div class=\"health-score-ring\">\n <svg viewBox=\"0 0 36 36\" class=\"circular-chart\">\n <path class=\"circle-bg\"\n d=\"M18 2.0845\n a 15.9155 15.9155 0 0 1 0 31.831\n a 15.9155 15.9155 0 0 1 0 -31.831\"\n />\n <path class=\"circle\"\n [attr.stroke-dasharray]=\"getHealthScore() + ', 100'\"\n d=\"M18 2.0845\n a 15.9155 15.9155 0 0 1 0 31.831\n a 15.9155 15.9155 0 0 1 0 -31.831\"\n />\n </svg>\n <div class=\"health-score-value\">{{getHealthScore()}}</div>\n </div>\n </div>\n <div class=\"health-info\">\n <div class=\"health-label\">{{getHealthLabel()}}</div>\n <div class=\"health-details\">\n @if (expiredCredentials > 0) {\n <span class=\"health-alert\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{expiredCredentials}} expired\n </span>\n }\n @if (expiringSoonCount > 0) {\n <span class=\"health-warning-text\" (click)=\"viewExpiringCredentials()\">\n <i class=\"fa-solid fa-clock\"></i>\n {{expiringSoonCount}} expiring soon\n </span>\n }\n @if (expiredCredentials === 0 && expiringSoonCount === 0) {\n <span class=\"health-ok\">\n <i class=\"fa-solid fa-check-circle\"></i>\n All credentials healthy\n </span>\n }\n </div>\n </div>\n </div>\n <!-- KPI Cards Row -->\n <div class=\"kpi-row\">\n <div class=\"kpi-card clickable\" (click)=\"viewAllCredentials()\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-key\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{totalCredentials}}</div>\n <div class=\"kpi-label\">Total Credentials</div>\n </div>\n <div class=\"kpi-trend\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n </div>\n </div>\n <div class=\"kpi-card active clickable\" (click)=\"viewAllCredentials()\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-check-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{activeCredentials}}</div>\n <div class=\"kpi-label\">Active</div>\n </div>\n <div class=\"kpi-trend success\">\n <span class=\"percentage\">{{totalCredentials > 0 ? (activeCredentials / totalCredentials * 100).toFixed(0) : 0}}%</span>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-cubes\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{credentialTypes}}</div>\n <div class=\"kpi-label\">Types</div>\n </div>\n </div>\n <div class=\"kpi-card clickable\" [class.warning]=\"expiringSoonCount > 0\" (click)=\"viewExpiringCredentials()\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-clock\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{expiringSoonCount}}</div>\n <div class=\"kpi-label\">Expiring Soon</div>\n </div>\n @if (expiringSoonCount > 0) {\n <div class=\"kpi-trend warning\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n </div>\n }\n </div>\n <div class=\"kpi-card\" [class.danger]=\"expiredCredentials > 0\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-circle-xmark\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{expiredCredentials}}</div>\n <div class=\"kpi-label\">Expired</div>\n </div>\n </div>\n </div>\n <!-- Content Grid -->\n <div class=\"content-grid\">\n <!-- Category Distribution Chart -->\n <div class=\"panel category-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-chart-pie\"></i>\n <span>Credentials by Category</span>\n </div>\n <span class=\"panel-subtitle\">Click to filter by category</span>\n </div>\n <div class=\"panel-body\">\n @if (categoryStats.length > 0) {\n <div class=\"category-chart\">\n <!-- Visual Donut Chart -->\n <div class=\"donut-chart-container\">\n <svg viewBox=\"0 0 100 100\" class=\"donut-chart\">\n <circle cx=\"50\" cy=\"50\" r=\"40\" fill=\"none\" stroke=\"var(--mj-border-default)\" stroke-width=\"12\"/>\n @for (stat of categoryStats; track stat; let i = $index) {\n <ng-container>\n <circle\n cx=\"50\" cy=\"50\" r=\"40\"\n fill=\"none\"\n [attr.stroke]=\"stat.color\"\n stroke-width=\"12\"\n [attr.stroke-dasharray]=\"stat.percentage * 2.51 + ' ' + (251 - stat.percentage * 2.51)\"\n [attr.stroke-dashoffset]=\"getDonutOffset(i)\"\n class=\"donut-segment\"\n (click)=\"onCategoryClick(stat)\"\n />\n </ng-container>\n }\n </svg>\n <div class=\"donut-center\">\n <div class=\"donut-total\">{{totalCredentials}}</div>\n <div class=\"donut-label\">Total</div>\n </div>\n </div>\n <!-- Legend -->\n <div class=\"category-legend\">\n @for (stat of categoryStats; track stat) {\n <div class=\"legend-item\" (click)=\"onCategoryClick(stat)\">\n <div class=\"legend-color\" [style.backgroundColor]=\"stat.color\"></div>\n <div class=\"legend-info\">\n <div class=\"legend-name\">\n <i [class]=\"stat.iconClass\"></i>\n {{stat.category}}\n </div>\n <div class=\"legend-value\">{{stat.count}} ({{stat.percentage}}%)</div>\n </div>\n <i class=\"fa-solid fa-chevron-right legend-arrow\"></i>\n </div>\n }\n </div>\n </div>\n }\n @if (categoryStats.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-folder-open\"></i>\n <span>No credentials configured</span>\n </div>\n }\n </div>\n </div>\n <!-- Types Breakdown -->\n <div class=\"panel types-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-cubes\"></i>\n <span>Top Credential Types</span>\n </div>\n <button class=\"panel-action\" (click)=\"viewAllTypes()\">\n View All <i class=\"fa-solid fa-arrow-right\"></i>\n </button>\n </div>\n <div class=\"panel-body\">\n @if (typeStats.length > 0) {\n <div class=\"type-list\">\n @for (type of typeStats.slice(0, 6); track type) {\n <div class=\"type-item\" (click)=\"onTypeClick(type)\">\n <div class=\"type-info\">\n <div class=\"type-name\">{{type.typeName}}</div>\n <div class=\"type-category\">{{type.category}}</div>\n </div>\n <div class=\"type-stats\">\n <div class=\"type-count\">\n <span class=\"count-value\">{{type.credentialCount}}</span>\n <span class=\"count-label\">credentials</span>\n </div>\n <div class=\"type-bar\">\n <div class=\"type-bar-fill\"\n [style.width.%]=\"totalCredentials > 0 ? (type.credentialCount / totalCredentials * 100) : 0\">\n </div>\n </div>\n <div class=\"type-indicators\">\n @if (type.activeCount > 0) {\n <span class=\"indicator active\" title=\"Active\">\n <i class=\"fa-solid fa-circle\"></i> {{type.activeCount}}\n </span>\n }\n @if (type.expiringCount > 0) {\n <span class=\"indicator warning\" title=\"Expiring Soon\">\n <i class=\"fa-solid fa-clock\"></i> {{type.expiringCount}}\n </span>\n }\n </div>\n </div>\n </div>\n }\n </div>\n }\n @if (typeStats.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shapes\"></i>\n <span>No credential types configured</span>\n </div>\n }\n </div>\n </div>\n <!-- Recent Activity -->\n <div class=\"panel activity-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n <span>Recent Activity</span>\n </div>\n <button class=\"panel-action\" (click)=\"viewAuditLog()\">\n View All <i class=\"fa-solid fa-arrow-right\"></i>\n </button>\n </div>\n <div class=\"panel-body\">\n @if (recentActivity.length > 0) {\n <div class=\"activity-list\">\n @for (activity of recentActivity; track activity) {\n <div class=\"activity-item\" (click)=\"onActivityClick(activity)\">\n <div class=\"activity-icon\" [ngClass]=\"getActionClass(activity.action)\">\n <i [class]=\"getActionIcon(activity.action)\"></i>\n </div>\n <div class=\"activity-info\">\n <div class=\"activity-name\">{{activity.credentialName}}</div>\n <div class=\"activity-meta\">\n <span class=\"activity-type\">{{activity.typeName}}</span>\n <span class=\"activity-action\">{{activity.action}}</span>\n @if (activity.user) {\n <span class=\"activity-user\">by {{activity.user}}</span>\n }\n </div>\n </div>\n <div class=\"activity-time\">\n {{formatDate(activity.date)}}\n </div>\n </div>\n }\n </div>\n }\n @if (recentActivity.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No recent activity</span>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Quick Actions -->\n @if (UserCanCreateCredentials) {\n <div class=\"quick-actions\">\n <div class=\"quick-actions-title\">Quick Actions</div>\n <div class=\"quick-actions-grid\">\n <button class=\"quick-action\" (click)=\"createNewCredential()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>Add Credential</span>\n </button>\n <button class=\"quick-action\" (click)=\"viewAllTypes()\">\n <i class=\"fa-solid fa-shapes\"></i>\n <span>Manage Types</span>\n </button>\n <button class=\"quick-action\" (click)=\"viewAllCategories()\">\n <i class=\"fa-solid fa-folder-tree\"></i>\n <span>Categories</span>\n </button>\n <button class=\"quick-action\" (click)=\"viewAuditLog()\">\n <i class=\"fa-solid fa-clipboard-list\"></i>\n <span>Audit Log</span>\n </button>\n </div>\n </div>\n }\n <!-- Security Notice -->\n <div class=\"security-notice\">\n <i class=\"fa-solid fa-shield-check\"></i>\n <div class=\"notice-content\">\n <strong>Security Note:</strong> All credential values are encrypted.\n Access to credentials is logged in the audit trail for compliance and security monitoring.\n </div>\n </div>\n }\n</div>\n"]}
|
|
@@ -809,14 +809,14 @@ let CredentialsTypesResourceComponent = class CredentialsTypesResourceComponent
|
|
|
809
809
|
}
|
|
810
810
|
getCategoryColor(category) {
|
|
811
811
|
const colorMap = {
|
|
812
|
-
'AI': '
|
|
813
|
-
'Communication': '
|
|
814
|
-
'Storage': '
|
|
815
|
-
'Database': '
|
|
816
|
-
'Authentication': '
|
|
817
|
-
'Integration': '
|
|
812
|
+
'AI': 'var(--mj-brand-primary)',
|
|
813
|
+
'Communication': 'var(--mj-brand-primary)',
|
|
814
|
+
'Storage': 'var(--mj-brand-primary)',
|
|
815
|
+
'Database': 'var(--mj-status-warning)',
|
|
816
|
+
'Authentication': 'var(--mj-status-success)',
|
|
817
|
+
'Integration': 'var(--mj-brand-primary)'
|
|
818
818
|
};
|
|
819
|
-
return colorMap[category] || '
|
|
819
|
+
return colorMap[category] || 'var(--mj-brand-primary)';
|
|
820
820
|
}
|
|
821
821
|
getTypesByCategory() {
|
|
822
822
|
const grouped = new Map();
|
|
@@ -859,7 +859,7 @@ let CredentialsTypesResourceComponent = class CredentialsTypesResourceComponent
|
|
|
859
859
|
i0.ɵɵconditional(ctx.isLoading ? 1 : -1);
|
|
860
860
|
i0.ɵɵadvance();
|
|
861
861
|
i0.ɵɵconditional(!ctx.isLoading ? 2 : -1);
|
|
862
|
-
} }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i3.LoadingComponent, i4.CredentialTypeEditPanelComponent, i5.SlicePipe, i5.KeyValuePipe], styles: [".types-container[_ngcontent-%COMP%] {\n height: 100%;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n padding: 24px;\n background: var(--page-background, #f8fafc);\n}\n\n\n\n.types-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.types-title[_ngcontent-%COMP%] {\n font-size: 24px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0;\n}\n\n.header-stats[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.stat-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n}\n\n.stat-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);\n color: white;\n border: none;\n border-radius: 10px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px rgba(99, 102, 241, 0.3);\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 16px rgba(99, 102, 241, 0.4);\n}\n\n.btn-primary[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n.toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 16px;\n flex-wrap: wrap;\n background: var(--card-background, #ffffff);\n padding: 16px;\n border-radius: 12px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n}\n\n.toolbar-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n flex: 1;\n}\n\n.toolbar-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.search-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n background: var(--input-background, #f9fafb);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n padding: 8px 12px;\n min-width: 240px;\n position: relative;\n}\n\n.search-container[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--text-secondary, #6b7280);\n margin-right: 8px;\n}\n\n.search-container[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n border: none;\n background: transparent;\n outline: none;\n flex: 1;\n font-size: 14px;\n color: var(--text-primary, #1f2937);\n}\n\n.search-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--border-color, #e5e7eb);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n color: var(--text-secondary, #6b7280);\n font-size: 10px;\n}\n\n.search-clear[_ngcontent-%COMP%]:hover {\n background: var(--text-secondary, #6b7280);\n color: white;\n}\n\n.filter-select[_ngcontent-%COMP%] {\n padding: 8px 12px;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n background: var(--input-background, #ffffff);\n font-size: 14px;\n color: var(--text-primary, #1f2937);\n cursor: pointer;\n min-width: 160px;\n}\n\n.results-info[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n white-space: nowrap;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n background: var(--button-background, #ffffff);\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover {\n background: var(--button-hover, #f3f4f6);\n color: var(--accent-color, #6366f1);\n}\n\n\n\n.types-layout[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 420px 1fr;\n flex: 1;\n min-height: 0;\n gap: 20px;\n}\n\n\n\n.types-list[_ngcontent-%COMP%] {\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n overflow-y: auto;\n padding: 16px;\n}\n\n.category-section[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.category-section[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.category-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--text-secondary, #6b7280);\n letter-spacing: 0.5px;\n border-left: 3px solid var(--accent-color, #6366f1);\n background: var(--header-background, #f9fafb);\n border-radius: 0 8px 8px 0;\n margin-bottom: 8px;\n}\n\n.category-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.category-name[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.category-header[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n background: white;\n padding: 2px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n.type-items[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.type-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px 14px;\n background: var(--item-background, #ffffff);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n border: 2px solid transparent;\n position: relative;\n}\n\n.type-item[_ngcontent-%COMP%]:hover {\n background: var(--item-hover, #f8fafc);\n border-color: var(--border-color, #e5e7eb);\n}\n\n.type-item.selected[_ngcontent-%COMP%] {\n background: linear-gradient(to right, rgba(99, 102, 241, 0.05), white);\n border-color: var(--accent-color, #6366f1);\n}\n\n.type-icon[_ngcontent-%COMP%] {\n width: 42px;\n height: 42px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.type-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.type-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.type-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--text-primary, #1f2937);\n}\n\n.type-description[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--text-secondary, #9ca3af);\n margin-top: 2px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.type-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-top: 6px;\n}\n\n.meta-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n background: var(--badge-background, #f3f4f6);\n border-radius: 10px;\n font-size: 11px;\n color: var(--text-secondary, #6b7280);\n}\n\n.meta-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 9px;\n}\n\n.meta-badge.active[_ngcontent-%COMP%] {\n background: #d1fae5;\n color: #059669;\n}\n\n.meta-badge.warning[_ngcontent-%COMP%] {\n background: #fef3c7;\n color: #d97706;\n}\n\n.type-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n margin-right: 8px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.type-item[_ngcontent-%COMP%]:hover .type-actions[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.action-btn[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: var(--input-background, #f3f4f6);\n border-radius: 6px;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n font-size: 12px;\n}\n\n.action-btn[_ngcontent-%COMP%]:hover {\n background: var(--accent-color, #6366f1);\n color: white;\n}\n\n.action-btn.danger[_ngcontent-%COMP%]:hover {\n background: #ef4444;\n}\n\n.arrow[_ngcontent-%COMP%] {\n color: var(--text-tertiary, #d1d5db);\n font-size: 12px;\n}\n\n\n\n.type-detail[_ngcontent-%COMP%] {\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n overflow-y: auto;\n}\n\n.detail-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 24px;\n border-bottom: 1px solid var(--border-color, #f3f4f6);\n}\n\n.detail-icon[_ngcontent-%COMP%] {\n width: 60px;\n height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 14px;\n margin-right: 16px;\n flex-shrink: 0;\n}\n\n.detail-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 26px;\n}\n\n.detail-title[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.detail-title[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0 0 8px 0;\n}\n\n.category-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.category-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n.detail-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.close-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: var(--button-background, #f3f4f6);\n border-radius: 8px;\n cursor: pointer;\n color: var(--text-secondary, #6b7280);\n transition: all 0.2s ease;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: var(--button-hover, #e5e7eb);\n color: var(--text-primary, #1f2937);\n}\n\n.detail-body[_ngcontent-%COMP%] {\n padding: 24px;\n}\n\n\n\n.detail-stats[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n margin-bottom: 24px;\n padding-bottom: 24px;\n border-bottom: 1px solid var(--border-color, #f3f4f6);\n}\n\n.detail-stat[_ngcontent-%COMP%] {\n flex: 1;\n text-align: center;\n padding: 16px;\n background: var(--stat-background, #f9fafb);\n border-radius: 12px;\n}\n\n.detail-stat[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 28px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n}\n\n.detail-stat[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n margin-top: 4px;\n}\n\n.detail-stat.active[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, rgba(16, 185, 129, 0.1) 0%, rgba(5, 150, 105, 0.05) 100%);\n}\n\n.detail-stat.active[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n color: #059669;\n}\n\n.detail-stat.warning[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, rgba(245, 158, 11, 0.1) 0%, rgba(217, 119, 6, 0.05) 100%);\n}\n\n.detail-stat.warning[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n color: #d97706;\n}\n\n.description[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n line-height: 1.6;\n margin: 0 0 24px 0;\n padding: 16px;\n background: var(--description-background, #f9fafb);\n border-radius: 10px;\n}\n\n.schema-section[_ngcontent-%COMP%], \n.validation-section[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n\n.schema-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%], \n.validation-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 14px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0 0 16px 0;\n}\n\n.schema-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.validation-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--accent-color, #6366f1);\n}\n\n.field-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.field-item[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--field-background, #f9fafb);\n border-radius: 10px;\n border: 1px solid var(--border-color, #e5e7eb);\n transition: all 0.2s ease;\n}\n\n.field-item[_ngcontent-%COMP%]:hover {\n border-color: var(--accent-color, #6366f1);\n background: var(--field-hover, #f3f4f6);\n}\n\n.field-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.field-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--text-primary, #1f2937);\n}\n\n.field-badges[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.badge[_ngcontent-%COMP%] {\n padding: 3px 10px;\n border-radius: 6px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.badge.type[_ngcontent-%COMP%] {\n background: var(--type-badge, #e5e7eb);\n color: var(--text-secondary, #6b7280);\n}\n\n.badge.secret[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);\n color: #b45309;\n}\n\n.badge.secret[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 3px;\n}\n\n.badge.required[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);\n color: #b91c1c;\n}\n\n.field-description[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n margin: 10px 0 0 0;\n line-height: 1.5;\n}\n\n.no-fields[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px;\n background: var(--field-background, #f9fafb);\n border-radius: 10px;\n color: var(--text-secondary, #9ca3af);\n font-size: 13px;\n}\n\n.no-fields[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--accent-color, #6366f1);\n}\n\n.validation-endpoint[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 18px;\n background: var(--endpoint-background, #f9fafb);\n border-radius: 10px;\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', monospace;\n border: 1px solid var(--border-color, #e5e7eb);\n}\n\n.validation-endpoint[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--accent-color, #6366f1);\n}\n\n.detail-quick-actions[_ngcontent-%COMP%] {\n margin-top: 24px;\n padding-top: 24px;\n border-top: 1px solid var(--border-color, #f3f4f6);\n}\n\n\n\n.no-selection[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n padding: 48px;\n}\n\n.no-selection-icon[_ngcontent-%COMP%] {\n width: 80px;\n height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%);\n border-radius: 20px;\n margin-bottom: 24px;\n}\n\n.no-selection-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--accent-color, #6366f1);\n}\n\n.no-selection[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0 0 8px 0;\n}\n\n.no-selection[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n margin: 0;\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: 60px 24px;\n text-align: center;\n}\n\n.empty-icon[_ngcontent-%COMP%] {\n width: 72px;\n height: 72px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%);\n border-radius: 18px;\n margin-bottom: 20px;\n}\n\n.empty-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--accent-color, #6366f1);\n}\n\n.empty-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0 0 8px 0;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n margin: 0 0 20px 0;\n}\n\n.btn-link[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--accent-color, #6366f1);\n font-size: 14px;\n cursor: pointer;\n text-decoration: underline;\n padding: 0;\n}\n\n.btn-link[_ngcontent-%COMP%]:hover {\n color: var(--accent-hover, #4f46e5);\n}\n\n\n\n@media (max-width: 1024px) {\n .types-layout[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .types-list[_ngcontent-%COMP%] {\n max-height: 400px;\n }\n}\n\n@media (max-width: 768px) {\n .types-container[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .types-header[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .toolbar[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n }\n\n .toolbar-left[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .search-container[_ngcontent-%COMP%] {\n min-width: 100%;\n }\n\n .filter-select[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .toolbar-right[_ngcontent-%COMP%] {\n justify-content: space-between;\n }\n\n .detail-stats[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n}"], changeDetection: 0 });
|
|
862
|
+
} }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i3.LoadingComponent, i4.CredentialTypeEditPanelComponent, i5.SlicePipe, i5.KeyValuePipe], styles: [".types-container[_ngcontent-%COMP%] {\n height: 100%;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n padding: 24px;\n background: var(--mj-bg-page);\n}\n\n\n\n.types-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.types-title[_ngcontent-%COMP%] {\n font-size: 24px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.header-stats[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.stat-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.stat-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 10px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n.btn-primary[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n.toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 16px;\n flex-wrap: wrap;\n background: var(--mj-bg-surface);\n padding: 16px;\n border-radius: 12px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n}\n\n.toolbar-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n flex: 1;\n}\n\n.toolbar-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.search-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 8px 12px;\n min-width: 240px;\n position: relative;\n}\n\n.search-container[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n margin-right: 8px;\n}\n\n.search-container[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n border: none;\n background: transparent;\n outline: none;\n flex: 1;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.search-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-border-default);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 10px;\n}\n\n.search-clear[_ngcontent-%COMP%]:hover {\n background: var(--mj-text-secondary);\n color: var(--mj-text-inverse);\n}\n\n.filter-select[_ngcontent-%COMP%] {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n min-width: 160px;\n}\n\n.results-info[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n\n\n.types-layout[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 420px 1fr;\n flex: 1;\n min-height: 0;\n gap: 20px;\n}\n\n\n\n.types-list[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n overflow-y: auto;\n padding: 16px;\n}\n\n.category-section[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.category-section[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.category-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--mj-text-secondary);\n letter-spacing: 0.5px;\n border-left: 3px solid var(--mj-brand-primary);\n background: var(--mj-bg-surface-card);\n border-radius: 0 8px 8px 0;\n margin-bottom: 8px;\n}\n\n.category-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.category-name[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.category-header[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 2px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n.type-items[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.type-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px 14px;\n background: var(--mj-bg-surface);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n border: 2px solid transparent;\n position: relative;\n}\n\n.type-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-page);\n border-color: var(--mj-border-default);\n}\n\n.type-item.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.type-icon[_ngcontent-%COMP%] {\n width: 42px;\n height: 42px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.type-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.type-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.type-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.type-description[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-disabled);\n margin-top: 2px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.type-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-top: 6px;\n}\n\n.meta-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 10px;\n font-size: 11px;\n color: var(--mj-text-secondary);\n}\n\n.meta-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 9px;\n}\n\n.meta-badge.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.meta-badge.warning[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.type-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n margin-right: 8px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.type-item[_ngcontent-%COMP%]:hover .type-actions[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.action-btn[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n font-size: 12px;\n}\n\n.action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.action-btn.danger[_ngcontent-%COMP%]:hover {\n background: var(--mj-status-error);\n}\n\n.arrow[_ngcontent-%COMP%] {\n color: var(--mj-border-strong);\n font-size: 12px;\n}\n\n\n\n.type-detail[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n overflow-y: auto;\n}\n\n.detail-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 24px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n}\n\n.detail-icon[_ngcontent-%COMP%] {\n width: 60px;\n height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 14px;\n margin-right: 16px;\n flex-shrink: 0;\n}\n\n.detail-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 26px;\n}\n\n.detail-title[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.detail-title[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0 0 8px 0;\n}\n\n.category-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.category-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n.detail-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.close-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all 0.2s ease;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.detail-body[_ngcontent-%COMP%] {\n padding: 24px;\n}\n\n\n\n.detail-stats[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n margin-bottom: 24px;\n padding-bottom: 24px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n}\n\n.detail-stat[_ngcontent-%COMP%] {\n flex: 1;\n text-align: center;\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border-radius: 12px;\n}\n\n.detail-stat[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.detail-stat[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n}\n\n.detail-stat.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n}\n\n.detail-stat.active[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.detail-stat.warning[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface));\n}\n\n.detail-stat.warning[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n.description[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n line-height: 1.6;\n margin: 0 0 24px 0;\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border-radius: 10px;\n}\n\n.schema-section[_ngcontent-%COMP%], \n.validation-section[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n\n.schema-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%], \n.validation-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 14px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0 0 16px 0;\n}\n\n.schema-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.validation-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.field-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.field-item[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border-radius: 10px;\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.field-item[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.field-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.field-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.field-badges[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.badge[_ngcontent-%COMP%] {\n padding: 3px 10px;\n border-radius: 6px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.badge.type[_ngcontent-%COMP%] {\n background: var(--mj-border-default);\n color: var(--mj-text-secondary);\n}\n\n.badge.secret[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.badge.secret[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 3px;\n}\n\n.badge.required[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.field-description[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n margin: 10px 0 0 0;\n line-height: 1.5;\n}\n\n.no-fields[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border-radius: 10px;\n color: var(--mj-text-disabled);\n font-size: 13px;\n}\n\n.no-fields[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.validation-endpoint[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 18px;\n background: var(--mj-bg-surface-card);\n border-radius: 10px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', monospace;\n border: 1px solid var(--mj-border-default);\n}\n\n.validation-endpoint[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.detail-quick-actions[_ngcontent-%COMP%] {\n margin-top: 24px;\n padding-top: 24px;\n border-top: 1px solid var(--mj-bg-surface-sunken);\n}\n\n\n\n.no-selection[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n padding: 48px;\n}\n\n.no-selection-icon[_ngcontent-%COMP%] {\n width: 80px;\n height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 20px;\n margin-bottom: 24px;\n}\n\n.no-selection-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.no-selection[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0 0 8px 0;\n}\n\n.no-selection[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin: 0;\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: 60px 24px;\n text-align: center;\n}\n\n.empty-icon[_ngcontent-%COMP%] {\n width: 72px;\n height: 72px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 18px;\n margin-bottom: 20px;\n}\n\n.empty-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.empty-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0 0 8px 0;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin: 0 0 20px 0;\n}\n\n.btn-link[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-brand-primary);\n font-size: 14px;\n cursor: pointer;\n text-decoration: underline;\n padding: 0;\n}\n\n.btn-link[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n\n\n@media (max-width: 1024px) {\n .types-layout[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .types-list[_ngcontent-%COMP%] {\n max-height: 400px;\n }\n}\n\n@media (max-width: 768px) {\n .types-container[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .types-header[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .toolbar[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n }\n\n .toolbar-left[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .search-container[_ngcontent-%COMP%] {\n min-width: 100%;\n }\n\n .filter-select[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .toolbar-right[_ngcontent-%COMP%] {\n justify-content: space-between;\n }\n\n .detail-stats[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n}"], changeDetection: 0 });
|
|
863
863
|
};
|
|
864
864
|
CredentialsTypesResourceComponent = __decorate([
|
|
865
865
|
RegisterClass(BaseResourceComponent, 'CredentialsTypesResource')
|
|
@@ -867,7 +867,7 @@ CredentialsTypesResourceComponent = __decorate([
|
|
|
867
867
|
export { CredentialsTypesResourceComponent };
|
|
868
868
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(CredentialsTypesResourceComponent, [{
|
|
869
869
|
type: Component,
|
|
870
|
-
args: [{ standalone: false, selector: 'mj-credentials-types-resource', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"types-container\">\n @if (isLoading) {\n <mj-loading text=\"Loading credential types...\"></mj-loading>\n }\n\n @if (!isLoading) {\n <!-- Header -->\n <div class=\"types-header\">\n <div class=\"header-info\">\n <h2 class=\"types-title\">Credential Types</h2>\n <div class=\"header-stats\">\n <span class=\"stat-item\">\n <i class=\"fa-solid fa-shapes\"></i>\n {{types.length}} types\n </span>\n <span class=\"stat-item\">\n <i class=\"fa-solid fa-folder\"></i>\n {{categories.length}} categories\n </span>\n <span class=\"stat-item\">\n <i class=\"fa-solid fa-key\"></i>\n {{getTotalCredentialCount()}} credentials\n </span>\n </div>\n </div>\n <div class=\"header-actions\">\n @if (UserCanCreate) {\n <button class=\"btn-primary\" (click)=\"createNewType()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New Type</span>\n </button>\n }\n </div>\n </div>\n <!-- Toolbar -->\n <div class=\"toolbar\">\n <div class=\"toolbar-left\">\n <div class=\"search-container\">\n <i class=\"fa-solid fa-search\"></i>\n <input\n type=\"text\"\n placeholder=\"Search types...\"\n [value]=\"searchText\"\n (input)=\"onSearchChange($any($event.target).value)\"\n />\n @if (searchText) {\n <button class=\"search-clear\" (click)=\"onSearchChange('')\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n <select\n class=\"filter-select\"\n [value]=\"selectedCategoryFilter\"\n (change)=\"onCategoryFilterChange($any($event.target).value)\"\n >\n <option value=\"\">All Categories</option>\n @for (cat of categories; track cat) {\n <option [value]=\"cat\">{{cat}}</option>\n }\n </select>\n </div>\n <div class=\"toolbar-right\">\n <div class=\"results-info\">\n {{filteredTypes.length}} of {{types.length}} types\n </div>\n <button class=\"btn-icon\" (click)=\"refresh()\" title=\"Refresh\">\n <i class=\"fa-solid fa-refresh\"></i>\n </button>\n </div>\n </div>\n <div class=\"types-layout\">\n <!-- Types List -->\n <div class=\"types-list\">\n @for (entry of getTypesByCategory() | keyvalue; track entry) {\n <div class=\"category-section\">\n <div class=\"category-header\" [style.borderLeftColor]=\"getCategoryColor(entry.key)\">\n <i [class]=\"getCategoryIcon(entry.key)\" [style.color]=\"getCategoryColor(entry.key)\"></i>\n <span class=\"category-name\">{{entry.key}}</span>\n <span class=\"count\">{{entry.value.length}}</span>\n </div>\n <div class=\"type-items\">\n @for (type of entry.value; track type) {\n <div\n class=\"type-item\"\n [class.selected]=\"IsTypeSelected(type)\"\n (click)=\"selectType(type)\"\n >\n <div class=\"type-icon\" [style.backgroundColor]=\"getCategoryColor(type.Category) + '15'\" [style.color]=\"getCategoryColor(type.Category)\">\n <i [class]=\"type.IconClass || 'fa-solid fa-key'\"></i>\n </div>\n <div class=\"type-info\">\n <div class=\"type-name\">{{type.Name}}</div>\n @if (type.Description) {\n <div class=\"type-description\">\n {{type.Description | slice:0:60}}{{type.Description.length > 60 ? '...' : ''}}\n </div>\n }\n <div class=\"type-meta\">\n @if (type.credentialCount > 0) {\n <span class=\"meta-badge\">\n <i class=\"fa-solid fa-key\"></i>\n {{type.credentialCount}}\n </span>\n }\n @if (type.activeCount > 0) {\n <span class=\"meta-badge active\">\n <i class=\"fa-solid fa-check\"></i>\n {{type.activeCount}} active\n </span>\n }\n @if (type.expiringCount > 0) {\n <span class=\"meta-badge warning\">\n <i class=\"fa-solid fa-clock\"></i>\n {{type.expiringCount}} expiring\n </span>\n }\n </div>\n </div>\n <div class=\"type-actions\">\n @if (UserCanCreateCredential) {\n <button\n class=\"action-btn\"\n (click)=\"createCredentialForType(type, $event)\"\n title=\"Add Credential\"\n >\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n }\n @if (UserCanUpdate) {\n <button\n class=\"action-btn\"\n (click)=\"editType(type, $event)\"\n title=\"Edit Type\"\n >\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n }\n @if (UserCanDelete && type.credentialCount === 0) {\n <button\n class=\"action-btn danger\"\n (click)=\"deleteType(type, $event)\"\n title=\"Delete Type\"\n >\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n }\n </div>\n <i class=\"fa-solid fa-chevron-right arrow\"></i>\n </div>\n }\n </div>\n </div>\n }\n @if (filteredTypes.length === 0) {\n <div class=\"empty-state\">\n <div class=\"empty-icon\">\n <i class=\"fa-solid fa-cubes\"></i>\n </div>\n <h3>No Credential Types Found</h3>\n @if (searchText || selectedCategoryFilter) {\n <p>\n No types match your current filters.\n <button class=\"btn-link\" (click)=\"clearFilters()\">Clear filters</button>\n </p>\n }\n @if (!searchText && !selectedCategoryFilter) {\n <p>\n Get started by creating your first credential type.\n </p>\n }\n @if (UserCanCreate && !searchText && !selectedCategoryFilter) {\n <button class=\"btn-primary\" (click)=\"createNewType()\">\n <i class=\"fa-solid fa-plus\"></i>\n Create Type\n </button>\n }\n </div>\n }\n </div>\n <!-- Type Detail -->\n @if (selectedType) {\n <div class=\"type-detail\">\n <div class=\"detail-header\">\n <div class=\"detail-icon\" [style.backgroundColor]=\"getCategoryColor(selectedType.Category) + '15'\" [style.color]=\"getCategoryColor(selectedType.Category)\">\n <i [class]=\"selectedType.IconClass || 'fa-solid fa-key'\"></i>\n </div>\n <div class=\"detail-title\">\n <h2>{{selectedType.Name}}</h2>\n <span class=\"category-badge\" [style.backgroundColor]=\"getCategoryColor(selectedType.Category) + '20'\" [style.color]=\"getCategoryColor(selectedType.Category)\">\n <i [class]=\"getCategoryIcon(selectedType.Category)\"></i>\n {{selectedType.Category}}\n </span>\n </div>\n <div class=\"detail-actions\">\n @if (UserCanUpdate) {\n <button class=\"action-btn\" (click)=\"editType(selectedType)\" title=\"Edit\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n }\n <button class=\"close-btn\" (click)=\"closeDetail()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n <div class=\"detail-body\">\n <!-- Stats Row -->\n <div class=\"detail-stats\">\n <div class=\"detail-stat\">\n <div class=\"stat-value\">{{selectedType.credentialCount}}</div>\n <div class=\"stat-label\">Credentials</div>\n </div>\n <div class=\"detail-stat active\">\n <div class=\"stat-value\">{{selectedType.activeCount}}</div>\n <div class=\"stat-label\">Active</div>\n </div>\n @if (selectedType.expiringCount > 0) {\n <div class=\"detail-stat warning\">\n <div class=\"stat-value\">{{selectedType.expiringCount}}</div>\n <div class=\"stat-label\">Expiring</div>\n </div>\n }\n </div>\n @if (selectedType.Description) {\n <p class=\"description\">\n {{selectedType.Description}}\n </p>\n }\n <div class=\"schema-section\">\n <h3>\n <i class=\"fa-solid fa-list-check\"></i>\n Field Schema\n </h3>\n @if (schemaProperties.length > 0) {\n <div class=\"field-list\">\n @for (prop of schemaProperties; track prop) {\n <div class=\"field-item\">\n <div class=\"field-header\">\n <span class=\"field-name\">{{prop.title}}</span>\n <span class=\"field-badges\">\n <span class=\"badge type\">{{prop.type}}</span>\n @if (prop.isSecret) {\n <span class=\"badge secret\">\n <i class=\"fa-solid fa-lock\"></i> Secret\n </span>\n }\n @if (prop.required) {\n <span class=\"badge required\">Required</span>\n }\n </span>\n </div>\n @if (prop.description) {\n <p class=\"field-description\">\n {{prop.description}}\n </p>\n }\n </div>\n }\n </div>\n }\n @if (schemaProperties.length === 0) {\n <div class=\"no-fields\">\n <i class=\"fa-solid fa-info-circle\"></i>\n <span>No fields defined in schema</span>\n </div>\n }\n </div>\n @if (selectedType.ValidationEndpoint) {\n <div class=\"validation-section\">\n <h3>\n <i class=\"fa-solid fa-check-circle\"></i>\n Validation\n </h3>\n <div class=\"validation-endpoint\">\n <i class=\"fa-solid fa-link\"></i>\n <span>{{selectedType.ValidationEndpoint}}</span>\n </div>\n </div>\n }\n <!-- Quick Actions -->\n @if (UserCanCreateCredential) {\n <div class=\"detail-quick-actions\">\n <button class=\"btn-primary\" (click)=\"createCredentialForType(selectedType)\">\n <i class=\"fa-solid fa-plus\"></i>\n Create Credential\n </button>\n </div>\n }\n </div>\n </div>\n }\n <!-- No Selection -->\n @if (!selectedType && filteredTypes.length > 0) {\n <div class=\"no-selection\">\n <div class=\"no-selection-icon\">\n <i class=\"fa-solid fa-hand-pointer\"></i>\n </div>\n <h3>Select a Credential Type</h3>\n <p>Click on a credential type to view its details and field schema</p>\n </div>\n }\n </div>\n }\n</div>\n\n<!-- Type Edit Panel -->\n<mj-credential-type-edit-panel\n #typeEditPanel\n (saved)=\"onTypeSaved($any($event))\"\n (deleted)=\"onTypeDeleted($any($event))\"\n></mj-credential-type-edit-panel>\n", styles: [".types-container {\n height: 100%;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n padding: 24px;\n background: var(--page-background, #f8fafc);\n}\n\n/* Header */\n.types-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-info {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.types-title {\n font-size: 24px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0;\n}\n\n.header-stats {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.stat-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n}\n\n.stat-item i {\n font-size: 12px;\n}\n\n.header-actions {\n display: flex;\n gap: 12px;\n}\n\n.btn-primary {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);\n color: white;\n border: none;\n border-radius: 10px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px rgba(99, 102, 241, 0.3);\n}\n\n.btn-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 16px rgba(99, 102, 241, 0.4);\n}\n\n.btn-primary i {\n font-size: 13px;\n}\n\n/* Toolbar */\n.toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 16px;\n flex-wrap: wrap;\n background: var(--card-background, #ffffff);\n padding: 16px;\n border-radius: 12px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n}\n\n.toolbar-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n flex: 1;\n}\n\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.search-container {\n display: flex;\n align-items: center;\n background: var(--input-background, #f9fafb);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n padding: 8px 12px;\n min-width: 240px;\n position: relative;\n}\n\n.search-container i {\n color: var(--text-secondary, #6b7280);\n margin-right: 8px;\n}\n\n.search-container input {\n border: none;\n background: transparent;\n outline: none;\n flex: 1;\n font-size: 14px;\n color: var(--text-primary, #1f2937);\n}\n\n.search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--border-color, #e5e7eb);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n color: var(--text-secondary, #6b7280);\n font-size: 10px;\n}\n\n.search-clear:hover {\n background: var(--text-secondary, #6b7280);\n color: white;\n}\n\n.filter-select {\n padding: 8px 12px;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n background: var(--input-background, #ffffff);\n font-size: 14px;\n color: var(--text-primary, #1f2937);\n cursor: pointer;\n min-width: 160px;\n}\n\n.results-info {\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n white-space: nowrap;\n}\n\n.btn-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n background: var(--button-background, #ffffff);\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon:hover {\n background: var(--button-hover, #f3f4f6);\n color: var(--accent-color, #6366f1);\n}\n\n/* Layout */\n.types-layout {\n display: grid;\n grid-template-columns: 420px 1fr;\n flex: 1;\n min-height: 0;\n gap: 20px;\n}\n\n/* Types List */\n.types-list {\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n overflow-y: auto;\n padding: 16px;\n}\n\n.category-section {\n margin-bottom: 20px;\n}\n\n.category-section:last-child {\n margin-bottom: 0;\n}\n\n.category-header {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--text-secondary, #6b7280);\n letter-spacing: 0.5px;\n border-left: 3px solid var(--accent-color, #6366f1);\n background: var(--header-background, #f9fafb);\n border-radius: 0 8px 8px 0;\n margin-bottom: 8px;\n}\n\n.category-header i {\n font-size: 14px;\n}\n\n.category-name {\n flex: 1;\n}\n\n.category-header .count {\n background: white;\n padding: 2px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n.type-items {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.type-item {\n display: flex;\n align-items: center;\n padding: 12px 14px;\n background: var(--item-background, #ffffff);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n border: 2px solid transparent;\n position: relative;\n}\n\n.type-item:hover {\n background: var(--item-hover, #f8fafc);\n border-color: var(--border-color, #e5e7eb);\n}\n\n.type-item.selected {\n background: linear-gradient(to right, rgba(99, 102, 241, 0.05), white);\n border-color: var(--accent-color, #6366f1);\n}\n\n.type-icon {\n width: 42px;\n height: 42px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.type-icon i {\n font-size: 16px;\n}\n\n.type-info {\n flex: 1;\n min-width: 0;\n}\n\n.type-name {\n font-weight: 600;\n font-size: 14px;\n color: var(--text-primary, #1f2937);\n}\n\n.type-description {\n font-size: 12px;\n color: var(--text-secondary, #9ca3af);\n margin-top: 2px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.type-meta {\n display: flex;\n gap: 8px;\n margin-top: 6px;\n}\n\n.meta-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n background: var(--badge-background, #f3f4f6);\n border-radius: 10px;\n font-size: 11px;\n color: var(--text-secondary, #6b7280);\n}\n\n.meta-badge i {\n font-size: 9px;\n}\n\n.meta-badge.active {\n background: #d1fae5;\n color: #059669;\n}\n\n.meta-badge.warning {\n background: #fef3c7;\n color: #d97706;\n}\n\n.type-actions {\n display: flex;\n gap: 4px;\n margin-right: 8px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.type-item:hover .type-actions {\n opacity: 1;\n}\n\n.action-btn {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: var(--input-background, #f3f4f6);\n border-radius: 6px;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n font-size: 12px;\n}\n\n.action-btn:hover {\n background: var(--accent-color, #6366f1);\n color: white;\n}\n\n.action-btn.danger:hover {\n background: #ef4444;\n}\n\n.arrow {\n color: var(--text-tertiary, #d1d5db);\n font-size: 12px;\n}\n\n/* Type Detail */\n.type-detail {\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n overflow-y: auto;\n}\n\n.detail-header {\n display: flex;\n align-items: center;\n padding: 24px;\n border-bottom: 1px solid var(--border-color, #f3f4f6);\n}\n\n.detail-icon {\n width: 60px;\n height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 14px;\n margin-right: 16px;\n flex-shrink: 0;\n}\n\n.detail-icon i {\n font-size: 26px;\n}\n\n.detail-title {\n flex: 1;\n}\n\n.detail-title h2 {\n font-size: 22px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0 0 8px 0;\n}\n\n.category-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.category-badge i {\n font-size: 11px;\n}\n\n.detail-actions {\n display: flex;\n gap: 8px;\n}\n\n.close-btn {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: var(--button-background, #f3f4f6);\n border-radius: 8px;\n cursor: pointer;\n color: var(--text-secondary, #6b7280);\n transition: all 0.2s ease;\n}\n\n.close-btn:hover {\n background: var(--button-hover, #e5e7eb);\n color: var(--text-primary, #1f2937);\n}\n\n.detail-body {\n padding: 24px;\n}\n\n/* Detail Stats */\n.detail-stats {\n display: flex;\n gap: 16px;\n margin-bottom: 24px;\n padding-bottom: 24px;\n border-bottom: 1px solid var(--border-color, #f3f4f6);\n}\n\n.detail-stat {\n flex: 1;\n text-align: center;\n padding: 16px;\n background: var(--stat-background, #f9fafb);\n border-radius: 12px;\n}\n\n.detail-stat .stat-value {\n font-size: 28px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n}\n\n.detail-stat .stat-label {\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n margin-top: 4px;\n}\n\n.detail-stat.active {\n background: linear-gradient(135deg, rgba(16, 185, 129, 0.1) 0%, rgba(5, 150, 105, 0.05) 100%);\n}\n\n.detail-stat.active .stat-value {\n color: #059669;\n}\n\n.detail-stat.warning {\n background: linear-gradient(135deg, rgba(245, 158, 11, 0.1) 0%, rgba(217, 119, 6, 0.05) 100%);\n}\n\n.detail-stat.warning .stat-value {\n color: #d97706;\n}\n\n.description {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n line-height: 1.6;\n margin: 0 0 24px 0;\n padding: 16px;\n background: var(--description-background, #f9fafb);\n border-radius: 10px;\n}\n\n.schema-section,\n.validation-section {\n margin-bottom: 24px;\n}\n\n.schema-section h3,\n.validation-section h3 {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 14px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0 0 16px 0;\n}\n\n.schema-section h3 i,\n.validation-section h3 i {\n color: var(--accent-color, #6366f1);\n}\n\n.field-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.field-item {\n padding: 16px;\n background: var(--field-background, #f9fafb);\n border-radius: 10px;\n border: 1px solid var(--border-color, #e5e7eb);\n transition: all 0.2s ease;\n}\n\n.field-item:hover {\n border-color: var(--accent-color, #6366f1);\n background: var(--field-hover, #f3f4f6);\n}\n\n.field-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.field-name {\n font-weight: 600;\n font-size: 14px;\n color: var(--text-primary, #1f2937);\n}\n\n.field-badges {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.badge {\n padding: 3px 10px;\n border-radius: 6px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.badge.type {\n background: var(--type-badge, #e5e7eb);\n color: var(--text-secondary, #6b7280);\n}\n\n.badge.secret {\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);\n color: #b45309;\n}\n\n.badge.secret i {\n margin-right: 3px;\n}\n\n.badge.required {\n background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);\n color: #b91c1c;\n}\n\n.field-description {\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n margin: 10px 0 0 0;\n line-height: 1.5;\n}\n\n.no-fields {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px;\n background: var(--field-background, #f9fafb);\n border-radius: 10px;\n color: var(--text-secondary, #9ca3af);\n font-size: 13px;\n}\n\n.no-fields i {\n color: var(--accent-color, #6366f1);\n}\n\n.validation-endpoint {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 18px;\n background: var(--endpoint-background, #f9fafb);\n border-radius: 10px;\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', monospace;\n border: 1px solid var(--border-color, #e5e7eb);\n}\n\n.validation-endpoint i {\n color: var(--accent-color, #6366f1);\n}\n\n.detail-quick-actions {\n margin-top: 24px;\n padding-top: 24px;\n border-top: 1px solid var(--border-color, #f3f4f6);\n}\n\n/* No Selection */\n.no-selection {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n padding: 48px;\n}\n\n.no-selection-icon {\n width: 80px;\n height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%);\n border-radius: 20px;\n margin-bottom: 24px;\n}\n\n.no-selection-icon i {\n font-size: 32px;\n color: var(--accent-color, #6366f1);\n}\n\n.no-selection h3 {\n font-size: 18px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0 0 8px 0;\n}\n\n.no-selection p {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n margin: 0;\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n}\n\n.empty-icon {\n width: 72px;\n height: 72px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%);\n border-radius: 18px;\n margin-bottom: 20px;\n}\n\n.empty-icon i {\n font-size: 32px;\n color: var(--accent-color, #6366f1);\n}\n\n.empty-state h3 {\n font-size: 18px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0 0 8px 0;\n}\n\n.empty-state p {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n margin: 0 0 20px 0;\n}\n\n.btn-link {\n background: none;\n border: none;\n color: var(--accent-color, #6366f1);\n font-size: 14px;\n cursor: pointer;\n text-decoration: underline;\n padding: 0;\n}\n\n.btn-link:hover {\n color: var(--accent-hover, #4f46e5);\n}\n\n/* Responsive */\n@media (max-width: 1024px) {\n .types-layout {\n grid-template-columns: 1fr;\n }\n\n .types-list {\n max-height: 400px;\n }\n}\n\n@media (max-width: 768px) {\n .types-container {\n padding: 16px;\n }\n\n .types-header {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .toolbar {\n flex-direction: column;\n align-items: stretch;\n }\n\n .toolbar-left {\n flex-direction: column;\n }\n\n .search-container {\n min-width: 100%;\n }\n\n .filter-select {\n width: 100%;\n }\n\n .toolbar-right {\n justify-content: space-between;\n }\n\n .detail-stats {\n flex-direction: column;\n }\n}\n"] }]
|
|
870
|
+
args: [{ standalone: false, selector: 'mj-credentials-types-resource', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"types-container\">\n @if (isLoading) {\n <mj-loading text=\"Loading credential types...\"></mj-loading>\n }\n\n @if (!isLoading) {\n <!-- Header -->\n <div class=\"types-header\">\n <div class=\"header-info\">\n <h2 class=\"types-title\">Credential Types</h2>\n <div class=\"header-stats\">\n <span class=\"stat-item\">\n <i class=\"fa-solid fa-shapes\"></i>\n {{types.length}} types\n </span>\n <span class=\"stat-item\">\n <i class=\"fa-solid fa-folder\"></i>\n {{categories.length}} categories\n </span>\n <span class=\"stat-item\">\n <i class=\"fa-solid fa-key\"></i>\n {{getTotalCredentialCount()}} credentials\n </span>\n </div>\n </div>\n <div class=\"header-actions\">\n @if (UserCanCreate) {\n <button class=\"btn-primary\" (click)=\"createNewType()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New Type</span>\n </button>\n }\n </div>\n </div>\n <!-- Toolbar -->\n <div class=\"toolbar\">\n <div class=\"toolbar-left\">\n <div class=\"search-container\">\n <i class=\"fa-solid fa-search\"></i>\n <input\n type=\"text\"\n placeholder=\"Search types...\"\n [value]=\"searchText\"\n (input)=\"onSearchChange($any($event.target).value)\"\n />\n @if (searchText) {\n <button class=\"search-clear\" (click)=\"onSearchChange('')\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n <select\n class=\"filter-select\"\n [value]=\"selectedCategoryFilter\"\n (change)=\"onCategoryFilterChange($any($event.target).value)\"\n >\n <option value=\"\">All Categories</option>\n @for (cat of categories; track cat) {\n <option [value]=\"cat\">{{cat}}</option>\n }\n </select>\n </div>\n <div class=\"toolbar-right\">\n <div class=\"results-info\">\n {{filteredTypes.length}} of {{types.length}} types\n </div>\n <button class=\"btn-icon\" (click)=\"refresh()\" title=\"Refresh\">\n <i class=\"fa-solid fa-refresh\"></i>\n </button>\n </div>\n </div>\n <div class=\"types-layout\">\n <!-- Types List -->\n <div class=\"types-list\">\n @for (entry of getTypesByCategory() | keyvalue; track entry) {\n <div class=\"category-section\">\n <div class=\"category-header\" [style.borderLeftColor]=\"getCategoryColor(entry.key)\">\n <i [class]=\"getCategoryIcon(entry.key)\" [style.color]=\"getCategoryColor(entry.key)\"></i>\n <span class=\"category-name\">{{entry.key}}</span>\n <span class=\"count\">{{entry.value.length}}</span>\n </div>\n <div class=\"type-items\">\n @for (type of entry.value; track type) {\n <div\n class=\"type-item\"\n [class.selected]=\"IsTypeSelected(type)\"\n (click)=\"selectType(type)\"\n >\n <div class=\"type-icon\" [style.backgroundColor]=\"getCategoryColor(type.Category) + '15'\" [style.color]=\"getCategoryColor(type.Category)\">\n <i [class]=\"type.IconClass || 'fa-solid fa-key'\"></i>\n </div>\n <div class=\"type-info\">\n <div class=\"type-name\">{{type.Name}}</div>\n @if (type.Description) {\n <div class=\"type-description\">\n {{type.Description | slice:0:60}}{{type.Description.length > 60 ? '...' : ''}}\n </div>\n }\n <div class=\"type-meta\">\n @if (type.credentialCount > 0) {\n <span class=\"meta-badge\">\n <i class=\"fa-solid fa-key\"></i>\n {{type.credentialCount}}\n </span>\n }\n @if (type.activeCount > 0) {\n <span class=\"meta-badge active\">\n <i class=\"fa-solid fa-check\"></i>\n {{type.activeCount}} active\n </span>\n }\n @if (type.expiringCount > 0) {\n <span class=\"meta-badge warning\">\n <i class=\"fa-solid fa-clock\"></i>\n {{type.expiringCount}} expiring\n </span>\n }\n </div>\n </div>\n <div class=\"type-actions\">\n @if (UserCanCreateCredential) {\n <button\n class=\"action-btn\"\n (click)=\"createCredentialForType(type, $event)\"\n title=\"Add Credential\"\n >\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n }\n @if (UserCanUpdate) {\n <button\n class=\"action-btn\"\n (click)=\"editType(type, $event)\"\n title=\"Edit Type\"\n >\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n }\n @if (UserCanDelete && type.credentialCount === 0) {\n <button\n class=\"action-btn danger\"\n (click)=\"deleteType(type, $event)\"\n title=\"Delete Type\"\n >\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n }\n </div>\n <i class=\"fa-solid fa-chevron-right arrow\"></i>\n </div>\n }\n </div>\n </div>\n }\n @if (filteredTypes.length === 0) {\n <div class=\"empty-state\">\n <div class=\"empty-icon\">\n <i class=\"fa-solid fa-cubes\"></i>\n </div>\n <h3>No Credential Types Found</h3>\n @if (searchText || selectedCategoryFilter) {\n <p>\n No types match your current filters.\n <button class=\"btn-link\" (click)=\"clearFilters()\">Clear filters</button>\n </p>\n }\n @if (!searchText && !selectedCategoryFilter) {\n <p>\n Get started by creating your first credential type.\n </p>\n }\n @if (UserCanCreate && !searchText && !selectedCategoryFilter) {\n <button class=\"btn-primary\" (click)=\"createNewType()\">\n <i class=\"fa-solid fa-plus\"></i>\n Create Type\n </button>\n }\n </div>\n }\n </div>\n <!-- Type Detail -->\n @if (selectedType) {\n <div class=\"type-detail\">\n <div class=\"detail-header\">\n <div class=\"detail-icon\" [style.backgroundColor]=\"getCategoryColor(selectedType.Category) + '15'\" [style.color]=\"getCategoryColor(selectedType.Category)\">\n <i [class]=\"selectedType.IconClass || 'fa-solid fa-key'\"></i>\n </div>\n <div class=\"detail-title\">\n <h2>{{selectedType.Name}}</h2>\n <span class=\"category-badge\" [style.backgroundColor]=\"getCategoryColor(selectedType.Category) + '20'\" [style.color]=\"getCategoryColor(selectedType.Category)\">\n <i [class]=\"getCategoryIcon(selectedType.Category)\"></i>\n {{selectedType.Category}}\n </span>\n </div>\n <div class=\"detail-actions\">\n @if (UserCanUpdate) {\n <button class=\"action-btn\" (click)=\"editType(selectedType)\" title=\"Edit\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n }\n <button class=\"close-btn\" (click)=\"closeDetail()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n <div class=\"detail-body\">\n <!-- Stats Row -->\n <div class=\"detail-stats\">\n <div class=\"detail-stat\">\n <div class=\"stat-value\">{{selectedType.credentialCount}}</div>\n <div class=\"stat-label\">Credentials</div>\n </div>\n <div class=\"detail-stat active\">\n <div class=\"stat-value\">{{selectedType.activeCount}}</div>\n <div class=\"stat-label\">Active</div>\n </div>\n @if (selectedType.expiringCount > 0) {\n <div class=\"detail-stat warning\">\n <div class=\"stat-value\">{{selectedType.expiringCount}}</div>\n <div class=\"stat-label\">Expiring</div>\n </div>\n }\n </div>\n @if (selectedType.Description) {\n <p class=\"description\">\n {{selectedType.Description}}\n </p>\n }\n <div class=\"schema-section\">\n <h3>\n <i class=\"fa-solid fa-list-check\"></i>\n Field Schema\n </h3>\n @if (schemaProperties.length > 0) {\n <div class=\"field-list\">\n @for (prop of schemaProperties; track prop) {\n <div class=\"field-item\">\n <div class=\"field-header\">\n <span class=\"field-name\">{{prop.title}}</span>\n <span class=\"field-badges\">\n <span class=\"badge type\">{{prop.type}}</span>\n @if (prop.isSecret) {\n <span class=\"badge secret\">\n <i class=\"fa-solid fa-lock\"></i> Secret\n </span>\n }\n @if (prop.required) {\n <span class=\"badge required\">Required</span>\n }\n </span>\n </div>\n @if (prop.description) {\n <p class=\"field-description\">\n {{prop.description}}\n </p>\n }\n </div>\n }\n </div>\n }\n @if (schemaProperties.length === 0) {\n <div class=\"no-fields\">\n <i class=\"fa-solid fa-info-circle\"></i>\n <span>No fields defined in schema</span>\n </div>\n }\n </div>\n @if (selectedType.ValidationEndpoint) {\n <div class=\"validation-section\">\n <h3>\n <i class=\"fa-solid fa-check-circle\"></i>\n Validation\n </h3>\n <div class=\"validation-endpoint\">\n <i class=\"fa-solid fa-link\"></i>\n <span>{{selectedType.ValidationEndpoint}}</span>\n </div>\n </div>\n }\n <!-- Quick Actions -->\n @if (UserCanCreateCredential) {\n <div class=\"detail-quick-actions\">\n <button class=\"btn-primary\" (click)=\"createCredentialForType(selectedType)\">\n <i class=\"fa-solid fa-plus\"></i>\n Create Credential\n </button>\n </div>\n }\n </div>\n </div>\n }\n <!-- No Selection -->\n @if (!selectedType && filteredTypes.length > 0) {\n <div class=\"no-selection\">\n <div class=\"no-selection-icon\">\n <i class=\"fa-solid fa-hand-pointer\"></i>\n </div>\n <h3>Select a Credential Type</h3>\n <p>Click on a credential type to view its details and field schema</p>\n </div>\n }\n </div>\n }\n</div>\n\n<!-- Type Edit Panel -->\n<mj-credential-type-edit-panel\n #typeEditPanel\n (saved)=\"onTypeSaved($any($event))\"\n (deleted)=\"onTypeDeleted($any($event))\"\n></mj-credential-type-edit-panel>\n", styles: [".types-container {\n height: 100%;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n padding: 24px;\n background: var(--mj-bg-page);\n}\n\n/* Header */\n.types-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-info {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.types-title {\n font-size: 24px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.header-stats {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.stat-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.stat-item i {\n font-size: 12px;\n}\n\n.header-actions {\n display: flex;\n gap: 12px;\n}\n\n.btn-primary {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 10px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n.btn-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n.btn-primary i {\n font-size: 13px;\n}\n\n/* Toolbar */\n.toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 16px;\n flex-wrap: wrap;\n background: var(--mj-bg-surface);\n padding: 16px;\n border-radius: 12px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n}\n\n.toolbar-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n flex: 1;\n}\n\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.search-container {\n display: flex;\n align-items: center;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 8px 12px;\n min-width: 240px;\n position: relative;\n}\n\n.search-container i {\n color: var(--mj-text-secondary);\n margin-right: 8px;\n}\n\n.search-container input {\n border: none;\n background: transparent;\n outline: none;\n flex: 1;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-border-default);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 10px;\n}\n\n.search-clear:hover {\n background: var(--mj-text-secondary);\n color: var(--mj-text-inverse);\n}\n\n.filter-select {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n min-width: 160px;\n}\n\n.results-info {\n font-size: 13px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}\n\n.btn-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n/* Layout */\n.types-layout {\n display: grid;\n grid-template-columns: 420px 1fr;\n flex: 1;\n min-height: 0;\n gap: 20px;\n}\n\n/* Types List */\n.types-list {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n overflow-y: auto;\n padding: 16px;\n}\n\n.category-section {\n margin-bottom: 20px;\n}\n\n.category-section:last-child {\n margin-bottom: 0;\n}\n\n.category-header {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--mj-text-secondary);\n letter-spacing: 0.5px;\n border-left: 3px solid var(--mj-brand-primary);\n background: var(--mj-bg-surface-card);\n border-radius: 0 8px 8px 0;\n margin-bottom: 8px;\n}\n\n.category-header i {\n font-size: 14px;\n}\n\n.category-name {\n flex: 1;\n}\n\n.category-header .count {\n background: var(--mj-bg-surface);\n padding: 2px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n.type-items {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.type-item {\n display: flex;\n align-items: center;\n padding: 12px 14px;\n background: var(--mj-bg-surface);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n border: 2px solid transparent;\n position: relative;\n}\n\n.type-item:hover {\n background: var(--mj-bg-page);\n border-color: var(--mj-border-default);\n}\n\n.type-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.type-icon {\n width: 42px;\n height: 42px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.type-icon i {\n font-size: 16px;\n}\n\n.type-info {\n flex: 1;\n min-width: 0;\n}\n\n.type-name {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.type-description {\n font-size: 12px;\n color: var(--mj-text-disabled);\n margin-top: 2px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.type-meta {\n display: flex;\n gap: 8px;\n margin-top: 6px;\n}\n\n.meta-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 10px;\n font-size: 11px;\n color: var(--mj-text-secondary);\n}\n\n.meta-badge i {\n font-size: 9px;\n}\n\n.meta-badge.active {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.meta-badge.warning {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.type-actions {\n display: flex;\n gap: 4px;\n margin-right: 8px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.type-item:hover .type-actions {\n opacity: 1;\n}\n\n.action-btn {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n font-size: 12px;\n}\n\n.action-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.action-btn.danger:hover {\n background: var(--mj-status-error);\n}\n\n.arrow {\n color: var(--mj-border-strong);\n font-size: 12px;\n}\n\n/* Type Detail */\n.type-detail {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n overflow-y: auto;\n}\n\n.detail-header {\n display: flex;\n align-items: center;\n padding: 24px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n}\n\n.detail-icon {\n width: 60px;\n height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 14px;\n margin-right: 16px;\n flex-shrink: 0;\n}\n\n.detail-icon i {\n font-size: 26px;\n}\n\n.detail-title {\n flex: 1;\n}\n\n.detail-title h2 {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0 0 8px 0;\n}\n\n.category-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.category-badge i {\n font-size: 11px;\n}\n\n.detail-actions {\n display: flex;\n gap: 8px;\n}\n\n.close-btn {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all 0.2s ease;\n}\n\n.close-btn:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.detail-body {\n padding: 24px;\n}\n\n/* Detail Stats */\n.detail-stats {\n display: flex;\n gap: 16px;\n margin-bottom: 24px;\n padding-bottom: 24px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n}\n\n.detail-stat {\n flex: 1;\n text-align: center;\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border-radius: 12px;\n}\n\n.detail-stat .stat-value {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.detail-stat .stat-label {\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n}\n\n.detail-stat.active {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n}\n\n.detail-stat.active .stat-value {\n color: var(--mj-status-success);\n}\n\n.detail-stat.warning {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface));\n}\n\n.detail-stat.warning .stat-value {\n color: var(--mj-status-warning);\n}\n\n.description {\n font-size: 14px;\n color: var(--mj-text-secondary);\n line-height: 1.6;\n margin: 0 0 24px 0;\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border-radius: 10px;\n}\n\n.schema-section,\n.validation-section {\n margin-bottom: 24px;\n}\n\n.schema-section h3,\n.validation-section h3 {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 14px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0 0 16px 0;\n}\n\n.schema-section h3 i,\n.validation-section h3 i {\n color: var(--mj-brand-primary);\n}\n\n.field-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.field-item {\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border-radius: 10px;\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.field-item:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.field-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.field-name {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.field-badges {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.badge {\n padding: 3px 10px;\n border-radius: 6px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.badge.type {\n background: var(--mj-border-default);\n color: var(--mj-text-secondary);\n}\n\n.badge.secret {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.badge.secret i {\n margin-right: 3px;\n}\n\n.badge.required {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.field-description {\n font-size: 13px;\n color: var(--mj-text-secondary);\n margin: 10px 0 0 0;\n line-height: 1.5;\n}\n\n.no-fields {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border-radius: 10px;\n color: var(--mj-text-disabled);\n font-size: 13px;\n}\n\n.no-fields i {\n color: var(--mj-brand-primary);\n}\n\n.validation-endpoint {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 18px;\n background: var(--mj-bg-surface-card);\n border-radius: 10px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', monospace;\n border: 1px solid var(--mj-border-default);\n}\n\n.validation-endpoint i {\n color: var(--mj-brand-primary);\n}\n\n.detail-quick-actions {\n margin-top: 24px;\n padding-top: 24px;\n border-top: 1px solid var(--mj-bg-surface-sunken);\n}\n\n/* No Selection */\n.no-selection {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n padding: 48px;\n}\n\n.no-selection-icon {\n width: 80px;\n height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 20px;\n margin-bottom: 24px;\n}\n\n.no-selection-icon i {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.no-selection h3 {\n font-size: 18px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0 0 8px 0;\n}\n\n.no-selection p {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n}\n\n.empty-icon {\n width: 72px;\n height: 72px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 18px;\n margin-bottom: 20px;\n}\n\n.empty-icon i {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.empty-state h3 {\n font-size: 18px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0 0 8px 0;\n}\n\n.empty-state p {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin: 0 0 20px 0;\n}\n\n.btn-link {\n background: none;\n border: none;\n color: var(--mj-brand-primary);\n font-size: 14px;\n cursor: pointer;\n text-decoration: underline;\n padding: 0;\n}\n\n.btn-link:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n/* Responsive */\n@media (max-width: 1024px) {\n .types-layout {\n grid-template-columns: 1fr;\n }\n\n .types-list {\n max-height: 400px;\n }\n}\n\n@media (max-width: 768px) {\n .types-container {\n padding: 16px;\n }\n\n .types-header {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .toolbar {\n flex-direction: column;\n align-items: stretch;\n }\n\n .toolbar-left {\n flex-direction: column;\n }\n\n .search-container {\n min-width: 100%;\n }\n\n .filter-select {\n width: 100%;\n }\n\n .toolbar-right {\n justify-content: space-between;\n }\n\n .detail-stats {\n flex-direction: column;\n }\n}\n"] }]
|
|
871
871
|
}], () => [{ type: i0.ChangeDetectorRef }, { type: i1.NavigationService }], { typeEditPanel: [{
|
|
872
872
|
type: ViewChild,
|
|
873
873
|
args: ['typeEditPanel']
|