@memberjunction/ng-dashboards 6.2.0-edge.4 → 6.2.0-edge.6
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/README.md +28 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +15 -7
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +7 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +209 -57
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts +12 -11
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.js +15 -15
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.js.map +1 -1
- package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +28 -16
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts +1 -0
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts.map +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +30 -6
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.js +15 -7
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/sensitive-fields.d.ts +58 -0
- package/dist/AI/components/vectors/sensitive-fields.d.ts.map +1 -0
- package/dist/AI/components/vectors/sensitive-fields.js +251 -0
- package/dist/AI/components/vectors/sensitive-fields.js.map +1 -0
- package/dist/AI/components/vectors/vector-document-rules.d.ts +139 -0
- package/dist/AI/components/vectors/vector-document-rules.d.ts.map +1 -0
- package/dist/AI/components/vectors/vector-document-rules.js +182 -0
- package/dist/AI/components/vectors/vector-document-rules.js.map +1 -0
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts +83 -14
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +546 -271
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-store-selection.d.ts +32 -0
- package/dist/AI/components/vectors/vector-store-selection.d.ts.map +1 -0
- package/dist/AI/components/vectors/vector-store-selection.js +57 -0
- package/dist/AI/components/vectors/vector-store-selection.js.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts +236 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.js +374 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.js.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.d.ts +195 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.d.ts.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.js +2910 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.js.map +1 -0
- package/dist/ChiefOfStaff/index.d.ts +3 -0
- package/dist/ChiefOfStaff/index.d.ts.map +1 -0
- package/dist/ChiefOfStaff/index.js +3 -0
- package/dist/ChiefOfStaff/index.js.map +1 -0
- package/dist/Communication/communication-agent-context.d.ts +11 -1
- package/dist/Communication/communication-agent-context.d.ts.map +1 -1
- package/dist/Communication/communication-agent-context.js +15 -0
- package/dist/Communication/communication-agent-context.js.map +1 -1
- package/dist/Communication/communication-dashboard.component.d.ts.map +1 -1
- package/dist/Communication/communication-dashboard.component.js +5 -0
- package/dist/Communication/communication-dashboard.component.js.map +1 -1
- package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-logs-resource.component.js +2 -1
- 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 +23 -18
- package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
- package/dist/Communication/communication-providers-resource.component.d.ts +27 -1
- package/dist/Communication/communication-providers-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-providers-resource.component.js +722 -78
- 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 +11 -10
- package/dist/Communication/communication-runs-resource.component.js.map +1 -1
- package/dist/DashboardEditor/dashboard-editor.component.d.ts +17 -2
- package/dist/DashboardEditor/dashboard-editor.component.d.ts.map +1 -1
- package/dist/DashboardEditor/dashboard-editor.component.js +94 -43
- package/dist/DashboardEditor/dashboard-editor.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +49 -0
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +220 -55
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DataExplorer/models/explorer-state.interface.d.ts +2 -0
- package/dist/DataExplorer/models/explorer-state.interface.d.ts.map +1 -1
- package/dist/DataExplorer/models/explorer-state.interface.js.map +1 -1
- package/dist/DevTools/app-state-inspector.component.d.ts.map +1 -1
- package/dist/DevTools/app-state-inspector.component.js +1 -0
- package/dist/DevTools/app-state-inspector.component.js.map +1 -1
- package/dist/DevTools/class-registry.component.d.ts.map +1 -1
- package/dist/DevTools/class-registry.component.js +1 -0
- package/dist/DevTools/class-registry.component.js.map +1 -1
- package/dist/DevTools/event-monitor.component.d.ts.map +1 -1
- package/dist/DevTools/event-monitor.component.js +2 -0
- package/dist/DevTools/event-monitor.component.js.map +1 -1
- package/dist/DevTools/graphql-console.component.d.ts.map +1 -1
- package/dist/DevTools/graphql-console.component.js.map +1 -1
- package/dist/DevTools/grid-width-lab.component.d.ts.map +1 -1
- package/dist/DevTools/grid-width-lab.component.js +1 -0
- package/dist/DevTools/grid-width-lab.component.js.map +1 -1
- package/dist/DevTools/layout-inspector.component.d.ts.map +1 -1
- package/dist/DevTools/layout-inspector.component.js +1 -0
- package/dist/DevTools/layout-inspector.component.js.map +1 -1
- package/dist/DevTools/lazy-module-status.component.d.ts.map +1 -1
- package/dist/DevTools/lazy-module-status.component.js +1 -0
- package/dist/DevTools/lazy-module-status.component.js.map +1 -1
- package/dist/DevTools/settings-explorer.component.d.ts.map +1 -1
- package/dist/DevTools/settings-explorer.component.js +1 -0
- package/dist/DevTools/settings-explorer.component.js.map +1 -1
- package/dist/DevTools/tab-strip-lab.component.d.ts.map +1 -1
- package/dist/DevTools/tab-strip-lab.component.js +1 -0
- package/dist/DevTools/tab-strip-lab.component.js.map +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.d.ts +5 -0
- package/dist/EntityAdmin/entity-admin-dashboard.component.d.ts.map +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.js +8 -5
- package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
- package/dist/Integration/components/overview/overview.component.js +2 -2
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +2 -2
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.d.ts +11 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.js +24 -2
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.js.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.d.ts +16 -2
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js +87 -33
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js.map +1 -1
- package/dist/LoginStudio/login-studio-inspector.component.d.ts +130 -0
- package/dist/LoginStudio/login-studio-inspector.component.d.ts.map +1 -0
- package/dist/LoginStudio/login-studio-inspector.component.js +781 -0
- package/dist/LoginStudio/login-studio-inspector.component.js.map +1 -0
- package/dist/LoginStudio/login-studio-resource.component.d.ts +161 -0
- package/dist/LoginStudio/login-studio-resource.component.d.ts.map +1 -0
- package/dist/LoginStudio/login-studio-resource.component.js +890 -0
- package/dist/LoginStudio/login-studio-resource.component.js.map +1 -0
- package/dist/MCP/mcp-dashboard.component.d.ts +24 -4
- package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +118 -65
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/PredictiveStudio/business-predictions.view-models.d.ts +1 -1
- package/dist/PredictiveStudio/business-predictions.view-models.d.ts.map +1 -1
- package/dist/PredictiveStudio/business-predictions.view-models.js +3 -3
- package/dist/PredictiveStudio/business-predictions.view-models.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-experiments.component.d.ts +6 -63
- package/dist/PredictiveStudio/components/ps-experiments.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-experiments.component.js +256 -521
- package/dist/PredictiveStudio/components/ps-experiments.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts +0 -18
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js +122 -249
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts +5 -9
- package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipelines.component.js +98 -130
- package/dist/PredictiveStudio/components/ps-pipelines.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts +53 -4
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.js +335 -326
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts +19 -0
- package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts.map +1 -0
- package/dist/PredictiveStudio/components/ps-row-drivers.component.js +85 -0
- package/dist/PredictiveStudio/components/ps-row-drivers.component.js.map +1 -0
- package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts +19 -1
- package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts.map +1 -1
- package/dist/PredictiveStudio/engine/predictive-studio.engine.js +51 -2
- package/dist/PredictiveStudio/engine/predictive-studio.engine.js.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts +3 -1
- package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-agent-context.js +3 -0
- package/dist/PredictiveStudio/predictive-studio-agent-context.js.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts +27 -4
- package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-score-history.service.js +94 -61
- package/dist/PredictiveStudio/predictive-studio-score-history.service.js.map +1 -1
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts +29 -5
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js +185 -103
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js.map +1 -1
- package/dist/PredictiveStudio/resources/ps-studio-resource.component.js +1 -1
- package/dist/PredictiveStudio/resources/ps-studio-resource.component.js.map +1 -1
- package/dist/Workflows/components/workflow-runs-resource.component.js +4 -4
- package/dist/Workflows/components/workflow-runs-resource.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +22 -21
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +8 -2
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/core-dashboards.module.d.ts +2 -1
- package/dist/core-dashboards.module.d.ts.map +1 -1
- package/dist/core-dashboards.module.js +11 -3
- package/dist/core-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +3 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +4 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +72 -69
- package/dist/PredictiveStudio/at-risk.view-models.d.ts +0 -120
- package/dist/PredictiveStudio/at-risk.view-models.d.ts.map +0 -1
- package/dist/PredictiveStudio/at-risk.view-models.js +0 -261
- package/dist/PredictiveStudio/at-risk.view-models.js.map +0 -1
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts +0 -109
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts.map +0 -1
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.js +0 -323
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.js.map +0 -1
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts +0 -137
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts.map +0 -1
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js +0 -826
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js.map +0 -1
|
@@ -27,7 +27,8 @@ import { RunViewParams } from '@memberjunction/core';
|
|
|
27
27
|
/** The slice of an `MJ: Duplicate Runs` row the board needs to choose which run it shows. */
|
|
28
28
|
export interface DuplicateRunCandidate {
|
|
29
29
|
ID: string;
|
|
30
|
-
|
|
30
|
+
/** The entity document the run used. */
|
|
31
|
+
EntityDocumentID: string;
|
|
31
32
|
ProcessingStatus: string;
|
|
32
33
|
StartedAt: Date | string | null;
|
|
33
34
|
/** Set when the run covered one list's records rather than the whole entity. */
|
|
@@ -38,26 +39,26 @@ export declare const MATCH_QUERY_DETAIL_CHUNK_SIZE = 500;
|
|
|
38
39
|
/** The slice of an entity-document picker option needed to choose a default. */
|
|
39
40
|
export interface EntityDocumentCandidate {
|
|
40
41
|
ID: string;
|
|
41
|
-
EntityID: string;
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
|
-
* Pick the run the board should display for an entity: the newest run that
|
|
45
|
-
* the whole entity, or, when there is none, the newest run of any kind.
|
|
44
|
+
* Pick the run the board should display for an entity document: the newest run of that document
|
|
45
|
+
* that did not fail and covered the whole entity, or, when there is none, the newest run of any kind.
|
|
46
46
|
*
|
|
47
47
|
* Not "most recent Complete run": a run the user cancels keeps `ProcessingStatus = 'In Progress'`
|
|
48
48
|
* (the detector marks it for resumption), and the board's own idle timer can finish a detection
|
|
49
49
|
* before the server does; both end with a reload while a newer run exists, and preferring an older
|
|
50
50
|
* Complete run there would hide the rows the user just watched being produced. Not plain "newest"
|
|
51
51
|
* either: a Failed run usually has no details, and a list-scoped run holds a small subset, so each
|
|
52
|
-
* would hide a good entity-wide run behind an empty or partial board. Runs
|
|
53
|
-
* never candidates
|
|
52
|
+
* would hide a good entity-wide run behind an empty or partial board. Runs of other documents are
|
|
53
|
+
* never candidates, including other documents for the same entity: their template and thresholds
|
|
54
|
+
* produced different matches. Returns null when there is no document or no run for it.
|
|
54
55
|
*/
|
|
55
|
-
export declare function
|
|
56
|
+
export declare function SelectCurrentRunForDocument<T extends DuplicateRunCandidate>(runs: readonly T[], entityDocumentID: string | null | undefined): T | null;
|
|
56
57
|
/**
|
|
57
|
-
* The entity document the board should show before the user picks one: the document
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
58
|
+
* The entity document the board should show before the user picks one: the document of the newest
|
|
59
|
+
* run worth showing (see {@link SelectCurrentRunForDocument}), so a first visit lands on results
|
|
60
|
+
* that exist. Falls back to the first document when no run matches any listed document, and to null
|
|
61
|
+
* when there are no documents at all.
|
|
61
62
|
*/
|
|
62
63
|
export declare function PickDefaultEntityDocument<D extends EntityDocumentCandidate>(documents: readonly D[], runs: readonly DuplicateRunCandidate[]): D | null;
|
|
63
64
|
/** The completed details of ONE run, newest first. Bounded by the run; `IgnoreMaxRows` per the file comment. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duplicate-detection-run-scope.d.ts","sourceRoot":"","sources":["../../../../src/AI/components/duplicates/duplicate-detection-run-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,6FAA6F;AAC7F,MAAM,WAAW,qBAAqB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,
|
|
1
|
+
{"version":3,"file":"duplicate-detection-run-scope.d.ts","sourceRoot":"","sources":["../../../../src/AI/components/duplicates/duplicate-detection-run-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,6FAA6F;AAC7F,MAAM,WAAW,qBAAqB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,wCAAwC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC;IAChC,gFAAgF;IAChF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAaD,6FAA6F;AAC7F,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAIjD,gFAAgF;AAChF,MAAM,WAAW,uBAAuB;IACpC,EAAE,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,SAAS,qBAAqB,EACvE,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC5C,CAAC,GAAG,IAAI,CAMV;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,SAAS,uBAAuB,EACvE,SAAS,EAAE,SAAS,CAAC,EAAE,EACvB,IAAI,EAAE,SAAS,qBAAqB,EAAE,GACvC,CAAC,GAAG,IAAI,CAaV;AAMD,gHAAgH;AAChH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAQvE;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CACzC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,SAAS,GAAE,MAAsC,GAClD,aAAa,EAAE,CAajB;AAED,4FAA4F;AAC5F,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,EAAE,CAO3E;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,CAAC,SAAS;IAAE,oBAAoB,EAAE,MAAM,CAAA;CAAE,EAC3E,OAAO,EAAE,SAAS,CAAC,EAAE,GACtB,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAWlB"}
|
|
@@ -12,39 +12,39 @@ function isPreferredRun(run) {
|
|
|
12
12
|
export const MATCH_QUERY_DETAIL_CHUNK_SIZE = 500;
|
|
13
13
|
const DETAIL_COMPLETE = 'Complete';
|
|
14
14
|
/**
|
|
15
|
-
* Pick the run the board should display for an entity: the newest run that
|
|
16
|
-
* the whole entity, or, when there is none, the newest run of any kind.
|
|
15
|
+
* Pick the run the board should display for an entity document: the newest run of that document
|
|
16
|
+
* that did not fail and covered the whole entity, or, when there is none, the newest run of any kind.
|
|
17
17
|
*
|
|
18
18
|
* Not "most recent Complete run": a run the user cancels keeps `ProcessingStatus = 'In Progress'`
|
|
19
19
|
* (the detector marks it for resumption), and the board's own idle timer can finish a detection
|
|
20
20
|
* before the server does; both end with a reload while a newer run exists, and preferring an older
|
|
21
21
|
* Complete run there would hide the rows the user just watched being produced. Not plain "newest"
|
|
22
22
|
* either: a Failed run usually has no details, and a list-scoped run holds a small subset, so each
|
|
23
|
-
* would hide a good entity-wide run behind an empty or partial board. Runs
|
|
24
|
-
* never candidates
|
|
23
|
+
* would hide a good entity-wide run behind an empty or partial board. Runs of other documents are
|
|
24
|
+
* never candidates, including other documents for the same entity: their template and thresholds
|
|
25
|
+
* produced different matches. Returns null when there is no document or no run for it.
|
|
25
26
|
*/
|
|
26
|
-
export function
|
|
27
|
-
if (!
|
|
27
|
+
export function SelectCurrentRunForDocument(runs, entityDocumentID) {
|
|
28
|
+
if (!entityDocumentID) {
|
|
28
29
|
return null;
|
|
29
30
|
}
|
|
30
|
-
const
|
|
31
|
-
return
|
|
31
|
+
const forDocument = newestFirst(runs.filter(r => UUIDsEqual(r.EntityDocumentID, entityDocumentID)));
|
|
32
|
+
return forDocument.find(isPreferredRun) ?? forDocument[0] ?? null;
|
|
32
33
|
}
|
|
33
34
|
/**
|
|
34
|
-
* The entity document the board should show before the user picks one: the document
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
35
|
+
* The entity document the board should show before the user picks one: the document of the newest
|
|
36
|
+
* run worth showing (see {@link SelectCurrentRunForDocument}), so a first visit lands on results
|
|
37
|
+
* that exist. Falls back to the first document when no run matches any listed document, and to null
|
|
38
|
+
* when there are no documents at all.
|
|
38
39
|
*/
|
|
39
40
|
export function PickDefaultEntityDocument(documents, runs) {
|
|
40
41
|
if (documents.length === 0) {
|
|
41
42
|
return null;
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
const documentsByEntity = IndexByUUID(documents, d => d.EntityID);
|
|
44
|
+
const documentsByID = IndexByUUID(documents, d => d.ID);
|
|
45
45
|
const ordered = [...newestFirst(runs.filter(isPreferredRun)), ...newestFirst(runs)];
|
|
46
46
|
for (const run of ordered) {
|
|
47
|
-
const match =
|
|
47
|
+
const match = documentsByID.Get(run.EntityDocumentID);
|
|
48
48
|
if (match) {
|
|
49
49
|
return match;
|
|
50
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duplicate-detection-run-scope.js","sourceRoot":"","sources":["../../../../src/AI/components/duplicates/duplicate-detection-run-scope.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAYlF,MAAM,UAAU,GAAG,QAAQ,CAAC;AAE5B;;;;GAIG;AACH,SAAS,cAAc,CAAC,GAA0B;IAC9C,OAAO,GAAG,CAAC,gBAAgB,KAAK,UAAU,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;AACpE,CAAC;AAED,6FAA6F;AAC7F,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAG,CAAC;AAEjD,MAAM,eAAe,GAAG,UAAU,CAAC;AAQnC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,yBAAyB,CACrC,IAAkB,EAClB,QAAmC;IAEnC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClF,OAAO,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAClE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACrC,SAAuB,EACvB,IAAsC;IAEtC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,6DAA6D;IAC7D,MAAM,iBAAiB,GAAG,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;IACpF,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,KAAK,EAAE,CAAC;YACR,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IACD,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,WAAW,CAAkC,IAAkB;IACpE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,gHAAgH;AAChH,MAAM,UAAU,0BAA0B,CAAC,KAAa;IACpD,OAAO;QACH,UAAU,EAAE,2BAA2B;QACvC,WAAW,EAAE,mBAAmB,eAAe,CAAC,KAAK,CAAC,sBAAsB,eAAe,GAAG;QAC9F,OAAO,EAAE,qBAAqB;QAC9B,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,eAAe;KAC9B,CAAC;AACN,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CACzC,SAA4B,EAC5B,YAAoB,6BAA6B;IAEjD,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,IAAI,SAAS,EAAE,CAAC;QAC/D,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,eAAe,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;QACjG,OAAO,CAAC,IAAI,CAAC;YACT,UAAU,EAAE,kCAAkC;YAC9C,WAAW,EAAE,4BAA4B,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG;YAC9D,OAAO,EAAE,uBAAuB;YAChC,aAAa,EAAE,IAAI;YACnB,UAAU,EAAE,eAAe;SAC9B,CAAC,CAAC;IACP,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,4BAA4B,CAAC,KAAoB;IAC7D,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,MAAM,IAAI,GAAG,mCAAmC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzE,OAAO,IAAI;SACN,KAAK,CAAC,KAAK,CAAC;SACZ,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;SAC3D,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,oBAAoB,CAChC,OAAqB;IAErB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAe,CAAC;IACxC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAC1D,IAAI,QAAQ,EAAE,CAAC;YACX,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACJ,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACtD,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED,SAAS,MAAM,CAAC,KAA2B;IACvC,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,OAAO,CAAC,CAAC;IACb,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClC,CAAC","sourcesContent":["/**\n * Pure helpers that scope the Record Duplicates board to ONE duplicate run.\n *\n * The board joins `MJ: Duplicate Run Details` to `MJ: Duplicate Run Detail Matches` by\n * DuplicateRunDetailID. Loading those two entities unscoped pulls every review row ever produced,\n * for every entity and every run (hundreds of thousands of rows on a busy tenant), and the load\n * grows with each run anyone performs. Restricting both sides to the run being viewed bounds the\n * load to that run's rows, which is what the board actually renders.\n *\n * The scoping is done in two steps, details first and then matches by the detail IDs just loaded,\n * on purpose. Matches carry no DuplicateRunID of their own, and the only single-query alternative is\n * a subquery against the details view, which means naming a schema and a view from the client. The\n * Angular client has no dialect knowledge (`QuoteSchemaAndView` lives on the server-side database\n * providers, not on the GraphQL provider); the server does rewrite bracketed identifiers for\n * PostgreSQL, but a view name chosen here is still a guess about the database behind the API. An\n * `IN (...)` list of IDs is plain SQL everywhere, names nothing, and the join it produces is exact\n * rather than re-derived. Cost: one extra round trip.\n *\n * Why both queries still carry `IgnoreMaxRows`: details truncate to the newest N by date while\n * matches truncate to the top N by probability. Those two subsets diverge as soon as a run exceeds\n * UserViewMaxRows (1000), leaving details with no loaded matches; buildGroups() then drops every\n * such detail and the board is empty with a full run behind it. Scoping bounds the volume, and the\n * flag keeps the join complete inside that bound. Dropping the flag would bring the empty board back\n * for any single run larger than 1000 rows.\n */\nimport { RunViewParams } from '@memberjunction/core';\nimport { EscapeSQLString, IndexByUUID, UUIDsEqual } from '@memberjunction/global';\n\n/** The slice of an `MJ: Duplicate Runs` row the board needs to choose which run it shows. */\nexport interface DuplicateRunCandidate {\n ID: string;\n EntityID: string;\n ProcessingStatus: string;\n StartedAt: Date | string | null;\n /** Set when the run covered one list's records rather than the whole entity. */\n SourceListID: string | null;\n}\n\nconst RUN_FAILED = 'Failed';\n\n/**\n * A run worth putting on the board ahead of others: it did not fail (a run is marked Failed on any\n * exception in detection, usually before a single detail is written) and it covered the whole\n * entity rather than one list (a list run is a small subset that would hide the entity-wide results).\n */\nfunction isPreferredRun(run: DuplicateRunCandidate): boolean {\n return run.ProcessingStatus !== RUN_FAILED && !run.SourceListID;\n}\n\n/** How many detail IDs go into one matches query; keeps each `IN (...)` list a sane size. */\nexport const MATCH_QUERY_DETAIL_CHUNK_SIZE = 500;\n\nconst DETAIL_COMPLETE = 'Complete';\n\n/** The slice of an entity-document picker option needed to choose a default. */\nexport interface EntityDocumentCandidate {\n ID: string;\n EntityID: string;\n}\n\n/**\n * Pick the run the board should display for an entity: the newest run that did not fail and covered\n * the whole entity, or, when there is none, the newest run of any kind.\n *\n * Not \"most recent Complete run\": a run the user cancels keeps `ProcessingStatus = 'In Progress'`\n * (the detector marks it for resumption), and the board's own idle timer can finish a detection\n * before the server does; both end with a reload while a newer run exists, and preferring an older\n * Complete run there would hide the rows the user just watched being produced. Not plain \"newest\"\n * either: a Failed run usually has no details, and a list-scoped run holds a small subset, so each\n * would hide a good entity-wide run behind an empty or partial board. Runs for other entities are\n * never candidates. Returns null when there is no entity or no run for it.\n */\nexport function SelectCurrentRunForEntity<T extends DuplicateRunCandidate>(\n runs: readonly T[],\n entityID: string | null | undefined\n): T | null {\n if (!entityID) {\n return null;\n }\n const forEntity = newestFirst(runs.filter(r => UUIDsEqual(r.EntityID, entityID)));\n return forEntity.find(isPreferredRun) ?? forEntity[0] ?? null;\n}\n\n/**\n * The entity document the board should show before the user picks one: the document for the entity\n * of the newest run worth showing (see {@link SelectCurrentRunForEntity}), so a first visit lands on\n * results that exist. Falls back to the first document when no run matches any document, and to\n * null when there are no documents at all.\n */\nexport function PickDefaultEntityDocument<D extends EntityDocumentCandidate>(\n documents: readonly D[],\n runs: readonly DuplicateRunCandidate[]\n): D | null {\n if (documents.length === 0) {\n return null;\n }\n // First document per entity wins, as documents.find() would.\n const documentsByEntity = IndexByUUID(documents, d => d.EntityID);\n const ordered = [...newestFirst(runs.filter(isPreferredRun)), ...newestFirst(runs)];\n for (const run of ordered) {\n const match = documentsByEntity.Get(run.EntityID);\n if (match) {\n return match;\n }\n }\n return documents[0];\n}\n\nfunction newestFirst<T extends DuplicateRunCandidate>(runs: readonly T[]): T[] {\n return [...runs].sort((a, b) => toTime(b.StartedAt) - toTime(a.StartedAt));\n}\n\n/** The completed details of ONE run, newest first. Bounded by the run; `IgnoreMaxRows` per the file comment. */\nexport function BuildRunScopedDetailsQuery(runID: string): RunViewParams {\n return {\n EntityName: 'MJ: Duplicate Run Details',\n ExtraFilter: `DuplicateRunID='${EscapeSQLString(runID)}' AND MatchStatus='${DETAIL_COMPLETE}'`,\n OrderBy: '__mj_CreatedAt DESC',\n IgnoreMaxRows: true,\n ResultType: 'entity_object'\n };\n}\n\n/**\n * The matches whose parent detail is one of `detailIDs`, as one query per chunk of\n * {@link MATCH_QUERY_DETAIL_CHUNK_SIZE} IDs. No IDs, no queries. Plain `IN (...)` so it runs on any\n * database behind the API; `IgnoreMaxRows` per the file comment.\n */\nexport function BuildMatchQueriesForDetailIDs(\n detailIDs: readonly string[],\n chunkSize: number = MATCH_QUERY_DETAIL_CHUNK_SIZE\n): RunViewParams[] {\n const queries: RunViewParams[] = [];\n for (let start = 0; start < detailIDs.length; start += chunkSize) {\n const literals = detailIDs.slice(start, start + chunkSize).map(id => `'${EscapeSQLString(id)}'`);\n queries.push({\n EntityName: 'MJ: Duplicate Run Detail Matches',\n ExtraFilter: `DuplicateRunDetailID IN (${literals.join(',')})`,\n OrderBy: 'MatchProbability DESC',\n IgnoreMaxRows: true,\n ResultType: 'entity_object'\n });\n }\n return queries;\n}\n\n/** The detail IDs a matches query built by {@link BuildMatchQueriesForDetailIDs} covers. */\nexport function DetailIDsCoveredByMatchQuery(query: RunViewParams): string[] {\n const filter = typeof query.ExtraFilter === 'string' ? query.ExtraFilter : '';\n const list = /DuplicateRunDetailID IN \\((.*)\\)/s.exec(filter)?.[1] ?? '';\n return list\n .split(/','/)\n .map(part => part.replace(/^'|'$/g, '').replace(/''/g, \"'\"))\n .filter(part => part.length > 0);\n}\n\n/** Index matches by their parent detail; the join buildGroups() performs. */\nexport function GroupMatchesByDetail<M extends { DuplicateRunDetailID: string }>(\n matches: readonly M[]\n): Map<string, M[]> {\n const byDetail = new Map<string, M[]>();\n for (const match of matches) {\n const existing = byDetail.get(match.DuplicateRunDetailID);\n if (existing) {\n existing.push(match);\n } else {\n byDetail.set(match.DuplicateRunDetailID, [match]);\n }\n }\n return byDetail;\n}\n\nfunction toTime(value: Date | string | null): number {\n if (!value) {\n return 0;\n }\n const time = new Date(value).getTime();\n return isNaN(time) ? 0 : time;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"duplicate-detection-run-scope.js","sourceRoot":"","sources":["../../../../src/AI/components/duplicates/duplicate-detection-run-scope.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure helpers that scope the Record Duplicates board to ONE duplicate run.\n *\n * The board joins `MJ: Duplicate Run Details` to `MJ: Duplicate Run Detail Matches` by\n * DuplicateRunDetailID. Loading those two entities unscoped pulls every review row ever produced,\n * for every entity and every run (hundreds of thousands of rows on a busy tenant), and the load\n * grows with each run anyone performs. Restricting both sides to the run being viewed bounds the\n * load to that run's rows, which is what the board actually renders.\n *\n * The scoping is done in two steps, details first and then matches by the detail IDs just loaded,\n * on purpose. Matches carry no DuplicateRunID of their own, and the only single-query alternative is\n * a subquery against the details view, which means naming a schema and a view from the client. The\n * Angular client has no dialect knowledge (`QuoteSchemaAndView` lives on the server-side database\n * providers, not on the GraphQL provider); the server does rewrite bracketed identifiers for\n * PostgreSQL, but a view name chosen here is still a guess about the database behind the API. An\n * `IN (...)` list of IDs is plain SQL everywhere, names nothing, and the join it produces is exact\n * rather than re-derived. Cost: one extra round trip.\n *\n * Why both queries still carry `IgnoreMaxRows`: details truncate to the newest N by date while\n * matches truncate to the top N by probability. Those two subsets diverge as soon as a run exceeds\n * UserViewMaxRows (1000), leaving details with no loaded matches; buildGroups() then drops every\n * such detail and the board is empty with a full run behind it. Scoping bounds the volume, and the\n * flag keeps the join complete inside that bound. Dropping the flag would bring the empty board back\n * for any single run larger than 1000 rows.\n */\nimport { RunViewParams } from '@memberjunction/core';\nimport { EscapeSQLString, IndexByUUID, UUIDsEqual } from '@memberjunction/global';\n\n/** The slice of an `MJ: Duplicate Runs` row the board needs to choose which run it shows. */\nexport interface DuplicateRunCandidate {\n ID: string;\n /** The entity document the run used. */\n EntityDocumentID: string;\n ProcessingStatus: string;\n StartedAt: Date | string | null;\n /** Set when the run covered one list's records rather than the whole entity. */\n SourceListID: string | null;\n}\n\nconst RUN_FAILED = 'Failed';\n\n/**\n * A run worth putting on the board ahead of others: it did not fail (a run is marked Failed on any\n * exception in detection, usually before a single detail is written) and it covered the whole\n * entity rather than one list (a list run is a small subset that would hide the entity-wide results).\n */\nfunction isPreferredRun(run: DuplicateRunCandidate): boolean {\n return run.ProcessingStatus !== RUN_FAILED && !run.SourceListID;\n}\n\n/** How many detail IDs go into one matches query; keeps each `IN (...)` list a sane size. */\nexport const MATCH_QUERY_DETAIL_CHUNK_SIZE = 500;\n\nconst DETAIL_COMPLETE = 'Complete';\n\n/** The slice of an entity-document picker option needed to choose a default. */\nexport interface EntityDocumentCandidate {\n ID: string;\n}\n\n/**\n * Pick the run the board should display for an entity document: the newest run of that document\n * that did not fail and covered the whole entity, or, when there is none, the newest run of any kind.\n *\n * Not \"most recent Complete run\": a run the user cancels keeps `ProcessingStatus = 'In Progress'`\n * (the detector marks it for resumption), and the board's own idle timer can finish a detection\n * before the server does; both end with a reload while a newer run exists, and preferring an older\n * Complete run there would hide the rows the user just watched being produced. Not plain \"newest\"\n * either: a Failed run usually has no details, and a list-scoped run holds a small subset, so each\n * would hide a good entity-wide run behind an empty or partial board. Runs of other documents are\n * never candidates, including other documents for the same entity: their template and thresholds\n * produced different matches. Returns null when there is no document or no run for it.\n */\nexport function SelectCurrentRunForDocument<T extends DuplicateRunCandidate>(\n runs: readonly T[],\n entityDocumentID: string | null | undefined\n): T | null {\n if (!entityDocumentID) {\n return null;\n }\n const forDocument = newestFirst(runs.filter(r => UUIDsEqual(r.EntityDocumentID, entityDocumentID)));\n return forDocument.find(isPreferredRun) ?? forDocument[0] ?? null;\n}\n\n/**\n * The entity document the board should show before the user picks one: the document of the newest\n * run worth showing (see {@link SelectCurrentRunForDocument}), so a first visit lands on results\n * that exist. Falls back to the first document when no run matches any listed document, and to null\n * when there are no documents at all.\n */\nexport function PickDefaultEntityDocument<D extends EntityDocumentCandidate>(\n documents: readonly D[],\n runs: readonly DuplicateRunCandidate[]\n): D | null {\n if (documents.length === 0) {\n return null;\n }\n const documentsByID = IndexByUUID(documents, d => d.ID);\n const ordered = [...newestFirst(runs.filter(isPreferredRun)), ...newestFirst(runs)];\n for (const run of ordered) {\n const match = documentsByID.Get(run.EntityDocumentID);\n if (match) {\n return match;\n }\n }\n return documents[0];\n}\n\nfunction newestFirst<T extends DuplicateRunCandidate>(runs: readonly T[]): T[] {\n return [...runs].sort((a, b) => toTime(b.StartedAt) - toTime(a.StartedAt));\n}\n\n/** The completed details of ONE run, newest first. Bounded by the run; `IgnoreMaxRows` per the file comment. */\nexport function BuildRunScopedDetailsQuery(runID: string): RunViewParams {\n return {\n EntityName: 'MJ: Duplicate Run Details',\n ExtraFilter: `DuplicateRunID='${EscapeSQLString(runID)}' AND MatchStatus='${DETAIL_COMPLETE}'`,\n OrderBy: '__mj_CreatedAt DESC',\n IgnoreMaxRows: true,\n ResultType: 'entity_object'\n };\n}\n\n/**\n * The matches whose parent detail is one of `detailIDs`, as one query per chunk of\n * {@link MATCH_QUERY_DETAIL_CHUNK_SIZE} IDs. No IDs, no queries. Plain `IN (...)` so it runs on any\n * database behind the API; `IgnoreMaxRows` per the file comment.\n */\nexport function BuildMatchQueriesForDetailIDs(\n detailIDs: readonly string[],\n chunkSize: number = MATCH_QUERY_DETAIL_CHUNK_SIZE\n): RunViewParams[] {\n const queries: RunViewParams[] = [];\n for (let start = 0; start < detailIDs.length; start += chunkSize) {\n const literals = detailIDs.slice(start, start + chunkSize).map(id => `'${EscapeSQLString(id)}'`);\n queries.push({\n EntityName: 'MJ: Duplicate Run Detail Matches',\n ExtraFilter: `DuplicateRunDetailID IN (${literals.join(',')})`,\n OrderBy: 'MatchProbability DESC',\n IgnoreMaxRows: true,\n ResultType: 'entity_object'\n });\n }\n return queries;\n}\n\n/** The detail IDs a matches query built by {@link BuildMatchQueriesForDetailIDs} covers. */\nexport function DetailIDsCoveredByMatchQuery(query: RunViewParams): string[] {\n const filter = typeof query.ExtraFilter === 'string' ? query.ExtraFilter : '';\n const list = /DuplicateRunDetailID IN \\((.*)\\)/s.exec(filter)?.[1] ?? '';\n return list\n .split(/','/)\n .map(part => part.replace(/^'|'$/g, '').replace(/''/g, \"'\"))\n .filter(part => part.length > 0);\n}\n\n/** Index matches by their parent detail; the join buildGroups() performs. */\nexport function GroupMatchesByDetail<M extends { DuplicateRunDetailID: string }>(\n matches: readonly M[]\n): Map<string, M[]> {\n const byDetail = new Map<string, M[]>();\n for (const match of matches) {\n const existing = byDetail.get(match.DuplicateRunDetailID);\n if (existing) {\n existing.push(match);\n } else {\n byDetail.set(match.DuplicateRunDetailID, [match]);\n }\n }\n return byDetail;\n}\n\nfunction toTime(value: Date | string | null): number {\n if (!value) {\n return 0;\n }\n const time = new Date(value).getTime();\n return isNaN(time) ? 0 : time;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution-monitoring.component.d.ts","sourceRoot":"","sources":["../../../src/AI/components/execution-monitoring.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAA2B,MAAM,eAAe,CAAC;AACzG,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE3C,OAAO,EACL,wBAAwB,EACxB,aAAa,EACb,SAAS,EACT,aAAa,EACb,SAAS,EACT,gBAAgB,EACjB,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AAErE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"execution-monitoring.component.d.ts","sourceRoot":"","sources":["../../../src/AI/components/execution-monitoring.component.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { Subject } from 'rxjs';
|
|
|
3
3
|
import { map, takeUntil, debounceTime } from 'rxjs/operators';
|
|
4
4
|
import { ComputeCoveragePercent, GetBucketSizeMs } from '../services/ai-usage-analytics.compute';
|
|
5
5
|
import { RunView, CompositeKey } from '@memberjunction/core';
|
|
6
|
+
import { AIEngineBase } from '@memberjunction/ai-engine-base';
|
|
6
7
|
import { BaseResourceComponent } from '@memberjunction/ng-shared';
|
|
7
8
|
import * as i0 from "@angular/core";
|
|
8
9
|
import * as i1 from "../services/ai-instrumentation.service";
|
|
@@ -1438,20 +1439,25 @@ export class ExecutionMonitoringComponent extends BaseResourceComponent {
|
|
|
1438
1439
|
endTime = new Date(tab.timestamp);
|
|
1439
1440
|
endTime.setHours(23, 59, 59, 999);
|
|
1440
1441
|
}
|
|
1441
|
-
// Load executions for this time period
|
|
1442
|
-
const
|
|
1443
|
-
|
|
1442
|
+
// Load executions for this time period in a single batched RunViews call with lightweight scalar projections
|
|
1443
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
1444
|
+
const [promptResults, agentResults] = await rv.RunViews([
|
|
1445
|
+
{
|
|
1444
1446
|
EntityName: 'MJ: AI Prompt Runs',
|
|
1445
1447
|
ExtraFilter: `RunAt >= '${startTime.toISOString()}' AND RunAt <= '${endTime.toISOString()}'`,
|
|
1446
1448
|
OrderBy: 'RunAt DESC',
|
|
1447
|
-
MaxRows: 500
|
|
1448
|
-
|
|
1449
|
-
|
|
1449
|
+
MaxRows: 500,
|
|
1450
|
+
Fields: ['ID', 'Prompt', 'Model', 'Success', 'RunAt', 'CompletedAt', 'Cost', 'TokensUsed', 'ErrorMessage'],
|
|
1451
|
+
ResultType: 'simple'
|
|
1452
|
+
},
|
|
1453
|
+
{
|
|
1450
1454
|
EntityName: 'MJ: AI Agent Runs',
|
|
1451
1455
|
ExtraFilter: `StartedAt >= '${startTime.toISOString()}' AND StartedAt <= '${endTime.toISOString()}'`,
|
|
1452
1456
|
OrderBy: 'StartedAt DESC',
|
|
1453
|
-
MaxRows: 500
|
|
1454
|
-
|
|
1457
|
+
MaxRows: 500,
|
|
1458
|
+
Fields: ['ID', 'Agent', 'Status', 'StartedAt', 'CompletedAt', 'TotalCost', 'TotalTokensUsed', 'ErrorMessage'],
|
|
1459
|
+
ResultType: 'simple'
|
|
1460
|
+
}
|
|
1455
1461
|
]);
|
|
1456
1462
|
// Convert to ExecutionRecord format
|
|
1457
1463
|
const executions = [];
|
|
@@ -1511,13 +1517,19 @@ export class ExecutionMonitoringComponent extends BaseResourceComponent {
|
|
|
1511
1517
|
async loadModelDetails(tab, modelName) {
|
|
1512
1518
|
this.LoadingDrillDown = true;
|
|
1513
1519
|
try {
|
|
1514
|
-
//
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1520
|
+
// Consult AIEngineBase in-memory cache first before issuing a network RunView
|
|
1521
|
+
await AIEngineBase.Instance.Config(false);
|
|
1522
|
+
let model = AIEngineBase.Instance.Models.find(m => m.Name === modelName);
|
|
1523
|
+
if (!model) {
|
|
1524
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
1525
|
+
const result = await rv.RunView({
|
|
1526
|
+
EntityName: 'MJ: AI Models',
|
|
1527
|
+
ExtraFilter: `Name = '${modelName.replace(/'/g, "''")}'`,
|
|
1528
|
+
Fields: ['ID', 'Name', 'Vendor', 'APIName', 'IsActive', 'Description'],
|
|
1529
|
+
ResultType: 'simple'
|
|
1530
|
+
});
|
|
1531
|
+
model = result.Results[0];
|
|
1532
|
+
}
|
|
1521
1533
|
if (model) {
|
|
1522
1534
|
tab.data = {
|
|
1523
1535
|
name: model.Name,
|
|
@@ -2297,5 +2309,5 @@ export class ExecutionMonitoringComponent extends BaseResourceComponent {
|
|
|
2297
2309
|
</div>
|
|
2298
2310
|
`, styles: ["\n .execution-monitoring {\n padding: 0;\n background: var(--mj-bg-surface-card);\n width: 100%;\n height: 100%;\n position: relative;\n overflow: auto;\n display: flex;\n flex-direction: column;\n }\n\n .execution-monitoring.loading {\n overflow: hidden;\n }\n\n /* Loading Overlay */\n .loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: color-mix(in srgb, var(--mj-bg-surface) 70%, transparent);\n z-index: 999;\n display: flex;\n align-items: center;\n justify-content: center;\n backdrop-filter: blur(4px);\n }\n\n /* === Dashboard Header - Clean White Style === */\n .monitoring-header {\n background: var(--mj-bg-surface);\n padding: 16px 24px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 16px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n border-bottom: 1px solid var(--mj-border-default);\n position: relative;\n z-index: 10;\n }\n\n .monitoring-title {\n margin: 0;\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .monitoring-title i {\n color: var(--mj-brand-primary);\n font-size: 22px;\n }\n\n .monitoring-controls {\n display: flex;\n gap: 12px;\n align-items: center;\n flex-wrap: wrap;\n }\n\n .time-range-control {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n }\n\n .time-range-control label {\n color: var(--mj-text-muted);\n font-weight: 500;\n }\n\n .time-range-control select {\n padding: 8px 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 13px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .time-range-control select:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n }\n\n .time-range-control select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n .time-range-control select:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .time-range-control select option {\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n }\n\n .refresh-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n padding: 8px 16px;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n }\n\n .refresh-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n }\n\n .refresh-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n }\n\n .refresh-btn i.spinning {\n animation: spin 1s linear infinite;\n }\n\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n\n .kpi-dashboard {\n padding: 20px;\n }\n\n .kpi-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 16px;\n }\n\n .dashboard-splitter {\n flex: 1;\n min-height: 500px;\n margin: 0 20px 20px 20px;\n }\n\n .dashboard-section {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: 0 4px 16px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .dashboard-section:hover {\n box-shadow: 0 8px 24px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n }\n\n /* Ensure splitter areas take full height */\n :host ::ng-deep as-split-area > .as-split-area-content {\n overflow: hidden;\n padding: 10px;\n }\n\n /* Cost Analysis Styles */\n .cost-chart-container, .efficiency-chart-container, .status-container {\n padding: 20px;\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n .chart-header {\n margin-bottom: 16px;\n }\n\n .chart-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .chart-title i {\n color: var(--mj-brand-primary);\n }\n\n .cost-bars, .efficiency-items {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .cost-bar-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 0;\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .cost-bar-item:last-child {\n border-bottom: none;\n }\n\n .cost-bar-info {\n min-width: 120px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .model-name {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-primary);\n }\n\n .cost-value {\n font-size: 11px;\n color: var(--mj-brand-primary);\n font-weight: 600;\n }\n\n .cost-bar-container {\n flex: 1;\n height: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n border-radius: 4px;\n overflow: hidden;\n }\n\n .cost-bar {\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: 4px;\n transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .token-info {\n font-size: 10px;\n color: var(--mj-text-muted);\n min-width: 80px;\n text-align: right;\n }\n\n /* Token Efficiency Styles */\n .efficiency-item {\n padding: 12px 0;\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .efficiency-item:last-child {\n border-bottom: none;\n }\n\n .efficiency-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n }\n\n .efficiency-ratio {\n font-size: 11px;\n color: var(--mj-brand-primary);\n font-weight: 600;\n }\n\n .token-breakdown {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .token-bar {\n height: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n border-radius: 4px;\n overflow: hidden;\n display: flex;\n }\n\n .token-segment {\n height: 100%;\n transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .token-segment--input {\n background: var(--mj-brand-primary);\n }\n\n .token-segment--output {\n background: var(--mj-brand-accent);\n }\n\n .token-labels {\n display: flex;\n justify-content: space-between;\n font-size: 10px;\n color: var(--mj-text-muted);\n }\n\n .input-label {\n color: var(--mj-brand-primary);\n font-weight: 500;\n }\n\n .output-label {\n color: var(--mj-brand-accent);\n font-weight: 500;\n }\n\n .cost-per-token {\n font-size: 10px;\n color: var(--mj-text-disabled);\n margin-top: 4px;\n }\n\n /* System Status Styles */\n .status-metrics {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n }\n\n .status-metric {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: var(--mj-bg-surface-card);\n border-radius: 6px;\n }\n\n .status-icon {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n\n .status-icon--success {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n\n .status-icon--warning {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n .status-icon--info {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .status-icon--primary {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .status-info {\n flex: 1;\n }\n\n .status-label {\n font-size: 12px;\n color: var(--mj-text-muted);\n font-weight: 500;\n }\n\n .status-value {\n font-size: 18px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 2px 0;\n }\n\n .status-subtitle {\n font-size: 10px;\n color: var(--mj-text-disabled);\n }\n\n /* Execution Modal Styles */\n .execution-modal {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 20px;\n }\n\n .execution-modal-content {\n background: var(--mj-bg-surface);\n border-radius: 8px;\n max-width: 800px;\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .execution-modal-header {\n padding: 20px;\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .execution-modal-header h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .modal-header-actions {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n\n .open-record-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n padding: 8px 16px;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n }\n\n .open-record-btn:hover {\n background: var(--mj-brand-primary-hover);\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n }\n\n .open-record-btn i {\n font-size: 12px;\n }\n\n .close-btn {\n background: none;\n border: none;\n font-size: 16px;\n color: var(--mj-text-disabled);\n cursor: pointer;\n padding: 4px;\n }\n\n .close-btn:hover {\n color: var(--mj-text-primary);\n }\n\n .execution-modal-body {\n padding: 20px;\n overflow-y: auto;\n flex: 1;\n }\n\n .execution-details {\n display: flex;\n flex-direction: column;\n gap: 20px;\n }\n\n .detail-section h4 {\n margin: 0 0 12px 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-border-default);\n padding-bottom: 6px;\n }\n\n .detail-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 12px;\n }\n\n .detail-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .detail-item label {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .detail-item span {\n font-size: 13px;\n color: var(--mj-text-primary);\n }\n\n .status-badge {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 10px;\n font-weight: 500;\n text-transform: uppercase;\n }\n\n .status-badge--completed {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n\n .status-badge--running {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .status-badge--failed {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n\n .error-message {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-warning);\n border-radius: 4px;\n padding: 12px;\n font-size: 12px;\n color: var(--mj-status-error);\n font-family: monospace;\n }\n\n .child-executions {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .child-execution {\n background: var(--mj-bg-surface-card);\n border-radius: 4px;\n padding: 12px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .child-info {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .child-name {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-primary);\n }\n\n .child-type {\n font-size: 10px;\n background: var(--mj-border-default);\n padding: 2px 6px;\n border-radius: 3px;\n color: var(--mj-text-muted);\n }\n\n .child-status {\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 3px;\n }\n\n .child-metrics {\n display: flex;\n gap: 12px;\n font-size: 11px;\n color: var(--mj-text-muted);\n }\n\n .loading-details {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px;\n gap: 12px;\n }\n\n /* Drill-down Tab Styles */\n .drill-down-container {\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n .drill-down-tabs {\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n .tab-header {\n display: flex;\n border-bottom: 1px solid color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n background: var(--mj-bg-surface-card);\n min-height: 44px;\n overflow-x: auto;\n }\n\n .tab-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-muted);\n white-space: nowrap;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 120px;\n justify-content: space-between;\n }\n\n .tab-item:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n color: var(--mj-brand-primary);\n }\n\n .tab-item.active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n border-bottom-color: var(--mj-brand-primary);\n font-weight: 600;\n }\n\n .tab-title {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .tab-close {\n background: none;\n border: none;\n color: var(--mj-text-disabled);\n cursor: pointer;\n padding: 2px;\n border-radius: 2px;\n font-size: 10px;\n width: 16px;\n height: 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n }\n\n .tab-close:hover {\n background: rgba(0, 0, 0, 0.1);\n color: var(--mj-text-primary);\n }\n\n .tab-content {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .tab-pane {\n height: 100%;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .trends-chart {\n padding: 0;\n }\n\n .trends-chart app-time-series-chart {\n height: 100%;\n display: block;\n overflow: hidden;\n }\n\n /* Ensure chart fits within tab pane */\n .tab-pane.trends-chart {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n /* Drill-down specific styles */\n .executions-drill-down {\n padding: 20px;\n overflow-y: auto;\n }\n\n .drill-down-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n padding-bottom: 12px;\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .drill-down-header h4 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .drill-down-meta {\n display: flex;\n gap: 12px;\n align-items: center;\n font-size: 12px;\n }\n\n .timestamp {\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 4px 8px;\n border-radius: 4px;\n }\n\n .metric-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n padding: 4px 10px;\n border-radius: 6px;\n font-weight: 600;\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n }\n\n .loading-spinner {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 40px;\n color: var(--mj-text-muted);\n gap: 12px;\n }\n\n .executions-table {\n display: flex;\n flex-direction: column;\n gap: 0;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n }\n\n .table-header {\n display: grid;\n grid-template-columns: 80px 1fr 120px 100px 100px 80px 100px 120px;\n gap: 12px;\n background: var(--mj-bg-surface-card);\n padding: 12px 16px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .table-row {\n display: grid;\n grid-template-columns: 80px 1fr 120px 100px 100px 80px 100px 120px;\n gap: 12px;\n padding: 12px 16px;\n border-top: 1px solid var(--mj-bg-surface-sunken);\n cursor: pointer;\n transition: background 0.2s ease;\n align-items: center;\n }\n\n .table-row:hover {\n background: var(--mj-bg-surface-card);\n }\n\n .table-cell {\n font-size: 12px;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .type-badge {\n background: color-mix(in srgb, var(--mj-text-muted) 10%, var(--mj-bg-surface));\n color: var(--mj-text-muted);\n padding: 3px 8px;\n border-radius: 4px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n }\n\n .type-badge--prompt {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .type-badge--agent {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n\n /* Model detail styles */\n .model-detail {\n padding: 20px;\n overflow-y: auto;\n }\n\n .model-details {\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n\n .model-info-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 16px;\n }\n\n .info-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border-radius: 6px;\n }\n\n .info-item label {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin: 0;\n }\n\n .info-item span {\n font-size: 14px;\n color: var(--mj-text-primary);\n font-weight: 500;\n }\n\n .status-indicator {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n }\n\n .status-indicator.active {\n color: var(--mj-status-success);\n }\n\n .status-indicator.active::before {\n content: '';\n width: 6px;\n height: 6px;\n background: var(--mj-status-success);\n border-radius: 50%;\n }\n\n .model-description {\n padding: 20px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n }\n\n .model-description h5 {\n margin: 0 0 12px 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .model-description p {\n margin: 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n line-height: 1.5;\n }\n\n /* Clickable KPI cards */\n .clickable {\n cursor: pointer;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n }\n\n .clickable:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n\n /* Collapsible Panel Styles */\n .analysis-panels {\n padding: 12px;\n height: 100%;\n overflow-y: auto;\n background: var(--mj-bg-surface-card);\n }\n\n /* Analysis panel chrome (wrapper/header/toggle-icon) now owned by <mj-accordion-panel>. */\n .panel-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 600;\n color: var(--mj-text-primary);\n font-size: 14px;\n }\n\n .panel-title i {\n color: var(--mj-brand-primary);\n width: 18px;\n }\n\n .panel-content {\n padding: 18px;\n }\n\n .live-executions-panel {\n padding: 0;\n }\n\n .live-executions-panel app-live-execution-widget {\n height: 300px;\n display: block;\n }\n\n /* Responsive Design */\n @media (max-width: 1200px) {\n .dashboard-splitter {\n min-height: 400px;\n }\n \n .table-header,\n .table-row {\n grid-template-columns: 60px 1fr 100px 80px 80px 60px 80px 100px;\n gap: 8px;\n }\n \n .model-info-grid {\n grid-template-columns: 1fr;\n }\n \n .analysis-panels {\n padding: 8px;\n }\n }\n\n @media (max-width: 768px) {\n .execution-monitoring {\n padding: 12px;\n }\n \n .monitoring-header {\n flex-direction: column;\n align-items: flex-start;\n }\n \n .monitoring-controls {\n width: 100%;\n justify-content: flex-start;\n }\n \n .dashboard-splitter {\n min-height: 350px;\n }\n \n .kpi-grid {\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n }\n\n /* Reduce padding on smaller screens */\n :host ::ng-deep as-split-area > .as-split-area-content {\n padding: 5px;\n }\n\n .tab-header {\n overflow-x: auto;\n }\n \n .tab-item {\n min-width: 100px;\n padding: 6px 12px;\n }\n \n .table-header,\n .table-row {\n grid-template-columns: 1fr;\n gap: 4px;\n text-align: left;\n }\n \n .table-row {\n display: block;\n padding: 16px;\n }\n \n .table-cell {\n display: block;\n margin-bottom: 8px;\n }\n \n .table-cell:before {\n content: attr(data-label) ': ';\n font-weight: 600;\n color: var(--mj-text-muted);\n font-size: 11px;\n text-transform: uppercase;\n }\n \n .executions-drill-down,\n .model-detail {\n padding: 12px;\n }\n \n .panel-content {\n padding: 12px;\n }\n\n .panel-title {\n font-size: 13px;\n }\n }\n "] }]
|
|
2299
2311
|
}], () => [{ type: i1.AIInstrumentationService }, { type: i0.ChangeDetectorRef }], null); })();
|
|
2300
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ExecutionMonitoringComponent, { className: "ExecutionMonitoringComponent", filePath: "src/AI/components/execution-monitoring.component.ts", lineNumber:
|
|
2312
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ExecutionMonitoringComponent, { className: "ExecutionMonitoringComponent", filePath: "src/AI/components/execution-monitoring.component.ts", lineNumber: 1685 }); })();
|
|
2301
2313
|
//# sourceMappingURL=execution-monitoring.component.js.map
|