@memberjunction/ng-dashboards 5.10.1 → 5.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.d.ts +6 -2
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +26 -8
- 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.js +2 -2
- 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.js +2 -2
- 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.d.ts +55 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +664 -199
- 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
|
@@ -2346,7 +2346,7 @@ let MappingWorkspaceComponent = class MappingWorkspaceComponent extends BaseReso
|
|
|
2346
2346
|
return 'fa-solid fa-diagram-project';
|
|
2347
2347
|
}
|
|
2348
2348
|
static ɵfac = /*@__PURE__*/ (() => { let ɵMappingWorkspaceComponent_BaseFactory; return function MappingWorkspaceComponent_Factory(__ngFactoryType__) { return (ɵMappingWorkspaceComponent_BaseFactory || (ɵMappingWorkspaceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(MappingWorkspaceComponent)))(__ngFactoryType__ || MappingWorkspaceComponent); }; })();
|
|
2349
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MappingWorkspaceComponent, selectors: [["app-mapping-workspace"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 7, vars: 1, consts: [[1, "mapping-workspace"], [1, "workspace-header"], [1, "fa-solid", "fa-diagram-project"], ["text", "Loading integrations...", "size", "medium"], [1, "workspace-body"], [1, "left-panel"], [1, "integration-selector"], [1, "panel-label"], [3, "ngModelChange", "valueChange", "data", "textField", "valueField", "valuePrimitive", "ngModel", "defaultItem"], ["text", "Loading entity maps...", "size", "small"], [1, "center-panel"], [1, "placeholder-message"], [1, "pending-entity-panel"], ["text", "Loading field maps...", "size", "medium"], [1, "right-panel"], [1, "empty-hint"], ["text", "Loading...", "size", "small"], [1, "entity-map-header"], [1, "panel-label", 2, "margin", "0"], [1, "header-actions"], ["kendoButton", "", "title", "Add entity map", 3, "click", "look", "size"], [1, "fa-solid", "fa-plus"], [1, "add-map-panel"], [1, "search-box"], [1, "entity-map-list"], [1, "add-panel-top"], [1, "fa-solid", "fa-plus-circle"], [1, "add-panel-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "form-group"], [1, "source-loading"], [1, "discover-error-inline"], [3, "data", "textField", "valueField", "valuePrimitive", "ngModel", "filterable", "defaultItem"], [1, "target-mode-toggle"], [1, "target-mode-btn", 3, "click"], [1, "fa-solid", "fa-database"], [1, "fa-solid", "fa-wand-magic-sparkles"], [1, "new-entity-form"], [3, "ngModelChange", "data", "ngModel"], [1, "add-form-actions"], ["kendoButton", "", 3, "click", "themeColor", "size", "disabled"], ["kendoButton", "", 3, "click", "size"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-triangle-exclamation"], [3, "ngModelChange", "valueChange", "data", "textField", "valueField", "valuePrimitive", "ngModel", "filterable", "defaultItem"], [3, "ngModelChange", "data", "textField", "valueField", "valuePrimitive", "ngModel", "filterable", "defaultItem"], [1, "section-label"], [3, "ngModelChange", "valueChange", "data", "ngModel", "allowCustom", "filterable", "placeholder"], [1, "form-row"], ["kendoTextBox", "", 3, "ngModelChange", "ngModel", "placeholder"], [1, "auto-hint"], [1, "ddl-preview-section"], ["kendoButton", "", 3, "click", "look", "size", "disabled"], [1, "discover-error-inline", 2, "margin-top", "8px"], [1, "ddl-preview-code"], [1, "fa-solid", "fa-check"], ["kendoTextBox", "", "placeholder", "Search entity maps...", 3, "ngModelChange", "ngModel"], ["href", "javascript:void(0)", 2, "color", "
|
|
2349
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MappingWorkspaceComponent, selectors: [["app-mapping-workspace"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 7, vars: 1, consts: [[1, "mapping-workspace"], [1, "workspace-header"], [1, "fa-solid", "fa-diagram-project"], ["text", "Loading integrations...", "size", "medium"], [1, "workspace-body"], [1, "left-panel"], [1, "integration-selector"], [1, "panel-label"], [3, "ngModelChange", "valueChange", "data", "textField", "valueField", "valuePrimitive", "ngModel", "defaultItem"], ["text", "Loading entity maps...", "size", "small"], [1, "center-panel"], [1, "placeholder-message"], [1, "pending-entity-panel"], ["text", "Loading field maps...", "size", "medium"], [1, "right-panel"], [1, "empty-hint"], ["text", "Loading...", "size", "small"], [1, "entity-map-header"], [1, "panel-label", 2, "margin", "0"], [1, "header-actions"], ["kendoButton", "", "title", "Add entity map", 3, "click", "look", "size"], [1, "fa-solid", "fa-plus"], [1, "add-map-panel"], [1, "search-box"], [1, "entity-map-list"], [1, "add-panel-top"], [1, "fa-solid", "fa-plus-circle"], [1, "add-panel-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "form-group"], [1, "source-loading"], [1, "discover-error-inline"], [3, "data", "textField", "valueField", "valuePrimitive", "ngModel", "filterable", "defaultItem"], [1, "target-mode-toggle"], [1, "target-mode-btn", 3, "click"], [1, "fa-solid", "fa-database"], [1, "fa-solid", "fa-wand-magic-sparkles"], [1, "new-entity-form"], [3, "ngModelChange", "data", "ngModel"], [1, "add-form-actions"], ["kendoButton", "", 3, "click", "themeColor", "size", "disabled"], ["kendoButton", "", 3, "click", "size"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-triangle-exclamation"], [3, "ngModelChange", "valueChange", "data", "textField", "valueField", "valuePrimitive", "ngModel", "filterable", "defaultItem"], [3, "ngModelChange", "data", "textField", "valueField", "valuePrimitive", "ngModel", "filterable", "defaultItem"], [1, "section-label"], [3, "ngModelChange", "valueChange", "data", "ngModel", "allowCustom", "filterable", "placeholder"], [1, "form-row"], ["kendoTextBox", "", 3, "ngModelChange", "ngModel", "placeholder"], [1, "auto-hint"], [1, "ddl-preview-section"], ["kendoButton", "", 3, "click", "look", "size", "disabled"], [1, "discover-error-inline", 2, "margin-top", "8px"], [1, "ddl-preview-code"], [1, "fa-solid", "fa-check"], ["kendoTextBox", "", "placeholder", "Search entity maps...", 3, "ngModelChange", "ngModel"], ["href", "javascript:void(0)", 2, "color", "var(--mj-brand-primary)", 3, "click"], [1, "entity-map-item", 3, "selected", "pending"], [1, "entity-map-item", 3, "click"], [1, "em-top-row"], [1, "em-name"], [1, "em-arrow"], [1, "fa-solid", "fa-arrow-right"], [1, "em-entity"], [1, "em-bottom-row"], [1, "em-badges"], [1, "badge", "badge-direction"], [1, "badge", "badge-pending"], [1, "em-actions"], ["title", "Delete", 1, "em-delete", 3, "click"], [1, "fa-solid", "fa-trash-can"], [3, "ngModel", "size"], [3, "ngModelChange", "valueChange", "ngModel", "size"], [1, "fa-solid", "fa-hand-pointer"], [1, "pending-icon"], [1, "fa-solid", "fa-clock"], [1, "pending-steps"], [1, "step"], [1, "step-circle", "done"], [1, "step-label"], [1, "step-connector"], [1, "step-circle", 3, "ngClass"], [1, "step-circle", "future"], [1, "ddl-preview-inline"], [1, "pending-fields-section"], [2, "font-size", "14px", "margin-bottom", "8px"], [1, "ddl-code-block"], [1, "ddl-actions"], ["kendoButton", "", 3, "click", "look", "size"], [1, "fa-solid", "fa-copy"], [2, "font-size", "14px", "margin", "16px 0 8px"], [1, "fa-solid", "fa-list"], [2, "color", "var(--mj-text-muted)", "font-weight", "400"], [1, "pending-fields-list"], [1, "pending-field-item"], [1, "pending-field-name"], [1, "pending-field-type"], ["title", "Key field", 1, "fa-solid", "fa-key", "key-icon"], [1, "pending-field-req"], [1, "auto-map-banner"], [1, "validation-banner"], [1, "field-mapping-header"], [1, "panel-title"], [1, "field-count"], [1, "field-mapping-actions"], ["kendoButton", "", "title", "Auto-match source and destination fields by name", 3, "click", "look", "size", "disabled"], [1, "field-map-cards"], [1, "data-preview-section"], [1, "preview-actions"], [1, "fa-solid", "fa-cloud-arrow-down"], [1, "preview-panel"], [1, "banner-text"], [1, "validation-warnings"], [1, "fa-solid", "fa-floppy-disk"], [1, "field-map-card", 3, "validation-error", "has-transform"], [1, "field-map-card"], [1, "fmc-row"], [1, "fmc-source"], ["type", "text", "placeholder", "Source field name", 1, "fmc-input", 3, "ngModel"], [1, "fmc-transform-zone"], [1, "fmc-transform-pill", 3, "title"], ["title", "Click to change transform type", 1, "fmc-transform-pill", "fmc-transform-direct"], [1, "fmc-dest"], [1, "fmc-select", 3, "ngModel"], ["type", "text", "placeholder", "Destination field", 1, "fmc-input", 3, "ngModel"], [1, "fmc-flags"], ["title", "Key field for matching", 1, "fmc-flag"], ["type", "checkbox", 3, "ngModelChange", "ngModel"], [1, "fa-solid", "fa-key"], ["title", "Required field", 1, "fmc-flag"], [1, "fmc-req-star"], ["title", "Remove mapping", 1, "fmc-remove", 3, "click"], [1, "fmc-transform-editor"], ["type", "text", "placeholder", "Source field name", 1, "fmc-input", 3, "ngModelChange", "ngModel"], [1, "fmc-field-name"], [1, "fmc-badges"], [1, "fmc-badge", "badge-type"], ["title", "Primary Key", 1, "fmc-badge", "badge-pk"], ["title", "Required", 1, "fmc-badge", "badge-req"], ["title", "Read-Only", 1, "fmc-badge", "badge-ro"], [1, "fmc-transform-pill", 3, "click", "title"], [1, "fmc-step-count"], ["title", "Click to change transform type", 1, "fmc-transform-pill", "fmc-transform-direct", 3, "click"], [1, "fmc-select", 3, "ngModelChange", "ngModel"], ["value", ""], [3, "value"], ["type", "text", "placeholder", "Destination field", 1, "fmc-input", 3, "ngModelChange", "ngModel"], [1, "fmc-te-header"], [1, "fmc-te-title"], ["title", "Add another step", 1, "fmc-te-add", 3, "click"], [1, "fmc-te-step"], [1, "fmc-te-step-header"], [1, "fmc-te-step-num"], [1, "fmc-te-type-select", 3, "ngModelChange", "ngModel"], ["title", "On error", 1, "fmc-te-error-select", 3, "ngModelChange", "ngModel"], ["value", "Fail"], ["value", "Skip"], ["value", "Null"], ["title", "Remove step", 1, "fmc-te-remove-step", 3, "click"], [1, "fmc-te-config"], [1, "fmc-te-field"], [1, "fmc-te-row"], [1, "fmc-te-field", "fmc-te-sm"], ["type", "text", "placeholder", "Leave empty for no default", 1, "fmc-input", 3, "ngModelChange", "ngModel"], ["type", "text", "placeholder", "e.g. (\\d{3})-(\\d{4})", 1, "fmc-input", "mono", 3, "ngModelChange", "ngModel"], ["type", "text", "placeholder", "e.g. $1$2", 1, "fmc-input", "mono", 3, "ngModelChange", "ngModel"], ["type", "text", "placeholder", "gi", 1, "fmc-input", "mono", 3, "ngModelChange", "ngModel"], ["type", "text", "placeholder", ",", 1, "fmc-input", "mono", 3, "ngModelChange", "ngModel"], ["type", "number", "min", "0", 1, "fmc-input", 3, "ngModelChange", "ngModel"], [1, "fmc-combine-chips"], [1, "fmc-chip", 3, "selected"], ["type", "text", "placeholder", " ", 1, "fmc-input", "mono", 3, "ngModelChange", "ngModel"], [1, "fmc-chip", 3, "click"], [1, "fmc-lookup-table"], [1, "fmc-lookup-row"], [1, "fmc-lookup-add", 3, "click"], ["type", "text", "placeholder", "null", 1, "fmc-input", 3, "ngModelChange", "ngModel"], ["type", "text", "placeholder", "Source value", 1, "fmc-input", 3, "change", "value"], [1, "fa-solid", "fa-arrow-right", "fmc-lookup-arrow"], ["type", "text", "placeholder", "Mapped value", 1, "fmc-input", 3, "change", "value"], [1, "fmc-lookup-del", 3, "click"], ["value", "date"], ["value", "number"], ["value", "string"], ["type", "text", "placeholder", "ISO or decimal places", 1, "fmc-input", "mono", 3, "ngModelChange", "ngModel"], ["value", "boolean"], ["type", "number", "min", "1", 1, "fmc-input", 3, "ngModelChange", "ngModel"], [1, "fmc-te-hint"], ["placeholder", "value.toUpperCase()", "rows", "2", 1, "fmc-input", "mono", "fmc-textarea", 3, "ngModelChange", "ngModel"], [1, "preview-panel-header"], [1, "fa-solid", "fa-cloud"], ["text", "Loading source data...", "size", "small"], [1, "preview-table-wrapper"], [1, "preview-table"], ["text", "Loading destination data...", "size", "small"], [1, "run-summary-card"], [1, "run-summary-row"], [1, "label"], [1, "run-status"], [1, "panel-label", 2, "margin-top", "16px"], [1, "entity-stat-card"], [1, "entity-stat-name"], [1, "entity-stat-grid"], [1, "mini-stat"], [1, "mini-val"], [1, "mini-label"]], template: function MappingWorkspaceComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2350
2350
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "h2");
|
|
2351
2351
|
i0.ɵɵelement(3, "i", 2);
|
|
2352
2352
|
i0.ɵɵtext(4, " Mapping Workspace");
|
|
@@ -2356,7 +2356,7 @@ let MappingWorkspaceComponent = class MappingWorkspaceComponent extends BaseReso
|
|
|
2356
2356
|
} if (rf & 2) {
|
|
2357
2357
|
i0.ɵɵadvance(5);
|
|
2358
2358
|
i0.ɵɵconditional(ctx.IsLoadingIntegrations ? 5 : 6);
|
|
2359
|
-
} }, dependencies: [i1.NgClass, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.NumberValueAccessor, i2.CheckboxControlValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.MinValidator, i2.NgModel, i3.ButtonComponent, i4.ComboBoxComponent, i4.DropDownListComponent, i5.TextBoxDirective, i5.SwitchComponent, i6.LoadingComponent, i1.DecimalPipe], styles: [".mapping-workspace[_ngcontent-%COMP%] { padding: 24px; height: 100%; display: flex; flex-direction: column; }\n.workspace-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 16px;\n}\n.workspace-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0; font-size: 20px; font-weight: 600;\n}\n.workspace-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 8px; color: var(--mj-color-indigo-500); }\n\n\n\n.workspace-body[_ngcontent-%COMP%] {\n display: flex; flex: 1; gap: 1px; background: var(--mj-border-default);\n border-radius: 10px; overflow: hidden; min-height: 500px;\n}\n\n.left-panel[_ngcontent-%COMP%] { width: 320px; min-width: 280px; background: var(--mj-bg-surface); padding: 16px; overflow-y: auto; flex-shrink: 0; }\n.center-panel[_ngcontent-%COMP%] { flex: 1; background: var(--mj-bg-surface); padding: 20px; overflow-y: auto; }\n.right-panel[_ngcontent-%COMP%] { width: 280px; min-width: 240px; background: var(--mj-bg-surface); padding: 16px; overflow-y: auto; flex-shrink: 0; }\n\n\n\n.panel-label[_ngcontent-%COMP%] {\n font-size: 11px; font-weight: 700; color: var(--mj-text-disabled);\n text-transform: uppercase; letter-spacing: 0.6px;\n margin: 0 0 6px 0; display: block;\n}\n.panel-title[_ngcontent-%COMP%] { margin: 0 0 12px 0; font-size: 16px; font-weight: 600; }\n.panel-title[_ngcontent-%COMP%] .field-count[_ngcontent-%COMP%] { color: var(--mj-text-disabled); font-weight: 400; font-size: 13px; }\n.empty-hint[_ngcontent-%COMP%] { color: var(--mj-text-disabled); font-size: 13px; font-style: italic; }\n.search-box[_ngcontent-%COMP%] { margin-bottom: 12px; }\n\n\n\n.integration-selector[_ngcontent-%COMP%] { margin-bottom: 20px; padding-bottom: 16px; border-bottom: 1px solid var(--mj-border-subtle); }\n\n\n\n.entity-map-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 10px;\n}\n.header-actions[_ngcontent-%COMP%] { display: flex; gap: 4px; }\n\n\n\n.add-map-panel[_ngcontent-%COMP%] {\n background: var(--mj-bg-page); border: 1px solid var(--mj-border-default); border-radius: 10px;\n padding: 16px; margin-bottom: 14px;\n}\n.add-panel-top[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 14px;\n}\n.add-panel-top[_ngcontent-%COMP%] h5[_ngcontent-%COMP%] { margin: 0; font-size: 14px; font-weight: 600; }\n.add-panel-close[_ngcontent-%COMP%] {\n background: none; border: none; cursor: pointer; color: var(--mj-text-disabled); font-size: 14px;\n}\n.add-panel-close[_ngcontent-%COMP%]:hover { color: var(--mj-text-primary); }\n\n.form-group[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }\n.form-group[_ngcontent-%COMP%] label[_ngcontent-%COMP%] { font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.form-row[_ngcontent-%COMP%] { display: flex; gap: 10px; }\n.form-row[_ngcontent-%COMP%] .form-group[_ngcontent-%COMP%] { flex: 1; }\n\n.source-loading[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 8px;\n font-size: 12px; color: var(--mj-text-disabled); padding: 6px 0;\n}\n.source-loading[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { color: var(--mj-color-indigo-500); }\n\n.discover-error-inline[_ngcontent-%COMP%] {\n font-size: 12px; color: var(--mj-color-error-600); padding: 6px 0;\n}\n.discover-error-inline[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 4px; }\n\n\n\n.target-mode-toggle[_ngcontent-%COMP%] {\n display: flex; border: 1px solid var(--mj-border-default); border-radius: 6px;\n overflow: hidden; margin-bottom: 12px;\n}\n.target-mode-btn[_ngcontent-%COMP%] {\n flex: 1; padding: 8px 12px; font-size: 12px; font-weight: 600;\n text-align: center; cursor: pointer; background: var(--mj-bg-surface); border: none;\n color: var(--mj-text-muted); transition: all 0.15s;\n}\n.target-mode-btn[_ngcontent-%COMP%]:first-child { border-right: 1px solid var(--mj-border-default); }\n.target-mode-btn.active[_ngcontent-%COMP%] { background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); }\n.target-mode-btn[_ngcontent-%COMP%]:not(.active):hover { background: var(--mj-status-info-bg); color: var(--mj-color-indigo-500); }\n.target-mode-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 4px; }\n\n\n\n.new-entity-form[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 8px;\n padding: 14px; margin-bottom: 12px;\n}\n.new-entity-form[_ngcontent-%COMP%] .section-label[_ngcontent-%COMP%] {\n font-size: 11px; font-weight: 700; color: var(--mj-color-indigo-500);\n text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 10px;\n}\n.auto-hint[_ngcontent-%COMP%] { font-size: 10px; color: var(--mj-text-disabled); font-style: italic; }\n\n\n\n.ddl-preview-section[_ngcontent-%COMP%] { margin-top: 8px; }\n.ddl-preview-code[_ngcontent-%COMP%] {\n background: var(--mj-color-neutral-900); color: var(--mj-color-neutral-300); padding: 10px;\n border-radius: 4px; font-size: 11px; line-height: 1.5;\n max-height: 200px; overflow: auto; white-space: pre-wrap;\n word-break: break-word; margin-top: 8px;\n}\n\n.add-form-actions[_ngcontent-%COMP%] { display: flex; gap: 6px; padding-top: 4px; }\n\n\n\n.entity-map-list[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 4px; }\n.entity-map-item[_ngcontent-%COMP%] {\n padding: 8px 10px; border-radius: 6px;\n cursor: pointer; border: 1px solid var(--mj-border-subtle); transition: all 0.15s;\n}\n.entity-map-item[_ngcontent-%COMP%]:hover { background: var(--mj-bg-page); }\n.entity-map-item.selected[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); border-color: var(--mj-color-indigo-500); }\n.entity-map-item.pending[_ngcontent-%COMP%] { border-left: 3px solid var(--mj-status-warning); }\n\n.em-top-row[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 4px;\n font-size: 13px; margin-bottom: 4px;\n}\n.em-name[_ngcontent-%COMP%] { font-weight: 600; }\n.em-arrow[_ngcontent-%COMP%] { color: var(--mj-text-disabled); font-size: 11px; }\n.em-entity[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n\n.em-bottom-row[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n font-size: 11px; color: var(--mj-text-disabled);\n}\n.em-badges[_ngcontent-%COMP%] { display: flex; gap: 4px; align-items: center; }\n.badge[_ngcontent-%COMP%] {\n font-size: 10px; padding: 1px 6px; border-radius: 4px; font-weight: 600;\n}\n.badge-direction[_ngcontent-%COMP%] { background: var(--mj-bg-surface-hover); color: var(--mj-text-muted); }\n.badge-pending[_ngcontent-%COMP%] { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n\n.em-actions[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 4px; }\n.em-delete[_ngcontent-%COMP%] {\n opacity: 0; transition: opacity 0.15s;\n cursor: pointer; color: var(--mj-color-error-600); background: none; border: none;\n padding: 2px 4px; font-size: 12px;\n}\n.entity-map-item[_ngcontent-%COMP%]:hover .em-delete[_ngcontent-%COMP%] { opacity: 1; }\n\n\n\n.placeholder-message[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; align-items: center;\n justify-content: center; height: 300px; color: var(--mj-text-disabled);\n}\n.placeholder-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 36px; margin-bottom: 12px; }\n.placeholder-message[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { text-align: center; }\n\n\n\n.pending-entity-panel[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg); border: 1px solid var(--mj-color-warning-200); border-radius: 10px;\n padding: 24px; text-align: center;\n}\n.pending-icon[_ngcontent-%COMP%] { font-size: 40px; color: var(--mj-status-warning); margin-bottom: 12px; }\n.pending-entity-panel[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { font-size: 16px; margin-bottom: 8px; }\n.pending-entity-panel[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-disabled); margin-bottom: 16px; line-height: 1.5; }\n\n\n\n.pending-steps[_ngcontent-%COMP%] {\n display: flex; gap: 0; margin: 20px 0; justify-content: center; align-items: center;\n}\n.step[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; align-items: center; gap: 6px;\n padding: 0 16px;\n}\n.step-circle[_ngcontent-%COMP%] {\n width: 36px; height: 36px; border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 14px; font-weight: 700;\n}\n.step-circle.done[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-color-success-700); }\n.step-circle.current[_ngcontent-%COMP%] { background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); }\n.step-circle.future[_ngcontent-%COMP%] { background: var(--mj-bg-surface-hover); color: var(--mj-text-disabled); }\n.step-label[_ngcontent-%COMP%] { font-size: 10px; font-weight: 600; color: var(--mj-text-disabled); text-transform: uppercase; white-space: nowrap; }\n.step-connector[_ngcontent-%COMP%] { width: 32px; height: 2px; background: var(--mj-border-default); align-self: center; margin-bottom: 18px; }\n.step-connector.done[_ngcontent-%COMP%] { background: var(--mj-color-success-700); }\n\n\n\n.ddl-preview-inline[_ngcontent-%COMP%] { margin-top: 16px; text-align: left; }\n.ddl-code-block[_ngcontent-%COMP%] {\n background: var(--mj-color-neutral-900); color: var(--mj-color-neutral-300); padding: 12px;\n border-radius: 6px; font-size: 12px; line-height: 1.5;\n max-height: 250px; overflow: auto; white-space: pre-wrap;\n}\n.ddl-actions[_ngcontent-%COMP%] { display: flex; gap: 8px; margin-top: 12px; justify-content: center; }\n\n\n\n.pending-fields-section[_ngcontent-%COMP%] { text-align: left; }\n.pending-fields-list[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; gap: 2px;\n max-height: 200px; overflow-y: auto;\n}\n.pending-field-item[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 8px;\n padding: 4px 8px; font-size: 13px; border-radius: 4px;\n}\n.pending-field-item[_ngcontent-%COMP%]:hover { background: var(--mj-status-warning-bg); }\n.pending-field-name[_ngcontent-%COMP%] { font-weight: 600; }\n.pending-field-type[_ngcontent-%COMP%] { font-size: 11px; color: var(--mj-text-disabled); background: var(--mj-bg-surface-hover); padding: 1px 6px; border-radius: 3px; }\n.pending-field-req[_ngcontent-%COMP%] { color: var(--mj-color-error-600); font-weight: 700; }\n\n\n\n.auto-map-banner[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg); border: 1px solid var(--mj-color-info-100); border-radius: 8px;\n padding: 12px 16px; margin-bottom: 16px;\n display: flex; align-items: center; gap: 12px;\n}\n.auto-map-banner[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] { color: var(--mj-color-indigo-500); font-size: 18px; }\n.auto-map-banner[_ngcontent-%COMP%] .banner-text[_ngcontent-%COMP%] { flex: 1; }\n.auto-map-banner[_ngcontent-%COMP%] .banner-text[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-muted); margin: 0; }\n.auto-map-banner[_ngcontent-%COMP%] .banner-text[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] { color: var(--mj-text-primary); }\n\n\n\n.field-mapping-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 16px;\n}\n.field-mapping-actions[_ngcontent-%COMP%] { display: flex; gap: 6px; }\n\n\n\n.field-map-cards[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; gap: 6px;\n}\n\n.field-map-card[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n overflow: hidden;\n}\n.field-map-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px rgba(74, 108, 247, 0.06);\n}\n.field-map-card.has-transform[_ngcontent-%COMP%] {\n border-left: 3px solid var(--mj-color-indigo-500);\n}\n.field-map-card.validation-error[_ngcontent-%COMP%] {\n border-color: var(--mj-color-warning-200);\n background: var(--mj-status-warning-bg);\n}\n\n\n\n.fmc-row[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 10px;\n padding: 10px 14px;\n}\n\n\n\n.fmc-source[_ngcontent-%COMP%] {\n flex: 1; min-width: 0;\n}\n.fmc-field-name[_ngcontent-%COMP%] {\n font-size: 13px; font-weight: 600; color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n}\n.fmc-badges[_ngcontent-%COMP%] {\n display: flex; gap: 4px; margin-top: 3px; flex-wrap: wrap;\n}\n.fmc-badge[_ngcontent-%COMP%] {\n font-size: 9px; font-weight: 700; padding: 1px 5px;\n border-radius: 3px; text-transform: uppercase; letter-spacing: 0.3px;\n white-space: nowrap; line-height: 1.5;\n}\n.badge-type[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-hover); color: var(--mj-text-muted);\n}\n.badge-pk[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-warning-100), var(--mj-color-warning-200));\n color: var(--mj-color-warning-800);\n}\n.badge-pk[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 8px; margin-right: 2px; }\n.badge-req[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-error-100), var(--mj-color-error-200));\n color: var(--mj-color-error-800);\n}\n.badge-ro[_ngcontent-%COMP%] {\n background: var(--mj-color-purple-50); color: var(--mj-color-purple-700);\n}\n\n\n\n.fmc-transform-zone[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex; align-items: center; justify-content: center;\n width: 100px;\n}\n.fmc-arrow-btn[_ngcontent-%COMP%] {\n width: 32px; height: 32px;\n border-radius: 50%; border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page); color: var(--mj-text-disabled);\n cursor: pointer; font-size: 12px;\n display: flex; align-items: center; justify-content: center;\n transition: all 0.2s;\n}\n.fmc-arrow-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); border-color: var(--mj-color-indigo-500);\n transform: scale(1.1);\n}\n.fmc-transform-pill[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 4px;\n padding: 4px 10px; border-radius: 16px;\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border: 1px solid var(--mj-color-indigo-200); color: var(--mj-color-indigo-700);\n font-size: 11px; font-weight: 600;\n cursor: pointer; transition: all 0.2s;\n white-space: nowrap;\n}\n.fmc-transform-pill[_ngcontent-%COMP%]:hover {\n background: linear-gradient(135deg, var(--mj-color-indigo-100), var(--mj-color-indigo-200));\n transform: scale(1.02);\n}\n.fmc-transform-pill[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 10px; }\n.fmc-transform-direct[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-bg-page), var(--mj-bg-surface-hover));\n border-color: var(--mj-color-neutral-300); color: var(--mj-text-muted);\n}\n.fmc-transform-direct[_ngcontent-%COMP%]:hover {\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border-color: var(--mj-color-indigo-200); color: var(--mj-color-indigo-700);\n}\n.fmc-step-count[_ngcontent-%COMP%] {\n background: var(--mj-color-indigo-700); color: var(--mj-bg-surface); font-size: 9px;\n padding: 0 4px; border-radius: 8px; font-weight: 700;\n}\n\n\n\n.fmc-dest[_ngcontent-%COMP%] {\n flex: 1; min-width: 0;\n}\n.fmc-select[_ngcontent-%COMP%] {\n width: 100%; padding: 6px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: border-color 0.15s;\n}\n.fmc-select[_ngcontent-%COMP%]:focus { border-color: var(--mj-color-indigo-500); outline: none; box-shadow: 0 0 0 2px rgba(74, 108, 247, 0.12); }\n\n\n\n.fmc-input[_ngcontent-%COMP%] {\n width: 100%; padding: 5px 8px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: border-color 0.15s;\n}\n.fmc-input[_ngcontent-%COMP%]:focus { border-color: var(--mj-color-indigo-500); outline: none; box-shadow: 0 0 0 2px rgba(74, 108, 247, 0.12); }\n.fmc-input.mono[_ngcontent-%COMP%] { font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; font-size: 12px; }\n\n\n\n.fmc-flags[_ngcontent-%COMP%] {\n display: flex; gap: 6px; flex-shrink: 0;\n}\n.fmc-flag[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 3px;\n font-size: 11px; color: var(--mj-text-disabled); cursor: pointer;\n padding: 2px 4px; border-radius: 4px;\n transition: color 0.15s;\n}\n.fmc-flag[_ngcontent-%COMP%]:hover { color: var(--mj-color-indigo-500); }\n.fmc-flag[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 13px; height: 13px; cursor: pointer;\n accent-color: var(--mj-color-indigo-500);\n}\n.fmc-flag[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 10px; }\n.fmc-req-star[_ngcontent-%COMP%] { font-size: 14px; font-weight: 700; color: inherit; }\n\n\n\n.fmc-remove[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 13px; padding: 4px;\n border-radius: 4px; transition: all 0.15s;\n}\n.fmc-remove[_ngcontent-%COMP%]:hover { color: var(--mj-status-error); background: var(--mj-status-error-bg); }\n\n\n\n.fmc-transform-editor[_ngcontent-%COMP%] {\n border-top: 1px solid var(--mj-bg-surface-hover);\n background: linear-gradient(180deg, var(--mj-color-indigo-50) 0%, var(--mj-bg-page) 100%);\n padding: 12px 14px;\n}\n.fmc-te-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 10px;\n}\n.fmc-te-title[_ngcontent-%COMP%] {\n font-size: 11px; font-weight: 700; color: var(--mj-color-indigo-500);\n text-transform: uppercase; letter-spacing: 0.5px;\n}\n.fmc-te-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 4px; }\n.fmc-te-add[_ngcontent-%COMP%] {\n font-size: 11px; font-weight: 600; color: var(--mj-color-indigo-500);\n background: none; border: 1px solid var(--mj-color-indigo-200);\n border-radius: 6px; padding: 3px 10px;\n cursor: pointer; transition: all 0.15s;\n}\n.fmc-te-add[_ngcontent-%COMP%]:hover { background: var(--mj-color-indigo-50); }\n.fmc-te-add[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 3px; font-size: 10px; }\n\n\n\n.fmc-te-step[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 10px 12px;\n margin-bottom: 8px;\n transition: box-shadow 0.15s;\n}\n.fmc-te-step[_ngcontent-%COMP%]:hover { box-shadow: 0 1px 4px rgba(0,0,0,0.05); }\n.fmc-te-step[_ngcontent-%COMP%]:last-child { margin-bottom: 0; }\n\n.fmc-te-step-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 8px; margin-bottom: 8px;\n}\n.fmc-te-step-num[_ngcontent-%COMP%] {\n width: 22px; height: 22px; border-radius: 50%;\n background: linear-gradient(135deg, var(--mj-color-indigo-500), var(--mj-color-indigo-500));\n color: var(--mj-bg-surface); font-size: 11px; font-weight: 700;\n display: flex; align-items: center; justify-content: center;\n flex-shrink: 0;\n}\n.fmc-te-type-select[_ngcontent-%COMP%] {\n flex: 1; padding: 4px 8px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 12px; font-weight: 600;\n color: var(--mj-text-primary); background: var(--mj-bg-page);\n}\n.fmc-te-type-select[_ngcontent-%COMP%]:focus { border-color: var(--mj-color-indigo-500); outline: none; }\n.fmc-te-error-select[_ngcontent-%COMP%] {\n width: 100px; padding: 4px 6px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 11px; color: var(--mj-text-muted);\n background: var(--mj-bg-page);\n}\n.fmc-te-error-select[_ngcontent-%COMP%]:focus { border-color: var(--mj-color-indigo-500); outline: none; }\n.fmc-te-remove-step[_ngcontent-%COMP%] {\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 12px; padding: 4px;\n border-radius: 4px; transition: all 0.15s;\n}\n.fmc-te-remove-step[_ngcontent-%COMP%]:hover { color: var(--mj-status-error); background: var(--mj-status-error-bg); }\n\n\n\n.fmc-te-config[_ngcontent-%COMP%] {\n padding-left: 30px;\n}\n.fmc-te-field[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n}\n.fmc-te-field[_ngcontent-%COMP%]:last-child { margin-bottom: 0; }\n.fmc-te-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block; font-size: 11px; font-weight: 600;\n color: var(--mj-text-muted); margin-bottom: 3px;\n}\n.fmc-te-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-hover); padding: 0 3px; border-radius: 3px;\n font-size: 10px; color: var(--mj-color-indigo-700);\n}\n.fmc-te-hint[_ngcontent-%COMP%] { font-weight: 400; color: var(--mj-text-disabled); }\n.fmc-te-row[_ngcontent-%COMP%] {\n display: flex; gap: 10px; align-items: flex-end;\n}\n.fmc-te-sm[_ngcontent-%COMP%] { max-width: 140px; }\n.fmc-textarea[_ngcontent-%COMP%] {\n resize: vertical; min-height: 40px;\n}\n\n\n\n.fmc-combine-chips[_ngcontent-%COMP%] {\n display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px;\n}\n.fmc-chip[_ngcontent-%COMP%] {\n font-size: 11px; padding: 3px 8px; border-radius: 14px;\n border: 1px solid var(--mj-border-default); background: var(--mj-bg-surface);\n color: var(--mj-text-muted); cursor: pointer;\n transition: all 0.15s; font-weight: 500;\n}\n.fmc-chip[_ngcontent-%COMP%]:hover { border-color: var(--mj-color-indigo-300); color: var(--mj-color-indigo-700); }\n.fmc-chip.selected[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border-color: var(--mj-color-indigo-400); color: var(--mj-color-indigo-700); font-weight: 600;\n}\n\n\n\n.fmc-lookup-table[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; gap: 4px; margin-top: 4px;\n}\n.fmc-lookup-row[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 6px;\n}\n.fmc-lookup-row[_ngcontent-%COMP%] .fmc-input[_ngcontent-%COMP%] { flex: 1; }\n.fmc-lookup-arrow[_ngcontent-%COMP%] { color: var(--mj-color-indigo-200); font-size: 10px; flex-shrink: 0; }\n.fmc-lookup-del[_ngcontent-%COMP%] {\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 11px; padding: 2px;\n transition: color 0.15s;\n}\n.fmc-lookup-del[_ngcontent-%COMP%]:hover { color: var(--mj-status-error); }\n.fmc-lookup-add[_ngcontent-%COMP%] {\n font-size: 11px; color: var(--mj-color-indigo-500); background: none;\n border: 1px dashed var(--mj-color-indigo-200); border-radius: 6px;\n padding: 4px 10px; cursor: pointer;\n transition: all 0.15s; margin-top: 2px;\n}\n.fmc-lookup-add[_ngcontent-%COMP%]:hover { background: var(--mj-color-indigo-50); }\n.fmc-lookup-add[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 3px; font-size: 10px; }\n\n\n\n.data-preview-section[_ngcontent-%COMP%] { margin-top: 24px; border-top: 1px solid var(--mj-border-subtle); padding-top: 16px; }\n.preview-actions[_ngcontent-%COMP%] { display: flex; gap: 8px; margin-bottom: 12px; }\n\n.preview-panel[_ngcontent-%COMP%] {\n background: var(--mj-bg-page); border: 1px solid var(--mj-border-default); border-radius: 8px;\n padding: 12px; margin-bottom: 12px;\n}\n.preview-panel-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 8px;\n}\n.preview-panel-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] { font-size: 13px; font-weight: 600; margin: 0; }\n.preview-panel-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 6px; color: var(--mj-color-indigo-500); }\n\n.preview-table-wrapper[_ngcontent-%COMP%] { overflow-x: auto; }\n.preview-table[_ngcontent-%COMP%] {\n width: 100%; border-collapse: collapse; font-size: 12px;\n}\n.preview-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left; padding: 5px 8px;\n background: var(--mj-border-default); font-weight: 600; font-size: 10px;\n text-transform: uppercase; color: var(--mj-text-muted);\n border-bottom: 1px solid var(--mj-border-default); white-space: nowrap;\n}\n.preview-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 4px 8px; border-bottom: 1px solid var(--mj-border-subtle);\n white-space: nowrap; max-width: 150px; overflow: hidden; text-overflow: ellipsis;\n}\n.preview-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover { background: var(--mj-status-info-bg); }\n\n\n\n.run-summary-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-page); border-radius: 8px; padding: 12px;\n}\n.run-summary-row[_ngcontent-%COMP%] {\n display: flex; justify-content: space-between;\n padding: 4px 0; font-size: 13px;\n}\n.run-summary-row[_ngcontent-%COMP%] .label[_ngcontent-%COMP%] { color: var(--mj-text-muted); font-weight: 500; }\n.run-status[_ngcontent-%COMP%] {\n font-size: 11px; padding: 2px 6px; border-radius: 4px; font-weight: 600;\n}\n.status-green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-color-success-700); }\n.status-amber[_ngcontent-%COMP%] { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n.status-red[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-color-error-600); }\n\n.entity-stat-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-page); border-radius: 6px; padding: 10px;\n margin-bottom: 8px;\n}\n.entity-stat-name[_ngcontent-%COMP%] { font-size: 13px; font-weight: 600; margin-bottom: 6px; }\n.entity-stat-grid[_ngcontent-%COMP%] { display: flex; gap: 12px; }\n.mini-stat[_ngcontent-%COMP%] { text-align: center; }\n.mini-val[_ngcontent-%COMP%] { display: block; font-size: 16px; font-weight: 600; }\n.mini-val.has-errors[_ngcontent-%COMP%] { color: var(--mj-color-error-600); }\n.mini-label[_ngcontent-%COMP%] { font-size: 10px; color: var(--mj-text-disabled); }\n\n\n\n.validation-banner[_ngcontent-%COMP%] {\n background: var(--mj-color-warning-50); border: 1px solid var(--mj-color-warning-200); border-radius: 8px;\n padding: 10px 14px; margin-bottom: 14px;\n display: flex; align-items: flex-start; gap: 10px;\n font-size: 13px; color: var(--mj-color-warning-600);\n}\n.validation-banner[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] { margin-top: 2px; }\n.validation-warnings[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 2px; }\n\n.field-map-card.validation-error[_ngcontent-%COMP%] .fmc-source[_ngcontent-%COMP%] {\n border-left: 3px solid var(--mj-color-warning-600);\n padding-left: 8px;\n}\n\n\n\n@media (max-width: 1100px) { .right-panel[_ngcontent-%COMP%] { display: none; } }\n@media (max-width: 800px) { .left-panel[_ngcontent-%COMP%] { width: 260px; } }"] });
|
|
2359
|
+
} }, dependencies: [i1.NgClass, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.NumberValueAccessor, i2.CheckboxControlValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.MinValidator, i2.NgModel, i3.ButtonComponent, i4.ComboBoxComponent, i4.DropDownListComponent, i5.TextBoxDirective, i5.SwitchComponent, i6.LoadingComponent, i1.DecimalPipe], styles: [".mapping-workspace[_ngcontent-%COMP%] { padding: 24px; height: 100%; display: flex; flex-direction: column; }\n.workspace-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 16px;\n}\n.workspace-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0; font-size: 20px; font-weight: 600;\n}\n.workspace-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 8px; color: var(--mj-color-indigo-500); }\n\n\n\n.workspace-body[_ngcontent-%COMP%] {\n display: flex; flex: 1; gap: 1px; background: var(--mj-border-default);\n border-radius: 10px; overflow: hidden; min-height: 500px;\n}\n\n.left-panel[_ngcontent-%COMP%] { width: 320px; min-width: 280px; background: var(--mj-bg-surface); padding: 16px; overflow-y: auto; flex-shrink: 0; }\n.center-panel[_ngcontent-%COMP%] { flex: 1; background: var(--mj-bg-surface); padding: 20px; overflow-y: auto; }\n.right-panel[_ngcontent-%COMP%] { width: 280px; min-width: 240px; background: var(--mj-bg-surface); padding: 16px; overflow-y: auto; flex-shrink: 0; }\n\n\n\n.panel-label[_ngcontent-%COMP%] {\n font-size: 11px; font-weight: 700; color: var(--mj-text-disabled);\n text-transform: uppercase; letter-spacing: 0.6px;\n margin: 0 0 6px 0; display: block;\n}\n.panel-title[_ngcontent-%COMP%] { margin: 0 0 12px 0; font-size: 16px; font-weight: 600; }\n.panel-title[_ngcontent-%COMP%] .field-count[_ngcontent-%COMP%] { color: var(--mj-text-disabled); font-weight: 400; font-size: 13px; }\n.empty-hint[_ngcontent-%COMP%] { color: var(--mj-text-disabled); font-size: 13px; font-style: italic; }\n.search-box[_ngcontent-%COMP%] { margin-bottom: 12px; }\n\n\n\n.integration-selector[_ngcontent-%COMP%] { margin-bottom: 20px; padding-bottom: 16px; border-bottom: 1px solid var(--mj-border-subtle); }\n\n\n\n.entity-map-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 10px;\n}\n.header-actions[_ngcontent-%COMP%] { display: flex; gap: 4px; }\n\n\n\n.add-map-panel[_ngcontent-%COMP%] {\n background: var(--mj-bg-page); border: 1px solid var(--mj-border-default); border-radius: 10px;\n padding: 16px; margin-bottom: 14px;\n}\n.add-panel-top[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 14px;\n}\n.add-panel-top[_ngcontent-%COMP%] h5[_ngcontent-%COMP%] { margin: 0; font-size: 14px; font-weight: 600; }\n.add-panel-close[_ngcontent-%COMP%] {\n background: none; border: none; cursor: pointer; color: var(--mj-text-disabled); font-size: 14px;\n}\n.add-panel-close[_ngcontent-%COMP%]:hover { color: var(--mj-text-primary); }\n\n.form-group[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }\n.form-group[_ngcontent-%COMP%] label[_ngcontent-%COMP%] { font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.form-row[_ngcontent-%COMP%] { display: flex; gap: 10px; }\n.form-row[_ngcontent-%COMP%] .form-group[_ngcontent-%COMP%] { flex: 1; }\n\n.source-loading[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 8px;\n font-size: 12px; color: var(--mj-text-disabled); padding: 6px 0;\n}\n.source-loading[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { color: var(--mj-color-indigo-500); }\n\n.discover-error-inline[_ngcontent-%COMP%] {\n font-size: 12px; color: var(--mj-color-error-600); padding: 6px 0;\n}\n.discover-error-inline[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 4px; }\n\n\n\n.target-mode-toggle[_ngcontent-%COMP%] {\n display: flex; border: 1px solid var(--mj-border-default); border-radius: 6px;\n overflow: hidden; margin-bottom: 12px;\n}\n.target-mode-btn[_ngcontent-%COMP%] {\n flex: 1; padding: 8px 12px; font-size: 12px; font-weight: 600;\n text-align: center; cursor: pointer; background: var(--mj-bg-surface); border: none;\n color: var(--mj-text-muted); transition: all 0.15s;\n}\n.target-mode-btn[_ngcontent-%COMP%]:first-child { border-right: 1px solid var(--mj-border-default); }\n.target-mode-btn.active[_ngcontent-%COMP%] { background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); }\n.target-mode-btn[_ngcontent-%COMP%]:not(.active):hover { background: var(--mj-status-info-bg); color: var(--mj-color-indigo-500); }\n.target-mode-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 4px; }\n\n\n\n.new-entity-form[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 8px;\n padding: 14px; margin-bottom: 12px;\n}\n.new-entity-form[_ngcontent-%COMP%] .section-label[_ngcontent-%COMP%] {\n font-size: 11px; font-weight: 700; color: var(--mj-color-indigo-500);\n text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 10px;\n}\n.auto-hint[_ngcontent-%COMP%] { font-size: 10px; color: var(--mj-text-disabled); font-style: italic; }\n\n\n\n.ddl-preview-section[_ngcontent-%COMP%] { margin-top: 8px; }\n.ddl-preview-code[_ngcontent-%COMP%] {\n background: var(--mj-text-primary); color: var(--mj-color-neutral-300); padding: 10px;\n border-radius: 4px; font-size: 11px; line-height: 1.5;\n max-height: 200px; overflow: auto; white-space: pre-wrap;\n word-break: break-word; margin-top: 8px;\n}\n\n.add-form-actions[_ngcontent-%COMP%] { display: flex; gap: 6px; padding-top: 4px; }\n\n\n\n.entity-map-list[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 4px; }\n.entity-map-item[_ngcontent-%COMP%] {\n padding: 8px 10px; border-radius: 6px;\n cursor: pointer; border: 1px solid var(--mj-border-subtle); transition: all 0.15s;\n}\n.entity-map-item[_ngcontent-%COMP%]:hover { background: var(--mj-bg-page); }\n.entity-map-item.selected[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); border-color: var(--mj-color-indigo-500); }\n.entity-map-item.pending[_ngcontent-%COMP%] { border-left: 3px solid var(--mj-status-warning); }\n\n.em-top-row[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 4px;\n font-size: 13px; margin-bottom: 4px;\n}\n.em-name[_ngcontent-%COMP%] { font-weight: 600; }\n.em-arrow[_ngcontent-%COMP%] { color: var(--mj-text-disabled); font-size: 11px; }\n.em-entity[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n\n.em-bottom-row[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n font-size: 11px; color: var(--mj-text-disabled);\n}\n.em-badges[_ngcontent-%COMP%] { display: flex; gap: 4px; align-items: center; }\n.badge[_ngcontent-%COMP%] {\n font-size: 10px; padding: 1px 6px; border-radius: 4px; font-weight: 600;\n}\n.badge-direction[_ngcontent-%COMP%] { background: var(--mj-bg-surface-hover); color: var(--mj-text-muted); }\n.badge-pending[_ngcontent-%COMP%] { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n\n.em-actions[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 4px; }\n.em-delete[_ngcontent-%COMP%] {\n opacity: 0; transition: opacity 0.15s;\n cursor: pointer; color: var(--mj-color-error-600); background: none; border: none;\n padding: 2px 4px; font-size: 12px;\n}\n.entity-map-item[_ngcontent-%COMP%]:hover .em-delete[_ngcontent-%COMP%] { opacity: 1; }\n\n\n\n.placeholder-message[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; align-items: center;\n justify-content: center; height: 300px; color: var(--mj-text-disabled);\n}\n.placeholder-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 36px; margin-bottom: 12px; }\n.placeholder-message[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { text-align: center; }\n\n\n\n.pending-entity-panel[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg); border: 1px solid var(--mj-color-warning-200); border-radius: 10px;\n padding: 24px; text-align: center;\n}\n.pending-icon[_ngcontent-%COMP%] { font-size: 40px; color: var(--mj-status-warning); margin-bottom: 12px; }\n.pending-entity-panel[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { font-size: 16px; margin-bottom: 8px; }\n.pending-entity-panel[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-disabled); margin-bottom: 16px; line-height: 1.5; }\n\n\n\n.pending-steps[_ngcontent-%COMP%] {\n display: flex; gap: 0; margin: 20px 0; justify-content: center; align-items: center;\n}\n.step[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; align-items: center; gap: 6px;\n padding: 0 16px;\n}\n.step-circle[_ngcontent-%COMP%] {\n width: 36px; height: 36px; border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 14px; font-weight: 700;\n}\n.step-circle.done[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-color-success-700); }\n.step-circle.current[_ngcontent-%COMP%] { background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); }\n.step-circle.future[_ngcontent-%COMP%] { background: var(--mj-bg-surface-hover); color: var(--mj-text-disabled); }\n.step-label[_ngcontent-%COMP%] { font-size: 10px; font-weight: 600; color: var(--mj-text-disabled); text-transform: uppercase; white-space: nowrap; }\n.step-connector[_ngcontent-%COMP%] { width: 32px; height: 2px; background: var(--mj-border-default); align-self: center; margin-bottom: 18px; }\n.step-connector.done[_ngcontent-%COMP%] { background: var(--mj-color-success-700); }\n\n\n\n.ddl-preview-inline[_ngcontent-%COMP%] { margin-top: 16px; text-align: left; }\n.ddl-code-block[_ngcontent-%COMP%] {\n background: var(--mj-text-primary); color: var(--mj-color-neutral-300); padding: 12px;\n border-radius: 6px; font-size: 12px; line-height: 1.5;\n max-height: 250px; overflow: auto; white-space: pre-wrap;\n}\n.ddl-actions[_ngcontent-%COMP%] { display: flex; gap: 8px; margin-top: 12px; justify-content: center; }\n\n\n\n.pending-fields-section[_ngcontent-%COMP%] { text-align: left; }\n.pending-fields-list[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; gap: 2px;\n max-height: 200px; overflow-y: auto;\n}\n.pending-field-item[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 8px;\n padding: 4px 8px; font-size: 13px; border-radius: 4px;\n}\n.pending-field-item[_ngcontent-%COMP%]:hover { background: var(--mj-status-warning-bg); }\n.pending-field-name[_ngcontent-%COMP%] { font-weight: 600; }\n.pending-field-type[_ngcontent-%COMP%] { font-size: 11px; color: var(--mj-text-disabled); background: var(--mj-bg-surface-hover); padding: 1px 6px; border-radius: 3px; }\n.pending-field-req[_ngcontent-%COMP%] { color: var(--mj-color-error-600); font-weight: 700; }\n\n\n\n.auto-map-banner[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg); border: 1px solid var(--mj-color-info-100); border-radius: 8px;\n padding: 12px 16px; margin-bottom: 16px;\n display: flex; align-items: center; gap: 12px;\n}\n.auto-map-banner[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] { color: var(--mj-color-indigo-500); font-size: 18px; }\n.auto-map-banner[_ngcontent-%COMP%] .banner-text[_ngcontent-%COMP%] { flex: 1; }\n.auto-map-banner[_ngcontent-%COMP%] .banner-text[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-muted); margin: 0; }\n.auto-map-banner[_ngcontent-%COMP%] .banner-text[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] { color: var(--mj-text-primary); }\n\n\n\n.field-mapping-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 16px;\n}\n.field-mapping-actions[_ngcontent-%COMP%] { display: flex; gap: 6px; }\n\n\n\n.field-map-cards[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; gap: 6px;\n}\n\n.field-map-card[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n overflow: hidden;\n}\n.field-map-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px rgba(74, 108, 247, 0.06);\n}\n.field-map-card.has-transform[_ngcontent-%COMP%] {\n border-left: 3px solid var(--mj-color-indigo-500);\n}\n.field-map-card.validation-error[_ngcontent-%COMP%] {\n border-color: var(--mj-color-warning-200);\n background: var(--mj-status-warning-bg);\n}\n\n\n\n.fmc-row[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 10px;\n padding: 10px 14px;\n}\n\n\n\n.fmc-source[_ngcontent-%COMP%] {\n flex: 1; min-width: 0;\n}\n.fmc-field-name[_ngcontent-%COMP%] {\n font-size: 13px; font-weight: 600; color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n}\n.fmc-badges[_ngcontent-%COMP%] {\n display: flex; gap: 4px; margin-top: 3px; flex-wrap: wrap;\n}\n.fmc-badge[_ngcontent-%COMP%] {\n font-size: 9px; font-weight: 700; padding: 1px 5px;\n border-radius: 3px; text-transform: uppercase; letter-spacing: 0.3px;\n white-space: nowrap; line-height: 1.5;\n}\n.badge-type[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-hover); color: var(--mj-text-muted);\n}\n.badge-pk[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-warning-100), var(--mj-color-warning-200));\n color: var(--mj-color-warning-800);\n}\n.badge-pk[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 8px; margin-right: 2px; }\n.badge-req[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-error-100), var(--mj-color-error-200));\n color: var(--mj-color-error-800);\n}\n.badge-ro[_ngcontent-%COMP%] {\n background: var(--mj-color-purple-50); color: var(--mj-color-purple-700);\n}\n\n\n\n.fmc-transform-zone[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex; align-items: center; justify-content: center;\n width: 100px;\n}\n.fmc-arrow-btn[_ngcontent-%COMP%] {\n width: 32px; height: 32px;\n border-radius: 50%; border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page); color: var(--mj-text-disabled);\n cursor: pointer; font-size: 12px;\n display: flex; align-items: center; justify-content: center;\n transition: all 0.2s;\n}\n.fmc-arrow-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); border-color: var(--mj-color-indigo-500);\n transform: scale(1.1);\n}\n.fmc-transform-pill[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 4px;\n padding: 4px 10px; border-radius: 16px;\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border: 1px solid var(--mj-color-indigo-200); color: var(--mj-color-indigo-700);\n font-size: 11px; font-weight: 600;\n cursor: pointer; transition: all 0.2s;\n white-space: nowrap;\n}\n.fmc-transform-pill[_ngcontent-%COMP%]:hover {\n background: linear-gradient(135deg, var(--mj-color-indigo-100), var(--mj-color-indigo-200));\n transform: scale(1.02);\n}\n.fmc-transform-pill[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 10px; }\n.fmc-transform-direct[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-bg-page), var(--mj-bg-surface-hover));\n border-color: var(--mj-color-neutral-300); color: var(--mj-text-muted);\n}\n.fmc-transform-direct[_ngcontent-%COMP%]:hover {\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border-color: var(--mj-color-indigo-200); color: var(--mj-color-indigo-700);\n}\n.fmc-step-count[_ngcontent-%COMP%] {\n background: var(--mj-color-indigo-700); color: var(--mj-bg-surface); font-size: 9px;\n padding: 0 4px; border-radius: 8px; font-weight: 700;\n}\n\n\n\n.fmc-dest[_ngcontent-%COMP%] {\n flex: 1; min-width: 0;\n}\n.fmc-select[_ngcontent-%COMP%] {\n width: 100%; padding: 6px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: border-color 0.15s;\n}\n.fmc-select[_ngcontent-%COMP%]:focus { border-color: var(--mj-color-indigo-500); outline: none; box-shadow: 0 0 0 2px rgba(74, 108, 247, 0.12); }\n\n\n\n.fmc-input[_ngcontent-%COMP%] {\n width: 100%; padding: 5px 8px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: border-color 0.15s;\n}\n.fmc-input[_ngcontent-%COMP%]:focus { border-color: var(--mj-color-indigo-500); outline: none; box-shadow: 0 0 0 2px rgba(74, 108, 247, 0.12); }\n.fmc-input.mono[_ngcontent-%COMP%] { font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; font-size: 12px; }\n\n\n\n.fmc-flags[_ngcontent-%COMP%] {\n display: flex; gap: 6px; flex-shrink: 0;\n}\n.fmc-flag[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 3px;\n font-size: 11px; color: var(--mj-text-disabled); cursor: pointer;\n padding: 2px 4px; border-radius: 4px;\n transition: color 0.15s;\n}\n.fmc-flag[_ngcontent-%COMP%]:hover { color: var(--mj-color-indigo-500); }\n.fmc-flag[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 13px; height: 13px; cursor: pointer;\n accent-color: var(--mj-color-indigo-500);\n}\n.fmc-flag[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 10px; }\n.fmc-req-star[_ngcontent-%COMP%] { font-size: 14px; font-weight: 700; color: inherit; }\n\n\n\n.fmc-remove[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 13px; padding: 4px;\n border-radius: 4px; transition: all 0.15s;\n}\n.fmc-remove[_ngcontent-%COMP%]:hover { color: var(--mj-status-error); background: var(--mj-status-error-bg); }\n\n\n\n.fmc-transform-editor[_ngcontent-%COMP%] {\n border-top: 1px solid var(--mj-bg-surface-hover);\n background: linear-gradient(180deg, var(--mj-color-indigo-50) 0%, var(--mj-bg-page) 100%);\n padding: 12px 14px;\n}\n.fmc-te-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 10px;\n}\n.fmc-te-title[_ngcontent-%COMP%] {\n font-size: 11px; font-weight: 700; color: var(--mj-color-indigo-500);\n text-transform: uppercase; letter-spacing: 0.5px;\n}\n.fmc-te-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 4px; }\n.fmc-te-add[_ngcontent-%COMP%] {\n font-size: 11px; font-weight: 600; color: var(--mj-color-indigo-500);\n background: none; border: 1px solid var(--mj-color-indigo-200);\n border-radius: 6px; padding: 3px 10px;\n cursor: pointer; transition: all 0.15s;\n}\n.fmc-te-add[_ngcontent-%COMP%]:hover { background: var(--mj-color-indigo-50); }\n.fmc-te-add[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 3px; font-size: 10px; }\n\n\n\n.fmc-te-step[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 10px 12px;\n margin-bottom: 8px;\n transition: box-shadow 0.15s;\n}\n.fmc-te-step[_ngcontent-%COMP%]:hover { box-shadow: 0 1px 4px rgba(0,0,0,0.05); }\n.fmc-te-step[_ngcontent-%COMP%]:last-child { margin-bottom: 0; }\n\n.fmc-te-step-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 8px; margin-bottom: 8px;\n}\n.fmc-te-step-num[_ngcontent-%COMP%] {\n width: 22px; height: 22px; border-radius: 50%;\n background: linear-gradient(135deg, var(--mj-color-indigo-500), var(--mj-color-indigo-500));\n color: var(--mj-bg-surface); font-size: 11px; font-weight: 700;\n display: flex; align-items: center; justify-content: center;\n flex-shrink: 0;\n}\n.fmc-te-type-select[_ngcontent-%COMP%] {\n flex: 1; padding: 4px 8px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 12px; font-weight: 600;\n color: var(--mj-text-primary); background: var(--mj-bg-page);\n}\n.fmc-te-type-select[_ngcontent-%COMP%]:focus { border-color: var(--mj-color-indigo-500); outline: none; }\n.fmc-te-error-select[_ngcontent-%COMP%] {\n width: 100px; padding: 4px 6px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 11px; color: var(--mj-text-muted);\n background: var(--mj-bg-page);\n}\n.fmc-te-error-select[_ngcontent-%COMP%]:focus { border-color: var(--mj-color-indigo-500); outline: none; }\n.fmc-te-remove-step[_ngcontent-%COMP%] {\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 12px; padding: 4px;\n border-radius: 4px; transition: all 0.15s;\n}\n.fmc-te-remove-step[_ngcontent-%COMP%]:hover { color: var(--mj-status-error); background: var(--mj-status-error-bg); }\n\n\n\n.fmc-te-config[_ngcontent-%COMP%] {\n padding-left: 30px;\n}\n.fmc-te-field[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n}\n.fmc-te-field[_ngcontent-%COMP%]:last-child { margin-bottom: 0; }\n.fmc-te-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block; font-size: 11px; font-weight: 600;\n color: var(--mj-text-muted); margin-bottom: 3px;\n}\n.fmc-te-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-hover); padding: 0 3px; border-radius: 3px;\n font-size: 10px; color: var(--mj-color-indigo-700);\n}\n.fmc-te-hint[_ngcontent-%COMP%] { font-weight: 400; color: var(--mj-text-disabled); }\n.fmc-te-row[_ngcontent-%COMP%] {\n display: flex; gap: 10px; align-items: flex-end;\n}\n.fmc-te-sm[_ngcontent-%COMP%] { max-width: 140px; }\n.fmc-textarea[_ngcontent-%COMP%] {\n resize: vertical; min-height: 40px;\n}\n\n\n\n.fmc-combine-chips[_ngcontent-%COMP%] {\n display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px;\n}\n.fmc-chip[_ngcontent-%COMP%] {\n font-size: 11px; padding: 3px 8px; border-radius: 14px;\n border: 1px solid var(--mj-border-default); background: var(--mj-bg-surface);\n color: var(--mj-text-muted); cursor: pointer;\n transition: all 0.15s; font-weight: 500;\n}\n.fmc-chip[_ngcontent-%COMP%]:hover { border-color: var(--mj-color-indigo-300); color: var(--mj-color-indigo-700); }\n.fmc-chip.selected[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border-color: var(--mj-color-indigo-400); color: var(--mj-color-indigo-700); font-weight: 600;\n}\n\n\n\n.fmc-lookup-table[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; gap: 4px; margin-top: 4px;\n}\n.fmc-lookup-row[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 6px;\n}\n.fmc-lookup-row[_ngcontent-%COMP%] .fmc-input[_ngcontent-%COMP%] { flex: 1; }\n.fmc-lookup-arrow[_ngcontent-%COMP%] { color: var(--mj-color-indigo-200); font-size: 10px; flex-shrink: 0; }\n.fmc-lookup-del[_ngcontent-%COMP%] {\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 11px; padding: 2px;\n transition: color 0.15s;\n}\n.fmc-lookup-del[_ngcontent-%COMP%]:hover { color: var(--mj-status-error); }\n.fmc-lookup-add[_ngcontent-%COMP%] {\n font-size: 11px; color: var(--mj-color-indigo-500); background: none;\n border: 1px dashed var(--mj-color-indigo-200); border-radius: 6px;\n padding: 4px 10px; cursor: pointer;\n transition: all 0.15s; margin-top: 2px;\n}\n.fmc-lookup-add[_ngcontent-%COMP%]:hover { background: var(--mj-color-indigo-50); }\n.fmc-lookup-add[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 3px; font-size: 10px; }\n\n\n\n.data-preview-section[_ngcontent-%COMP%] { margin-top: 24px; border-top: 1px solid var(--mj-border-subtle); padding-top: 16px; }\n.preview-actions[_ngcontent-%COMP%] { display: flex; gap: 8px; margin-bottom: 12px; }\n\n.preview-panel[_ngcontent-%COMP%] {\n background: var(--mj-bg-page); border: 1px solid var(--mj-border-default); border-radius: 8px;\n padding: 12px; margin-bottom: 12px;\n}\n.preview-panel-header[_ngcontent-%COMP%] {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 8px;\n}\n.preview-panel-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] { font-size: 13px; font-weight: 600; margin: 0; }\n.preview-panel-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-right: 6px; color: var(--mj-color-indigo-500); }\n\n.preview-table-wrapper[_ngcontent-%COMP%] { overflow-x: auto; }\n.preview-table[_ngcontent-%COMP%] {\n width: 100%; border-collapse: collapse; font-size: 12px;\n}\n.preview-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left; padding: 5px 8px;\n background: var(--mj-border-default); font-weight: 600; font-size: 10px;\n text-transform: uppercase; color: var(--mj-text-muted);\n border-bottom: 1px solid var(--mj-border-default); white-space: nowrap;\n}\n.preview-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 4px 8px; border-bottom: 1px solid var(--mj-border-subtle);\n white-space: nowrap; max-width: 150px; overflow: hidden; text-overflow: ellipsis;\n}\n.preview-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover { background: var(--mj-status-info-bg); }\n\n\n\n.run-summary-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-page); border-radius: 8px; padding: 12px;\n}\n.run-summary-row[_ngcontent-%COMP%] {\n display: flex; justify-content: space-between;\n padding: 4px 0; font-size: 13px;\n}\n.run-summary-row[_ngcontent-%COMP%] .label[_ngcontent-%COMP%] { color: var(--mj-text-muted); font-weight: 500; }\n.run-status[_ngcontent-%COMP%] {\n font-size: 11px; padding: 2px 6px; border-radius: 4px; font-weight: 600;\n}\n.status-green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-color-success-700); }\n.status-amber[_ngcontent-%COMP%] { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n.status-red[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-color-error-600); }\n\n.entity-stat-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-page); border-radius: 6px; padding: 10px;\n margin-bottom: 8px;\n}\n.entity-stat-name[_ngcontent-%COMP%] { font-size: 13px; font-weight: 600; margin-bottom: 6px; }\n.entity-stat-grid[_ngcontent-%COMP%] { display: flex; gap: 12px; }\n.mini-stat[_ngcontent-%COMP%] { text-align: center; }\n.mini-val[_ngcontent-%COMP%] { display: block; font-size: 16px; font-weight: 600; }\n.mini-val.has-errors[_ngcontent-%COMP%] { color: var(--mj-color-error-600); }\n.mini-label[_ngcontent-%COMP%] { font-size: 10px; color: var(--mj-text-disabled); }\n\n\n\n.validation-banner[_ngcontent-%COMP%] {\n background: var(--mj-color-warning-50); border: 1px solid var(--mj-color-warning-200); border-radius: 8px;\n padding: 10px 14px; margin-bottom: 14px;\n display: flex; align-items: flex-start; gap: 10px;\n font-size: 13px; color: var(--mj-color-warning-600);\n}\n.validation-banner[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] { margin-top: 2px; }\n.validation-warnings[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 2px; }\n\n.field-map-card.validation-error[_ngcontent-%COMP%] .fmc-source[_ngcontent-%COMP%] {\n border-left: 3px solid var(--mj-color-warning-600);\n padding-left: 8px;\n}\n\n\n\n@media (max-width: 1100px) { .right-panel[_ngcontent-%COMP%] { display: none; } }\n@media (max-width: 800px) { .left-panel[_ngcontent-%COMP%] { width: 260px; } }"] });
|
|
2360
2360
|
};
|
|
2361
2361
|
MappingWorkspaceComponent = __decorate([
|
|
2362
2362
|
RegisterClass(BaseResourceComponent, 'IntegrationMappingWorkspace')
|
|
@@ -2364,7 +2364,7 @@ MappingWorkspaceComponent = __decorate([
|
|
|
2364
2364
|
export { MappingWorkspaceComponent };
|
|
2365
2365
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MappingWorkspaceComponent, [{
|
|
2366
2366
|
type: Component,
|
|
2367
|
-
args: [{ standalone: false, selector: 'app-mapping-workspace', template: "<div class=\"mapping-workspace\">\n <div class=\"workspace-header\">\n <h2><i class=\"fa-solid fa-diagram-project\"></i> Mapping Workspace</h2>\n </div>\n\n @if (IsLoadingIntegrations) {\n <mj-loading text=\"Loading integrations...\" size=\"medium\"></mj-loading>\n } @else {\n <div class=\"workspace-body\">\n <!-- ============================================================ -->\n <!-- LEFT PANEL: Integration selector + Entity map list -->\n <!-- ============================================================ -->\n <div class=\"left-panel\">\n <div class=\"integration-selector\">\n <label class=\"panel-label\">Integration</label>\n <kendo-dropdownlist\n [data]=\"Integrations\"\n [textField]=\"'Name'\"\n [valueField]=\"'ID'\"\n [valuePrimitive]=\"true\"\n [(ngModel)]=\"SelectedIntegrationID\"\n (valueChange)=\"OnIntegrationChange($event)\"\n [defaultItem]=\"{ ID: '', Name: '-- Select --' }\">\n </kendo-dropdownlist>\n </div>\n\n @if (IsLoadingEntityMaps) {\n <mj-loading text=\"Loading entity maps...\" size=\"small\"></mj-loading>\n } @else if (SelectedIntegrationID) {\n <!-- Entity Map Header -->\n <div class=\"entity-map-header\">\n <span class=\"panel-label\" style=\"margin: 0;\">Entity Maps</span>\n <div class=\"header-actions\">\n <button kendoButton [look]=\"'flat'\" [size]=\"'small'\"\n (click)=\"OpenAddPanel()\" title=\"Add entity map\">\n <i class=\"fa-solid fa-plus\"></i> Add Map\n </button>\n </div>\n </div>\n\n <!-- ==================== ADD MAP PANEL ==================== -->\n @if (ShowAddPanel) {\n <div class=\"add-map-panel\">\n <div class=\"add-panel-top\">\n <h5><i class=\"fa-solid fa-plus-circle\"></i> Add Entity Map</h5>\n <button class=\"add-panel-close\" (click)=\"CloseAddPanel()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Source Object Dropdown -->\n <div class=\"form-group\">\n <label>Source Object</label>\n @if (IsDiscoveringObjects) {\n <div class=\"source-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Discovering objects...\n </div>\n } @else if (DiscoverError) {\n <div class=\"discover-error-inline\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n {{ DiscoverError }}\n </div>\n } @else if (DiscoveredObjects.length === 0) {\n <div class=\"discover-error-inline\">\n No objects found in external system.\n </div>\n } @else {\n <kendo-dropdownlist\n [data]=\"DiscoveredObjects\"\n [textField]=\"'Label'\"\n [valueField]=\"'Name'\"\n [valuePrimitive]=\"true\"\n [(ngModel)]=\"SelectedSourceObjectName\"\n (valueChange)=\"OnSourceObjectChange($event)\"\n [filterable]=\"true\"\n [defaultItem]=\"{ Name: '', Label: 'Select source object...' }\">\n </kendo-dropdownlist>\n }\n </div>\n\n <!-- Target Mode Toggle -->\n <div class=\"target-mode-toggle\">\n <button class=\"target-mode-btn\"\n [class.active]=\"TargetMode === 'existing'\"\n (click)=\"SetTargetMode('existing')\">\n <i class=\"fa-solid fa-database\"></i> Existing Entity\n </button>\n <button class=\"target-mode-btn\"\n [class.active]=\"TargetMode === 'new'\"\n (click)=\"SetTargetMode('new')\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i> New Entity\n </button>\n </div>\n\n <!-- Existing entity picker -->\n @if (TargetMode === 'existing') {\n <div class=\"form-group\">\n <label>Target MJ Entity</label>\n @if (IsLoadingEntities) {\n <mj-loading text=\"Loading...\" size=\"small\"></mj-loading>\n } @else {\n <kendo-dropdownlist\n [data]=\"MJEntities\"\n [textField]=\"'Name'\"\n [valueField]=\"'ID'\"\n [valuePrimitive]=\"true\"\n [(ngModel)]=\"SelectedEntityID\"\n [filterable]=\"true\"\n [defaultItem]=\"{ ID: null, Name: 'Select entity...' }\">\n </kendo-dropdownlist>\n }\n </div>\n }\n\n <!-- New entity form -->\n @if (TargetMode === 'new') {\n <div class=\"new-entity-form\">\n <div class=\"section-label\">Define New Entity</div>\n <div class=\"form-group\">\n <label>DB Schema</label>\n <kendo-combobox\n [data]=\"DBSchemas\"\n [(ngModel)]=\"NewEntitySchemaName\"\n (valueChange)=\"OnSchemaNameChange()\"\n [allowCustom]=\"true\"\n [filterable]=\"true\"\n [placeholder]=\"'Select or type schema...'\">\n </kendo-combobox>\n </div>\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label>Table Name</label>\n <input kendoTextBox [(ngModel)]=\"NewEntityTableName\"\n [placeholder]=\"SuggestedTableName || 'Table name'\" />\n @if (SuggestedTableName && !NewEntityTableName) {\n <span class=\"auto-hint\">Suggested: {{ SuggestedTableName }}</span>\n }\n </div>\n <div class=\"form-group\">\n <label>Entity Name</label>\n <input kendoTextBox [(ngModel)]=\"NewEntityName\"\n [placeholder]=\"SuggestedEntityName || 'Entity name'\" />\n </div>\n </div>\n\n <!-- DDL Preview -->\n @if (SelectedSourceObjectName && NewEntitySchemaName && NewEntityTableName) {\n <div class=\"ddl-preview-section\">\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n [disabled]=\"IsGeneratingDDL\"\n (click)=\"PreviewDDL()\">\n @if (IsGeneratingDDL) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Generating...\n } @else {\n <i class=\"fa-solid fa-database\"></i> Preview DDL\n }\n </button>\n @if (DDLPreviewError) {\n <div class=\"discover-error-inline\" style=\"margin-top: 8px;\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i> {{ DDLPreviewError }}\n </div>\n }\n @if (DDLPreviewContent) {\n <pre class=\"ddl-preview-code\">{{ DDLPreviewContent }}</pre>\n }\n </div>\n }\n </div>\n }\n\n <!-- Sync direction -->\n <div class=\"form-group\">\n <label>Sync Direction</label>\n <kendo-dropdownlist\n [data]=\"['Pull', 'Push', 'Bidirectional']\"\n [(ngModel)]=\"AddSyncDirection\">\n </kendo-dropdownlist>\n </div>\n\n <!-- Save / Cancel -->\n <div class=\"add-form-actions\">\n <button kendoButton [themeColor]=\"'primary'\" [size]=\"'small'\"\n [disabled]=\"!IsAddFormValid || IsSavingEntityMap\"\n (click)=\"SaveAddMap()\">\n @if (IsSavingEntityMap) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else if (TargetMode === 'new') {\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i> Create Pending Map\n } @else {\n <i class=\"fa-solid fa-check\"></i> Add Map\n }\n </button>\n <button kendoButton [size]=\"'small'\" (click)=\"CloseAddPanel()\">\n Cancel\n </button>\n </div>\n </div>\n }\n\n <!-- Search -->\n @if (AllMaps.length > 0) {\n <div class=\"search-box\">\n <input kendoTextBox\n [(ngModel)]=\"EntityMapSearchText\"\n placeholder=\"Search entity maps...\" />\n </div>\n }\n\n <!-- Entity Map List -->\n @if (AllMaps.length === 0 && !ShowAddPanel) {\n <p class=\"empty-hint\">\n No entity maps configured.\n <a href=\"javascript:void(0)\" (click)=\"OpenAddPanel()\" style=\"color: #4a6cf7;\">Add one</a>\n </p>\n } @else if (FilteredMaps.length === 0 && AllMaps.length > 0) {\n <p class=\"empty-hint\">No matches for \"{{ EntityMapSearchText }}\".</p>\n } @else {\n <div class=\"entity-map-list\">\n @for (item of FilteredMaps; track item.ID) {\n <div class=\"entity-map-item\"\n [class.selected]=\"IsSelectedMap(item.ID)\"\n [class.pending]=\"item.IsPending\"\n (click)=\"OnMapSelect(item)\">\n <div class=\"em-top-row\">\n <span class=\"em-name\">{{ item.SourceName }}</span>\n <span class=\"em-arrow\"><i class=\"fa-solid fa-arrow-right\"></i></span>\n <span class=\"em-entity\">{{ item.TargetName }}</span>\n </div>\n <div class=\"em-bottom-row\">\n <div class=\"em-badges\">\n <span class=\"badge badge-direction\">{{ item.SyncDirection }}</span>\n @if (item.IsPending) {\n <span class=\"badge badge-pending\">Pending</span>\n }\n </div>\n <div class=\"em-actions\">\n <button class=\"em-delete\" title=\"Delete\"\n (click)=\"OnDeleteMap(item, $event)\">\n <i class=\"fa-solid fa-trash-can\"></i>\n </button>\n @if (!item.IsPending && item.RealMap) {\n <kendo-switch\n [(ngModel)]=\"item.RealMap.SyncEnabled\"\n [size]=\"'small'\"\n (valueChange)=\"OnToggleEntityMap(item.RealMap)\">\n </kendo-switch>\n }\n </div>\n </div>\n </div>\n }\n </div>\n }\n }\n </div>\n\n <!-- ============================================================ -->\n <!-- CENTER PANEL: Field mapping / Pending entity / Placeholder -->\n <!-- ============================================================ -->\n <div class=\"center-panel\">\n @if (!SelectedMapID) {\n <!-- No selection placeholder -->\n <div class=\"placeholder-message\">\n <i class=\"fa-solid fa-hand-pointer\"></i>\n <p>Select an entity map from the left panel to view and edit field mappings.</p>\n </div>\n } @else if (SelectedPendingMap) {\n <!-- ==================== PENDING ENTITY VIEW ==================== -->\n <div class=\"pending-entity-panel\">\n <div class=\"pending-icon\"><i class=\"fa-solid fa-clock\"></i></div>\n <h3>Pending Entity: {{ SelectedPendingMap.EntityName }}</h3>\n <p>\n This entity map is waiting for the target entity\n <strong>{{ SelectedPendingMap.SchemaName }}.{{ SelectedPendingMap.TableName }}</strong>\n to be created. Run the DDL migration and CodeGen to activate this mapping.\n </p>\n\n <!-- Progress stepper -->\n <div class=\"pending-steps\">\n <div class=\"step\">\n <div class=\"step-circle done\"><i class=\"fa-solid fa-check\"></i></div>\n <span class=\"step-label\">Map Created</span>\n </div>\n <div class=\"step-connector\" [class.done]=\"SelectedPendingMap.DDLContent\"></div>\n <div class=\"step\">\n <div class=\"step-circle\" [ngClass]=\"GetPendingStepStatus(SelectedPendingMap, 2)\">\n @if (SelectedPendingMap.DDLContent) {\n <i class=\"fa-solid fa-check\"></i>\n } @else {\n 2\n }\n </div>\n <span class=\"step-label\">DDL Generated</span>\n </div>\n <div class=\"step-connector\"></div>\n <div class=\"step\">\n <div class=\"step-circle future\">3</div>\n <span class=\"step-label\">Deploy & CodeGen</span>\n </div>\n <div class=\"step-connector\"></div>\n <div class=\"step\">\n <div class=\"step-circle future\">4</div>\n <span class=\"step-label\">Ready to Sync</span>\n </div>\n </div>\n\n <!-- DDL content -->\n @if (SelectedPendingMap.DDLContent) {\n <div class=\"ddl-preview-inline\">\n <h4 style=\"font-size: 14px; margin-bottom: 8px;\">\n <i class=\"fa-solid fa-database\"></i> Generated DDL\n </h4>\n <pre class=\"ddl-code-block\">{{ SelectedPendingMap.DDLContent }}</pre>\n <div class=\"ddl-actions\">\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n (click)=\"CopyDDLToClipboard(SelectedPendingMap.DDLContent)\">\n <i class=\"fa-solid fa-copy\"></i> Copy DDL\n </button>\n </div>\n </div>\n }\n\n <!-- Source fields list -->\n @if (SelectedPendingMap.SourceFields.length > 0) {\n <div class=\"pending-fields-section\">\n <h4 style=\"font-size: 14px; margin: 16px 0 8px;\">\n <i class=\"fa-solid fa-list\"></i> Source Fields\n <span style=\"color: #999; font-weight: 400;\">({{ SelectedPendingMap.SourceFields.length }})</span>\n </h4>\n <div class=\"pending-fields-list\">\n @for (field of SelectedPendingMap.SourceFields; track field.Name) {\n <div class=\"pending-field-item\">\n <span class=\"pending-field-name\">{{ field.Name }}</span>\n <span class=\"pending-field-type\">{{ field.Type }}</span>\n @if (field.IsPrimaryKey) {\n <i class=\"fa-solid fa-key key-icon\" title=\"Key field\"></i>\n }\n @if (field.IsRequired) {\n <span class=\"pending-field-req\">*</span>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n } @else if (IsLoadingFieldMaps) {\n <mj-loading text=\"Loading field maps...\" size=\"medium\"></mj-loading>\n } @else {\n <!-- ==================== FIELD MAPPING EDITOR ==================== -->\n\n <!-- Auto-map banner -->\n @if (ShowAutoMapBanner) {\n <div class=\"auto-map-banner\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i>\n <div class=\"banner-text\">\n <p><strong>{{ AutoMapCount }} field{{ AutoMapCount !== 1 ? 's' : '' }} auto-mapped</strong> by matching source and destination field names.</p>\n </div>\n <button kendoButton [look]=\"'flat'\" [size]=\"'small'\" (click)=\"DismissAutoMapBanner()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n <!-- Validation warnings -->\n @if (ActiveEditableFields.length > 0 && !MappingValidation.IsValid) {\n <div class=\"validation-banner\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <div class=\"validation-warnings\">\n @for (warning of MappingValidation.Warnings; track warning) {\n <span>{{ warning }}</span>\n }\n </div>\n </div>\n }\n\n <div class=\"field-mapping-header\">\n <h3 class=\"panel-title\">\n Field Mappings\n <span class=\"field-count\">({{ ActiveEditableFields.length }})</span>\n </h3>\n <div class=\"field-mapping-actions\">\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n [disabled]=\"IsLoadingSourceFields\"\n (click)=\"RerunAutoMap()\" title=\"Auto-match source and destination fields by name\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i> Auto-Map\n </button>\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n (click)=\"AddFieldMapping()\">\n <i class=\"fa-solid fa-plus\"></i> Add Field\n </button>\n <button kendoButton [themeColor]=\"'primary'\" [size]=\"'small'\"\n [disabled]=\"!HasDirtyFields || IsSavingFields\"\n (click)=\"SaveFieldMappings()\">\n @if (IsSavingFields) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else {\n <i class=\"fa-solid fa-floppy-disk\"></i> Save\n }\n </button>\n </div>\n </div>\n\n @if (ActiveEditableFields.length === 0) {\n <p class=\"empty-hint\">\n No field mappings yet.\n <a href=\"javascript:void(0)\" (click)=\"AddFieldMapping()\" style=\"color: #4a6cf7;\">Add one</a>\n </p>\n } @else {\n <div class=\"field-map-cards\">\n @for (field of ActiveEditableFields; track field; let i = $index) {\n <div class=\"field-map-card\" [class.validation-error]=\"field.IsRequired && !field.DestinationFieldName\"\n [class.has-transform]=\"field.TransformPipeline.length > 0\">\n\n <!-- Main mapping row -->\n <div class=\"fmc-row\">\n <!-- Source column -->\n <div class=\"fmc-source\">\n @if (field.IsNew) {\n <input type=\"text\" class=\"fmc-input\" [(ngModel)]=\"field.SourceFieldName\"\n (ngModelChange)=\"OnFieldChanged(field)\" placeholder=\"Source field name\" />\n } @else {\n <div class=\"fmc-field-name\">{{ field.SourceFieldName }}</div>\n <div class=\"fmc-badges\">\n @if (field.SourceFieldType) {\n <span class=\"fmc-badge badge-type\">{{ field.SourceFieldType }}</span>\n }\n @if (field.IsSourcePK) {\n <span class=\"fmc-badge badge-pk\" title=\"Primary Key\"><i class=\"fa-solid fa-key\"></i> PK</span>\n }\n @if (field.IsSourceRequired) {\n <span class=\"fmc-badge badge-req\" title=\"Required\">REQ</span>\n }\n @if (field.IsSourceReadOnly) {\n <span class=\"fmc-badge badge-ro\" title=\"Read-Only\">RO</span>\n }\n </div>\n }\n </div>\n\n <!-- Transform indicator -->\n <div class=\"fmc-transform-zone\">\n @if (field.TransformPipeline.length > 1) {\n <button class=\"fmc-transform-pill\" (click)=\"ToggleTransformEditor(field)\"\n [title]=\"field.TransformPipeline.length + ' transform step(s)'\">\n <i [class]=\"GetTransformIcon(field.TransformPipeline[0].Type)\"></i>\n <span>{{ GetTransformLabel(field.TransformPipeline[0].Type) }}</span>\n <span class=\"fmc-step-count\">+{{ field.TransformPipeline.length - 1 }}</span>\n </button>\n } @else {\n <button class=\"fmc-transform-pill fmc-transform-direct\" (click)=\"ToggleTransformEditor(field)\"\n title=\"Click to change transform type\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n <span>{{ field.TransformPipeline.length > 0 ? GetTransformLabel(field.TransformPipeline[0].Type) : 'Direct' }}</span>\n </button>\n }\n </div>\n\n <!-- Destination column -->\n <div class=\"fmc-dest\">\n @if (DestinationFields.length > 0) {\n <select class=\"fmc-select\" [(ngModel)]=\"field.DestinationFieldName\"\n (ngModelChange)=\"OnFieldChanged(field)\">\n <option value=\"\">-- Select destination --</option>\n @for (df of DestinationFields; track df.ID) {\n <option [value]=\"df.Name\">{{ df.Name }}</option>\n }\n </select>\n } @else {\n <input type=\"text\" class=\"fmc-input\" [(ngModel)]=\"field.DestinationFieldName\"\n (ngModelChange)=\"OnFieldChanged(field)\" placeholder=\"Destination field\" />\n }\n </div>\n\n <!-- Sync flags -->\n <div class=\"fmc-flags\">\n <label class=\"fmc-flag\" title=\"Key field for matching\">\n <input type=\"checkbox\" [(ngModel)]=\"field.IsKeyField\"\n (ngModelChange)=\"OnFieldChanged(field)\" />\n <i class=\"fa-solid fa-key\"></i>\n </label>\n <label class=\"fmc-flag\" title=\"Required field\">\n <input type=\"checkbox\" [(ngModel)]=\"field.IsRequired\"\n (ngModelChange)=\"OnFieldChanged(field)\" />\n <span class=\"fmc-req-star\">*</span>\n </label>\n </div>\n\n <!-- Remove button -->\n <button class=\"fmc-remove\" title=\"Remove mapping\" (click)=\"RemoveFieldMapping(i)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Transform pipeline editor (expandable) -->\n @if (field.ShowTransformEditor && field.TransformPipeline.length > 0) {\n <div class=\"fmc-transform-editor\">\n <div class=\"fmc-te-header\">\n <span class=\"fmc-te-title\"><i class=\"fa-solid fa-wand-magic-sparkles\"></i> Transform Pipeline</span>\n <button class=\"fmc-te-add\" (click)=\"AddTransformStep(field)\" title=\"Add another step\">\n <i class=\"fa-solid fa-plus\"></i> Add Step\n </button>\n </div>\n @for (step of field.TransformPipeline; track $index; let si = $index) {\n <div class=\"fmc-te-step\">\n <div class=\"fmc-te-step-header\">\n <span class=\"fmc-te-step-num\">{{ si + 1 }}</span>\n <select class=\"fmc-te-type-select\" [ngModel]=\"step.Type\"\n (ngModelChange)=\"OnTransformTypeChange(field, step, $event)\">\n @for (tt of TransformTypes; track tt.Value) {\n <option [value]=\"tt.Value\">{{ tt.Label }}</option>\n }\n </select>\n <select class=\"fmc-te-error-select\" [(ngModel)]=\"step.OnError\"\n (ngModelChange)=\"OnTransformConfigChange(field)\" title=\"On error\">\n <option value=\"Fail\">Fail</option>\n <option value=\"Skip\">Skip row</option>\n <option value=\"Null\">Set null</option>\n </select>\n <button class=\"fmc-te-remove-step\" (click)=\"RemoveTransformStep(field, si)\" title=\"Remove step\">\n <i class=\"fa-solid fa-trash-can\"></i>\n </button>\n </div>\n\n <!-- Config editors per type -->\n <div class=\"fmc-te-config\">\n @switch (step.Type) {\n @case ('direct') {\n <div class=\"fmc-te-field\">\n <label>Default value (when source is null)</label>\n <input type=\"text\" class=\"fmc-input\" [ngModel]=\"step.Config['DefaultValue'] ?? ''\"\n (ngModelChange)=\"step.Config['DefaultValue'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"Leave empty for no default\" />\n </div>\n }\n @case ('regex') {\n <div class=\"fmc-te-row\">\n <div class=\"fmc-te-field\">\n <label>Pattern</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['Pattern'] ?? ''\"\n (ngModelChange)=\"step.Config['Pattern'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"e.g. (\\d{3})-(\\d{4})\" />\n </div>\n <div class=\"fmc-te-field\">\n <label>Replacement</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['Replacement'] ?? ''\"\n (ngModelChange)=\"step.Config['Replacement'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"e.g. $1$2\" />\n </div>\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Flags</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['Flags'] ?? 'g'\"\n (ngModelChange)=\"step.Config['Flags'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"gi\" />\n </div>\n </div>\n }\n @case ('split') {\n <div class=\"fmc-te-row\">\n <div class=\"fmc-te-field\">\n <label>Delimiter</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['Delimiter'] ?? ','\"\n (ngModelChange)=\"step.Config['Delimiter'] = $event; OnTransformConfigChange(field)\"\n placeholder=\",\" />\n </div>\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Part index (0-based)</label>\n <input type=\"number\" class=\"fmc-input\" [ngModel]=\"step.Config['Index'] ?? 0\"\n (ngModelChange)=\"step.Config['Index'] = +$event; OnTransformConfigChange(field)\"\n min=\"0\" />\n </div>\n </div>\n }\n @case ('combine') {\n <div class=\"fmc-te-field\">\n <label>Source fields to combine</label>\n <div class=\"fmc-combine-chips\">\n @for (sf of GetAvailableSourceFields(); track sf) {\n <button class=\"fmc-chip\" [class.selected]=\"IsCombineFieldSelected(step.Config, sf)\"\n (click)=\"ToggleCombineField(step.Config, sf); OnTransformConfigChange(field)\">\n {{ sf }}\n </button>\n }\n </div>\n </div>\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Separator</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['Separator'] ?? ' '\"\n (ngModelChange)=\"step.Config['Separator'] = $event; OnTransformConfigChange(field)\"\n placeholder=\" \" />\n </div>\n }\n @case ('lookup') {\n <div class=\"fmc-te-field\">\n <label>Value mapping</label>\n <div class=\"fmc-lookup-table\">\n @for (entry of GetLookupEntries(step.Config); track $index) {\n <div class=\"fmc-lookup-row\">\n <input type=\"text\" class=\"fmc-input\" [value]=\"entry.key\" placeholder=\"Source value\"\n (change)=\"UpdateLookupEntry(step.Config, entry.key, $any($event.target).value, entry.value); OnTransformConfigChange(field)\" />\n <i class=\"fa-solid fa-arrow-right fmc-lookup-arrow\"></i>\n <input type=\"text\" class=\"fmc-input\" [value]=\"entry.value\" placeholder=\"Mapped value\"\n (change)=\"UpdateLookupEntry(step.Config, entry.key, entry.key, $any($event.target).value); OnTransformConfigChange(field)\" />\n <button class=\"fmc-lookup-del\" (click)=\"RemoveLookupEntry(step.Config, entry.key); OnTransformConfigChange(field)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n <button class=\"fmc-lookup-add\" (click)=\"AddLookupEntry(step.Config); OnTransformConfigChange(field)\">\n <i class=\"fa-solid fa-plus\"></i> Add mapping\n </button>\n </div>\n </div>\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Default (when no match)</label>\n <input type=\"text\" class=\"fmc-input\" [ngModel]=\"step.Config['Default'] ?? ''\"\n (ngModelChange)=\"step.Config['Default'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"null\" />\n </div>\n }\n @case ('format') {\n <div class=\"fmc-te-row\">\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Format type</label>\n <select class=\"fmc-select\" [ngModel]=\"step.Config['FormatType'] ?? 'date'\"\n (ngModelChange)=\"step.Config['FormatType'] = $event; OnTransformConfigChange(field)\">\n <option value=\"date\">Date</option>\n <option value=\"number\">Number</option>\n <option value=\"string\">String</option>\n </select>\n </div>\n <div class=\"fmc-te-field\">\n <label>Format string</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['FormatString'] ?? 'ISO'\"\n (ngModelChange)=\"step.Config['FormatString'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"ISO or decimal places\" />\n </div>\n </div>\n }\n @case ('coerce') {\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Target type</label>\n <select class=\"fmc-select\" [ngModel]=\"step.Config['TargetType'] ?? 'string'\"\n (ngModelChange)=\"step.Config['TargetType'] = $event; OnTransformConfigChange(field)\">\n <option value=\"string\">String</option>\n <option value=\"number\">Number</option>\n <option value=\"boolean\">Boolean</option>\n <option value=\"date\">Date</option>\n </select>\n </div>\n }\n @case ('substring') {\n <div class=\"fmc-te-row\">\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Start index</label>\n <input type=\"number\" class=\"fmc-input\" [ngModel]=\"step.Config['Start'] ?? 0\"\n (ngModelChange)=\"step.Config['Start'] = +$event; OnTransformConfigChange(field)\"\n min=\"0\" />\n </div>\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Length (blank = to end)</label>\n <input type=\"number\" class=\"fmc-input\" [ngModel]=\"step.Config['Length'] ?? ''\"\n (ngModelChange)=\"step.Config['Length'] = $event ? +$event : undefined; OnTransformConfigChange(field)\"\n min=\"1\" />\n </div>\n </div>\n }\n @case ('custom') {\n <div class=\"fmc-te-field\">\n <label>JavaScript expression <span class=\"fmc-te-hint\">(use <code>value</code> and <code>fields</code>)</span></label>\n <textarea class=\"fmc-input mono fmc-textarea\" [ngModel]=\"step.Config['Expression'] ?? 'value'\"\n (ngModelChange)=\"step.Config['Expression'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"value.toUpperCase()\" rows=\"2\"></textarea>\n </div>\n }\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Data Preview Section -->\n <div class=\"data-preview-section\">\n <div class=\"preview-actions\">\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n [disabled]=\"IsLoadingSourcePreview\"\n (click)=\"LoadSourcePreview()\">\n <i class=\"fa-solid fa-cloud-arrow-down\"></i> Preview Source\n </button>\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n [disabled]=\"IsLoadingDestPreview\"\n (click)=\"LoadDestPreview()\">\n <i class=\"fa-solid fa-database\"></i> Preview Destination\n </button>\n </div>\n\n @if (ShowSourcePreview) {\n <div class=\"preview-panel\">\n <div class=\"preview-panel-header\">\n <h4><i class=\"fa-solid fa-cloud\"></i> Source Data Preview</h4>\n <button class=\"add-panel-close\" (click)=\"CloseSourcePreview()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n @if (IsLoadingSourcePreview) {\n <mj-loading text=\"Loading source data...\" size=\"small\"></mj-loading>\n } @else if (SourcePreviewData.length === 0) {\n <p class=\"empty-hint\">No source data available.</p>\n } @else {\n <div class=\"preview-table-wrapper\">\n <table class=\"preview-table\">\n <thead>\n <tr>\n @for (col of GetPreviewColumns(SourcePreviewData); track col) {\n <th>{{ col }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of SourcePreviewData; track $index) {\n <tr>\n @for (col of GetPreviewColumns(SourcePreviewData); track col) {\n <td>{{ FormatPreviewValue(row[col]) }}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n }\n\n @if (ShowDestPreview) {\n <div class=\"preview-panel\">\n <div class=\"preview-panel-header\">\n <h4><i class=\"fa-solid fa-database\"></i> Destination Data Preview</h4>\n <button class=\"add-panel-close\" (click)=\"CloseDestPreview()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n @if (IsLoadingDestPreview) {\n <mj-loading text=\"Loading destination data...\" size=\"small\"></mj-loading>\n } @else if (DestPreviewData.length === 0) {\n <p class=\"empty-hint\">No destination data available.</p>\n } @else {\n <div class=\"preview-table-wrapper\">\n <table class=\"preview-table\">\n <thead>\n <tr>\n @for (col of GetPreviewColumns(DestPreviewData); track col) {\n <th>{{ col }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of DestPreviewData; track $index) {\n <tr>\n @for (col of GetPreviewColumns(DestPreviewData); track col) {\n <td>{{ FormatPreviewValue(row[col]) }}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- ============================================================ -->\n <!-- RIGHT PANEL: Last run details -->\n <!-- ============================================================ -->\n <div class=\"right-panel\">\n <h4 class=\"panel-label\">Last Run Details</h4>\n @if (!SelectedIntegrationID) {\n <p class=\"empty-hint\">Select an integration to see run details.</p>\n } @else if (IsLoadingRunDetails) {\n <mj-loading text=\"Loading...\" size=\"small\"></mj-loading>\n } @else if (!LatestRun) {\n <p class=\"empty-hint\">No runs found.</p>\n } @else {\n <div class=\"run-summary-card\">\n <div class=\"run-summary-row\">\n <span class=\"label\">Status</span>\n <span class=\"run-status\" [class]=\"'status-' + RunStatusColor\">\n {{ LatestRun.Status }}\n </span>\n </div>\n <div class=\"run-summary-row\">\n <span class=\"label\">Started</span>\n <span>{{ FormatDate(LatestRun.StartedAt) }}</span>\n </div>\n <div class=\"run-summary-row\">\n <span class=\"label\">Total Records</span>\n <span>{{ LatestRun.TotalRecords | number }}</span>\n </div>\n <div class=\"run-summary-row\">\n <span class=\"label\">Run By</span>\n <span>{{ LatestRun.RunByUser }}</span>\n </div>\n </div>\n\n @if (RunEntityDetails.length > 0) {\n <h4 class=\"panel-label\" style=\"margin-top: 16px;\">Per-Entity Stats</h4>\n @for (detail of RunEntityDetails; track detail.EntityID) {\n <div class=\"entity-stat-card\">\n <div class=\"entity-stat-name\">{{ detail.Entity }}</div>\n <div class=\"entity-stat-grid\">\n <div class=\"mini-stat\">\n <span class=\"mini-val\">{{ detail.RecordsCreated }}</span>\n <span class=\"mini-label\">Created</span>\n </div>\n <div class=\"mini-stat\">\n <span class=\"mini-val\">{{ detail.RecordsUpdated }}</span>\n <span class=\"mini-label\">Updated</span>\n </div>\n <div class=\"mini-stat\">\n <span class=\"mini-val\" [class.has-errors]=\"detail.RecordsErrored > 0\">\n {{ detail.RecordsErrored }}\n </span>\n <span class=\"mini-label\">Errors</span>\n </div>\n </div>\n </div>\n }\n }\n }\n </div>\n </div>\n }\n</div>\n", styles: [".mapping-workspace { padding: 24px; height: 100%; display: flex; flex-direction: column; }\n.workspace-header {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 16px;\n}\n.workspace-header h2 {\n margin: 0; font-size: 20px; font-weight: 600;\n}\n.workspace-header h2 i { margin-right: 8px; color: var(--mj-color-indigo-500); }\n\n/* ===== Three-panel layout ===== */\n.workspace-body {\n display: flex; flex: 1; gap: 1px; background: var(--mj-border-default);\n border-radius: 10px; overflow: hidden; min-height: 500px;\n}\n\n.left-panel { width: 320px; min-width: 280px; background: var(--mj-bg-surface); padding: 16px; overflow-y: auto; flex-shrink: 0; }\n.center-panel { flex: 1; background: var(--mj-bg-surface); padding: 20px; overflow-y: auto; }\n.right-panel { width: 280px; min-width: 240px; background: var(--mj-bg-surface); padding: 16px; overflow-y: auto; flex-shrink: 0; }\n\n/* ===== Shared ===== */\n.panel-label {\n font-size: 11px; font-weight: 700; color: var(--mj-text-disabled);\n text-transform: uppercase; letter-spacing: 0.6px;\n margin: 0 0 6px 0; display: block;\n}\n.panel-title { margin: 0 0 12px 0; font-size: 16px; font-weight: 600; }\n.panel-title .field-count { color: var(--mj-text-disabled); font-weight: 400; font-size: 13px; }\n.empty-hint { color: var(--mj-text-disabled); font-size: 13px; font-style: italic; }\n.search-box { margin-bottom: 12px; }\n\n/* ===== Integration selector ===== */\n.integration-selector { margin-bottom: 20px; padding-bottom: 16px; border-bottom: 1px solid var(--mj-border-subtle); }\n\n/* ===== Entity Map Header ===== */\n.entity-map-header {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 10px;\n}\n.header-actions { display: flex; gap: 4px; }\n\n/* ===== Add Map Panel ===== */\n.add-map-panel {\n background: var(--mj-bg-page); border: 1px solid var(--mj-border-default); border-radius: 10px;\n padding: 16px; margin-bottom: 14px;\n}\n.add-panel-top {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 14px;\n}\n.add-panel-top h5 { margin: 0; font-size: 14px; font-weight: 600; }\n.add-panel-close {\n background: none; border: none; cursor: pointer; color: var(--mj-text-disabled); font-size: 14px;\n}\n.add-panel-close:hover { color: var(--mj-text-primary); }\n\n.form-group { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }\n.form-group label { font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.form-row { display: flex; gap: 10px; }\n.form-row .form-group { flex: 1; }\n\n.source-loading {\n display: flex; align-items: center; gap: 8px;\n font-size: 12px; color: var(--mj-text-disabled); padding: 6px 0;\n}\n.source-loading i { color: var(--mj-color-indigo-500); }\n\n.discover-error-inline {\n font-size: 12px; color: var(--mj-color-error-600); padding: 6px 0;\n}\n.discover-error-inline i { margin-right: 4px; }\n\n/* Target mode toggle */\n.target-mode-toggle {\n display: flex; border: 1px solid var(--mj-border-default); border-radius: 6px;\n overflow: hidden; margin-bottom: 12px;\n}\n.target-mode-btn {\n flex: 1; padding: 8px 12px; font-size: 12px; font-weight: 600;\n text-align: center; cursor: pointer; background: var(--mj-bg-surface); border: none;\n color: var(--mj-text-muted); transition: all 0.15s;\n}\n.target-mode-btn:first-child { border-right: 1px solid var(--mj-border-default); }\n.target-mode-btn.active { background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); }\n.target-mode-btn:not(.active):hover { background: var(--mj-status-info-bg); color: var(--mj-color-indigo-500); }\n.target-mode-btn i { margin-right: 4px; }\n\n/* New entity form */\n.new-entity-form {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 8px;\n padding: 14px; margin-bottom: 12px;\n}\n.new-entity-form .section-label {\n font-size: 11px; font-weight: 700; color: var(--mj-color-indigo-500);\n text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 10px;\n}\n.auto-hint { font-size: 10px; color: var(--mj-text-disabled); font-style: italic; }\n\n/* DDL preview in add panel */\n.ddl-preview-section { margin-top: 8px; }\n.ddl-preview-code {\n background: var(--mj-color-neutral-900); color: var(--mj-color-neutral-300); padding: 10px;\n border-radius: 4px; font-size: 11px; line-height: 1.5;\n max-height: 200px; overflow: auto; white-space: pre-wrap;\n word-break: break-word; margin-top: 8px;\n}\n\n.add-form-actions { display: flex; gap: 6px; padding-top: 4px; }\n\n/* ===== Entity Map List ===== */\n.entity-map-list { display: flex; flex-direction: column; gap: 4px; }\n.entity-map-item {\n padding: 8px 10px; border-radius: 6px;\n cursor: pointer; border: 1px solid var(--mj-border-subtle); transition: all 0.15s;\n}\n.entity-map-item:hover { background: var(--mj-bg-page); }\n.entity-map-item.selected { background: var(--mj-status-info-bg); border-color: var(--mj-color-indigo-500); }\n.entity-map-item.pending { border-left: 3px solid var(--mj-status-warning); }\n\n.em-top-row {\n display: flex; align-items: center; gap: 4px;\n font-size: 13px; margin-bottom: 4px;\n}\n.em-name { font-weight: 600; }\n.em-arrow { color: var(--mj-text-disabled); font-size: 11px; }\n.em-entity { color: var(--mj-text-muted); }\n\n.em-bottom-row {\n display: flex; align-items: center; justify-content: space-between;\n font-size: 11px; color: var(--mj-text-disabled);\n}\n.em-badges { display: flex; gap: 4px; align-items: center; }\n.badge {\n font-size: 10px; padding: 1px 6px; border-radius: 4px; font-weight: 600;\n}\n.badge-direction { background: var(--mj-bg-surface-hover); color: var(--mj-text-muted); }\n.badge-pending { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n\n.em-actions { display: flex; align-items: center; gap: 4px; }\n.em-delete {\n opacity: 0; transition: opacity 0.15s;\n cursor: pointer; color: var(--mj-color-error-600); background: none; border: none;\n padding: 2px 4px; font-size: 12px;\n}\n.entity-map-item:hover .em-delete { opacity: 1; }\n\n/* ===== Center Panel: Placeholder ===== */\n.placeholder-message {\n display: flex; flex-direction: column; align-items: center;\n justify-content: center; height: 300px; color: var(--mj-text-disabled);\n}\n.placeholder-message i { font-size: 36px; margin-bottom: 12px; }\n.placeholder-message p { text-align: center; }\n\n/* ===== Pending Entity Panel ===== */\n.pending-entity-panel {\n background: var(--mj-status-warning-bg); border: 1px solid var(--mj-color-warning-200); border-radius: 10px;\n padding: 24px; text-align: center;\n}\n.pending-icon { font-size: 40px; color: var(--mj-status-warning); margin-bottom: 12px; }\n.pending-entity-panel h3 { font-size: 16px; margin-bottom: 8px; }\n.pending-entity-panel p { font-size: 13px; color: var(--mj-text-disabled); margin-bottom: 16px; line-height: 1.5; }\n\n/* Stepper */\n.pending-steps {\n display: flex; gap: 0; margin: 20px 0; justify-content: center; align-items: center;\n}\n.step {\n display: flex; flex-direction: column; align-items: center; gap: 6px;\n padding: 0 16px;\n}\n.step-circle {\n width: 36px; height: 36px; border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 14px; font-weight: 700;\n}\n.step-circle.done { background: var(--mj-status-success-bg); color: var(--mj-color-success-700); }\n.step-circle.current { background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); }\n.step-circle.future { background: var(--mj-bg-surface-hover); color: var(--mj-text-disabled); }\n.step-label { font-size: 10px; font-weight: 600; color: var(--mj-text-disabled); text-transform: uppercase; white-space: nowrap; }\n.step-connector { width: 32px; height: 2px; background: var(--mj-border-default); align-self: center; margin-bottom: 18px; }\n.step-connector.done { background: var(--mj-color-success-700); }\n\n/* DDL in pending view */\n.ddl-preview-inline { margin-top: 16px; text-align: left; }\n.ddl-code-block {\n background: var(--mj-color-neutral-900); color: var(--mj-color-neutral-300); padding: 12px;\n border-radius: 6px; font-size: 12px; line-height: 1.5;\n max-height: 250px; overflow: auto; white-space: pre-wrap;\n}\n.ddl-actions { display: flex; gap: 8px; margin-top: 12px; justify-content: center; }\n\n/* Pending fields list */\n.pending-fields-section { text-align: left; }\n.pending-fields-list {\n display: flex; flex-direction: column; gap: 2px;\n max-height: 200px; overflow-y: auto;\n}\n.pending-field-item {\n display: flex; align-items: center; gap: 8px;\n padding: 4px 8px; font-size: 13px; border-radius: 4px;\n}\n.pending-field-item:hover { background: var(--mj-status-warning-bg); }\n.pending-field-name { font-weight: 600; }\n.pending-field-type { font-size: 11px; color: var(--mj-text-disabled); background: var(--mj-bg-surface-hover); padding: 1px 6px; border-radius: 3px; }\n.pending-field-req { color: var(--mj-color-error-600); font-weight: 700; }\n\n/* ===== Auto-map banner ===== */\n.auto-map-banner {\n background: var(--mj-status-info-bg); border: 1px solid var(--mj-color-info-100); border-radius: 8px;\n padding: 12px 16px; margin-bottom: 16px;\n display: flex; align-items: center; gap: 12px;\n}\n.auto-map-banner > i { color: var(--mj-color-indigo-500); font-size: 18px; }\n.auto-map-banner .banner-text { flex: 1; }\n.auto-map-banner .banner-text p { font-size: 13px; color: var(--mj-text-muted); margin: 0; }\n.auto-map-banner .banner-text strong { color: var(--mj-text-primary); }\n\n/* ===== Field Mapping Editor ===== */\n.field-mapping-header {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 16px;\n}\n.field-mapping-actions { display: flex; gap: 6px; }\n\n/* ===== Field Map Cards (New world-class design) ===== */\n.field-map-cards {\n display: flex; flex-direction: column; gap: 6px;\n}\n\n.field-map-card {\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n overflow: hidden;\n}\n.field-map-card:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px rgba(74, 108, 247, 0.06);\n}\n.field-map-card.has-transform {\n border-left: 3px solid var(--mj-color-indigo-500);\n}\n.field-map-card.validation-error {\n border-color: var(--mj-color-warning-200);\n background: var(--mj-status-warning-bg);\n}\n\n/* Main mapping row */\n.fmc-row {\n display: flex; align-items: center; gap: 10px;\n padding: 10px 14px;\n}\n\n/* Source column */\n.fmc-source {\n flex: 1; min-width: 0;\n}\n.fmc-field-name {\n font-size: 13px; font-weight: 600; color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n}\n.fmc-badges {\n display: flex; gap: 4px; margin-top: 3px; flex-wrap: wrap;\n}\n.fmc-badge {\n font-size: 9px; font-weight: 700; padding: 1px 5px;\n border-radius: 3px; text-transform: uppercase; letter-spacing: 0.3px;\n white-space: nowrap; line-height: 1.5;\n}\n.badge-type {\n background: var(--mj-bg-surface-hover); color: var(--mj-text-muted);\n}\n.badge-pk {\n background: linear-gradient(135deg, var(--mj-color-warning-100), var(--mj-color-warning-200));\n color: var(--mj-color-warning-800);\n}\n.badge-pk i { font-size: 8px; margin-right: 2px; }\n.badge-req {\n background: linear-gradient(135deg, var(--mj-color-error-100), var(--mj-color-error-200));\n color: var(--mj-color-error-800);\n}\n.badge-ro {\n background: var(--mj-color-purple-50); color: var(--mj-color-purple-700);\n}\n\n/* Transform zone (center arrow / pill) */\n.fmc-transform-zone {\n flex-shrink: 0;\n display: flex; align-items: center; justify-content: center;\n width: 100px;\n}\n.fmc-arrow-btn {\n width: 32px; height: 32px;\n border-radius: 50%; border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page); color: var(--mj-text-disabled);\n cursor: pointer; font-size: 12px;\n display: flex; align-items: center; justify-content: center;\n transition: all 0.2s;\n}\n.fmc-arrow-btn:hover {\n background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); border-color: var(--mj-color-indigo-500);\n transform: scale(1.1);\n}\n.fmc-transform-pill {\n display: flex; align-items: center; gap: 4px;\n padding: 4px 10px; border-radius: 16px;\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border: 1px solid var(--mj-color-indigo-200); color: var(--mj-color-indigo-700);\n font-size: 11px; font-weight: 600;\n cursor: pointer; transition: all 0.2s;\n white-space: nowrap;\n}\n.fmc-transform-pill:hover {\n background: linear-gradient(135deg, var(--mj-color-indigo-100), var(--mj-color-indigo-200));\n transform: scale(1.02);\n}\n.fmc-transform-pill i { font-size: 10px; }\n.fmc-transform-direct {\n background: linear-gradient(135deg, var(--mj-bg-page), var(--mj-bg-surface-hover));\n border-color: var(--mj-color-neutral-300); color: var(--mj-text-muted);\n}\n.fmc-transform-direct:hover {\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border-color: var(--mj-color-indigo-200); color: var(--mj-color-indigo-700);\n}\n.fmc-step-count {\n background: var(--mj-color-indigo-700); color: var(--mj-bg-surface); font-size: 9px;\n padding: 0 4px; border-radius: 8px; font-weight: 700;\n}\n\n/* Destination column */\n.fmc-dest {\n flex: 1; min-width: 0;\n}\n.fmc-select {\n width: 100%; padding: 6px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: border-color 0.15s;\n}\n.fmc-select:focus { border-color: var(--mj-color-indigo-500); outline: none; box-shadow: 0 0 0 2px rgba(74, 108, 247, 0.12); }\n\n/* Shared input style */\n.fmc-input {\n width: 100%; padding: 5px 8px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: border-color 0.15s;\n}\n.fmc-input:focus { border-color: var(--mj-color-indigo-500); outline: none; box-shadow: 0 0 0 2px rgba(74, 108, 247, 0.12); }\n.fmc-input.mono { font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; font-size: 12px; }\n\n/* Flags (key, required) */\n.fmc-flags {\n display: flex; gap: 6px; flex-shrink: 0;\n}\n.fmc-flag {\n display: flex; align-items: center; gap: 3px;\n font-size: 11px; color: var(--mj-text-disabled); cursor: pointer;\n padding: 2px 4px; border-radius: 4px;\n transition: color 0.15s;\n}\n.fmc-flag:hover { color: var(--mj-color-indigo-500); }\n.fmc-flag input[type=\"checkbox\"] {\n width: 13px; height: 13px; cursor: pointer;\n accent-color: var(--mj-color-indigo-500);\n}\n.fmc-flag i { font-size: 10px; }\n.fmc-req-star { font-size: 14px; font-weight: 700; color: inherit; }\n\n/* Remove button */\n.fmc-remove {\n flex-shrink: 0;\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 13px; padding: 4px;\n border-radius: 4px; transition: all 0.15s;\n}\n.fmc-remove:hover { color: var(--mj-status-error); background: var(--mj-status-error-bg); }\n\n/* ===== Transform Pipeline Editor ===== */\n.fmc-transform-editor {\n border-top: 1px solid var(--mj-bg-surface-hover);\n background: linear-gradient(180deg, var(--mj-color-indigo-50) 0%, var(--mj-bg-page) 100%);\n padding: 12px 14px;\n}\n.fmc-te-header {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 10px;\n}\n.fmc-te-title {\n font-size: 11px; font-weight: 700; color: var(--mj-color-indigo-500);\n text-transform: uppercase; letter-spacing: 0.5px;\n}\n.fmc-te-title i { margin-right: 4px; }\n.fmc-te-add {\n font-size: 11px; font-weight: 600; color: var(--mj-color-indigo-500);\n background: none; border: 1px solid var(--mj-color-indigo-200);\n border-radius: 6px; padding: 3px 10px;\n cursor: pointer; transition: all 0.15s;\n}\n.fmc-te-add:hover { background: var(--mj-color-indigo-50); }\n.fmc-te-add i { margin-right: 3px; font-size: 10px; }\n\n/* Individual transform step */\n.fmc-te-step {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 10px 12px;\n margin-bottom: 8px;\n transition: box-shadow 0.15s;\n}\n.fmc-te-step:hover { box-shadow: 0 1px 4px rgba(0,0,0,0.05); }\n.fmc-te-step:last-child { margin-bottom: 0; }\n\n.fmc-te-step-header {\n display: flex; align-items: center; gap: 8px; margin-bottom: 8px;\n}\n.fmc-te-step-num {\n width: 22px; height: 22px; border-radius: 50%;\n background: linear-gradient(135deg, var(--mj-color-indigo-500), var(--mj-color-indigo-500));\n color: var(--mj-bg-surface); font-size: 11px; font-weight: 700;\n display: flex; align-items: center; justify-content: center;\n flex-shrink: 0;\n}\n.fmc-te-type-select {\n flex: 1; padding: 4px 8px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 12px; font-weight: 600;\n color: var(--mj-text-primary); background: var(--mj-bg-page);\n}\n.fmc-te-type-select:focus { border-color: var(--mj-color-indigo-500); outline: none; }\n.fmc-te-error-select {\n width: 100px; padding: 4px 6px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 11px; color: var(--mj-text-muted);\n background: var(--mj-bg-page);\n}\n.fmc-te-error-select:focus { border-color: var(--mj-color-indigo-500); outline: none; }\n.fmc-te-remove-step {\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 12px; padding: 4px;\n border-radius: 4px; transition: all 0.15s;\n}\n.fmc-te-remove-step:hover { color: var(--mj-status-error); background: var(--mj-status-error-bg); }\n\n/* Config area */\n.fmc-te-config {\n padding-left: 30px;\n}\n.fmc-te-field {\n margin-bottom: 8px;\n}\n.fmc-te-field:last-child { margin-bottom: 0; }\n.fmc-te-field label {\n display: block; font-size: 11px; font-weight: 600;\n color: var(--mj-text-muted); margin-bottom: 3px;\n}\n.fmc-te-field label code {\n background: var(--mj-bg-surface-hover); padding: 0 3px; border-radius: 3px;\n font-size: 10px; color: var(--mj-color-indigo-700);\n}\n.fmc-te-hint { font-weight: 400; color: var(--mj-text-disabled); }\n.fmc-te-row {\n display: flex; gap: 10px; align-items: flex-end;\n}\n.fmc-te-sm { max-width: 140px; }\n.fmc-textarea {\n resize: vertical; min-height: 40px;\n}\n\n/* Combine chips */\n.fmc-combine-chips {\n display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px;\n}\n.fmc-chip {\n font-size: 11px; padding: 3px 8px; border-radius: 14px;\n border: 1px solid var(--mj-border-default); background: var(--mj-bg-surface);\n color: var(--mj-text-muted); cursor: pointer;\n transition: all 0.15s; font-weight: 500;\n}\n.fmc-chip:hover { border-color: var(--mj-color-indigo-300); color: var(--mj-color-indigo-700); }\n.fmc-chip.selected {\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border-color: var(--mj-color-indigo-400); color: var(--mj-color-indigo-700); font-weight: 600;\n}\n\n/* Lookup table */\n.fmc-lookup-table {\n display: flex; flex-direction: column; gap: 4px; margin-top: 4px;\n}\n.fmc-lookup-row {\n display: flex; align-items: center; gap: 6px;\n}\n.fmc-lookup-row .fmc-input { flex: 1; }\n.fmc-lookup-arrow { color: var(--mj-color-indigo-200); font-size: 10px; flex-shrink: 0; }\n.fmc-lookup-del {\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 11px; padding: 2px;\n transition: color 0.15s;\n}\n.fmc-lookup-del:hover { color: var(--mj-status-error); }\n.fmc-lookup-add {\n font-size: 11px; color: var(--mj-color-indigo-500); background: none;\n border: 1px dashed var(--mj-color-indigo-200); border-radius: 6px;\n padding: 4px 10px; cursor: pointer;\n transition: all 0.15s; margin-top: 2px;\n}\n.fmc-lookup-add:hover { background: var(--mj-color-indigo-50); }\n.fmc-lookup-add i { margin-right: 3px; font-size: 10px; }\n\n/* ===== Data Preview ===== */\n.data-preview-section { margin-top: 24px; border-top: 1px solid var(--mj-border-subtle); padding-top: 16px; }\n.preview-actions { display: flex; gap: 8px; margin-bottom: 12px; }\n\n.preview-panel {\n background: var(--mj-bg-page); border: 1px solid var(--mj-border-default); border-radius: 8px;\n padding: 12px; margin-bottom: 12px;\n}\n.preview-panel-header {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 8px;\n}\n.preview-panel-header h4 { font-size: 13px; font-weight: 600; margin: 0; }\n.preview-panel-header h4 i { margin-right: 6px; color: var(--mj-color-indigo-500); }\n\n.preview-table-wrapper { overflow-x: auto; }\n.preview-table {\n width: 100%; border-collapse: collapse; font-size: 12px;\n}\n.preview-table th {\n text-align: left; padding: 5px 8px;\n background: var(--mj-border-default); font-weight: 600; font-size: 10px;\n text-transform: uppercase; color: var(--mj-text-muted);\n border-bottom: 1px solid var(--mj-border-default); white-space: nowrap;\n}\n.preview-table td {\n padding: 4px 8px; border-bottom: 1px solid var(--mj-border-subtle);\n white-space: nowrap; max-width: 150px; overflow: hidden; text-overflow: ellipsis;\n}\n.preview-table tr:hover { background: var(--mj-status-info-bg); }\n\n/* ===== Right panel: run details ===== */\n.run-summary-card {\n background: var(--mj-bg-page); border-radius: 8px; padding: 12px;\n}\n.run-summary-row {\n display: flex; justify-content: space-between;\n padding: 4px 0; font-size: 13px;\n}\n.run-summary-row .label { color: var(--mj-text-muted); font-weight: 500; }\n.run-status {\n font-size: 11px; padding: 2px 6px; border-radius: 4px; font-weight: 600;\n}\n.status-green { background: var(--mj-status-success-bg); color: var(--mj-color-success-700); }\n.status-amber { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n.status-red { background: var(--mj-status-error-bg); color: var(--mj-color-error-600); }\n\n.entity-stat-card {\n background: var(--mj-bg-page); border-radius: 6px; padding: 10px;\n margin-bottom: 8px;\n}\n.entity-stat-name { font-size: 13px; font-weight: 600; margin-bottom: 6px; }\n.entity-stat-grid { display: flex; gap: 12px; }\n.mini-stat { text-align: center; }\n.mini-val { display: block; font-size: 16px; font-weight: 600; }\n.mini-val.has-errors { color: var(--mj-color-error-600); }\n.mini-label { font-size: 10px; color: var(--mj-text-disabled); }\n\n/* ===== Validation ===== */\n.validation-banner {\n background: var(--mj-color-warning-50); border: 1px solid var(--mj-color-warning-200); border-radius: 8px;\n padding: 10px 14px; margin-bottom: 14px;\n display: flex; align-items: flex-start; gap: 10px;\n font-size: 13px; color: var(--mj-color-warning-600);\n}\n.validation-banner > i { margin-top: 2px; }\n.validation-warnings { display: flex; flex-direction: column; gap: 2px; }\n\n.field-map-card.validation-error .fmc-source {\n border-left: 3px solid var(--mj-color-warning-600);\n padding-left: 8px;\n}\n\n/* ===== Responsive ===== */\n@media (max-width: 1100px) { .right-panel { display: none; } }\n@media (max-width: 800px) { .left-panel { width: 260px; } }\n"] }]
|
|
2367
|
+
args: [{ standalone: false, selector: 'app-mapping-workspace', template: "<div class=\"mapping-workspace\">\n <div class=\"workspace-header\">\n <h2><i class=\"fa-solid fa-diagram-project\"></i> Mapping Workspace</h2>\n </div>\n\n @if (IsLoadingIntegrations) {\n <mj-loading text=\"Loading integrations...\" size=\"medium\"></mj-loading>\n } @else {\n <div class=\"workspace-body\">\n <!-- ============================================================ -->\n <!-- LEFT PANEL: Integration selector + Entity map list -->\n <!-- ============================================================ -->\n <div class=\"left-panel\">\n <div class=\"integration-selector\">\n <label class=\"panel-label\">Integration</label>\n <kendo-dropdownlist\n [data]=\"Integrations\"\n [textField]=\"'Name'\"\n [valueField]=\"'ID'\"\n [valuePrimitive]=\"true\"\n [(ngModel)]=\"SelectedIntegrationID\"\n (valueChange)=\"OnIntegrationChange($event)\"\n [defaultItem]=\"{ ID: '', Name: '-- Select --' }\">\n </kendo-dropdownlist>\n </div>\n\n @if (IsLoadingEntityMaps) {\n <mj-loading text=\"Loading entity maps...\" size=\"small\"></mj-loading>\n } @else if (SelectedIntegrationID) {\n <!-- Entity Map Header -->\n <div class=\"entity-map-header\">\n <span class=\"panel-label\" style=\"margin: 0;\">Entity Maps</span>\n <div class=\"header-actions\">\n <button kendoButton [look]=\"'flat'\" [size]=\"'small'\"\n (click)=\"OpenAddPanel()\" title=\"Add entity map\">\n <i class=\"fa-solid fa-plus\"></i> Add Map\n </button>\n </div>\n </div>\n\n <!-- ==================== ADD MAP PANEL ==================== -->\n @if (ShowAddPanel) {\n <div class=\"add-map-panel\">\n <div class=\"add-panel-top\">\n <h5><i class=\"fa-solid fa-plus-circle\"></i> Add Entity Map</h5>\n <button class=\"add-panel-close\" (click)=\"CloseAddPanel()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Source Object Dropdown -->\n <div class=\"form-group\">\n <label>Source Object</label>\n @if (IsDiscoveringObjects) {\n <div class=\"source-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Discovering objects...\n </div>\n } @else if (DiscoverError) {\n <div class=\"discover-error-inline\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n {{ DiscoverError }}\n </div>\n } @else if (DiscoveredObjects.length === 0) {\n <div class=\"discover-error-inline\">\n No objects found in external system.\n </div>\n } @else {\n <kendo-dropdownlist\n [data]=\"DiscoveredObjects\"\n [textField]=\"'Label'\"\n [valueField]=\"'Name'\"\n [valuePrimitive]=\"true\"\n [(ngModel)]=\"SelectedSourceObjectName\"\n (valueChange)=\"OnSourceObjectChange($event)\"\n [filterable]=\"true\"\n [defaultItem]=\"{ Name: '', Label: 'Select source object...' }\">\n </kendo-dropdownlist>\n }\n </div>\n\n <!-- Target Mode Toggle -->\n <div class=\"target-mode-toggle\">\n <button class=\"target-mode-btn\"\n [class.active]=\"TargetMode === 'existing'\"\n (click)=\"SetTargetMode('existing')\">\n <i class=\"fa-solid fa-database\"></i> Existing Entity\n </button>\n <button class=\"target-mode-btn\"\n [class.active]=\"TargetMode === 'new'\"\n (click)=\"SetTargetMode('new')\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i> New Entity\n </button>\n </div>\n\n <!-- Existing entity picker -->\n @if (TargetMode === 'existing') {\n <div class=\"form-group\">\n <label>Target MJ Entity</label>\n @if (IsLoadingEntities) {\n <mj-loading text=\"Loading...\" size=\"small\"></mj-loading>\n } @else {\n <kendo-dropdownlist\n [data]=\"MJEntities\"\n [textField]=\"'Name'\"\n [valueField]=\"'ID'\"\n [valuePrimitive]=\"true\"\n [(ngModel)]=\"SelectedEntityID\"\n [filterable]=\"true\"\n [defaultItem]=\"{ ID: null, Name: 'Select entity...' }\">\n </kendo-dropdownlist>\n }\n </div>\n }\n\n <!-- New entity form -->\n @if (TargetMode === 'new') {\n <div class=\"new-entity-form\">\n <div class=\"section-label\">Define New Entity</div>\n <div class=\"form-group\">\n <label>DB Schema</label>\n <kendo-combobox\n [data]=\"DBSchemas\"\n [(ngModel)]=\"NewEntitySchemaName\"\n (valueChange)=\"OnSchemaNameChange()\"\n [allowCustom]=\"true\"\n [filterable]=\"true\"\n [placeholder]=\"'Select or type schema...'\">\n </kendo-combobox>\n </div>\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label>Table Name</label>\n <input kendoTextBox [(ngModel)]=\"NewEntityTableName\"\n [placeholder]=\"SuggestedTableName || 'Table name'\" />\n @if (SuggestedTableName && !NewEntityTableName) {\n <span class=\"auto-hint\">Suggested: {{ SuggestedTableName }}</span>\n }\n </div>\n <div class=\"form-group\">\n <label>Entity Name</label>\n <input kendoTextBox [(ngModel)]=\"NewEntityName\"\n [placeholder]=\"SuggestedEntityName || 'Entity name'\" />\n </div>\n </div>\n\n <!-- DDL Preview -->\n @if (SelectedSourceObjectName && NewEntitySchemaName && NewEntityTableName) {\n <div class=\"ddl-preview-section\">\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n [disabled]=\"IsGeneratingDDL\"\n (click)=\"PreviewDDL()\">\n @if (IsGeneratingDDL) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Generating...\n } @else {\n <i class=\"fa-solid fa-database\"></i> Preview DDL\n }\n </button>\n @if (DDLPreviewError) {\n <div class=\"discover-error-inline\" style=\"margin-top: 8px;\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i> {{ DDLPreviewError }}\n </div>\n }\n @if (DDLPreviewContent) {\n <pre class=\"ddl-preview-code\">{{ DDLPreviewContent }}</pre>\n }\n </div>\n }\n </div>\n }\n\n <!-- Sync direction -->\n <div class=\"form-group\">\n <label>Sync Direction</label>\n <kendo-dropdownlist\n [data]=\"['Pull', 'Push', 'Bidirectional']\"\n [(ngModel)]=\"AddSyncDirection\">\n </kendo-dropdownlist>\n </div>\n\n <!-- Save / Cancel -->\n <div class=\"add-form-actions\">\n <button kendoButton [themeColor]=\"'primary'\" [size]=\"'small'\"\n [disabled]=\"!IsAddFormValid || IsSavingEntityMap\"\n (click)=\"SaveAddMap()\">\n @if (IsSavingEntityMap) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else if (TargetMode === 'new') {\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i> Create Pending Map\n } @else {\n <i class=\"fa-solid fa-check\"></i> Add Map\n }\n </button>\n <button kendoButton [size]=\"'small'\" (click)=\"CloseAddPanel()\">\n Cancel\n </button>\n </div>\n </div>\n }\n\n <!-- Search -->\n @if (AllMaps.length > 0) {\n <div class=\"search-box\">\n <input kendoTextBox\n [(ngModel)]=\"EntityMapSearchText\"\n placeholder=\"Search entity maps...\" />\n </div>\n }\n\n <!-- Entity Map List -->\n @if (AllMaps.length === 0 && !ShowAddPanel) {\n <p class=\"empty-hint\">\n No entity maps configured.\n <a href=\"javascript:void(0)\" (click)=\"OpenAddPanel()\" style=\"color: var(--mj-brand-primary);\">Add one</a>\n </p>\n } @else if (FilteredMaps.length === 0 && AllMaps.length > 0) {\n <p class=\"empty-hint\">No matches for \"{{ EntityMapSearchText }}\".</p>\n } @else {\n <div class=\"entity-map-list\">\n @for (item of FilteredMaps; track item.ID) {\n <div class=\"entity-map-item\"\n [class.selected]=\"IsSelectedMap(item.ID)\"\n [class.pending]=\"item.IsPending\"\n (click)=\"OnMapSelect(item)\">\n <div class=\"em-top-row\">\n <span class=\"em-name\">{{ item.SourceName }}</span>\n <span class=\"em-arrow\"><i class=\"fa-solid fa-arrow-right\"></i></span>\n <span class=\"em-entity\">{{ item.TargetName }}</span>\n </div>\n <div class=\"em-bottom-row\">\n <div class=\"em-badges\">\n <span class=\"badge badge-direction\">{{ item.SyncDirection }}</span>\n @if (item.IsPending) {\n <span class=\"badge badge-pending\">Pending</span>\n }\n </div>\n <div class=\"em-actions\">\n <button class=\"em-delete\" title=\"Delete\"\n (click)=\"OnDeleteMap(item, $event)\">\n <i class=\"fa-solid fa-trash-can\"></i>\n </button>\n @if (!item.IsPending && item.RealMap) {\n <kendo-switch\n [(ngModel)]=\"item.RealMap.SyncEnabled\"\n [size]=\"'small'\"\n (valueChange)=\"OnToggleEntityMap(item.RealMap)\">\n </kendo-switch>\n }\n </div>\n </div>\n </div>\n }\n </div>\n }\n }\n </div>\n\n <!-- ============================================================ -->\n <!-- CENTER PANEL: Field mapping / Pending entity / Placeholder -->\n <!-- ============================================================ -->\n <div class=\"center-panel\">\n @if (!SelectedMapID) {\n <!-- No selection placeholder -->\n <div class=\"placeholder-message\">\n <i class=\"fa-solid fa-hand-pointer\"></i>\n <p>Select an entity map from the left panel to view and edit field mappings.</p>\n </div>\n } @else if (SelectedPendingMap) {\n <!-- ==================== PENDING ENTITY VIEW ==================== -->\n <div class=\"pending-entity-panel\">\n <div class=\"pending-icon\"><i class=\"fa-solid fa-clock\"></i></div>\n <h3>Pending Entity: {{ SelectedPendingMap.EntityName }}</h3>\n <p>\n This entity map is waiting for the target entity\n <strong>{{ SelectedPendingMap.SchemaName }}.{{ SelectedPendingMap.TableName }}</strong>\n to be created. Run the DDL migration and CodeGen to activate this mapping.\n </p>\n\n <!-- Progress stepper -->\n <div class=\"pending-steps\">\n <div class=\"step\">\n <div class=\"step-circle done\"><i class=\"fa-solid fa-check\"></i></div>\n <span class=\"step-label\">Map Created</span>\n </div>\n <div class=\"step-connector\" [class.done]=\"SelectedPendingMap.DDLContent\"></div>\n <div class=\"step\">\n <div class=\"step-circle\" [ngClass]=\"GetPendingStepStatus(SelectedPendingMap, 2)\">\n @if (SelectedPendingMap.DDLContent) {\n <i class=\"fa-solid fa-check\"></i>\n } @else {\n 2\n }\n </div>\n <span class=\"step-label\">DDL Generated</span>\n </div>\n <div class=\"step-connector\"></div>\n <div class=\"step\">\n <div class=\"step-circle future\">3</div>\n <span class=\"step-label\">Deploy & CodeGen</span>\n </div>\n <div class=\"step-connector\"></div>\n <div class=\"step\">\n <div class=\"step-circle future\">4</div>\n <span class=\"step-label\">Ready to Sync</span>\n </div>\n </div>\n\n <!-- DDL content -->\n @if (SelectedPendingMap.DDLContent) {\n <div class=\"ddl-preview-inline\">\n <h4 style=\"font-size: 14px; margin-bottom: 8px;\">\n <i class=\"fa-solid fa-database\"></i> Generated DDL\n </h4>\n <pre class=\"ddl-code-block\">{{ SelectedPendingMap.DDLContent }}</pre>\n <div class=\"ddl-actions\">\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n (click)=\"CopyDDLToClipboard(SelectedPendingMap.DDLContent)\">\n <i class=\"fa-solid fa-copy\"></i> Copy DDL\n </button>\n </div>\n </div>\n }\n\n <!-- Source fields list -->\n @if (SelectedPendingMap.SourceFields.length > 0) {\n <div class=\"pending-fields-section\">\n <h4 style=\"font-size: 14px; margin: 16px 0 8px;\">\n <i class=\"fa-solid fa-list\"></i> Source Fields\n <span style=\"color: var(--mj-text-muted); font-weight: 400;\">({{ SelectedPendingMap.SourceFields.length }})</span>\n </h4>\n <div class=\"pending-fields-list\">\n @for (field of SelectedPendingMap.SourceFields; track field.Name) {\n <div class=\"pending-field-item\">\n <span class=\"pending-field-name\">{{ field.Name }}</span>\n <span class=\"pending-field-type\">{{ field.Type }}</span>\n @if (field.IsPrimaryKey) {\n <i class=\"fa-solid fa-key key-icon\" title=\"Key field\"></i>\n }\n @if (field.IsRequired) {\n <span class=\"pending-field-req\">*</span>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n } @else if (IsLoadingFieldMaps) {\n <mj-loading text=\"Loading field maps...\" size=\"medium\"></mj-loading>\n } @else {\n <!-- ==================== FIELD MAPPING EDITOR ==================== -->\n\n <!-- Auto-map banner -->\n @if (ShowAutoMapBanner) {\n <div class=\"auto-map-banner\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i>\n <div class=\"banner-text\">\n <p><strong>{{ AutoMapCount }} field{{ AutoMapCount !== 1 ? 's' : '' }} auto-mapped</strong> by matching source and destination field names.</p>\n </div>\n <button kendoButton [look]=\"'flat'\" [size]=\"'small'\" (click)=\"DismissAutoMapBanner()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n <!-- Validation warnings -->\n @if (ActiveEditableFields.length > 0 && !MappingValidation.IsValid) {\n <div class=\"validation-banner\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <div class=\"validation-warnings\">\n @for (warning of MappingValidation.Warnings; track warning) {\n <span>{{ warning }}</span>\n }\n </div>\n </div>\n }\n\n <div class=\"field-mapping-header\">\n <h3 class=\"panel-title\">\n Field Mappings\n <span class=\"field-count\">({{ ActiveEditableFields.length }})</span>\n </h3>\n <div class=\"field-mapping-actions\">\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n [disabled]=\"IsLoadingSourceFields\"\n (click)=\"RerunAutoMap()\" title=\"Auto-match source and destination fields by name\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i> Auto-Map\n </button>\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n (click)=\"AddFieldMapping()\">\n <i class=\"fa-solid fa-plus\"></i> Add Field\n </button>\n <button kendoButton [themeColor]=\"'primary'\" [size]=\"'small'\"\n [disabled]=\"!HasDirtyFields || IsSavingFields\"\n (click)=\"SaveFieldMappings()\">\n @if (IsSavingFields) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else {\n <i class=\"fa-solid fa-floppy-disk\"></i> Save\n }\n </button>\n </div>\n </div>\n\n @if (ActiveEditableFields.length === 0) {\n <p class=\"empty-hint\">\n No field mappings yet.\n <a href=\"javascript:void(0)\" (click)=\"AddFieldMapping()\" style=\"color: var(--mj-brand-primary);\">Add one</a>\n </p>\n } @else {\n <div class=\"field-map-cards\">\n @for (field of ActiveEditableFields; track field; let i = $index) {\n <div class=\"field-map-card\" [class.validation-error]=\"field.IsRequired && !field.DestinationFieldName\"\n [class.has-transform]=\"field.TransformPipeline.length > 0\">\n\n <!-- Main mapping row -->\n <div class=\"fmc-row\">\n <!-- Source column -->\n <div class=\"fmc-source\">\n @if (field.IsNew) {\n <input type=\"text\" class=\"fmc-input\" [(ngModel)]=\"field.SourceFieldName\"\n (ngModelChange)=\"OnFieldChanged(field)\" placeholder=\"Source field name\" />\n } @else {\n <div class=\"fmc-field-name\">{{ field.SourceFieldName }}</div>\n <div class=\"fmc-badges\">\n @if (field.SourceFieldType) {\n <span class=\"fmc-badge badge-type\">{{ field.SourceFieldType }}</span>\n }\n @if (field.IsSourcePK) {\n <span class=\"fmc-badge badge-pk\" title=\"Primary Key\"><i class=\"fa-solid fa-key\"></i> PK</span>\n }\n @if (field.IsSourceRequired) {\n <span class=\"fmc-badge badge-req\" title=\"Required\">REQ</span>\n }\n @if (field.IsSourceReadOnly) {\n <span class=\"fmc-badge badge-ro\" title=\"Read-Only\">RO</span>\n }\n </div>\n }\n </div>\n\n <!-- Transform indicator -->\n <div class=\"fmc-transform-zone\">\n @if (field.TransformPipeline.length > 1) {\n <button class=\"fmc-transform-pill\" (click)=\"ToggleTransformEditor(field)\"\n [title]=\"field.TransformPipeline.length + ' transform step(s)'\">\n <i [class]=\"GetTransformIcon(field.TransformPipeline[0].Type)\"></i>\n <span>{{ GetTransformLabel(field.TransformPipeline[0].Type) }}</span>\n <span class=\"fmc-step-count\">+{{ field.TransformPipeline.length - 1 }}</span>\n </button>\n } @else {\n <button class=\"fmc-transform-pill fmc-transform-direct\" (click)=\"ToggleTransformEditor(field)\"\n title=\"Click to change transform type\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n <span>{{ field.TransformPipeline.length > 0 ? GetTransformLabel(field.TransformPipeline[0].Type) : 'Direct' }}</span>\n </button>\n }\n </div>\n\n <!-- Destination column -->\n <div class=\"fmc-dest\">\n @if (DestinationFields.length > 0) {\n <select class=\"fmc-select\" [(ngModel)]=\"field.DestinationFieldName\"\n (ngModelChange)=\"OnFieldChanged(field)\">\n <option value=\"\">-- Select destination --</option>\n @for (df of DestinationFields; track df.ID) {\n <option [value]=\"df.Name\">{{ df.Name }}</option>\n }\n </select>\n } @else {\n <input type=\"text\" class=\"fmc-input\" [(ngModel)]=\"field.DestinationFieldName\"\n (ngModelChange)=\"OnFieldChanged(field)\" placeholder=\"Destination field\" />\n }\n </div>\n\n <!-- Sync flags -->\n <div class=\"fmc-flags\">\n <label class=\"fmc-flag\" title=\"Key field for matching\">\n <input type=\"checkbox\" [(ngModel)]=\"field.IsKeyField\"\n (ngModelChange)=\"OnFieldChanged(field)\" />\n <i class=\"fa-solid fa-key\"></i>\n </label>\n <label class=\"fmc-flag\" title=\"Required field\">\n <input type=\"checkbox\" [(ngModel)]=\"field.IsRequired\"\n (ngModelChange)=\"OnFieldChanged(field)\" />\n <span class=\"fmc-req-star\">*</span>\n </label>\n </div>\n\n <!-- Remove button -->\n <button class=\"fmc-remove\" title=\"Remove mapping\" (click)=\"RemoveFieldMapping(i)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Transform pipeline editor (expandable) -->\n @if (field.ShowTransformEditor && field.TransformPipeline.length > 0) {\n <div class=\"fmc-transform-editor\">\n <div class=\"fmc-te-header\">\n <span class=\"fmc-te-title\"><i class=\"fa-solid fa-wand-magic-sparkles\"></i> Transform Pipeline</span>\n <button class=\"fmc-te-add\" (click)=\"AddTransformStep(field)\" title=\"Add another step\">\n <i class=\"fa-solid fa-plus\"></i> Add Step\n </button>\n </div>\n @for (step of field.TransformPipeline; track $index; let si = $index) {\n <div class=\"fmc-te-step\">\n <div class=\"fmc-te-step-header\">\n <span class=\"fmc-te-step-num\">{{ si + 1 }}</span>\n <select class=\"fmc-te-type-select\" [ngModel]=\"step.Type\"\n (ngModelChange)=\"OnTransformTypeChange(field, step, $event)\">\n @for (tt of TransformTypes; track tt.Value) {\n <option [value]=\"tt.Value\">{{ tt.Label }}</option>\n }\n </select>\n <select class=\"fmc-te-error-select\" [(ngModel)]=\"step.OnError\"\n (ngModelChange)=\"OnTransformConfigChange(field)\" title=\"On error\">\n <option value=\"Fail\">Fail</option>\n <option value=\"Skip\">Skip row</option>\n <option value=\"Null\">Set null</option>\n </select>\n <button class=\"fmc-te-remove-step\" (click)=\"RemoveTransformStep(field, si)\" title=\"Remove step\">\n <i class=\"fa-solid fa-trash-can\"></i>\n </button>\n </div>\n\n <!-- Config editors per type -->\n <div class=\"fmc-te-config\">\n @switch (step.Type) {\n @case ('direct') {\n <div class=\"fmc-te-field\">\n <label>Default value (when source is null)</label>\n <input type=\"text\" class=\"fmc-input\" [ngModel]=\"step.Config['DefaultValue'] ?? ''\"\n (ngModelChange)=\"step.Config['DefaultValue'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"Leave empty for no default\" />\n </div>\n }\n @case ('regex') {\n <div class=\"fmc-te-row\">\n <div class=\"fmc-te-field\">\n <label>Pattern</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['Pattern'] ?? ''\"\n (ngModelChange)=\"step.Config['Pattern'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"e.g. (\\d{3})-(\\d{4})\" />\n </div>\n <div class=\"fmc-te-field\">\n <label>Replacement</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['Replacement'] ?? ''\"\n (ngModelChange)=\"step.Config['Replacement'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"e.g. $1$2\" />\n </div>\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Flags</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['Flags'] ?? 'g'\"\n (ngModelChange)=\"step.Config['Flags'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"gi\" />\n </div>\n </div>\n }\n @case ('split') {\n <div class=\"fmc-te-row\">\n <div class=\"fmc-te-field\">\n <label>Delimiter</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['Delimiter'] ?? ','\"\n (ngModelChange)=\"step.Config['Delimiter'] = $event; OnTransformConfigChange(field)\"\n placeholder=\",\" />\n </div>\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Part index (0-based)</label>\n <input type=\"number\" class=\"fmc-input\" [ngModel]=\"step.Config['Index'] ?? 0\"\n (ngModelChange)=\"step.Config['Index'] = +$event; OnTransformConfigChange(field)\"\n min=\"0\" />\n </div>\n </div>\n }\n @case ('combine') {\n <div class=\"fmc-te-field\">\n <label>Source fields to combine</label>\n <div class=\"fmc-combine-chips\">\n @for (sf of GetAvailableSourceFields(); track sf) {\n <button class=\"fmc-chip\" [class.selected]=\"IsCombineFieldSelected(step.Config, sf)\"\n (click)=\"ToggleCombineField(step.Config, sf); OnTransformConfigChange(field)\">\n {{ sf }}\n </button>\n }\n </div>\n </div>\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Separator</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['Separator'] ?? ' '\"\n (ngModelChange)=\"step.Config['Separator'] = $event; OnTransformConfigChange(field)\"\n placeholder=\" \" />\n </div>\n }\n @case ('lookup') {\n <div class=\"fmc-te-field\">\n <label>Value mapping</label>\n <div class=\"fmc-lookup-table\">\n @for (entry of GetLookupEntries(step.Config); track $index) {\n <div class=\"fmc-lookup-row\">\n <input type=\"text\" class=\"fmc-input\" [value]=\"entry.key\" placeholder=\"Source value\"\n (change)=\"UpdateLookupEntry(step.Config, entry.key, $any($event.target).value, entry.value); OnTransformConfigChange(field)\" />\n <i class=\"fa-solid fa-arrow-right fmc-lookup-arrow\"></i>\n <input type=\"text\" class=\"fmc-input\" [value]=\"entry.value\" placeholder=\"Mapped value\"\n (change)=\"UpdateLookupEntry(step.Config, entry.key, entry.key, $any($event.target).value); OnTransformConfigChange(field)\" />\n <button class=\"fmc-lookup-del\" (click)=\"RemoveLookupEntry(step.Config, entry.key); OnTransformConfigChange(field)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n <button class=\"fmc-lookup-add\" (click)=\"AddLookupEntry(step.Config); OnTransformConfigChange(field)\">\n <i class=\"fa-solid fa-plus\"></i> Add mapping\n </button>\n </div>\n </div>\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Default (when no match)</label>\n <input type=\"text\" class=\"fmc-input\" [ngModel]=\"step.Config['Default'] ?? ''\"\n (ngModelChange)=\"step.Config['Default'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"null\" />\n </div>\n }\n @case ('format') {\n <div class=\"fmc-te-row\">\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Format type</label>\n <select class=\"fmc-select\" [ngModel]=\"step.Config['FormatType'] ?? 'date'\"\n (ngModelChange)=\"step.Config['FormatType'] = $event; OnTransformConfigChange(field)\">\n <option value=\"date\">Date</option>\n <option value=\"number\">Number</option>\n <option value=\"string\">String</option>\n </select>\n </div>\n <div class=\"fmc-te-field\">\n <label>Format string</label>\n <input type=\"text\" class=\"fmc-input mono\" [ngModel]=\"step.Config['FormatString'] ?? 'ISO'\"\n (ngModelChange)=\"step.Config['FormatString'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"ISO or decimal places\" />\n </div>\n </div>\n }\n @case ('coerce') {\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Target type</label>\n <select class=\"fmc-select\" [ngModel]=\"step.Config['TargetType'] ?? 'string'\"\n (ngModelChange)=\"step.Config['TargetType'] = $event; OnTransformConfigChange(field)\">\n <option value=\"string\">String</option>\n <option value=\"number\">Number</option>\n <option value=\"boolean\">Boolean</option>\n <option value=\"date\">Date</option>\n </select>\n </div>\n }\n @case ('substring') {\n <div class=\"fmc-te-row\">\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Start index</label>\n <input type=\"number\" class=\"fmc-input\" [ngModel]=\"step.Config['Start'] ?? 0\"\n (ngModelChange)=\"step.Config['Start'] = +$event; OnTransformConfigChange(field)\"\n min=\"0\" />\n </div>\n <div class=\"fmc-te-field fmc-te-sm\">\n <label>Length (blank = to end)</label>\n <input type=\"number\" class=\"fmc-input\" [ngModel]=\"step.Config['Length'] ?? ''\"\n (ngModelChange)=\"step.Config['Length'] = $event ? +$event : undefined; OnTransformConfigChange(field)\"\n min=\"1\" />\n </div>\n </div>\n }\n @case ('custom') {\n <div class=\"fmc-te-field\">\n <label>JavaScript expression <span class=\"fmc-te-hint\">(use <code>value</code> and <code>fields</code>)</span></label>\n <textarea class=\"fmc-input mono fmc-textarea\" [ngModel]=\"step.Config['Expression'] ?? 'value'\"\n (ngModelChange)=\"step.Config['Expression'] = $event; OnTransformConfigChange(field)\"\n placeholder=\"value.toUpperCase()\" rows=\"2\"></textarea>\n </div>\n }\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Data Preview Section -->\n <div class=\"data-preview-section\">\n <div class=\"preview-actions\">\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n [disabled]=\"IsLoadingSourcePreview\"\n (click)=\"LoadSourcePreview()\">\n <i class=\"fa-solid fa-cloud-arrow-down\"></i> Preview Source\n </button>\n <button kendoButton [look]=\"'outline'\" [size]=\"'small'\"\n [disabled]=\"IsLoadingDestPreview\"\n (click)=\"LoadDestPreview()\">\n <i class=\"fa-solid fa-database\"></i> Preview Destination\n </button>\n </div>\n\n @if (ShowSourcePreview) {\n <div class=\"preview-panel\">\n <div class=\"preview-panel-header\">\n <h4><i class=\"fa-solid fa-cloud\"></i> Source Data Preview</h4>\n <button class=\"add-panel-close\" (click)=\"CloseSourcePreview()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n @if (IsLoadingSourcePreview) {\n <mj-loading text=\"Loading source data...\" size=\"small\"></mj-loading>\n } @else if (SourcePreviewData.length === 0) {\n <p class=\"empty-hint\">No source data available.</p>\n } @else {\n <div class=\"preview-table-wrapper\">\n <table class=\"preview-table\">\n <thead>\n <tr>\n @for (col of GetPreviewColumns(SourcePreviewData); track col) {\n <th>{{ col }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of SourcePreviewData; track $index) {\n <tr>\n @for (col of GetPreviewColumns(SourcePreviewData); track col) {\n <td>{{ FormatPreviewValue(row[col]) }}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n }\n\n @if (ShowDestPreview) {\n <div class=\"preview-panel\">\n <div class=\"preview-panel-header\">\n <h4><i class=\"fa-solid fa-database\"></i> Destination Data Preview</h4>\n <button class=\"add-panel-close\" (click)=\"CloseDestPreview()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n @if (IsLoadingDestPreview) {\n <mj-loading text=\"Loading destination data...\" size=\"small\"></mj-loading>\n } @else if (DestPreviewData.length === 0) {\n <p class=\"empty-hint\">No destination data available.</p>\n } @else {\n <div class=\"preview-table-wrapper\">\n <table class=\"preview-table\">\n <thead>\n <tr>\n @for (col of GetPreviewColumns(DestPreviewData); track col) {\n <th>{{ col }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of DestPreviewData; track $index) {\n <tr>\n @for (col of GetPreviewColumns(DestPreviewData); track col) {\n <td>{{ FormatPreviewValue(row[col]) }}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- ============================================================ -->\n <!-- RIGHT PANEL: Last run details -->\n <!-- ============================================================ -->\n <div class=\"right-panel\">\n <h4 class=\"panel-label\">Last Run Details</h4>\n @if (!SelectedIntegrationID) {\n <p class=\"empty-hint\">Select an integration to see run details.</p>\n } @else if (IsLoadingRunDetails) {\n <mj-loading text=\"Loading...\" size=\"small\"></mj-loading>\n } @else if (!LatestRun) {\n <p class=\"empty-hint\">No runs found.</p>\n } @else {\n <div class=\"run-summary-card\">\n <div class=\"run-summary-row\">\n <span class=\"label\">Status</span>\n <span class=\"run-status\" [class]=\"'status-' + RunStatusColor\">\n {{ LatestRun.Status }}\n </span>\n </div>\n <div class=\"run-summary-row\">\n <span class=\"label\">Started</span>\n <span>{{ FormatDate(LatestRun.StartedAt) }}</span>\n </div>\n <div class=\"run-summary-row\">\n <span class=\"label\">Total Records</span>\n <span>{{ LatestRun.TotalRecords | number }}</span>\n </div>\n <div class=\"run-summary-row\">\n <span class=\"label\">Run By</span>\n <span>{{ LatestRun.RunByUser }}</span>\n </div>\n </div>\n\n @if (RunEntityDetails.length > 0) {\n <h4 class=\"panel-label\" style=\"margin-top: 16px;\">Per-Entity Stats</h4>\n @for (detail of RunEntityDetails; track detail.EntityID) {\n <div class=\"entity-stat-card\">\n <div class=\"entity-stat-name\">{{ detail.Entity }}</div>\n <div class=\"entity-stat-grid\">\n <div class=\"mini-stat\">\n <span class=\"mini-val\">{{ detail.RecordsCreated }}</span>\n <span class=\"mini-label\">Created</span>\n </div>\n <div class=\"mini-stat\">\n <span class=\"mini-val\">{{ detail.RecordsUpdated }}</span>\n <span class=\"mini-label\">Updated</span>\n </div>\n <div class=\"mini-stat\">\n <span class=\"mini-val\" [class.has-errors]=\"detail.RecordsErrored > 0\">\n {{ detail.RecordsErrored }}\n </span>\n <span class=\"mini-label\">Errors</span>\n </div>\n </div>\n </div>\n }\n }\n }\n </div>\n </div>\n }\n</div>\n", styles: [".mapping-workspace { padding: 24px; height: 100%; display: flex; flex-direction: column; }\n.workspace-header {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 16px;\n}\n.workspace-header h2 {\n margin: 0; font-size: 20px; font-weight: 600;\n}\n.workspace-header h2 i { margin-right: 8px; color: var(--mj-color-indigo-500); }\n\n/* ===== Three-panel layout ===== */\n.workspace-body {\n display: flex; flex: 1; gap: 1px; background: var(--mj-border-default);\n border-radius: 10px; overflow: hidden; min-height: 500px;\n}\n\n.left-panel { width: 320px; min-width: 280px; background: var(--mj-bg-surface); padding: 16px; overflow-y: auto; flex-shrink: 0; }\n.center-panel { flex: 1; background: var(--mj-bg-surface); padding: 20px; overflow-y: auto; }\n.right-panel { width: 280px; min-width: 240px; background: var(--mj-bg-surface); padding: 16px; overflow-y: auto; flex-shrink: 0; }\n\n/* ===== Shared ===== */\n.panel-label {\n font-size: 11px; font-weight: 700; color: var(--mj-text-disabled);\n text-transform: uppercase; letter-spacing: 0.6px;\n margin: 0 0 6px 0; display: block;\n}\n.panel-title { margin: 0 0 12px 0; font-size: 16px; font-weight: 600; }\n.panel-title .field-count { color: var(--mj-text-disabled); font-weight: 400; font-size: 13px; }\n.empty-hint { color: var(--mj-text-disabled); font-size: 13px; font-style: italic; }\n.search-box { margin-bottom: 12px; }\n\n/* ===== Integration selector ===== */\n.integration-selector { margin-bottom: 20px; padding-bottom: 16px; border-bottom: 1px solid var(--mj-border-subtle); }\n\n/* ===== Entity Map Header ===== */\n.entity-map-header {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 10px;\n}\n.header-actions { display: flex; gap: 4px; }\n\n/* ===== Add Map Panel ===== */\n.add-map-panel {\n background: var(--mj-bg-page); border: 1px solid var(--mj-border-default); border-radius: 10px;\n padding: 16px; margin-bottom: 14px;\n}\n.add-panel-top {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 14px;\n}\n.add-panel-top h5 { margin: 0; font-size: 14px; font-weight: 600; }\n.add-panel-close {\n background: none; border: none; cursor: pointer; color: var(--mj-text-disabled); font-size: 14px;\n}\n.add-panel-close:hover { color: var(--mj-text-primary); }\n\n.form-group { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }\n.form-group label { font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.form-row { display: flex; gap: 10px; }\n.form-row .form-group { flex: 1; }\n\n.source-loading {\n display: flex; align-items: center; gap: 8px;\n font-size: 12px; color: var(--mj-text-disabled); padding: 6px 0;\n}\n.source-loading i { color: var(--mj-color-indigo-500); }\n\n.discover-error-inline {\n font-size: 12px; color: var(--mj-color-error-600); padding: 6px 0;\n}\n.discover-error-inline i { margin-right: 4px; }\n\n/* Target mode toggle */\n.target-mode-toggle {\n display: flex; border: 1px solid var(--mj-border-default); border-radius: 6px;\n overflow: hidden; margin-bottom: 12px;\n}\n.target-mode-btn {\n flex: 1; padding: 8px 12px; font-size: 12px; font-weight: 600;\n text-align: center; cursor: pointer; background: var(--mj-bg-surface); border: none;\n color: var(--mj-text-muted); transition: all 0.15s;\n}\n.target-mode-btn:first-child { border-right: 1px solid var(--mj-border-default); }\n.target-mode-btn.active { background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); }\n.target-mode-btn:not(.active):hover { background: var(--mj-status-info-bg); color: var(--mj-color-indigo-500); }\n.target-mode-btn i { margin-right: 4px; }\n\n/* New entity form */\n.new-entity-form {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 8px;\n padding: 14px; margin-bottom: 12px;\n}\n.new-entity-form .section-label {\n font-size: 11px; font-weight: 700; color: var(--mj-color-indigo-500);\n text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 10px;\n}\n.auto-hint { font-size: 10px; color: var(--mj-text-disabled); font-style: italic; }\n\n/* DDL preview in add panel */\n.ddl-preview-section { margin-top: 8px; }\n.ddl-preview-code {\n background: var(--mj-text-primary); color: var(--mj-color-neutral-300); padding: 10px;\n border-radius: 4px; font-size: 11px; line-height: 1.5;\n max-height: 200px; overflow: auto; white-space: pre-wrap;\n word-break: break-word; margin-top: 8px;\n}\n\n.add-form-actions { display: flex; gap: 6px; padding-top: 4px; }\n\n/* ===== Entity Map List ===== */\n.entity-map-list { display: flex; flex-direction: column; gap: 4px; }\n.entity-map-item {\n padding: 8px 10px; border-radius: 6px;\n cursor: pointer; border: 1px solid var(--mj-border-subtle); transition: all 0.15s;\n}\n.entity-map-item:hover { background: var(--mj-bg-page); }\n.entity-map-item.selected { background: var(--mj-status-info-bg); border-color: var(--mj-color-indigo-500); }\n.entity-map-item.pending { border-left: 3px solid var(--mj-status-warning); }\n\n.em-top-row {\n display: flex; align-items: center; gap: 4px;\n font-size: 13px; margin-bottom: 4px;\n}\n.em-name { font-weight: 600; }\n.em-arrow { color: var(--mj-text-disabled); font-size: 11px; }\n.em-entity { color: var(--mj-text-muted); }\n\n.em-bottom-row {\n display: flex; align-items: center; justify-content: space-between;\n font-size: 11px; color: var(--mj-text-disabled);\n}\n.em-badges { display: flex; gap: 4px; align-items: center; }\n.badge {\n font-size: 10px; padding: 1px 6px; border-radius: 4px; font-weight: 600;\n}\n.badge-direction { background: var(--mj-bg-surface-hover); color: var(--mj-text-muted); }\n.badge-pending { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n\n.em-actions { display: flex; align-items: center; gap: 4px; }\n.em-delete {\n opacity: 0; transition: opacity 0.15s;\n cursor: pointer; color: var(--mj-color-error-600); background: none; border: none;\n padding: 2px 4px; font-size: 12px;\n}\n.entity-map-item:hover .em-delete { opacity: 1; }\n\n/* ===== Center Panel: Placeholder ===== */\n.placeholder-message {\n display: flex; flex-direction: column; align-items: center;\n justify-content: center; height: 300px; color: var(--mj-text-disabled);\n}\n.placeholder-message i { font-size: 36px; margin-bottom: 12px; }\n.placeholder-message p { text-align: center; }\n\n/* ===== Pending Entity Panel ===== */\n.pending-entity-panel {\n background: var(--mj-status-warning-bg); border: 1px solid var(--mj-color-warning-200); border-radius: 10px;\n padding: 24px; text-align: center;\n}\n.pending-icon { font-size: 40px; color: var(--mj-status-warning); margin-bottom: 12px; }\n.pending-entity-panel h3 { font-size: 16px; margin-bottom: 8px; }\n.pending-entity-panel p { font-size: 13px; color: var(--mj-text-disabled); margin-bottom: 16px; line-height: 1.5; }\n\n/* Stepper */\n.pending-steps {\n display: flex; gap: 0; margin: 20px 0; justify-content: center; align-items: center;\n}\n.step {\n display: flex; flex-direction: column; align-items: center; gap: 6px;\n padding: 0 16px;\n}\n.step-circle {\n width: 36px; height: 36px; border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 14px; font-weight: 700;\n}\n.step-circle.done { background: var(--mj-status-success-bg); color: var(--mj-color-success-700); }\n.step-circle.current { background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); }\n.step-circle.future { background: var(--mj-bg-surface-hover); color: var(--mj-text-disabled); }\n.step-label { font-size: 10px; font-weight: 600; color: var(--mj-text-disabled); text-transform: uppercase; white-space: nowrap; }\n.step-connector { width: 32px; height: 2px; background: var(--mj-border-default); align-self: center; margin-bottom: 18px; }\n.step-connector.done { background: var(--mj-color-success-700); }\n\n/* DDL in pending view */\n.ddl-preview-inline { margin-top: 16px; text-align: left; }\n.ddl-code-block {\n background: var(--mj-text-primary); color: var(--mj-color-neutral-300); padding: 12px;\n border-radius: 6px; font-size: 12px; line-height: 1.5;\n max-height: 250px; overflow: auto; white-space: pre-wrap;\n}\n.ddl-actions { display: flex; gap: 8px; margin-top: 12px; justify-content: center; }\n\n/* Pending fields list */\n.pending-fields-section { text-align: left; }\n.pending-fields-list {\n display: flex; flex-direction: column; gap: 2px;\n max-height: 200px; overflow-y: auto;\n}\n.pending-field-item {\n display: flex; align-items: center; gap: 8px;\n padding: 4px 8px; font-size: 13px; border-radius: 4px;\n}\n.pending-field-item:hover { background: var(--mj-status-warning-bg); }\n.pending-field-name { font-weight: 600; }\n.pending-field-type { font-size: 11px; color: var(--mj-text-disabled); background: var(--mj-bg-surface-hover); padding: 1px 6px; border-radius: 3px; }\n.pending-field-req { color: var(--mj-color-error-600); font-weight: 700; }\n\n/* ===== Auto-map banner ===== */\n.auto-map-banner {\n background: var(--mj-status-info-bg); border: 1px solid var(--mj-color-info-100); border-radius: 8px;\n padding: 12px 16px; margin-bottom: 16px;\n display: flex; align-items: center; gap: 12px;\n}\n.auto-map-banner > i { color: var(--mj-color-indigo-500); font-size: 18px; }\n.auto-map-banner .banner-text { flex: 1; }\n.auto-map-banner .banner-text p { font-size: 13px; color: var(--mj-text-muted); margin: 0; }\n.auto-map-banner .banner-text strong { color: var(--mj-text-primary); }\n\n/* ===== Field Mapping Editor ===== */\n.field-mapping-header {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 16px;\n}\n.field-mapping-actions { display: flex; gap: 6px; }\n\n/* ===== Field Map Cards (New world-class design) ===== */\n.field-map-cards {\n display: flex; flex-direction: column; gap: 6px;\n}\n\n.field-map-card {\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n overflow: hidden;\n}\n.field-map-card:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px rgba(74, 108, 247, 0.06);\n}\n.field-map-card.has-transform {\n border-left: 3px solid var(--mj-color-indigo-500);\n}\n.field-map-card.validation-error {\n border-color: var(--mj-color-warning-200);\n background: var(--mj-status-warning-bg);\n}\n\n/* Main mapping row */\n.fmc-row {\n display: flex; align-items: center; gap: 10px;\n padding: 10px 14px;\n}\n\n/* Source column */\n.fmc-source {\n flex: 1; min-width: 0;\n}\n.fmc-field-name {\n font-size: 13px; font-weight: 600; color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n}\n.fmc-badges {\n display: flex; gap: 4px; margin-top: 3px; flex-wrap: wrap;\n}\n.fmc-badge {\n font-size: 9px; font-weight: 700; padding: 1px 5px;\n border-radius: 3px; text-transform: uppercase; letter-spacing: 0.3px;\n white-space: nowrap; line-height: 1.5;\n}\n.badge-type {\n background: var(--mj-bg-surface-hover); color: var(--mj-text-muted);\n}\n.badge-pk {\n background: linear-gradient(135deg, var(--mj-color-warning-100), var(--mj-color-warning-200));\n color: var(--mj-color-warning-800);\n}\n.badge-pk i { font-size: 8px; margin-right: 2px; }\n.badge-req {\n background: linear-gradient(135deg, var(--mj-color-error-100), var(--mj-color-error-200));\n color: var(--mj-color-error-800);\n}\n.badge-ro {\n background: var(--mj-color-purple-50); color: var(--mj-color-purple-700);\n}\n\n/* Transform zone (center arrow / pill) */\n.fmc-transform-zone {\n flex-shrink: 0;\n display: flex; align-items: center; justify-content: center;\n width: 100px;\n}\n.fmc-arrow-btn {\n width: 32px; height: 32px;\n border-radius: 50%; border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page); color: var(--mj-text-disabled);\n cursor: pointer; font-size: 12px;\n display: flex; align-items: center; justify-content: center;\n transition: all 0.2s;\n}\n.fmc-arrow-btn:hover {\n background: var(--mj-color-indigo-500); color: var(--mj-bg-surface); border-color: var(--mj-color-indigo-500);\n transform: scale(1.1);\n}\n.fmc-transform-pill {\n display: flex; align-items: center; gap: 4px;\n padding: 4px 10px; border-radius: 16px;\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border: 1px solid var(--mj-color-indigo-200); color: var(--mj-color-indigo-700);\n font-size: 11px; font-weight: 600;\n cursor: pointer; transition: all 0.2s;\n white-space: nowrap;\n}\n.fmc-transform-pill:hover {\n background: linear-gradient(135deg, var(--mj-color-indigo-100), var(--mj-color-indigo-200));\n transform: scale(1.02);\n}\n.fmc-transform-pill i { font-size: 10px; }\n.fmc-transform-direct {\n background: linear-gradient(135deg, var(--mj-bg-page), var(--mj-bg-surface-hover));\n border-color: var(--mj-color-neutral-300); color: var(--mj-text-muted);\n}\n.fmc-transform-direct:hover {\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border-color: var(--mj-color-indigo-200); color: var(--mj-color-indigo-700);\n}\n.fmc-step-count {\n background: var(--mj-color-indigo-700); color: var(--mj-bg-surface); font-size: 9px;\n padding: 0 4px; border-radius: 8px; font-weight: 700;\n}\n\n/* Destination column */\n.fmc-dest {\n flex: 1; min-width: 0;\n}\n.fmc-select {\n width: 100%; padding: 6px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: border-color 0.15s;\n}\n.fmc-select:focus { border-color: var(--mj-color-indigo-500); outline: none; box-shadow: 0 0 0 2px rgba(74, 108, 247, 0.12); }\n\n/* Shared input style */\n.fmc-input {\n width: 100%; padding: 5px 8px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: border-color 0.15s;\n}\n.fmc-input:focus { border-color: var(--mj-color-indigo-500); outline: none; box-shadow: 0 0 0 2px rgba(74, 108, 247, 0.12); }\n.fmc-input.mono { font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; font-size: 12px; }\n\n/* Flags (key, required) */\n.fmc-flags {\n display: flex; gap: 6px; flex-shrink: 0;\n}\n.fmc-flag {\n display: flex; align-items: center; gap: 3px;\n font-size: 11px; color: var(--mj-text-disabled); cursor: pointer;\n padding: 2px 4px; border-radius: 4px;\n transition: color 0.15s;\n}\n.fmc-flag:hover { color: var(--mj-color-indigo-500); }\n.fmc-flag input[type=\"checkbox\"] {\n width: 13px; height: 13px; cursor: pointer;\n accent-color: var(--mj-color-indigo-500);\n}\n.fmc-flag i { font-size: 10px; }\n.fmc-req-star { font-size: 14px; font-weight: 700; color: inherit; }\n\n/* Remove button */\n.fmc-remove {\n flex-shrink: 0;\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 13px; padding: 4px;\n border-radius: 4px; transition: all 0.15s;\n}\n.fmc-remove:hover { color: var(--mj-status-error); background: var(--mj-status-error-bg); }\n\n/* ===== Transform Pipeline Editor ===== */\n.fmc-transform-editor {\n border-top: 1px solid var(--mj-bg-surface-hover);\n background: linear-gradient(180deg, var(--mj-color-indigo-50) 0%, var(--mj-bg-page) 100%);\n padding: 12px 14px;\n}\n.fmc-te-header {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 10px;\n}\n.fmc-te-title {\n font-size: 11px; font-weight: 700; color: var(--mj-color-indigo-500);\n text-transform: uppercase; letter-spacing: 0.5px;\n}\n.fmc-te-title i { margin-right: 4px; }\n.fmc-te-add {\n font-size: 11px; font-weight: 600; color: var(--mj-color-indigo-500);\n background: none; border: 1px solid var(--mj-color-indigo-200);\n border-radius: 6px; padding: 3px 10px;\n cursor: pointer; transition: all 0.15s;\n}\n.fmc-te-add:hover { background: var(--mj-color-indigo-50); }\n.fmc-te-add i { margin-right: 3px; font-size: 10px; }\n\n/* Individual transform step */\n.fmc-te-step {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 10px 12px;\n margin-bottom: 8px;\n transition: box-shadow 0.15s;\n}\n.fmc-te-step:hover { box-shadow: 0 1px 4px rgba(0,0,0,0.05); }\n.fmc-te-step:last-child { margin-bottom: 0; }\n\n.fmc-te-step-header {\n display: flex; align-items: center; gap: 8px; margin-bottom: 8px;\n}\n.fmc-te-step-num {\n width: 22px; height: 22px; border-radius: 50%;\n background: linear-gradient(135deg, var(--mj-color-indigo-500), var(--mj-color-indigo-500));\n color: var(--mj-bg-surface); font-size: 11px; font-weight: 700;\n display: flex; align-items: center; justify-content: center;\n flex-shrink: 0;\n}\n.fmc-te-type-select {\n flex: 1; padding: 4px 8px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 12px; font-weight: 600;\n color: var(--mj-text-primary); background: var(--mj-bg-page);\n}\n.fmc-te-type-select:focus { border-color: var(--mj-color-indigo-500); outline: none; }\n.fmc-te-error-select {\n width: 100px; padding: 4px 6px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 11px; color: var(--mj-text-muted);\n background: var(--mj-bg-page);\n}\n.fmc-te-error-select:focus { border-color: var(--mj-color-indigo-500); outline: none; }\n.fmc-te-remove-step {\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 12px; padding: 4px;\n border-radius: 4px; transition: all 0.15s;\n}\n.fmc-te-remove-step:hover { color: var(--mj-status-error); background: var(--mj-status-error-bg); }\n\n/* Config area */\n.fmc-te-config {\n padding-left: 30px;\n}\n.fmc-te-field {\n margin-bottom: 8px;\n}\n.fmc-te-field:last-child { margin-bottom: 0; }\n.fmc-te-field label {\n display: block; font-size: 11px; font-weight: 600;\n color: var(--mj-text-muted); margin-bottom: 3px;\n}\n.fmc-te-field label code {\n background: var(--mj-bg-surface-hover); padding: 0 3px; border-radius: 3px;\n font-size: 10px; color: var(--mj-color-indigo-700);\n}\n.fmc-te-hint { font-weight: 400; color: var(--mj-text-disabled); }\n.fmc-te-row {\n display: flex; gap: 10px; align-items: flex-end;\n}\n.fmc-te-sm { max-width: 140px; }\n.fmc-textarea {\n resize: vertical; min-height: 40px;\n}\n\n/* Combine chips */\n.fmc-combine-chips {\n display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px;\n}\n.fmc-chip {\n font-size: 11px; padding: 3px 8px; border-radius: 14px;\n border: 1px solid var(--mj-border-default); background: var(--mj-bg-surface);\n color: var(--mj-text-muted); cursor: pointer;\n transition: all 0.15s; font-weight: 500;\n}\n.fmc-chip:hover { border-color: var(--mj-color-indigo-300); color: var(--mj-color-indigo-700); }\n.fmc-chip.selected {\n background: linear-gradient(135deg, var(--mj-color-indigo-50), var(--mj-color-indigo-100));\n border-color: var(--mj-color-indigo-400); color: var(--mj-color-indigo-700); font-weight: 600;\n}\n\n/* Lookup table */\n.fmc-lookup-table {\n display: flex; flex-direction: column; gap: 4px; margin-top: 4px;\n}\n.fmc-lookup-row {\n display: flex; align-items: center; gap: 6px;\n}\n.fmc-lookup-row .fmc-input { flex: 1; }\n.fmc-lookup-arrow { color: var(--mj-color-indigo-200); font-size: 10px; flex-shrink: 0; }\n.fmc-lookup-del {\n background: none; border: none; cursor: pointer;\n color: var(--mj-color-neutral-300); font-size: 11px; padding: 2px;\n transition: color 0.15s;\n}\n.fmc-lookup-del:hover { color: var(--mj-status-error); }\n.fmc-lookup-add {\n font-size: 11px; color: var(--mj-color-indigo-500); background: none;\n border: 1px dashed var(--mj-color-indigo-200); border-radius: 6px;\n padding: 4px 10px; cursor: pointer;\n transition: all 0.15s; margin-top: 2px;\n}\n.fmc-lookup-add:hover { background: var(--mj-color-indigo-50); }\n.fmc-lookup-add i { margin-right: 3px; font-size: 10px; }\n\n/* ===== Data Preview ===== */\n.data-preview-section { margin-top: 24px; border-top: 1px solid var(--mj-border-subtle); padding-top: 16px; }\n.preview-actions { display: flex; gap: 8px; margin-bottom: 12px; }\n\n.preview-panel {\n background: var(--mj-bg-page); border: 1px solid var(--mj-border-default); border-radius: 8px;\n padding: 12px; margin-bottom: 12px;\n}\n.preview-panel-header {\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 8px;\n}\n.preview-panel-header h4 { font-size: 13px; font-weight: 600; margin: 0; }\n.preview-panel-header h4 i { margin-right: 6px; color: var(--mj-color-indigo-500); }\n\n.preview-table-wrapper { overflow-x: auto; }\n.preview-table {\n width: 100%; border-collapse: collapse; font-size: 12px;\n}\n.preview-table th {\n text-align: left; padding: 5px 8px;\n background: var(--mj-border-default); font-weight: 600; font-size: 10px;\n text-transform: uppercase; color: var(--mj-text-muted);\n border-bottom: 1px solid var(--mj-border-default); white-space: nowrap;\n}\n.preview-table td {\n padding: 4px 8px; border-bottom: 1px solid var(--mj-border-subtle);\n white-space: nowrap; max-width: 150px; overflow: hidden; text-overflow: ellipsis;\n}\n.preview-table tr:hover { background: var(--mj-status-info-bg); }\n\n/* ===== Right panel: run details ===== */\n.run-summary-card {\n background: var(--mj-bg-page); border-radius: 8px; padding: 12px;\n}\n.run-summary-row {\n display: flex; justify-content: space-between;\n padding: 4px 0; font-size: 13px;\n}\n.run-summary-row .label { color: var(--mj-text-muted); font-weight: 500; }\n.run-status {\n font-size: 11px; padding: 2px 6px; border-radius: 4px; font-weight: 600;\n}\n.status-green { background: var(--mj-status-success-bg); color: var(--mj-color-success-700); }\n.status-amber { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n.status-red { background: var(--mj-status-error-bg); color: var(--mj-color-error-600); }\n\n.entity-stat-card {\n background: var(--mj-bg-page); border-radius: 6px; padding: 10px;\n margin-bottom: 8px;\n}\n.entity-stat-name { font-size: 13px; font-weight: 600; margin-bottom: 6px; }\n.entity-stat-grid { display: flex; gap: 12px; }\n.mini-stat { text-align: center; }\n.mini-val { display: block; font-size: 16px; font-weight: 600; }\n.mini-val.has-errors { color: var(--mj-color-error-600); }\n.mini-label { font-size: 10px; color: var(--mj-text-disabled); }\n\n/* ===== Validation ===== */\n.validation-banner {\n background: var(--mj-color-warning-50); border: 1px solid var(--mj-color-warning-200); border-radius: 8px;\n padding: 10px 14px; margin-bottom: 14px;\n display: flex; align-items: flex-start; gap: 10px;\n font-size: 13px; color: var(--mj-color-warning-600);\n}\n.validation-banner > i { margin-top: 2px; }\n.validation-warnings { display: flex; flex-direction: column; gap: 2px; }\n\n.field-map-card.validation-error .fmc-source {\n border-left: 3px solid var(--mj-color-warning-600);\n padding-left: 8px;\n}\n\n/* ===== Responsive ===== */\n@media (max-width: 1100px) { .right-panel { display: none; } }\n@media (max-width: 800px) { .left-panel { width: 260px; } }\n"] }]
|
|
2368
2368
|
}], null, null); })();
|
|
2369
2369
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MappingWorkspaceComponent, { className: "MappingWorkspaceComponent", filePath: "src/Integration/components/mapping-workspace/mapping-workspace.component.ts", lineNumber: 118 }); })();
|
|
2370
2370
|
export function LoadMappingWorkspace() {
|