@memberjunction/ng-dashboards 6.2.0-edge.1 → 6.2.0-edge.2
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/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +3 -1
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -1
- package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/sources-tab.component.js +1 -2
- package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -1
- package/dist/AI/components/rubric-drift-series.d.ts +32 -0
- package/dist/AI/components/rubric-drift-series.d.ts.map +1 -0
- package/dist/AI/components/rubric-drift-series.js +49 -0
- package/dist/AI/components/rubric-drift-series.js.map +1 -0
- package/dist/AI/components/rubric-drift.component.d.ts +42 -0
- package/dist/AI/components/rubric-drift.component.d.ts.map +1 -0
- package/dist/AI/components/rubric-drift.component.js +197 -0
- package/dist/AI/components/rubric-drift.component.js.map +1 -0
- package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.js +4 -3
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +5 -2
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.d.ts +5 -0
- package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +151 -136
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +3 -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 -0
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.js +17 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.js.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js +52 -45
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts +11 -0
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +47 -10
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/Rubrics/catalog-grid.d.ts +4 -0
- package/dist/Rubrics/catalog-grid.d.ts.map +1 -0
- package/dist/Rubrics/catalog-grid.js +22 -0
- package/dist/Rubrics/catalog-grid.js.map +1 -0
- package/dist/Rubrics/rubrics-dashboard.component.d.ts +31 -0
- package/dist/Rubrics/rubrics-dashboard.component.d.ts.map +1 -0
- package/dist/Rubrics/rubrics-dashboard.component.js +285 -0
- package/dist/Rubrics/rubrics-dashboard.component.js.map +1 -0
- package/dist/Rubrics/rubrics-resource.component.d.ts +13 -0
- package/dist/Rubrics/rubrics-resource.component.d.ts.map +1 -0
- package/dist/Rubrics/rubrics-resource.component.js +42 -0
- package/dist/Rubrics/rubrics-resource.component.js.map +1 -0
- package/dist/Rubrics/scales-dashboard.component.d.ts +34 -0
- package/dist/Rubrics/scales-dashboard.component.d.ts.map +1 -0
- package/dist/Rubrics/scales-dashboard.component.js +204 -0
- package/dist/Rubrics/scales-dashboard.component.js.map +1 -0
- package/dist/Rubrics/scales-resource.component.d.ts +13 -0
- package/dist/Rubrics/scales-resource.component.d.ts.map +1 -0
- package/dist/Rubrics/scales-resource.component.js +42 -0
- package/dist/Rubrics/scales-resource.component.js.map +1 -0
- package/dist/Testing/components/testing-analytics.component.d.ts +15 -0
- package/dist/Testing/components/testing-analytics.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-analytics.component.js +465 -296
- package/dist/Testing/components/testing-analytics.component.js.map +1 -1
- package/dist/Testing/components/testing-review.component.d.ts +6 -0
- package/dist/Testing/components/testing-review.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-review.component.js +289 -173
- package/dist/Testing/components/testing-review.component.js.map +1 -1
- package/dist/Testing/components/widgets/test-run-detail-panel.component.d.ts +8 -1
- package/dist/Testing/components/widgets/test-run-detail-panel.component.d.ts.map +1 -1
- package/dist/Testing/components/widgets/test-run-detail-panel.component.js +68 -43
- package/dist/Testing/components/widgets/test-run-detail-panel.component.js.map +1 -1
- package/dist/module.d.ts +23 -22
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +7 -0
- package/dist/module.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/dist/rubrics-dashboards.module.d.ts +17 -0
- package/dist/rubrics-dashboards.module.d.ts.map +1 -0
- package/dist/rubrics-dashboards.module.js +76 -0
- package/dist/rubrics-dashboards.module.js.map +1 -0
- package/package.json +70 -64
|
@@ -55,6 +55,11 @@ export interface FeaturePipelineSummary {
|
|
|
55
55
|
LastRunSuccess: number | null;
|
|
56
56
|
/** Records that errored in the most recent run, or null. */
|
|
57
57
|
LastRunErrors: number | null;
|
|
58
|
+
/**
|
|
59
|
+
* The pipeline type ('LLM' or 'Decision' or custom). Defaults to 'LLM' when unset. The two built-in
|
|
60
|
+
* names are given in their canonical case whatever case the spec uses, as the processor matches them.
|
|
61
|
+
*/
|
|
62
|
+
PipelineType: string;
|
|
58
63
|
}
|
|
59
64
|
/**
|
|
60
65
|
* **FeaturePipelineEngine** (Knowledge Hub, Angular) — the discovery + monitoring
|
|
@@ -117,5 +122,11 @@ export declare class FeaturePipelineEngine extends BaseEngine<FeaturePipelineEng
|
|
|
117
122
|
private static deriveOutputAttribute;
|
|
118
123
|
/** Collect field names from either an object map or an array of names. */
|
|
119
124
|
private static fieldNamesFrom;
|
|
125
|
+
/**
|
|
126
|
+
* Best-effort pipeline type derived from the Record Process `Configuration` JSON
|
|
127
|
+
* (which serializes `DataFeatureSpec`). Returns 'LLM' when unset, empty, or unparseable, and a built-in
|
|
128
|
+
* name ('decision') in its canonical case ('Decision').
|
|
129
|
+
*/
|
|
130
|
+
private static derivePipelineType;
|
|
120
131
|
}
|
|
121
132
|
//# sourceMappingURL=feature-pipeline.engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-pipeline.engine.d.ts","sourceRoot":"","sources":["../../../../src/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAEV,iBAAiB,EAEjB,QAAQ,EACT,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAC1F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAEvC;;;;;;;;GAQG;AACH,eAAO,MAAM,8BAA8B,qBAAqB,CAAC;AAEjE,mGAAmG;AACnG,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAElG;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,oGAAoG;IACpG,EAAE,EAAE,MAAM,CAAC;IACX,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,uCAAuC;IACvC,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;IACxC;;;;OAIG;IACH,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAC5C,+EAA+E;IAC/E,cAAc,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,0FAA0F;IAC1F,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,6EAA6E;IAC7E,eAAe,EAAE,OAAO,CAAC;IACzB,oDAAoD;IACpD,eAAe,EAAE,OAAO,CAAC;IACzB,wFAAwF;IACxF,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,gDAAgD;IAChD,aAAa,EAAE,wBAAwB,CAAC;IACxC,6DAA6D;IAC7D,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,2EAA2E;IAC3E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,4DAA4D;IAC5D,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"feature-pipeline.engine.d.ts","sourceRoot":"","sources":["../../../../src/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseEngine, Metadata, } from '@memberjunction/core';
|
|
2
|
-
import { UUIDsEqual } from '@memberjunction/global';
|
|
2
|
+
import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
|
|
3
3
|
/**
|
|
4
4
|
* Name of the seeded `MJ: Record Process Categories` row that marks a Record
|
|
5
5
|
* Process as a Feature Pipeline. Authored in
|
|
@@ -10,6 +10,8 @@ import { UUIDsEqual } from '@memberjunction/global';
|
|
|
10
10
|
* rather than re-exported across the package boundary).
|
|
11
11
|
*/
|
|
12
12
|
export const FEATURE_PIPELINE_CATEGORY_NAME = 'Feature Pipeline';
|
|
13
|
+
/** The built-in pipeline type names, by their lower-case form. */
|
|
14
|
+
const BUILT_IN_PIPELINE_TYPES = { llm: 'LLM', decision: 'Decision' };
|
|
13
15
|
/**
|
|
14
16
|
* **FeaturePipelineEngine** (Knowledge Hub, Angular) — the discovery + monitoring
|
|
15
17
|
* cache for Feature Pipelines (Predictive Studio SP6).
|
|
@@ -101,6 +103,7 @@ export class FeaturePipelineEngine extends BaseEngine {
|
|
|
101
103
|
LastRunProcessed: latest?.ProcessedItems ?? null,
|
|
102
104
|
LastRunSuccess: latest?.SuccessCount ?? null,
|
|
103
105
|
LastRunErrors: latest?.ErrorCount ?? null,
|
|
106
|
+
PipelineType: FeaturePipelineEngine.derivePipelineType(p.Configuration),
|
|
104
107
|
};
|
|
105
108
|
}
|
|
106
109
|
/** Newest run for a pipeline id, scanning by StartTime/EndTime/createdAt regardless of input order. */
|
|
@@ -173,5 +176,18 @@ export class FeaturePipelineEngine extends BaseEngine {
|
|
|
173
176
|
}
|
|
174
177
|
return [];
|
|
175
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* Best-effort pipeline type derived from the Record Process `Configuration` JSON
|
|
181
|
+
* (which serializes `DataFeatureSpec`). Returns 'LLM' when unset, empty, or unparseable, and a built-in
|
|
182
|
+
* name ('decision') in its canonical case ('Decision').
|
|
183
|
+
*/
|
|
184
|
+
static derivePipelineType(config) {
|
|
185
|
+
const parsed = config ? SafeJSONParse(config) : null;
|
|
186
|
+
const typeName = parsed && typeof parsed === 'object' && typeof parsed.PipelineType === 'string' ? parsed.PipelineType.trim() : '';
|
|
187
|
+
if (typeName.length === 0) {
|
|
188
|
+
return 'LLM';
|
|
189
|
+
}
|
|
190
|
+
return BUILT_IN_PIPELINE_TYPES[typeName.toLowerCase()] ?? typeName;
|
|
191
|
+
}
|
|
176
192
|
}
|
|
177
193
|
//# sourceMappingURL=feature-pipeline.engine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-pipeline.engine.js","sourceRoot":"","sources":["../../../../src/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseEngine,\n BaseEnginePropertyConfig,\n IMetadataProvider,\n Metadata,\n UserInfo,\n} from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { MJRecordProcessEntity, MJProcessRunEntity } from '@memberjunction/core-entities';\nimport type { Observable } from 'rxjs';\n\n/**\n * Name of the seeded `MJ: Record Process Categories` row that marks a Record\n * Process as a Feature Pipeline. Authored in\n * `metadata/record-process-categories/.record-process-categories.json` and pushed\n * with `mj sync`. Mirrors `FEATURE_PIPELINE_CATEGORY_NAME` in the server-side\n * `@memberjunction/predictive-studio` engine — kept in sync by value (the two\n * packages don't share a dependency, so the constant is intentionally duplicated\n * rather than re-exported across the package boundary).\n */\nexport const FEATURE_PIPELINE_CATEGORY_NAME = 'Feature Pipeline';\n\n/** Normalized last-run status for a Feature Pipeline, derived from the most recent Process Run. */\nexport type FeaturePipelineRunStatus = 'Never' | 'Running' | 'Completed' | 'Failed' | 'Cancelled';\n\n/**\n * UI-facing summary of one Feature Pipeline: what it is, the entity it writes to,\n * the attribute it produces, and last-run / freshness. Built purely from the\n * cached Record Process + Process Run entities by {@link FeaturePipelineEngine.GetSummaries}.\n */\nexport interface FeaturePipelineSummary {\n /** The underlying `MJ: Record Processes` id (also the `RunFeaturePipeline` `featurePipelineID`). */\n ID: string;\n /** Display name (the Record Process name). */\n Name: string;\n /** Optional description. */\n Description: string | null;\n /** Record Process lifecycle status. */\n Status: 'Active' | 'Disabled' | 'Draft';\n /**\n * The per-record work the pipeline performs. Derived from the entity's `WorkType` so it tracks\n * the CodeGen-generated union (sourced from the `CK_RecordProcess_WorkType` CHECK constraint) and\n * never drifts as work types are added (e.g. `'ML Model'`).\n */\n WorkType: MJRecordProcessEntity['WorkType'];\n /** Id of the target entity whose records the pipeline derives features for. */\n TargetEntityID: string;\n /** Display name of the target entity. */\n TargetEntity: string;\n /** Best-effort attribute written back, parsed from the Record Process `OutputMapping`. */\n OutputAttribute: string | null;\n /** Whether the pipeline can be run on demand (the Run button is enabled). */\n OnDemandEnabled: boolean;\n /** Whether the pipeline runs on a cron schedule. */\n ScheduleEnabled: boolean;\n /** Timestamp of the most recent run (start time, falling back to end time), or null. */\n LastRunAt: Date | null;\n /** Normalized status of the most recent run. */\n LastRunStatus: FeaturePipelineRunStatus;\n /** Id of the most recent `MJ: Process Runs` row, or null. */\n LastRunProcessRunID: string | null;\n /** Records processed in the most recent run, or null. */\n LastRunProcessed: number | null;\n /** Records whose features were written in the most recent run, or null. */\n LastRunSuccess: number | null;\n /** Records that errored in the most recent run, or null. */\n LastRunErrors: number | null;\n}\n\n/**\n * **FeaturePipelineEngine** (Knowledge Hub, Angular) — the discovery + monitoring\n * cache for Feature Pipelines (Predictive Studio SP6).\n *\n * A Feature Pipeline has no dedicated entity: it IS an `MJ: Record Processes` row\n * categorized into the seeded {@link FEATURE_PIPELINE_CATEGORY_NAME} category. This\n * engine caches those rows (plus the recent `MJ: Process Runs` headers) so the KH\n * UI can list \"what feature pipelines exist, what entity each writes to, and when\n * each last ran\" — reactively, via the canonical MJ BaseEngine pattern (`Config()`\n * declaring `BaseEnginePropertyConfig[]`, lazy-loaded, `ObserveProperty`\n * reactivity for free).\n *\n * The freshness/projection logic is a pure static function ({@link BuildSummaries})\n * so it can be exercised without a provider, and it intentionally mirrors the\n * server-side `@memberjunction/predictive-studio` engine of the same name (the two\n * don't share a dependency).\n */\nexport class FeaturePipelineEngine extends BaseEngine<FeaturePipelineEngine> {\n /** Singleton accessor for the default provider — never `new` this directly. */\n public static get Instance(): FeaturePipelineEngine {\n return super.getInstance<FeaturePipelineEngine>();\n }\n\n private _recordProcesses: MJRecordProcessEntity[] = [];\n private _processRuns: MJProcessRunEntity[] = [];\n\n /**\n * Lazy-load the Record Process + recent Process Run caches. Safe to call from\n * every entry point — a no-op when already loaded (unless `forceRefresh`).\n * Process Runs are ordered newest-first so the most recent run per pipeline is\n * the first match.\n */\n public async Config(\n forceRefresh?: boolean,\n contextUser?: UserInfo,\n provider?: IMetadataProvider,\n ): Promise<void> {\n const c: Partial<BaseEnginePropertyConfig>[] = [\n { Type: 'entity', EntityName: 'MJ: Record Processes', PropertyName: '_recordProcesses', OrderBy: 'Name' },\n { Type: 'entity', EntityName: 'MJ: Process Runs', PropertyName: '_processRuns', OrderBy: '__mj_CreatedAt DESC' },\n ];\n await super.Load(c, provider ?? Metadata.Provider, forceRefresh, contextUser);\n }\n\n // ---- Cached arrays (sync getters; observe via the streams for reactive UI) ----\n\n /** Every cached Record Process categorized as a Feature Pipeline. */\n public get Pipelines(): MJRecordProcessEntity[] {\n return (this._recordProcesses ?? []).filter((rp) => FeaturePipelineEngine.isFeaturePipeline(rp));\n }\n\n /** All cached Process Run headers (newest first; all entities — callers filter). */\n public get Runs(): MJProcessRunEntity[] {\n return this._processRuns ?? [];\n }\n\n /** Reactive stream of the raw Record Processes — re-emits on any save/delete/remote-invalidate. */\n public get Pipelines$(): Observable<MJRecordProcessEntity[]> {\n return this.ObserveProperty<MJRecordProcessEntity>('_recordProcesses');\n }\n\n /** Reactive stream of the Process Run headers. */\n public get Runs$(): Observable<MJProcessRunEntity[]> {\n return this.ObserveProperty<MJProcessRunEntity>('_processRuns');\n }\n\n // ---- Projection ----\n\n /** Build the UI summaries for every feature pipeline from the loaded caches. */\n public GetSummaries(): FeaturePipelineSummary[] {\n return FeaturePipelineEngine.BuildSummaries(this.Pipelines, this.Runs);\n }\n\n /**\n * Pure, side-effect-free summary builder — used by {@link GetSummaries} and by\n * unit tests (which pass in-memory arrays, no provider).\n */\n public static BuildSummaries(\n pipelines: ReadonlyArray<MJRecordProcessEntity>,\n runs: ReadonlyArray<MJProcessRunEntity>,\n ): FeaturePipelineSummary[] {\n return pipelines.map((p) => FeaturePipelineEngine.buildSummary(p, runs));\n }\n\n // ---- Internal helpers ----\n\n /** Whether a Record Process belongs to the seeded Feature Pipeline category. */\n private static isFeaturePipeline(rp: MJRecordProcessEntity): boolean {\n return (rp.Category ?? '').trim().toLowerCase() === FEATURE_PIPELINE_CATEGORY_NAME.toLowerCase();\n }\n\n /** Project one pipeline + the run set into a {@link FeaturePipelineSummary}. */\n private static buildSummary(\n p: MJRecordProcessEntity,\n runs: ReadonlyArray<MJProcessRunEntity>,\n ): FeaturePipelineSummary {\n const latest = FeaturePipelineEngine.newestRun(runs, p.ID);\n return {\n ID: p.ID,\n Name: p.Name,\n Description: p.Description ?? null,\n Status: p.Status,\n WorkType: p.WorkType,\n TargetEntityID: p.EntityID,\n TargetEntity: p.Entity,\n OutputAttribute: FeaturePipelineEngine.deriveOutputAttribute(p.OutputMapping),\n OnDemandEnabled: p.OnDemandEnabled,\n ScheduleEnabled: p.ScheduleEnabled,\n LastRunAt: latest?.StartTime ?? latest?.EndTime ?? null,\n LastRunStatus: FeaturePipelineEngine.mapRunStatus(latest),\n LastRunProcessRunID: latest?.ID ?? null,\n LastRunProcessed: latest?.ProcessedItems ?? null,\n LastRunSuccess: latest?.SuccessCount ?? null,\n LastRunErrors: latest?.ErrorCount ?? null,\n };\n }\n\n /** Newest run for a pipeline id, scanning by StartTime/EndTime/createdAt regardless of input order. */\n private static newestRun(\n runs: ReadonlyArray<MJProcessRunEntity>,\n recordProcessID: string,\n ): MJProcessRunEntity | undefined {\n let best: MJProcessRunEntity | undefined;\n let bestTime = -Infinity;\n for (const r of runs) {\n if (r.RecordProcessID == null || !UUIDsEqual(r.RecordProcessID, recordProcessID)) continue;\n const candidate = r.StartTime ?? r.EndTime ?? r.__mj_CreatedAt;\n const t = candidate ? new Date(candidate).getTime() : -Infinity;\n if (t > bestTime) {\n bestTime = t;\n best = r;\n }\n }\n return best;\n }\n\n /** Normalize a Process Run status into the small union the UI renders. `undefined` → `'Never'`. */\n private static mapRunStatus(run: MJProcessRunEntity | undefined): FeaturePipelineRunStatus {\n if (!run) return 'Never';\n switch (run.Status) {\n case 'Completed':\n return 'Completed';\n case 'Failed':\n return 'Failed';\n case 'Cancelled':\n return 'Cancelled';\n case 'Running':\n case 'Pending':\n case 'Paused':\n return 'Running';\n default:\n return 'Never';\n }\n }\n\n /**\n * Best-effort attribute the pipeline writes, parsed from the Record Process\n * `OutputMapping` JSON. Probes the common shapes (`field` / `targetField` /\n * `attribute`, or a `fields` array / object) and returns null otherwise. Never\n * throws on malformed JSON.\n */\n private static deriveOutputAttribute(outputMapping: string | null): string | null {\n if (!outputMapping) return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(outputMapping);\n } catch {\n return null;\n }\n if (parsed == null || typeof parsed !== 'object') return null;\n const obj = parsed as Record<string, unknown>;\n\n const single = obj['field'] ?? obj['targetField'] ?? obj['attribute'];\n if (typeof single === 'string' && single.trim()) return single.trim();\n\n const names = FeaturePipelineEngine.fieldNamesFrom(obj['fields']);\n return names.length > 0 ? names.join(', ') : null;\n }\n\n /** Collect field names from either an object map or an array of names. */\n private static fieldNamesFrom(fields: unknown): string[] {\n if (Array.isArray(fields)) {\n return fields.filter((f): f is string => typeof f === 'string' && f.trim().length > 0);\n }\n if (fields != null && typeof fields === 'object') {\n return Object.keys(fields as Record<string, unknown>);\n }\n return [];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"feature-pipeline.engine.js","sourceRoot":"","sources":["../../../../src/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseEngine,\n BaseEnginePropertyConfig,\n IMetadataProvider,\n Metadata,\n UserInfo,\n} from '@memberjunction/core';\nimport { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';\nimport { MJRecordProcessEntity, MJProcessRunEntity } from '@memberjunction/core-entities';\nimport type { Observable } from 'rxjs';\n\n/**\n * Name of the seeded `MJ: Record Process Categories` row that marks a Record\n * Process as a Feature Pipeline. Authored in\n * `metadata/record-process-categories/.record-process-categories.json` and pushed\n * with `mj sync`. Mirrors `FEATURE_PIPELINE_CATEGORY_NAME` in the server-side\n * `@memberjunction/predictive-studio` engine — kept in sync by value (the two\n * packages don't share a dependency, so the constant is intentionally duplicated\n * rather than re-exported across the package boundary).\n */\nexport const FEATURE_PIPELINE_CATEGORY_NAME = 'Feature Pipeline';\n\n/** Normalized last-run status for a Feature Pipeline, derived from the most recent Process Run. */\nexport type FeaturePipelineRunStatus = 'Never' | 'Running' | 'Completed' | 'Failed' | 'Cancelled';\n\n/**\n * UI-facing summary of one Feature Pipeline: what it is, the entity it writes to,\n * the attribute it produces, and last-run / freshness. Built purely from the\n * cached Record Process + Process Run entities by {@link FeaturePipelineEngine.GetSummaries}.\n */\nexport interface FeaturePipelineSummary {\n /** The underlying `MJ: Record Processes` id (also the `RunFeaturePipeline` `featurePipelineID`). */\n ID: string;\n /** Display name (the Record Process name). */\n Name: string;\n /** Optional description. */\n Description: string | null;\n /** Record Process lifecycle status. */\n Status: 'Active' | 'Disabled' | 'Draft';\n /**\n * The per-record work the pipeline performs. Derived from the entity's `WorkType` so it tracks\n * the CodeGen-generated union (sourced from the `CK_RecordProcess_WorkType` CHECK constraint) and\n * never drifts as work types are added (e.g. `'ML Model'`).\n */\n WorkType: MJRecordProcessEntity['WorkType'];\n /** Id of the target entity whose records the pipeline derives features for. */\n TargetEntityID: string;\n /** Display name of the target entity. */\n TargetEntity: string;\n /** Best-effort attribute written back, parsed from the Record Process `OutputMapping`. */\n OutputAttribute: string | null;\n /** Whether the pipeline can be run on demand (the Run button is enabled). */\n OnDemandEnabled: boolean;\n /** Whether the pipeline runs on a cron schedule. */\n ScheduleEnabled: boolean;\n /** Timestamp of the most recent run (start time, falling back to end time), or null. */\n LastRunAt: Date | null;\n /** Normalized status of the most recent run. */\n LastRunStatus: FeaturePipelineRunStatus;\n /** Id of the most recent `MJ: Process Runs` row, or null. */\n LastRunProcessRunID: string | null;\n /** Records processed in the most recent run, or null. */\n LastRunProcessed: number | null;\n /** Records whose features were written in the most recent run, or null. */\n LastRunSuccess: number | null;\n /** Records that errored in the most recent run, or null. */\n LastRunErrors: number | null;\n /**\n * The pipeline type ('LLM' or 'Decision' or custom). Defaults to 'LLM' when unset. The two built-in\n * names are given in their canonical case whatever case the spec uses, as the processor matches them.\n */\n PipelineType: string;\n}\n\n/** The one DataFeatureSpec property the summary reads from a Record Process `Configuration`. */\ninterface ConfigurationPipelineType {\n PipelineType?: string | null;\n}\n\n/** The built-in pipeline type names, by their lower-case form. */\nconst BUILT_IN_PIPELINE_TYPES: Record<string, string> = { llm: 'LLM', decision: 'Decision' };\n\n/**\n * **FeaturePipelineEngine** (Knowledge Hub, Angular) — the discovery + monitoring\n * cache for Feature Pipelines (Predictive Studio SP6).\n *\n * A Feature Pipeline has no dedicated entity: it IS an `MJ: Record Processes` row\n * categorized into the seeded {@link FEATURE_PIPELINE_CATEGORY_NAME} category. This\n * engine caches those rows (plus the recent `MJ: Process Runs` headers) so the KH\n * UI can list \"what feature pipelines exist, what entity each writes to, and when\n * each last ran\" — reactively, via the canonical MJ BaseEngine pattern (`Config()`\n * declaring `BaseEnginePropertyConfig[]`, lazy-loaded, `ObserveProperty`\n * reactivity for free).\n *\n * The freshness/projection logic is a pure static function ({@link BuildSummaries})\n * so it can be exercised without a provider, and it intentionally mirrors the\n * server-side `@memberjunction/predictive-studio` engine of the same name (the two\n * don't share a dependency).\n */\nexport class FeaturePipelineEngine extends BaseEngine<FeaturePipelineEngine> {\n /** Singleton accessor for the default provider — never `new` this directly. */\n public static get Instance(): FeaturePipelineEngine {\n return super.getInstance<FeaturePipelineEngine>();\n }\n\n private _recordProcesses: MJRecordProcessEntity[] = [];\n private _processRuns: MJProcessRunEntity[] = [];\n\n /**\n * Lazy-load the Record Process + recent Process Run caches. Safe to call from\n * every entry point — a no-op when already loaded (unless `forceRefresh`).\n * Process Runs are ordered newest-first so the most recent run per pipeline is\n * the first match.\n */\n public async Config(\n forceRefresh?: boolean,\n contextUser?: UserInfo,\n provider?: IMetadataProvider,\n ): Promise<void> {\n const c: Partial<BaseEnginePropertyConfig>[] = [\n { Type: 'entity', EntityName: 'MJ: Record Processes', PropertyName: '_recordProcesses', OrderBy: 'Name' },\n { Type: 'entity', EntityName: 'MJ: Process Runs', PropertyName: '_processRuns', OrderBy: '__mj_CreatedAt DESC' },\n ];\n await super.Load(c, provider ?? Metadata.Provider, forceRefresh, contextUser);\n }\n\n // ---- Cached arrays (sync getters; observe via the streams for reactive UI) ----\n\n /** Every cached Record Process categorized as a Feature Pipeline. */\n public get Pipelines(): MJRecordProcessEntity[] {\n return (this._recordProcesses ?? []).filter((rp) => FeaturePipelineEngine.isFeaturePipeline(rp));\n }\n\n /** All cached Process Run headers (newest first; all entities — callers filter). */\n public get Runs(): MJProcessRunEntity[] {\n return this._processRuns ?? [];\n }\n\n /** Reactive stream of the raw Record Processes — re-emits on any save/delete/remote-invalidate. */\n public get Pipelines$(): Observable<MJRecordProcessEntity[]> {\n return this.ObserveProperty<MJRecordProcessEntity>('_recordProcesses');\n }\n\n /** Reactive stream of the Process Run headers. */\n public get Runs$(): Observable<MJProcessRunEntity[]> {\n return this.ObserveProperty<MJProcessRunEntity>('_processRuns');\n }\n\n // ---- Projection ----\n\n /** Build the UI summaries for every feature pipeline from the loaded caches. */\n public GetSummaries(): FeaturePipelineSummary[] {\n return FeaturePipelineEngine.BuildSummaries(this.Pipelines, this.Runs);\n }\n\n /**\n * Pure, side-effect-free summary builder — used by {@link GetSummaries} and by\n * unit tests (which pass in-memory arrays, no provider).\n */\n public static BuildSummaries(\n pipelines: ReadonlyArray<MJRecordProcessEntity>,\n runs: ReadonlyArray<MJProcessRunEntity>,\n ): FeaturePipelineSummary[] {\n return pipelines.map((p) => FeaturePipelineEngine.buildSummary(p, runs));\n }\n\n // ---- Internal helpers ----\n\n /** Whether a Record Process belongs to the seeded Feature Pipeline category. */\n private static isFeaturePipeline(rp: MJRecordProcessEntity): boolean {\n return (rp.Category ?? '').trim().toLowerCase() === FEATURE_PIPELINE_CATEGORY_NAME.toLowerCase();\n }\n\n /** Project one pipeline + the run set into a {@link FeaturePipelineSummary}. */\n private static buildSummary(\n p: MJRecordProcessEntity,\n runs: ReadonlyArray<MJProcessRunEntity>,\n ): FeaturePipelineSummary {\n const latest = FeaturePipelineEngine.newestRun(runs, p.ID);\n return {\n ID: p.ID,\n Name: p.Name,\n Description: p.Description ?? null,\n Status: p.Status,\n WorkType: p.WorkType,\n TargetEntityID: p.EntityID,\n TargetEntity: p.Entity,\n OutputAttribute: FeaturePipelineEngine.deriveOutputAttribute(p.OutputMapping),\n OnDemandEnabled: p.OnDemandEnabled,\n ScheduleEnabled: p.ScheduleEnabled,\n LastRunAt: latest?.StartTime ?? latest?.EndTime ?? null,\n LastRunStatus: FeaturePipelineEngine.mapRunStatus(latest),\n LastRunProcessRunID: latest?.ID ?? null,\n LastRunProcessed: latest?.ProcessedItems ?? null,\n LastRunSuccess: latest?.SuccessCount ?? null,\n LastRunErrors: latest?.ErrorCount ?? null,\n PipelineType: FeaturePipelineEngine.derivePipelineType(p.Configuration),\n };\n }\n\n /** Newest run for a pipeline id, scanning by StartTime/EndTime/createdAt regardless of input order. */\n private static newestRun(\n runs: ReadonlyArray<MJProcessRunEntity>,\n recordProcessID: string,\n ): MJProcessRunEntity | undefined {\n let best: MJProcessRunEntity | undefined;\n let bestTime = -Infinity;\n for (const r of runs) {\n if (r.RecordProcessID == null || !UUIDsEqual(r.RecordProcessID, recordProcessID)) continue;\n const candidate = r.StartTime ?? r.EndTime ?? r.__mj_CreatedAt;\n const t = candidate ? new Date(candidate).getTime() : -Infinity;\n if (t > bestTime) {\n bestTime = t;\n best = r;\n }\n }\n return best;\n }\n\n /** Normalize a Process Run status into the small union the UI renders. `undefined` → `'Never'`. */\n private static mapRunStatus(run: MJProcessRunEntity | undefined): FeaturePipelineRunStatus {\n if (!run) return 'Never';\n switch (run.Status) {\n case 'Completed':\n return 'Completed';\n case 'Failed':\n return 'Failed';\n case 'Cancelled':\n return 'Cancelled';\n case 'Running':\n case 'Pending':\n case 'Paused':\n return 'Running';\n default:\n return 'Never';\n }\n }\n\n /**\n * Best-effort attribute the pipeline writes, parsed from the Record Process\n * `OutputMapping` JSON. Probes the common shapes (`field` / `targetField` /\n * `attribute`, or a `fields` array / object) and returns null otherwise. Never\n * throws on malformed JSON.\n */\n private static deriveOutputAttribute(outputMapping: string | null): string | null {\n if (!outputMapping) return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(outputMapping);\n } catch {\n return null;\n }\n if (parsed == null || typeof parsed !== 'object') return null;\n const obj = parsed as Record<string, unknown>;\n\n const single = obj['field'] ?? obj['targetField'] ?? obj['attribute'];\n if (typeof single === 'string' && single.trim()) return single.trim();\n\n const names = FeaturePipelineEngine.fieldNamesFrom(obj['fields']);\n return names.length > 0 ? names.join(', ') : null;\n }\n\n /** Collect field names from either an object map or an array of names. */\n private static fieldNamesFrom(fields: unknown): string[] {\n if (Array.isArray(fields)) {\n return fields.filter((f): f is string => typeof f === 'string' && f.trim().length > 0);\n }\n if (fields != null && typeof fields === 'object') {\n return Object.keys(fields as Record<string, unknown>);\n }\n return [];\n }\n\n /**\n * Best-effort pipeline type derived from the Record Process `Configuration` JSON\n * (which serializes `DataFeatureSpec`). Returns 'LLM' when unset, empty, or unparseable, and a built-in\n * name ('decision') in its canonical case ('Decision').\n */\n private static derivePipelineType(config: string | null): string {\n const parsed = config ? SafeJSONParse<ConfigurationPipelineType>(config) : null;\n const typeName = parsed && typeof parsed === 'object' && typeof parsed.PipelineType === 'string' ? parsed.PipelineType.trim() : '';\n if (typeName.length === 0) {\n return 'LLM';\n }\n return BUILT_IN_PIPELINE_TYPES[typeName.toLowerCase()] ?? typeName;\n }\n}\n\n"]}
|
package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js
CHANGED
|
@@ -65,8 +65,8 @@ function FeaturePipelinesResourceComponent_Conditional_14_Template(rf, ctx) { if
|
|
|
65
65
|
function FeaturePipelinesResourceComponent_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
66
66
|
i0.ɵɵelement(0, "mj-empty-state", 13);
|
|
67
67
|
} }
|
|
68
|
-
function
|
|
69
|
-
i0.ɵɵelementStart(0, "p",
|
|
68
|
+
function FeaturePipelinesResourceComponent_Conditional_16_For_2_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
69
|
+
i0.ɵɵelementStart(0, "p", 27);
|
|
70
70
|
i0.ɵɵtext(1);
|
|
71
71
|
i0.ɵɵelementEnd();
|
|
72
72
|
} if (rf & 2) {
|
|
@@ -75,8 +75,8 @@ function FeaturePipelinesResourceComponent_Conditional_16_For_2_Conditional_10_T
|
|
|
75
75
|
i0.ɵɵadvance();
|
|
76
76
|
i0.ɵɵtextInterpolate(pipeline_r4.Description);
|
|
77
77
|
} }
|
|
78
|
-
function
|
|
79
|
-
i0.ɵɵelementStart(0, "span",
|
|
78
|
+
function FeaturePipelinesResourceComponent_Conditional_16_For_2_Conditional_33_Template(rf, ctx) { if (rf & 1) {
|
|
79
|
+
i0.ɵɵelementStart(0, "span", 35);
|
|
80
80
|
i0.ɵɵtext(1);
|
|
81
81
|
i0.ɵɵelementEnd();
|
|
82
82
|
} if (rf & 2) {
|
|
@@ -84,12 +84,12 @@ function FeaturePipelinesResourceComponent_Conditional_16_For_2_Conditional_30_T
|
|
|
84
84
|
i0.ɵɵadvance();
|
|
85
85
|
i0.ɵɵtextInterpolate2("\u00B7 ", pipeline_r4.LastRunSuccess, "/", pipeline_r4.LastRunProcessed, " written");
|
|
86
86
|
} }
|
|
87
|
-
function
|
|
88
|
-
i0.ɵɵelement(0, "i",
|
|
87
|
+
function FeaturePipelinesResourceComponent_Conditional_16_For_2_Conditional_36_Template(rf, ctx) { if (rf & 1) {
|
|
88
|
+
i0.ɵɵelement(0, "i", 40);
|
|
89
89
|
i0.ɵɵtext(1, " Running\u2026 ");
|
|
90
90
|
} }
|
|
91
|
-
function
|
|
92
|
-
i0.ɵɵelement(0, "i",
|
|
91
|
+
function FeaturePipelinesResourceComponent_Conditional_16_For_2_Conditional_37_Template(rf, ctx) { if (rf & 1) {
|
|
92
|
+
i0.ɵɵelement(0, "i", 41);
|
|
93
93
|
i0.ɵɵtext(1, " Run ");
|
|
94
94
|
} }
|
|
95
95
|
function FeaturePipelinesResourceComponent_Conditional_16_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -99,43 +99,46 @@ function FeaturePipelinesResourceComponent_Conditional_16_For_2_Template(rf, ctx
|
|
|
99
99
|
i0.ɵɵelementStart(3, "div", 21)(4, "h3", 22);
|
|
100
100
|
i0.ɵɵtext(5);
|
|
101
101
|
i0.ɵɵelementEnd();
|
|
102
|
-
i0.ɵɵelementStart(6, "
|
|
103
|
-
i0.ɵɵtext(
|
|
104
|
-
i0.ɵɵelementEnd()
|
|
105
|
-
i0.ɵɵelementStart(
|
|
106
|
-
i0.ɵɵtext(
|
|
102
|
+
i0.ɵɵelementStart(6, "div", 23)(7, "span", 24);
|
|
103
|
+
i0.ɵɵtext(8);
|
|
104
|
+
i0.ɵɵelementEnd();
|
|
105
|
+
i0.ɵɵelementStart(9, "span", 25);
|
|
106
|
+
i0.ɵɵtext(10);
|
|
107
|
+
i0.ɵɵelementEnd()()();
|
|
108
|
+
i0.ɵɵelementStart(11, "span", 26);
|
|
109
|
+
i0.ɵɵtext(12);
|
|
107
110
|
i0.ɵɵelementEnd()();
|
|
108
|
-
i0.ɵɵconditionalCreate(
|
|
109
|
-
i0.ɵɵelementStart(
|
|
110
|
-
i0.ɵɵelement(
|
|
111
|
-
i0.ɵɵtext(
|
|
111
|
+
i0.ɵɵconditionalCreate(13, FeaturePipelinesResourceComponent_Conditional_16_For_2_Conditional_13_Template, 2, 2, "p", 27);
|
|
112
|
+
i0.ɵɵelementStart(14, "div", 28)(15, "div", 29)(16, "span", 30);
|
|
113
|
+
i0.ɵɵelement(17, "i", 31);
|
|
114
|
+
i0.ɵɵtext(18, " Target");
|
|
112
115
|
i0.ɵɵelementEnd();
|
|
113
|
-
i0.ɵɵelementStart(
|
|
114
|
-
i0.ɵɵtext(
|
|
116
|
+
i0.ɵɵelementStart(19, "span", 32);
|
|
117
|
+
i0.ɵɵtext(20);
|
|
115
118
|
i0.ɵɵelementEnd()();
|
|
116
|
-
i0.ɵɵelementStart(
|
|
117
|
-
i0.ɵɵelement(
|
|
118
|
-
i0.ɵɵtext(
|
|
119
|
+
i0.ɵɵelementStart(21, "div", 29)(22, "span", 30);
|
|
120
|
+
i0.ɵɵelement(23, "i", 33);
|
|
121
|
+
i0.ɵɵtext(24, " Writes");
|
|
119
122
|
i0.ɵɵelementEnd();
|
|
120
|
-
i0.ɵɵelementStart(
|
|
121
|
-
i0.ɵɵtext(
|
|
123
|
+
i0.ɵɵelementStart(25, "span", 32);
|
|
124
|
+
i0.ɵɵtext(26);
|
|
122
125
|
i0.ɵɵelementEnd()();
|
|
123
|
-
i0.ɵɵelementStart(
|
|
124
|
-
i0.ɵɵelement(
|
|
125
|
-
i0.ɵɵtext(
|
|
126
|
+
i0.ɵɵelementStart(27, "div", 29)(28, "span", 30);
|
|
127
|
+
i0.ɵɵelement(29, "i", 34);
|
|
128
|
+
i0.ɵɵtext(30, " Last run");
|
|
126
129
|
i0.ɵɵelementEnd();
|
|
127
|
-
i0.ɵɵelementStart(
|
|
128
|
-
i0.ɵɵtext(
|
|
129
|
-
i0.ɵɵconditionalCreate(
|
|
130
|
+
i0.ɵɵelementStart(31, "span", 32);
|
|
131
|
+
i0.ɵɵtext(32);
|
|
132
|
+
i0.ɵɵconditionalCreate(33, FeaturePipelinesResourceComponent_Conditional_16_For_2_Conditional_33_Template, 2, 2, "span", 35);
|
|
130
133
|
i0.ɵɵelementEnd()()();
|
|
131
|
-
i0.ɵɵelementStart(
|
|
132
|
-
i0.ɵɵlistener("click", function
|
|
133
|
-
i0.ɵɵconditionalCreate(
|
|
134
|
+
i0.ɵɵelementStart(34, "div", 36)(35, "button", 37);
|
|
135
|
+
i0.ɵɵlistener("click", function FeaturePipelinesResourceComponent_Conditional_16_For_2_Template_button_click_35_listener() { const pipeline_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnRunPipeline(pipeline_r4)); });
|
|
136
|
+
i0.ɵɵconditionalCreate(36, FeaturePipelinesResourceComponent_Conditional_16_For_2_Conditional_36_Template, 2, 0)(37, FeaturePipelinesResourceComponent_Conditional_16_For_2_Conditional_37_Template, 2, 0);
|
|
134
137
|
i0.ɵɵelementEnd();
|
|
135
|
-
i0.ɵɵelementStart(
|
|
136
|
-
i0.ɵɵlistener("click", function
|
|
137
|
-
i0.ɵɵelement(
|
|
138
|
-
i0.ɵɵtext(
|
|
138
|
+
i0.ɵɵelementStart(38, "button", 38);
|
|
139
|
+
i0.ɵɵlistener("click", function FeaturePipelinesResourceComponent_Conditional_16_For_2_Template_button_click_38_listener() { const pipeline_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnViewPipeline(pipeline_r4)); });
|
|
140
|
+
i0.ɵɵelement(39, "i", 39);
|
|
141
|
+
i0.ɵɵtext(40, " View ");
|
|
139
142
|
i0.ɵɵelementEnd()()();
|
|
140
143
|
} if (rf & 2) {
|
|
141
144
|
const pipeline_r4 = ctx.$implicit;
|
|
@@ -147,14 +150,18 @@ function FeaturePipelinesResourceComponent_Conditional_16_For_2_Template(rf, ctx
|
|
|
147
150
|
i0.ɵɵproperty("title", pipeline_r4.Name);
|
|
148
151
|
i0.ɵɵadvance();
|
|
149
152
|
i0.ɵɵtextInterpolate(pipeline_r4.Name);
|
|
150
|
-
i0.ɵɵadvance(
|
|
153
|
+
i0.ɵɵadvance(3);
|
|
151
154
|
i0.ɵɵtextInterpolate(pipeline_r4.WorkType);
|
|
152
155
|
i0.ɵɵadvance();
|
|
156
|
+
i0.ɵɵclassProp("fp-type-badge--decision", pipeline_r4.PipelineType === "Decision");
|
|
157
|
+
i0.ɵɵadvance();
|
|
158
|
+
i0.ɵɵtextInterpolate(pipeline_r4.PipelineType);
|
|
159
|
+
i0.ɵɵadvance();
|
|
153
160
|
i0.ɵɵclassMap(ctx_r0.RunStatusClass(pipeline_r4.LastRunStatus));
|
|
154
161
|
i0.ɵɵadvance();
|
|
155
162
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.RunStatusLabel(pipeline_r4.LastRunStatus), " ");
|
|
156
163
|
i0.ɵɵadvance();
|
|
157
|
-
i0.ɵɵconditional(pipeline_r4.Description ?
|
|
164
|
+
i0.ɵɵconditional(pipeline_r4.Description ? 13 : -1);
|
|
158
165
|
i0.ɵɵadvance(7);
|
|
159
166
|
i0.ɵɵtextInterpolate(pipeline_r4.TargetEntity);
|
|
160
167
|
i0.ɵɵadvance(6);
|
|
@@ -162,15 +169,15 @@ function FeaturePipelinesResourceComponent_Conditional_16_For_2_Template(rf, ctx
|
|
|
162
169
|
i0.ɵɵadvance(6);
|
|
163
170
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.TimeAgo(pipeline_r4.LastRunAt), " ");
|
|
164
171
|
i0.ɵɵadvance();
|
|
165
|
-
i0.ɵɵconditional(pipeline_r4.LastRunProcessed != null ?
|
|
172
|
+
i0.ɵɵconditional(pipeline_r4.LastRunProcessed != null ? 33 : -1);
|
|
166
173
|
i0.ɵɵadvance(2);
|
|
167
174
|
i0.ɵɵproperty("disabled", !pipeline_r4.OnDemandEnabled || pipeline_r4.Status !== "Active" || ctx_r0.IsRunning(pipeline_r4.ID));
|
|
168
175
|
i0.ɵɵadvance();
|
|
169
|
-
i0.ɵɵconditional(ctx_r0.IsRunning(pipeline_r4.ID) ?
|
|
176
|
+
i0.ɵɵconditional(ctx_r0.IsRunning(pipeline_r4.ID) ? 36 : 37);
|
|
170
177
|
} }
|
|
171
178
|
function FeaturePipelinesResourceComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
172
179
|
i0.ɵɵelementStart(0, "div", 14);
|
|
173
|
-
i0.ɵɵrepeaterCreate(1, FeaturePipelinesResourceComponent_Conditional_16_For_2_Template,
|
|
180
|
+
i0.ɵɵrepeaterCreate(1, FeaturePipelinesResourceComponent_Conditional_16_For_2_Template, 41, 20, "div", 17, _forTrack0);
|
|
174
181
|
i0.ɵɵelementEnd();
|
|
175
182
|
} if (rf & 2) {
|
|
176
183
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -502,7 +509,7 @@ let FeaturePipelinesResourceComponent = class FeaturePipelinesResourceComponent
|
|
|
502
509
|
]);
|
|
503
510
|
}
|
|
504
511
|
static ɵfac = /*@__PURE__*/ (() => { let ɵFeaturePipelinesResourceComponent_BaseFactory; return function FeaturePipelinesResourceComponent_Factory(__ngFactoryType__) { return (ɵFeaturePipelinesResourceComponent_BaseFactory || (ɵFeaturePipelinesResourceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(FeaturePipelinesResourceComponent)))(__ngFactoryType__ || FeaturePipelinesResourceComponent); }; })();
|
|
505
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FeaturePipelinesResourceComponent, selectors: [["app-feature-pipelines-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 17, vars: 5, consts: [["Title", "Feature Pipelines", "Icon", "fa-solid fa-diagram-project", "Subtitle", "Derive feature attributes from your data and persist them back to entities"], ["meta", ""], ["Label", "last run failed", "Variant", "error", 3, "Count"], ["Label", "pipelines", 3, "Count", "Total"], ["actions", ""], [3, "Clicked", "Loading"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-plus"], ["toolbar", ""], ["Placeholder", "Search by name, entity, or attribute\u2026", 3, "ValueChange", "Value"], [3, "Flex"], [1, "fp-loading"], ["Icon", "fa-solid fa-diagram-project", "Title", "No feature pipelines yet", "Message", "A Feature Pipeline derives an attribute per record (e.g. an LLM summary or score) and writes it back to your data \u2014 reusable analytics, independent of any model.", "ActionText", "New Pipeline", "ActionIcon", "fa-solid fa-plus"], ["Variant", "no-results", "Icon", "fa-solid fa-magnifying-glass", "Title", "No matching pipelines", "Message", "No feature pipelines match your search."], [1, "fp-grid"], ["text", "Loading feature pipelines\u2026", "size", "medium"], ["Icon", "fa-solid fa-diagram-project", "Title", "No feature pipelines yet", "Message", "A Feature Pipeline derives an attribute per record (e.g. an LLM summary or score) and writes it back to your data \u2014 reusable analytics, independent of any model.", "ActionText", "New Pipeline", "ActionIcon", "fa-solid fa-plus", 3, "Action"], [1, "fp-card", 3, "fp-card--disabled"], [1, "fp-card"], [1, "fp-card__head"], [1, "fp-card__icon"], [1, "fp-card__title"], [3, "title"], [1, "fp-card__worktype"], [1, "fp-status"], [1, "fp-card__desc", 3, "title"], [1, "fp-card__meta"], [1, "fp-meta-row"], [1, "fp-meta-row__k"], [1, "fa-solid", "fa-table"], [1, "fp-meta-row__v"], [1, "fa-solid", "fa-pen-to-square"], [1, "fa-solid", "fa-clock-rotate-left"], [1, "fp-meta-row__sub"], [1, "fp-card__actions"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-eye"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-play"]], template: function FeaturePipelinesResourceComponent_Template(rf, ctx) { if (rf & 1) {
|
|
512
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FeaturePipelinesResourceComponent, selectors: [["app-feature-pipelines-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 17, vars: 5, consts: [["Title", "Feature Pipelines", "Icon", "fa-solid fa-diagram-project", "Subtitle", "Derive feature attributes from your data and persist them back to entities"], ["meta", ""], ["Label", "last run failed", "Variant", "error", 3, "Count"], ["Label", "pipelines", 3, "Count", "Total"], ["actions", ""], [3, "Clicked", "Loading"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-plus"], ["toolbar", ""], ["Placeholder", "Search by name, entity, or attribute\u2026", 3, "ValueChange", "Value"], [3, "Flex"], [1, "fp-loading"], ["Icon", "fa-solid fa-diagram-project", "Title", "No feature pipelines yet", "Message", "A Feature Pipeline derives an attribute per record (e.g. an LLM summary or score) and writes it back to your data \u2014 reusable analytics, independent of any model.", "ActionText", "New Pipeline", "ActionIcon", "fa-solid fa-plus"], ["Variant", "no-results", "Icon", "fa-solid fa-magnifying-glass", "Title", "No matching pipelines", "Message", "No feature pipelines match your search."], [1, "fp-grid"], ["text", "Loading feature pipelines\u2026", "size", "medium"], ["Icon", "fa-solid fa-diagram-project", "Title", "No feature pipelines yet", "Message", "A Feature Pipeline derives an attribute per record (e.g. an LLM summary or score) and writes it back to your data \u2014 reusable analytics, independent of any model.", "ActionText", "New Pipeline", "ActionIcon", "fa-solid fa-plus", 3, "Action"], [1, "fp-card", 3, "fp-card--disabled"], [1, "fp-card"], [1, "fp-card__head"], [1, "fp-card__icon"], [1, "fp-card__title"], [3, "title"], [1, "fp-card__subhead"], [1, "fp-card__worktype"], [1, "fp-type-badge"], [1, "fp-status"], [1, "fp-card__desc", 3, "title"], [1, "fp-card__meta"], [1, "fp-meta-row"], [1, "fp-meta-row__k"], [1, "fa-solid", "fa-table"], [1, "fp-meta-row__v"], [1, "fa-solid", "fa-pen-to-square"], [1, "fa-solid", "fa-clock-rotate-left"], [1, "fp-meta-row__sub"], [1, "fp-card__actions"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-eye"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-play"]], template: function FeaturePipelinesResourceComponent_Template(rf, ctx) { if (rf & 1) {
|
|
506
513
|
i0.ɵɵelementStart(0, "mj-page-layout")(1, "mj-page-header", 0)(2, "div", 1);
|
|
507
514
|
i0.ɵɵconditionalCreate(3, FeaturePipelinesResourceComponent_Conditional_3_Template, 1, 1, "mj-stat-badge", 2)(4, FeaturePipelinesResourceComponent_Conditional_4_Template, 1, 2, "mj-stat-badge", 3);
|
|
508
515
|
i0.ɵɵelementEnd();
|
|
@@ -531,7 +538,7 @@ let FeaturePipelinesResourceComponent = class FeaturePipelinesResourceComponent
|
|
|
531
538
|
i0.ɵɵproperty("Flex", true);
|
|
532
539
|
i0.ɵɵadvance();
|
|
533
540
|
i0.ɵɵconditional(ctx.IsLoading ? 13 : ctx.AllPipelines.length === 0 ? 14 : ctx.FilteredPipelines.length === 0 ? 15 : 16);
|
|
534
|
-
} }, dependencies: [i1.LoadingComponent, i2.MJButtonDirective, i2.MJPageHeaderComponent, i2.MJPageLayoutComponent, i2.MJPageBodyComponent, i2.MJPageSearchComponent, i2.MJStatBadgeComponent, i2.MJRefreshButtonComponent, i2.MJEmptyStateComponent], styles: ["\n\n\n\n\n\n\n\n\n\n\n.fp-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 240px;\n width: 100%;\n}\n\n.fp-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n gap: 16px;\n padding: 4px;\n align-content: start;\n}\n\n.fp-card[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg, 10px);\n background: var(--mj-bg-surface-card);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n\n.fp-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.fp-card--disabled[_ngcontent-%COMP%] {\n opacity: 0.65;\n}\n\n.fp-card__head[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.fp-card__icon[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--mj-radius-md, 8px);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.fp-card__title[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.fp-card__title[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.fp-card__worktype[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-muted);\n}\n\n.fp-card__desc[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n line-height: 1.4;\n color: var(--mj-text-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.fp-card__meta[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 0;\n border-top: 1px solid var(--mj-border-subtle);\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.fp-meta-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n font-size: 13px;\n}\n\n.fp-meta-row__k[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n color: var(--mj-text-muted);\n}\n\n.fp-meta-row__k[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 14px;\n margin-right: 4px;\n}\n\n.fp-meta-row__v[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n text-align: right;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.fp-meta-row__sub[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.fp-card__actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-top: auto;\n}\n\n\n.fp-status[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n align-self: flex-start;\n padding: 2px 10px;\n border-radius: var(--mj-radius-full, 999px);\n font-size: 11px;\n font-weight: 600;\n white-space: nowrap;\n}\n\n.fp-status.status--never[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.fp-status.status--running[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n}\n\n.fp-status.status--completed[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.fp-status.status--failed[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.fp-status.status--cancelled[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}"] });
|
|
541
|
+
} }, dependencies: [i1.LoadingComponent, i2.MJButtonDirective, i2.MJPageHeaderComponent, i2.MJPageLayoutComponent, i2.MJPageBodyComponent, i2.MJPageSearchComponent, i2.MJStatBadgeComponent, i2.MJRefreshButtonComponent, i2.MJEmptyStateComponent], styles: ["\n\n\n\n\n\n\n\n\n\n\n.fp-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 240px;\n width: 100%;\n}\n\n.fp-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n gap: 16px;\n padding: 4px;\n align-content: start;\n}\n\n.fp-card[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg, 10px);\n background: var(--mj-bg-surface-card);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n\n.fp-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.fp-card--disabled[_ngcontent-%COMP%] {\n opacity: 0.65;\n}\n\n.fp-card__head[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.fp-card__icon[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--mj-radius-md, 8px);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.fp-card__title[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.fp-card__title[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.fp-card__worktype[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-muted);\n}\n\n.fp-card__subhead[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 2px;\n}\n\n.fp-type-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 1px 6px;\n border-radius: var(--mj-radius-sm, 4px);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.02em;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n.fp-type-badge--decision[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n border-color: var(--mj-status-info-border);\n}\n\n.fp-card__desc[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n line-height: 1.4;\n color: var(--mj-text-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.fp-card__meta[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 0;\n border-top: 1px solid var(--mj-border-subtle);\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.fp-meta-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n font-size: 13px;\n}\n\n.fp-meta-row__k[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n color: var(--mj-text-muted);\n}\n\n.fp-meta-row__k[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 14px;\n margin-right: 4px;\n}\n\n.fp-meta-row__v[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n text-align: right;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.fp-meta-row__sub[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.fp-card__actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-top: auto;\n}\n\n\n.fp-status[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n align-self: flex-start;\n padding: 2px 10px;\n border-radius: var(--mj-radius-full, 999px);\n font-size: 11px;\n font-weight: 600;\n white-space: nowrap;\n}\n\n.fp-status.status--never[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.fp-status.status--running[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n}\n\n.fp-status.status--completed[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.fp-status.status--failed[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.fp-status.status--cancelled[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}"] });
|
|
535
542
|
};
|
|
536
543
|
FeaturePipelinesResourceComponent = __decorate([
|
|
537
544
|
RegisterClass(BaseResourceComponent, 'FeaturePipelinesResource')
|
|
@@ -539,7 +546,7 @@ FeaturePipelinesResourceComponent = __decorate([
|
|
|
539
546
|
export { FeaturePipelinesResourceComponent };
|
|
540
547
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FeaturePipelinesResourceComponent, [{
|
|
541
548
|
type: Component,
|
|
542
|
-
args: [{ standalone: false, selector: 'app-feature-pipelines-resource', template: "<mj-page-layout>\n <mj-page-header\n Title=\"Feature Pipelines\"\n Icon=\"fa-solid fa-diagram-project\"\n Subtitle=\"Derive feature attributes from your data and persist them back to entities\">\n <div meta>\n @if (FailedCount > 0) {\n <mj-stat-badge [Count]=\"FailedCount\" Label=\"last run failed\" Variant=\"error\"></mj-stat-badge>\n } @else {\n <mj-stat-badge\n [Count]=\"FilteredPipelines.length\"\n [Total]=\"AllPipelines.length\"\n Label=\"pipelines\">\n </mj-stat-badge>\n }\n </div>\n <div actions>\n <mj-refresh-button [Loading]=\"IsLoading\" (Clicked)=\"Refresh()\"></mj-refresh-button>\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"OnNewPipeline()\">\n <i class=\"fa-solid fa-plus\"></i> New Pipeline\n </button>\n </div>\n <div toolbar>\n <mj-page-search\n [Value]=\"SearchQuery\"\n Placeholder=\"Search by name, entity, or attribute\u2026\"\n (ValueChange)=\"SearchQuery = $event; OnSearchChanged()\">\n </mj-page-search>\n </div>\n </mj-page-header>\n\n <mj-page-body [Flex]=\"true\">\n @if (IsLoading) {\n <div class=\"fp-loading\">\n <mj-loading text=\"Loading feature pipelines\u2026\" size=\"medium\"></mj-loading>\n </div>\n } @else if (AllPipelines.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-diagram-project\"\n Title=\"No feature pipelines yet\"\n Message=\"A Feature Pipeline derives an attribute per record (e.g. an LLM summary or score) and writes it back to your data \u2014 reusable analytics, independent of any model.\"\n ActionText=\"New Pipeline\"\n ActionIcon=\"fa-solid fa-plus\"\n (Action)=\"OnNewPipeline()\">\n </mj-empty-state>\n } @else if (FilteredPipelines.length === 0) {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-magnifying-glass\"\n Title=\"No matching pipelines\"\n Message=\"No feature pipelines match your search.\">\n </mj-empty-state>\n } @else {\n <div class=\"fp-grid\">\n @for (pipeline of FilteredPipelines; track pipeline.ID) {\n <div class=\"fp-card\" [class.fp-card--disabled]=\"pipeline.Status !== 'Active'\">\n <div class=\"fp-card__head\">\n <i class=\"fp-card__icon\" [class]=\"WorkTypeIcon(pipeline.WorkType)\"></i>\n <div class=\"fp-card__title\">\n <h3 [title]=\"pipeline.Name\">{{ pipeline.Name }}</h3>\n <span class=\"fp-card__worktype\">{{ pipeline.WorkType }}</span>\n </div>\n <span class=\"fp-status\" [class]=\"RunStatusClass(pipeline.LastRunStatus)\">\n {{ RunStatusLabel(pipeline.LastRunStatus) }}\n </span>\n </div>\n\n @if (pipeline.Description) {\n <p class=\"fp-card__desc\" [title]=\"pipeline.Description\">{{ pipeline.Description }}</p>\n }\n\n <div class=\"fp-card__meta\">\n <div class=\"fp-meta-row\">\n <span class=\"fp-meta-row__k\"><i class=\"fa-solid fa-table\"></i> Target</span>\n <span class=\"fp-meta-row__v\">{{ pipeline.TargetEntity }}</span>\n </div>\n <div class=\"fp-meta-row\">\n <span class=\"fp-meta-row__k\"><i class=\"fa-solid fa-pen-to-square\"></i> Writes</span>\n <span class=\"fp-meta-row__v\">{{ pipeline.OutputAttribute || '\u2014' }}</span>\n </div>\n <div class=\"fp-meta-row\">\n <span class=\"fp-meta-row__k\"><i class=\"fa-solid fa-clock-rotate-left\"></i> Last run</span>\n <span class=\"fp-meta-row__v\">\n {{ TimeAgo(pipeline.LastRunAt) }}\n @if (pipeline.LastRunProcessed != null) {\n <span class=\"fp-meta-row__sub\">\u00B7 {{ pipeline.LastRunSuccess }}/{{ pipeline.LastRunProcessed }} written</span>\n }\n </span>\n </div>\n </div>\n\n <div class=\"fp-card__actions\">\n <button\n mjButton\n variant=\"primary\"\n size=\"sm\"\n [disabled]=\"!pipeline.OnDemandEnabled || pipeline.Status !== 'Active' || IsRunning(pipeline.ID)\"\n (click)=\"OnRunPipeline(pipeline)\">\n @if (IsRunning(pipeline.ID)) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Running\u2026\n } @else {\n <i class=\"fa-solid fa-play\"></i> Run\n }\n </button>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"OnViewPipeline(pipeline)\">\n <i class=\"fa-solid fa-eye\"></i> View\n </button>\n </div>\n </div>\n }\n </div>\n }\n </mj-page-body>\n</mj-page-layout>\n", styles: ["/**\n * Feature Pipelines (Knowledge Hub) \u2014 card-grid layout.\n * All colors use semantic design tokens (dark-mode + white-label safe).\n *\n * NOTE: this package builds with bare `ngc` (no Sass step) \u2014 component styles\n * are embedded RAW into the compiled JS. Keep this file FLAT, plain CSS.\n * Sass nesting / BEM selector concatenation would be silently dropped by the\n * browser and the rules would be DEAD. See .github/scripts/check-ngc-scss.sh\n * (CI gate) and MemberJunction/MJ#3105.\n */\n\n.fp-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 240px;\n width: 100%;\n}\n\n.fp-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n gap: 16px;\n padding: 4px;\n align-content: start;\n}\n\n.fp-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg, 10px);\n background: var(--mj-bg-surface-card);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n\n.fp-card:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.fp-card--disabled {\n opacity: 0.65;\n}\n\n.fp-card__head {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.fp-card__icon {\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--mj-radius-md, 8px);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.fp-card__title {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.fp-card__title h3 {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.fp-card__worktype {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-muted);\n}\n\n.fp-card__desc {\n margin: 0;\n font-size: 13px;\n line-height: 1.4;\n color: var(--mj-text-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.fp-card__meta {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 0;\n border-top: 1px solid var(--mj-border-subtle);\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.fp-meta-row {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n font-size: 13px;\n}\n\n.fp-meta-row__k {\n flex: 0 0 auto;\n color: var(--mj-text-muted);\n}\n\n.fp-meta-row__k i {\n width: 14px;\n margin-right: 4px;\n}\n\n.fp-meta-row__v {\n flex: 1 1 auto;\n text-align: right;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.fp-meta-row__sub {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.fp-card__actions {\n display: flex;\n gap: 8px;\n margin-top: auto;\n}\n\n/* Run-status pill \u2014 semantic status tokens */\n.fp-status {\n flex: 0 0 auto;\n align-self: flex-start;\n padding: 2px 10px;\n border-radius: var(--mj-radius-full, 999px);\n font-size: 11px;\n font-weight: 600;\n white-space: nowrap;\n}\n\n.fp-status.status--never {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.fp-status.status--running {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n}\n\n.fp-status.status--completed {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.fp-status.status--failed {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.fp-status.status--cancelled {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n"] }]
|
|
549
|
+
args: [{ standalone: false, selector: 'app-feature-pipelines-resource', template: "<mj-page-layout>\n <mj-page-header\n Title=\"Feature Pipelines\"\n Icon=\"fa-solid fa-diagram-project\"\n Subtitle=\"Derive feature attributes from your data and persist them back to entities\">\n <div meta>\n @if (FailedCount > 0) {\n <mj-stat-badge [Count]=\"FailedCount\" Label=\"last run failed\" Variant=\"error\"></mj-stat-badge>\n } @else {\n <mj-stat-badge\n [Count]=\"FilteredPipelines.length\"\n [Total]=\"AllPipelines.length\"\n Label=\"pipelines\">\n </mj-stat-badge>\n }\n </div>\n <div actions>\n <mj-refresh-button [Loading]=\"IsLoading\" (Clicked)=\"Refresh()\"></mj-refresh-button>\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"OnNewPipeline()\">\n <i class=\"fa-solid fa-plus\"></i> New Pipeline\n </button>\n </div>\n <div toolbar>\n <mj-page-search\n [Value]=\"SearchQuery\"\n Placeholder=\"Search by name, entity, or attribute\u2026\"\n (ValueChange)=\"SearchQuery = $event; OnSearchChanged()\">\n </mj-page-search>\n </div>\n </mj-page-header>\n\n <mj-page-body [Flex]=\"true\">\n @if (IsLoading) {\n <div class=\"fp-loading\">\n <mj-loading text=\"Loading feature pipelines\u2026\" size=\"medium\"></mj-loading>\n </div>\n } @else if (AllPipelines.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-diagram-project\"\n Title=\"No feature pipelines yet\"\n Message=\"A Feature Pipeline derives an attribute per record (e.g. an LLM summary or score) and writes it back to your data \u2014 reusable analytics, independent of any model.\"\n ActionText=\"New Pipeline\"\n ActionIcon=\"fa-solid fa-plus\"\n (Action)=\"OnNewPipeline()\">\n </mj-empty-state>\n } @else if (FilteredPipelines.length === 0) {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-magnifying-glass\"\n Title=\"No matching pipelines\"\n Message=\"No feature pipelines match your search.\">\n </mj-empty-state>\n } @else {\n <div class=\"fp-grid\">\n @for (pipeline of FilteredPipelines; track pipeline.ID) {\n <div class=\"fp-card\" [class.fp-card--disabled]=\"pipeline.Status !== 'Active'\">\n <div class=\"fp-card__head\">\n <i class=\"fp-card__icon\" [class]=\"WorkTypeIcon(pipeline.WorkType)\"></i>\n <div class=\"fp-card__title\">\n <h3 [title]=\"pipeline.Name\">{{ pipeline.Name }}</h3>\n <div class=\"fp-card__subhead\">\n <span class=\"fp-card__worktype\">{{ pipeline.WorkType }}</span>\n <span class=\"fp-type-badge\" [class.fp-type-badge--decision]=\"pipeline.PipelineType === 'Decision'\">{{ pipeline.PipelineType }}</span>\n </div>\n </div>\n <span class=\"fp-status\" [class]=\"RunStatusClass(pipeline.LastRunStatus)\">\n {{ RunStatusLabel(pipeline.LastRunStatus) }}\n </span>\n </div>\n\n @if (pipeline.Description) {\n <p class=\"fp-card__desc\" [title]=\"pipeline.Description\">{{ pipeline.Description }}</p>\n }\n\n <div class=\"fp-card__meta\">\n <div class=\"fp-meta-row\">\n <span class=\"fp-meta-row__k\"><i class=\"fa-solid fa-table\"></i> Target</span>\n <span class=\"fp-meta-row__v\">{{ pipeline.TargetEntity }}</span>\n </div>\n <div class=\"fp-meta-row\">\n <span class=\"fp-meta-row__k\"><i class=\"fa-solid fa-pen-to-square\"></i> Writes</span>\n <span class=\"fp-meta-row__v\">{{ pipeline.OutputAttribute || '\u2014' }}</span>\n </div>\n <div class=\"fp-meta-row\">\n <span class=\"fp-meta-row__k\"><i class=\"fa-solid fa-clock-rotate-left\"></i> Last run</span>\n <span class=\"fp-meta-row__v\">\n {{ TimeAgo(pipeline.LastRunAt) }}\n @if (pipeline.LastRunProcessed != null) {\n <span class=\"fp-meta-row__sub\">\u00B7 {{ pipeline.LastRunSuccess }}/{{ pipeline.LastRunProcessed }} written</span>\n }\n </span>\n </div>\n </div>\n\n <div class=\"fp-card__actions\">\n <button\n mjButton\n variant=\"primary\"\n size=\"sm\"\n [disabled]=\"!pipeline.OnDemandEnabled || pipeline.Status !== 'Active' || IsRunning(pipeline.ID)\"\n (click)=\"OnRunPipeline(pipeline)\">\n @if (IsRunning(pipeline.ID)) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Running\u2026\n } @else {\n <i class=\"fa-solid fa-play\"></i> Run\n }\n </button>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"OnViewPipeline(pipeline)\">\n <i class=\"fa-solid fa-eye\"></i> View\n </button>\n </div>\n </div>\n }\n </div>\n }\n </mj-page-body>\n</mj-page-layout>\n", styles: ["/**\n * Feature Pipelines (Knowledge Hub) \u2014 card-grid layout.\n * All colors use semantic design tokens (dark-mode + white-label safe).\n *\n * NOTE: this package builds with bare `ngc` (no Sass step) \u2014 component styles\n * are embedded RAW into the compiled JS. Keep this file FLAT, plain CSS.\n * Sass nesting / BEM selector concatenation would be silently dropped by the\n * browser and the rules would be DEAD. See .github/scripts/check-ngc-scss.sh\n * (CI gate) and MemberJunction/MJ#3105.\n */\n\n.fp-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 240px;\n width: 100%;\n}\n\n.fp-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n gap: 16px;\n padding: 4px;\n align-content: start;\n}\n\n.fp-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg, 10px);\n background: var(--mj-bg-surface-card);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n\n.fp-card:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.fp-card--disabled {\n opacity: 0.65;\n}\n\n.fp-card__head {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.fp-card__icon {\n flex: 0 0 auto;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--mj-radius-md, 8px);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.fp-card__title {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.fp-card__title h3 {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.fp-card__worktype {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-muted);\n}\n\n.fp-card__subhead {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 2px;\n}\n\n.fp-type-badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 6px;\n border-radius: var(--mj-radius-sm, 4px);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.02em;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n.fp-type-badge--decision {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n border-color: var(--mj-status-info-border);\n}\n\n.fp-card__desc {\n margin: 0;\n font-size: 13px;\n line-height: 1.4;\n color: var(--mj-text-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.fp-card__meta {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 0;\n border-top: 1px solid var(--mj-border-subtle);\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.fp-meta-row {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n font-size: 13px;\n}\n\n.fp-meta-row__k {\n flex: 0 0 auto;\n color: var(--mj-text-muted);\n}\n\n.fp-meta-row__k i {\n width: 14px;\n margin-right: 4px;\n}\n\n.fp-meta-row__v {\n flex: 1 1 auto;\n text-align: right;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.fp-meta-row__sub {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.fp-card__actions {\n display: flex;\n gap: 8px;\n margin-top: auto;\n}\n\n/* Run-status pill \u2014 semantic status tokens */\n.fp-status {\n flex: 0 0 auto;\n align-self: flex-start;\n padding: 2px 10px;\n border-radius: var(--mj-radius-full, 999px);\n font-size: 11px;\n font-weight: 600;\n white-space: nowrap;\n}\n\n.fp-status.status--never {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.fp-status.status--running {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n}\n\n.fp-status.status--completed {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.fp-status.status--failed {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.fp-status.status--cancelled {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n"] }]
|
|
543
550
|
}], null, null); })();
|
|
544
551
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(FeaturePipelinesResourceComponent, { className: "FeaturePipelinesResourceComponent", filePath: "src/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.ts", lineNumber: 65 }); })();
|
|
545
552
|
/** Tree-shaking prevention — keeps the component in the bundle. */
|