@memberjunction/ng-artifacts 5.43.0 → 5.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/lib/artifacts.module.d.ts +28 -25
- package/dist/lib/artifacts.module.d.ts.map +1 -1
- package/dist/lib/artifacts.module.js +22 -2
- package/dist/lib/artifacts.module.js.map +1 -1
- package/dist/lib/components/artifact-version-history.component.d.ts.map +1 -1
- package/dist/lib/components/artifact-version-history.component.js +26 -29
- package/dist/lib/components/artifact-version-history.component.js.map +1 -1
- package/dist/lib/components/artifact-viewer-panel.component.d.ts +3 -0
- package/dist/lib/components/artifact-viewer-panel.component.d.ts.map +1 -1
- package/dist/lib/components/artifact-viewer-panel.component.js +198 -112
- package/dist/lib/components/artifact-viewer-panel.component.js.map +1 -1
- package/dist/lib/components/plugins/audio-artifact-viewer.component.d.ts +11 -0
- package/dist/lib/components/plugins/audio-artifact-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/plugins/audio-artifact-viewer.component.js +37 -12
- package/dist/lib/components/plugins/audio-artifact-viewer.component.js.map +1 -1
- package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.d.ts.map +1 -1
- package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.js +40 -51
- package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.js.map +1 -1
- package/dist/lib/components/plugins/data-artifact-viewer.component.js +27 -47
- package/dist/lib/components/plugins/data-artifact-viewer.component.js.map +1 -1
- package/dist/lib/components/plugins/data-requirements-viewer/data-requirements-viewer.component.js +89 -95
- package/dist/lib/components/plugins/data-requirements-viewer/data-requirements-viewer.component.js.map +1 -1
- package/dist/lib/components/plugins/ml-experiment-results-viewer.component.d.ts +227 -0
- package/dist/lib/components/plugins/ml-experiment-results-viewer.component.d.ts.map +1 -0
- package/dist/lib/components/plugins/ml-experiment-results-viewer.component.js +630 -0
- package/dist/lib/components/plugins/ml-experiment-results-viewer.component.js.map +1 -0
- package/dist/lib/components/plugins/video-artifact-viewer.component.d.ts +11 -0
- package/dist/lib/components/plugins/video-artifact-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/plugins/video-artifact-viewer.component.js +37 -12
- package/dist/lib/components/plugins/video-artifact-viewer.component.js.map +1 -1
- package/dist/lib/components/previews/audio-artifact-preview.component.d.ts +18 -4
- package/dist/lib/components/previews/audio-artifact-preview.component.d.ts.map +1 -1
- package/dist/lib/components/previews/audio-artifact-preview.component.js +54 -21
- package/dist/lib/components/previews/audio-artifact-preview.component.js.map +1 -1
- package/dist/lib/components/previews/video-artifact-preview.component.d.ts +19 -5
- package/dist/lib/components/previews/video-artifact-preview.component.d.ts.map +1 -1
- package/dist/lib/components/previews/video-artifact-preview.component.js +54 -22
- package/dist/lib/components/previews/video-artifact-preview.component.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/package.json +21 -18
- package/dist/__tests__/exports.test.d.ts +0 -2
- package/dist/__tests__/exports.test.d.ts.map +0 -1
- package/dist/__tests__/exports.test.js +0 -17
- package/dist/__tests__/exports.test.js.map +0 -1
- package/dist/__tests__/image-artifact-viewer.test.d.ts +0 -2
- package/dist/__tests__/image-artifact-viewer.test.d.ts.map +0 -1
- package/dist/__tests__/image-artifact-viewer.test.js +0 -62
- package/dist/__tests__/image-artifact-viewer.test.js.map +0 -1
- package/dist/__tests__/index.test.d.ts +0 -2
- package/dist/__tests__/index.test.d.ts.map +0 -1
- package/dist/__tests__/index.test.js +0 -7
- package/dist/__tests__/index.test.js.map +0 -1
- package/dist/lib/__tests__/artifact-snapshots.test.d.ts +0 -2
- package/dist/lib/__tests__/artifact-snapshots.test.d.ts.map +0 -1
- package/dist/lib/__tests__/artifact-snapshots.test.js +0 -155
- package/dist/lib/__tests__/artifact-snapshots.test.js.map +0 -1
- package/dist/lib/__tests__/interactive-form-apply.service.test.d.ts +0 -2
- package/dist/lib/__tests__/interactive-form-apply.service.test.d.ts.map +0 -1
- package/dist/lib/__tests__/interactive-form-apply.service.test.js +0 -211
- package/dist/lib/__tests__/interactive-form-apply.service.test.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ml-experiment-results-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/ml-experiment-results-viewer.component.ts","../../../../src/lib/components/plugins/ml-experiment-results-viewer.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ChangeDetectorRef, Output, EventEmitter, inject } from '@angular/core';\nimport { DataSnapshot } from '@memberjunction/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent, ArtifactViewerTab, NavigationRequest } from '../base-artifact-viewer.component';\nimport { createMarkdownSnapshot } from '../../snapshot-helpers';\n\n/**\n * A single feature-importance entry for the winning model.\n */\ninterface MLFeatureImportance {\n /** Display name of the feature */\n feature?: string;\n name?: string;\n /** Importance weight (0..1 or any positive scale — bars are normalized to the max) */\n importance?: number;\n weight?: number;\n value?: number;\n}\n\n/**\n * A single leaderboard iteration row.\n *\n * Accepts both the **canonical** Core `ModelingPlanSpec.Leaderboard` shape\n * (PascalCase: `Metric`/`ModelID`/`IterationID`, produced by the deterministic\n * `ExperimentOrchestrator`) and the older / LLM-authored lowercase shape. All\n * fields are optional so partial artifacts degrade gracefully.\n */\ninterface MLLeaderboardEntry {\n // ── Canonical (Core ModelingPlanSpec.Leaderboard entry) ──\n /** The iteration this entry scores (`MJ: Experiment Session Iterations` id). */\n IterationID?: string;\n /** The normalized leaderboard metric value (the Experiment's TargetMetric). */\n Metric?: number;\n /** The trained ML Model record ID for drill-through. */\n ModelID?: string;\n\n // ── Lowercase / LLM-authored fallbacks + display-only fields ──\n /** Rank (1 = best). If absent, derived from array order. */\n rank?: number;\n /** Algorithm name, e.g. \"XGBoost\" */\n algorithm?: string;\n algorithmName?: string;\n /** Feature set label, e.g. \"engagement\", \"full\", \"interpretable\" */\n featureSet?: string;\n /** Primary normalized leaderboard score (the Experiment's TargetMetric) */\n score?: number;\n /** Optional secondary metric (e.g. cross-validation score) */\n cvScore?: number;\n /** The trained ML Model record ID for drill-through (lowercase fallback) */\n modelId?: string;\n /** Named metric label for the primary score column header */\n metricName?: string;\n}\n\n/**\n * Headline / extra metrics for the winning model card.\n */\ninterface MLWinningMetric {\n label?: string;\n value?: number | string;\n}\n\n/**\n * The reporting-phase block authored by the Model Development Agent.\n */\ninterface MLExperimentReport {\n name?: string;\n summary?: string;\n markdown?: string;\n /** The winning ML Model record ID (drill-through target) */\n bestModelId?: string;\n bestModelName?: string;\n bestModelVersion?: string;\n}\n\n/**\n * The canonical best-model pointer on a `ModelingPlanSpec`-shaped artifact.\n */\ninterface MLBestModel {\n ID?: string;\n Name?: string;\n Version?: string | number;\n}\n\n/**\n * ML Experiment Results artifact content shape.\n *\n * The **canonical** shape is the Core `ModelingPlanSpec` (PascalCase: `Goal`,\n * `Leaderboard`, `BestModel`/`BestModelID`, `Markdown`, …) produced by the\n * deterministic `ExperimentOrchestrator` and the Model Development Agent's\n * reporting phase (content type `application/vnd.mj.ml-experiment-results`).\n *\n * Older / LLM-authored lowercase fields (`goal`, `leaderboard`, `report`, …)\n * are retained as graceful fallbacks. All fields are optional so partial/older\n * artifacts degrade gracefully.\n */\ninterface MLExperimentResultsSpec {\n // ── Canonical (Core ModelingPlanSpec) ──\n /** Display name / title of the session (PascalCase). */\n Name?: string;\n /** The modeling goal, plain language (PascalCase). */\n Goal?: string;\n /** Plain-language summary of the results (PascalCase). */\n Summary?: string;\n /** The full results narrative in markdown (PascalCase). */\n Markdown?: string;\n /** Ranked leaderboard of experiment iterations (PascalCase Core shape). */\n Leaderboard?: MLLeaderboardEntry[];\n /** Feature importance for the winning model (PascalCase). */\n FeatureImportance?: MLFeatureImportance[];\n /** The winning model pointer (PascalCase). */\n BestModel?: MLBestModel;\n /** Convenience scalar pointer to the winning model ID (PascalCase). */\n BestModelID?: string;\n /** The normalized target metric name (PascalCase). */\n TargetMetric?: string;\n\n // ── Lowercase / LLM-authored fallbacks ──\n /** The modeling goal, plain language */\n goal?: string;\n /** Prediction target (e.g. \"Renewed\") */\n target?: string;\n /** As-of cutoff description (leakage guard) */\n asOf?: string;\n /** Validation strategy description */\n validation?: string;\n /** Budget usage description (e.g. \"22 / 25 runs · 58 min\") */\n budgetUsed?: string;\n /** The normalized target metric name (column header / headline label) */\n targetMetric?: string;\n /** Ranked leaderboard of experiment iterations */\n leaderboard?: MLLeaderboardEntry[];\n /** Feature importance for the winning model */\n featureImportance?: MLFeatureImportance[];\n /** Convenience pointer to the winning model ID (also resolvable via report/leaderboard) */\n bestModelId?: string;\n /** Extra headline metrics for the winning-model card */\n winningMetrics?: MLWinningMetric[];\n /** The reporting-phase block (markdown, summary, best model) */\n report?: MLExperimentReport;\n}\n\n/**\n * Normalized leaderboard row for the template (resolves alias fields + derived rank).\n */\ninterface NormalizedLeaderboardRow {\n rank: number;\n algorithm: string;\n featureSet: string;\n score: number | null;\n cvScore: number | null;\n modelId: string | null;\n isWinner: boolean;\n}\n\n/**\n * Normalized feature-importance bar for the template (resolves alias + percent width).\n */\ninterface NormalizedFeatureBar {\n feature: string;\n importance: number;\n /** Width percentage relative to the most important feature (0..100) */\n widthPct: number;\n}\n\n/**\n * Viewer plugin for **ML Experiment Results** artifacts (Predictive Studio).\n *\n * Renders the experiment goal + headline best metric, a ranked leaderboard of\n * iterations, feature-importance bars for the winning model, and a winning-model\n * card with a drill-through button that issues a {@link NavigationRequest} to open\n * the winning `MJ: ML Models` record in Predictive Studio's \"Models\" nav item.\n *\n * Falls back to a friendly empty state when the JSON can't be parsed, and exposes\n * the agent-authored markdown report as an additional \"Report\" tab when present.\n */\n@Component({\n standalone: false,\n selector: 'mj-ml-experiment-results-viewer',\n templateUrl: './ml-experiment-results-viewer.component.html',\n styleUrls: ['./ml-experiment-results-viewer.component.css']\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'MLExperimentResultsViewerPlugin')\nexport class MLExperimentResultsViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit {\n /** Emitted to request app-level navigation (drill-through to the ML Model record). */\n @Output() override navigationRequest = new EventEmitter<NavigationRequest>();\n\n private cdr = inject(ChangeDetectorRef);\n\n /** Parsed artifact content. */\n public Spec: MLExperimentResultsSpec | null = null;\n\n public IsLoading = true;\n public HasError = false;\n public ErrorMessage = '';\n\n /** Normalized, ranked leaderboard rows for rendering. */\n public LeaderboardRows: NormalizedLeaderboardRow[] = [];\n\n /** Normalized feature-importance bars for rendering. */\n public FeatureBars: NormalizedFeatureBar[] = [];\n\n // ─── Lifecycle ───────────────────────────────────────────────────\n\n ngOnInit(): void {\n try {\n this.Spec = this.parseJsonContent<MLExperimentResultsSpec>();\n if (!this.Spec) {\n this.HasError = true;\n this.ErrorMessage = 'Could not parse the ML Experiment Results content as JSON.';\n return;\n }\n\n this.LeaderboardRows = this.buildLeaderboardRows(this.Spec.Leaderboard ?? this.Spec.leaderboard ?? []);\n this.FeatureBars = this.buildFeatureBars(this.Spec.FeatureImportance ?? this.Spec.featureImportance ?? []);\n } catch (error) {\n this.HasError = true;\n this.ErrorMessage = error instanceof Error ? error.message : 'Failed to load experiment results.';\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n // ─── Base-class contract ─────────────────────────────────────────\n\n public override get hasDisplayContent(): boolean {\n return this.Spec != null;\n }\n\n public override GetCurrentStateSnapshot(): DataSnapshot | null {\n // The richest portable representation is the agent-authored markdown report.\n return createMarkdownSnapshot(this.WinningMarkdown ?? this.getRawContent(), this.getDisplayTitle());\n }\n\n /**\n * Expose the agent-authored markdown report as an additional \"Report\" tab\n * so users can read the full narrative alongside the rich visual display.\n */\n public GetAdditionalTabs(): ArtifactViewerTab[] {\n const markdown = this.Spec?.Markdown ?? this.Spec?.report?.markdown;\n if (!markdown) {\n return [];\n }\n return [\n {\n label: 'Report',\n icon: 'fa-file-lines',\n contentType: 'markdown',\n content: markdown\n }\n ];\n }\n\n // ─── Display getters ─────────────────────────────────────────────\n\n public get Goal(): string {\n return this.Spec?.Goal ?? this.Spec?.goal ?? this.Spec?.Summary ?? this.Spec?.report?.summary ?? '';\n }\n\n public get Summary(): string {\n return this.Spec?.Summary ?? this.Spec?.report?.summary ?? '';\n }\n\n public get TargetMetricLabel(): string {\n return this.Spec?.TargetMetric ?? this.Spec?.targetMetric ?? this.firstMetricName() ?? 'Score';\n }\n\n /** The winning row (rank 1) if any. */\n public get WinningRow(): NormalizedLeaderboardRow | null {\n return this.LeaderboardRows.find(r => r.isWinner) ?? this.LeaderboardRows[0] ?? null;\n }\n\n /** Headline best score (the winning row's primary score), formatted. */\n public get HeadlineScore(): string | null {\n const score = this.WinningRow?.score;\n return score != null ? this.formatScore(score) : null;\n }\n\n public get WinningAlgorithm(): string {\n return this.Spec?.BestModel?.Name ?? this.Spec?.report?.bestModelName ?? this.WinningRow?.algorithm ?? 'Winning model';\n }\n\n public get WinningModelSubtitle(): string {\n const parts: string[] = [];\n if (this.WinningRow?.featureSet) {\n parts.push(this.WinningRow.featureSet);\n }\n const version = this.Spec?.BestModel?.Version ?? this.Spec?.report?.bestModelVersion;\n if (version != null && `${version}`.trim()) {\n parts.push(`${version}`);\n }\n return parts.join(' · ');\n }\n\n /** Extra headline metrics for the winning-model card. */\n public get WinningMetrics(): MLWinningMetric[] {\n const provided = this.Spec?.winningMetrics ?? [];\n if (provided.length > 0) {\n return provided;\n }\n // Synthesize a single metric from the headline score when nothing explicit was provided.\n const row = this.WinningRow;\n if (row?.score != null) {\n return [{ label: this.firstMetricName() ?? 'Score', value: this.formatScore(row.score) }];\n }\n return [];\n }\n\n public get WinningMarkdown(): string | null {\n return this.Spec?.Markdown ?? this.Spec?.report?.markdown ?? null;\n }\n\n /** Whether we have a resolvable model ID to drill through to. */\n public get HasDrillThroughTarget(): boolean {\n return this.resolveBestModelId() != null;\n }\n\n public get LeaderboardSize(): number {\n return this.LeaderboardRows.length;\n }\n\n // ─── Actions ─────────────────────────────────────────────────────\n\n /**\n * Drill through to the winning ML Model record in Predictive Studio.\n * Matches the §9.4 contract: NavigationRequest to the 'Models' nav item.\n */\n public OnDrillThroughToModel(): void {\n const modelId = this.resolveBestModelId();\n if (!modelId) {\n return;\n }\n this.navigationRequest.emit({\n appName: 'Predictive Studio',\n navItemName: 'Models',\n queryParams: { modelId }\n });\n }\n\n /**\n * Drill through to a specific leaderboard row's model, when that row carries a modelId.\n */\n public OnOpenRowModel(row: NormalizedLeaderboardRow): void {\n if (!row.modelId) {\n return;\n }\n this.navigationRequest.emit({\n appName: 'Predictive Studio',\n navItemName: 'Models',\n queryParams: { modelId: row.modelId }\n });\n }\n\n // ─── Helpers ─────────────────────────────────────────────────────\n\n /**\n * Resolve the winning model ID. Priority (canonical PascalCase first):\n * BestModel.ID → BestModelID → report block → lowercase field → top leaderboard row.\n */\n private resolveBestModelId(): string | null {\n return this.Spec?.BestModel?.ID\n ?? this.Spec?.BestModelID\n ?? this.Spec?.report?.bestModelId\n ?? this.Spec?.bestModelId\n ?? this.WinningRow?.modelId\n ?? null;\n }\n\n /** Build normalized, ranked leaderboard rows from raw entries. */\n private buildLeaderboardRows(entries: MLLeaderboardEntry[]): NormalizedLeaderboardRow[] {\n if (!Array.isArray(entries) || entries.length === 0) {\n return [];\n }\n\n const rows = entries.map((e, index) => ({\n // Canonical `Leaderboard` is already best-first; derive rank from order.\n rank: e.rank ?? index + 1,\n algorithm: e.algorithm ?? e.algorithmName ?? 'Unknown',\n featureSet: e.featureSet ?? '',\n // Canonical: `Metric`; fallback: lowercase `score`.\n score: this.firstDefined(e.Metric ?? e.score),\n cvScore: this.firstDefined(e.cvScore),\n // Canonical: `ModelID`; fallback: lowercase `modelId`.\n modelId: e.ModelID ?? e.modelId ?? null,\n isWinner: false\n }));\n\n // Sort by explicit rank ascending (rank 1 is best).\n rows.sort((a, b) => a.rank - b.rank);\n if (rows.length > 0) {\n rows[0].isWinner = true;\n }\n return rows;\n }\n\n /** Build normalized feature-importance bars (widths relative to the max). */\n private buildFeatureBars(entries: MLFeatureImportance[]): NormalizedFeatureBar[] {\n if (!Array.isArray(entries) || entries.length === 0) {\n return [];\n }\n\n const resolved = entries.map(e => ({\n feature: e.feature ?? e.name ?? 'Feature',\n importance: this.firstDefined(e.importance ?? e.weight ?? e.value) ?? 0\n }));\n\n const max = resolved.reduce((m, r) => Math.max(m, r.importance), 0);\n // Sort descending by importance for a clean ranked bar chart.\n resolved.sort((a, b) => b.importance - a.importance);\n\n return resolved.map(r => ({\n feature: r.feature,\n importance: r.importance,\n widthPct: max > 0 ? Math.max(2, Math.round((r.importance / max) * 100)) : 0\n }));\n }\n\n /** First metric name found on the leaderboard, for column/label fallback. */\n private firstMetricName(): string | null {\n const entry = (this.Spec?.Leaderboard ?? this.Spec?.leaderboard)?.[0];\n return entry?.metricName ?? null;\n }\n\n /** Return the value if it's a finite number, else null. */\n private firstDefined(value: number | undefined | null): number | null {\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n }\n\n /** Format a numeric score for display (3 decimals, trimmed). */\n public formatScore(value: number | null): string {\n if (value == null) {\n return '—';\n }\n // Scores in [0,1] (AUC/F1) look best at 3 decimals; larger metrics (RMSE) at 2.\n const decimals = Math.abs(value) < 1 ? 3 : 2;\n return value.toFixed(decimals);\n }\n\n /** Format an importance weight for the small bar label. */\n public formatImportance(value: number): string {\n if (!Number.isFinite(value)) {\n return '';\n }\n // Show .31 style for sub-1 weights, otherwise 2 decimals.\n return Math.abs(value) < 1 ? value.toFixed(2).replace(/^0/, '') : value.toFixed(2);\n }\n}\n","<div class=\"ml-exp-viewer\" [ngClass]=\"cssClass\">\n\n @if (IsLoading) {\n <div class=\"ml-exp-loading\">\n <mj-loading text=\"Loading experiment results…\" size=\"medium\"></mj-loading>\n </div>\n } @else if (HasError || !Spec) {\n <div class=\"ml-exp-empty\">\n <i class=\"fa-solid fa-flask-vial\"></i>\n <h3>No experiment results to display</h3>\n <p>{{ ErrorMessage || 'This artifact does not contain readable ML experiment results.' }}</p>\n </div>\n } @else {\n\n <!-- HERO -->\n <div class=\"ml-exp-hero\">\n <div class=\"hero-badge\"><i class=\"fa-solid fa-flask-vial\"></i></div>\n <div class=\"hero-titles\">\n <h2 class=\"hero-title\">ML Experiment Results</h2>\n @if (Summary) {\n <div class=\"hero-sub\">{{ Summary }}</div>\n }\n </div>\n @if (HeadlineScore != null) {\n <div class=\"hero-metric\">\n <div class=\"hero-metric-value\">{{ HeadlineScore }}</div>\n <div class=\"hero-metric-label\">{{ TargetMetricLabel }} · winner</div>\n </div>\n }\n </div>\n\n <div class=\"ml-exp-body\">\n\n <!-- GOAL BAR -->\n <div class=\"goalbar\">\n @if (Goal) {\n <div class=\"goal-item\">\n <span class=\"goal-key\">Goal</span>\n <span class=\"goal-val\">{{ Goal }}</span>\n </div>\n }\n @if (Spec.target) {\n <div class=\"goal-item\">\n <span class=\"goal-key\">Target</span>\n <span class=\"goal-val\">{{ Spec.target }}</span>\n </div>\n }\n @if (Spec.asOf) {\n <div class=\"goal-item\">\n <span class=\"goal-key\">As-of</span>\n <span class=\"goal-val\">{{ Spec.asOf }}</span>\n </div>\n }\n @if (Spec.validation) {\n <div class=\"goal-item\">\n <span class=\"goal-key\">Validation</span>\n <span class=\"goal-val\">{{ Spec.validation }}</span>\n </div>\n }\n @if (Spec.budgetUsed) {\n <div class=\"goal-item\">\n <span class=\"goal-key\">Budget used</span>\n <span class=\"goal-val\">{{ Spec.budgetUsed }}</span>\n </div>\n }\n </div>\n\n <div class=\"ml-exp-cols\">\n\n <!-- LEFT COLUMN: leaderboard + feature importance -->\n <div class=\"col-main\">\n\n <div class=\"section-title\">Leaderboard</div>\n @if (LeaderboardRows.length > 0) {\n <div class=\"lb-card\">\n <table class=\"lb-table\">\n <thead>\n <tr>\n <th class=\"lb-rank-col\">#</th>\n <th>Algorithm</th>\n <th>Feature set</th>\n <th class=\"num\">{{ TargetMetricLabel }}</th>\n <th class=\"num\">CV</th>\n </tr>\n </thead>\n <tbody>\n @for (row of LeaderboardRows; track row.rank) {\n <tr [class.is-winner]=\"row.isWinner\"\n [class.has-model]=\"row.modelId\"\n (click)=\"OnOpenRowModel(row)\">\n <td>\n <span class=\"rank\" [class.gold]=\"row.isWinner\">{{ row.rank }}</span>\n </td>\n <td class=\"algo\">\n @if (row.isWinner) {\n <strong>{{ row.algorithm }}</strong>\n } @else {\n {{ row.algorithm }}\n }\n @if (row.modelId) {\n <i class=\"fa-solid fa-arrow-up-right-from-square row-link-icon\"\n title=\"Open this model\"></i>\n }\n </td>\n <td class=\"muted\">{{ row.featureSet || '—' }}</td>\n <td class=\"num\">\n @if (row.isWinner) {\n <strong>{{ formatScore(row.score) }}</strong>\n } @else {\n {{ formatScore(row.score) }}\n }\n </td>\n <td class=\"num muted\">{{ formatScore(row.cvScore) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"inline-empty\">No leaderboard iterations were recorded.</div>\n }\n\n @if (FeatureBars.length > 0) {\n <div class=\"section-title\">Feature Importance — winning model</div>\n <div class=\"fi-card\">\n @for (bar of FeatureBars; track bar.feature) {\n <div class=\"fbar\">\n <div class=\"fbar-label\" [title]=\"bar.feature\">{{ bar.feature }}</div>\n <div class=\"fbar-track\">\n <span class=\"fbar-fill\" [style.width.%]=\"bar.widthPct\"></span>\n </div>\n <div class=\"fbar-num\">{{ formatImportance(bar.importance) }}</div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- RIGHT COLUMN: winning model card + drill-through -->\n <div class=\"col-side\">\n <div class=\"section-title\">Winning Model</div>\n <div class=\"winner-card\">\n <div class=\"winner-top\">\n <div class=\"crown\"><i class=\"fa-solid fa-crown\"></i></div>\n <div class=\"winner-head\">\n <h3 class=\"winner-name\">{{ WinningAlgorithm }}</h3>\n @if (WinningModelSubtitle) {\n <div class=\"muted\">{{ WinningModelSubtitle }}</div>\n }\n </div>\n </div>\n\n @if (WinningMetrics.length > 0) {\n <div class=\"wmetrics\">\n @for (m of WinningMetrics; track m.label) {\n <div class=\"wmetric\">\n <div class=\"wmetric-value\">{{ m.value }}</div>\n <div class=\"wmetric-label\">{{ m.label }}</div>\n </div>\n }\n </div>\n }\n\n <button mjButton variant=\"primary\" class=\"drill-btn\"\n [disabled]=\"!HasDrillThroughTarget\"\n (click)=\"OnDrillThroughToModel()\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i>\n Drill through to ML Model\n </button>\n\n @if (!HasDrillThroughTarget) {\n <div class=\"drill-hint muted\">\n No linked ML Model record on this artifact yet.\n </div>\n }\n </div>\n </div>\n\n </div>\n </div>\n }\n</div>\n"]}
|
|
@@ -2,6 +2,7 @@ import { OnInit, Type } from '@angular/core';
|
|
|
2
2
|
import { DataSnapshot } from '@memberjunction/core';
|
|
3
3
|
import { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';
|
|
4
4
|
import { IArtifactPreviewComponent } from '../../interfaces/artifact-viewer-plugin.interface';
|
|
5
|
+
import { MediaTrack } from '@memberjunction/ng-media-player';
|
|
5
6
|
import * as i0 from "@angular/core";
|
|
6
7
|
/**
|
|
7
8
|
* Minimal full-size viewer plugin for video artifacts. Renders a `<video controls>` player that
|
|
@@ -17,6 +18,14 @@ export declare class VideoArtifactViewerComponent extends BaseArtifactViewerPlug
|
|
|
17
18
|
private readonly cdr;
|
|
18
19
|
videoUrl: string;
|
|
19
20
|
errorMessage: string;
|
|
21
|
+
/**
|
|
22
|
+
* Single-track input for the generic {@link MJMediaPlayerComponent}. Rebuilt whenever
|
|
23
|
+
* {@link videoUrl} is (re)resolved via {@link setVideoUrl}; empty until a URL exists so the
|
|
24
|
+
* player shows its own empty state.
|
|
25
|
+
*/
|
|
26
|
+
MediaTracks: MediaTrack[];
|
|
27
|
+
/** Set the resolved URL and recompute the single-element {@link MediaTracks} array in lockstep. */
|
|
28
|
+
private setVideoUrl;
|
|
20
29
|
/**
|
|
21
30
|
* Inline-preview component for video artifacts ({@link IArtifactViewerPluginPreviewStatics}).
|
|
22
31
|
* STATIC so the resolver reads it off the constructor without instantiating this DI-using component.
|
|
@@ -27,6 +36,8 @@ export declare class VideoArtifactViewerComponent extends BaseArtifactViewerPlug
|
|
|
27
36
|
get hasDisplayContent(): boolean;
|
|
28
37
|
ngOnInit(): Promise<void>;
|
|
29
38
|
onMediaError(): void;
|
|
39
|
+
/** Fired when the generic player reaches the end of the track. No-op affordance hook. */
|
|
40
|
+
onMediaEnded(): void;
|
|
30
41
|
GetCurrentStateSnapshot(): DataSnapshot | null;
|
|
31
42
|
static ɵfac: i0.ɵɵFactoryDeclaration<VideoArtifactViewerComponent, never>;
|
|
32
43
|
static ɵcmp: i0.ɵɵComponentDeclaration<VideoArtifactViewerComponent, "mj-video-artifact-viewer", never, {}, {}, never, never, false, never>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/video-artifact-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,MAAM,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;AAEtF,OAAO,EAAE,yBAAyB,EAAE,MAAM,mDAAmD,CAAC;;
|
|
1
|
+
{"version":3,"file":"video-artifact-viewer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/plugins/video-artifact-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,MAAM,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;AAEtF,OAAO,EAAE,yBAAyB,EAAE,MAAM,mDAAmD,CAAC;AAE9F,OAAO,EAA0B,UAAU,EAAE,MAAM,iCAAiC,CAAC;;AAErF;;;;;;;;GAQG;AACH,qBA8Da,4BAA6B,SAAQ,iCAAkC,YAAW,MAAM;IACjG,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+B;IAC3D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IAE1C,QAAQ,SAAM;IACd,YAAY,SAAM;IAEzB;;;;OAIG;IACI,WAAW,EAAE,UAAU,EAAE,CAAM;IAEtC,mGAAmG;IACnG,OAAO,CAAC,WAAW;IAcnB;;;OAGG;IACH,gBAAuB,oBAAoB,EAAE,IAAI,CAAC,yBAAyB,CAAC,CAAiC;IAE7G,kGAAkG;WACpF,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO;IAQvF,IAAoB,iBAAiB,IAAI,OAAO,CAE/C;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBxB,YAAY,IAAI,IAAI;IAM3B,yFAAyF;IAClF,YAAY,IAAI,IAAI;IAIX,uBAAuB,IAAI,YAAY,GAAG,IAAI;yCA9ErD,4BAA4B;2CAA5B,4BAA4B;CA4FxC"}
|
|
@@ -12,6 +12,7 @@ import { ArtifactFileService } from '../../services/artifact-file.service';
|
|
|
12
12
|
import { VideoArtifactPreviewComponent } from '../previews/video-artifact-preview.component';
|
|
13
13
|
import * as i0 from "@angular/core";
|
|
14
14
|
import * as i1 from "@angular/common";
|
|
15
|
+
import * as i2 from "@memberjunction/ng-media-player";
|
|
15
16
|
function VideoArtifactViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
16
17
|
i0.ɵɵelementStart(0, "div", 1);
|
|
17
18
|
i0.ɵɵelement(1, "i", 4);
|
|
@@ -25,12 +26,12 @@ function VideoArtifactViewerComponent_Conditional_1_Template(rf, ctx) { if (rf &
|
|
|
25
26
|
} }
|
|
26
27
|
function VideoArtifactViewerComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
27
28
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
28
|
-
i0.ɵɵelementStart(0, "
|
|
29
|
-
i0.ɵɵlistener("
|
|
29
|
+
i0.ɵɵelementStart(0, "mj-media-player", 5);
|
|
30
|
+
i0.ɵɵlistener("Ended", function VideoArtifactViewerComponent_Conditional_2_Template_mj_media_player_Ended_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onMediaEnded()); });
|
|
30
31
|
i0.ɵɵelementEnd();
|
|
31
32
|
} if (rf & 2) {
|
|
32
33
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
33
|
-
i0.ɵɵproperty("
|
|
34
|
+
i0.ɵɵproperty("Tracks", ctx_r0.MediaTracks);
|
|
34
35
|
} }
|
|
35
36
|
function VideoArtifactViewerComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
36
37
|
i0.ɵɵelementStart(0, "div", 3);
|
|
@@ -53,6 +54,26 @@ let VideoArtifactViewerComponent = class VideoArtifactViewerComponent extends Ba
|
|
|
53
54
|
cdr = inject(ChangeDetectorRef);
|
|
54
55
|
videoUrl = '';
|
|
55
56
|
errorMessage = '';
|
|
57
|
+
/**
|
|
58
|
+
* Single-track input for the generic {@link MJMediaPlayerComponent}. Rebuilt whenever
|
|
59
|
+
* {@link videoUrl} is (re)resolved via {@link setVideoUrl}; empty until a URL exists so the
|
|
60
|
+
* player shows its own empty state.
|
|
61
|
+
*/
|
|
62
|
+
MediaTracks = [];
|
|
63
|
+
/** Set the resolved URL and recompute the single-element {@link MediaTracks} array in lockstep. */
|
|
64
|
+
setVideoUrl(url) {
|
|
65
|
+
this.videoUrl = url;
|
|
66
|
+
this.MediaTracks = url
|
|
67
|
+
? [
|
|
68
|
+
{
|
|
69
|
+
Id: this.artifactVersion?.ID ?? 'video',
|
|
70
|
+
Kind: 'video',
|
|
71
|
+
Url: url,
|
|
72
|
+
MimeType: this.artifactVersion?.MimeType ?? undefined,
|
|
73
|
+
},
|
|
74
|
+
]
|
|
75
|
+
: [];
|
|
76
|
+
}
|
|
56
77
|
/**
|
|
57
78
|
* Inline-preview component for video artifacts ({@link IArtifactViewerPluginPreviewStatics}).
|
|
58
79
|
* STATIC so the resolver reads it off the constructor without instantiating this DI-using component.
|
|
@@ -72,12 +93,12 @@ let VideoArtifactViewerComponent = class VideoArtifactViewerComponent extends Ba
|
|
|
72
93
|
async ngOnInit() {
|
|
73
94
|
try {
|
|
74
95
|
if (this.artifactVersion?.ContentMode === 'File' && this.artifactVersion.ID) {
|
|
75
|
-
this.
|
|
96
|
+
this.setVideoUrl(await this.fileService.getDownloadUrl(this.artifactVersion.ID));
|
|
76
97
|
}
|
|
77
98
|
else {
|
|
78
99
|
const content = this.artifactVersion?.Content;
|
|
79
100
|
if (content) {
|
|
80
|
-
this.
|
|
101
|
+
this.setVideoUrl(content);
|
|
81
102
|
}
|
|
82
103
|
else {
|
|
83
104
|
this.errorMessage = 'This artifact has no video content.';
|
|
@@ -92,9 +113,13 @@ let VideoArtifactViewerComponent = class VideoArtifactViewerComponent extends Ba
|
|
|
92
113
|
}
|
|
93
114
|
onMediaError() {
|
|
94
115
|
this.errorMessage = 'The video could not be played. It may be corrupt or in an unsupported format.';
|
|
95
|
-
this.
|
|
116
|
+
this.setVideoUrl('');
|
|
96
117
|
this.cdr.markForCheck();
|
|
97
118
|
}
|
|
119
|
+
/** Fired when the generic player reaches the end of the track. No-op affordance hook. */
|
|
120
|
+
onMediaEnded() {
|
|
121
|
+
// Playback finished — nothing to persist for a one-shot artifact viewer.
|
|
122
|
+
}
|
|
98
123
|
GetCurrentStateSnapshot() {
|
|
99
124
|
if (!this.artifactVersion) {
|
|
100
125
|
return null;
|
|
@@ -110,15 +135,15 @@ let VideoArtifactViewerComponent = class VideoArtifactViewerComponent extends Ba
|
|
|
110
135
|
return snap;
|
|
111
136
|
}
|
|
112
137
|
static ɵfac = /*@__PURE__*/ (() => { let ɵVideoArtifactViewerComponent_BaseFactory; return function VideoArtifactViewerComponent_Factory(__ngFactoryType__) { return (ɵVideoArtifactViewerComponent_BaseFactory || (ɵVideoArtifactViewerComponent_BaseFactory = i0.ɵɵgetInheritedFactory(VideoArtifactViewerComponent)))(__ngFactoryType__ || VideoArtifactViewerComponent); }; })();
|
|
113
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: VideoArtifactViewerComponent, selectors: [["mj-video-artifact-viewer"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 2, consts: [[1, "video-viewer", 3, "ngClass"], [1, "video-viewer__state", "video-viewer__state--error"], [
|
|
138
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: VideoArtifactViewerComponent, selectors: [["mj-video-artifact-viewer"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 2, consts: [[1, "video-viewer", 3, "ngClass"], [1, "video-viewer__state", "video-viewer__state--error"], [1, "video-viewer__player", 3, "Tracks"], [1, "video-viewer__state"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "video-viewer__player", 3, "Ended", "Tracks"], [1, "fa-solid", "fa-spinner", "fa-spin"]], template: function VideoArtifactViewerComponent_Template(rf, ctx) { if (rf & 1) {
|
|
114
139
|
i0.ɵɵelementStart(0, "div", 0);
|
|
115
|
-
i0.ɵɵconditionalCreate(1, VideoArtifactViewerComponent_Conditional_1_Template, 4, 1, "div", 1)(2, VideoArtifactViewerComponent_Conditional_2_Template, 1, 1, "
|
|
140
|
+
i0.ɵɵconditionalCreate(1, VideoArtifactViewerComponent_Conditional_1_Template, 4, 1, "div", 1)(2, VideoArtifactViewerComponent_Conditional_2_Template, 1, 1, "mj-media-player", 2)(3, VideoArtifactViewerComponent_Conditional_3_Template, 4, 0, "div", 3);
|
|
116
141
|
i0.ɵɵelementEnd();
|
|
117
142
|
} if (rf & 2) {
|
|
118
143
|
i0.ɵɵproperty("ngClass", ctx.cssClass);
|
|
119
144
|
i0.ɵɵadvance();
|
|
120
145
|
i0.ɵɵconditional(ctx.errorMessage ? 1 : ctx.videoUrl ? 2 : 3);
|
|
121
|
-
} }, dependencies: [i1.NgClass], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n }\n\n .video-viewer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .video-
|
|
146
|
+
} }, dependencies: [i1.NgClass, i2.MJMediaPlayerComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n }\n\n .video-viewer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .video-viewer__player[_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n max-width: 100%;\n max-height: 100%;\n border-radius: 4px;\n background: var(--mj-bg-surface);\n }\n\n .video-viewer__state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .video-viewer__state--error[_ngcontent-%COMP%] {\n color: var(--mj-status-error-text);\n }"] });
|
|
122
147
|
};
|
|
123
148
|
VideoArtifactViewerComponent = __decorate([
|
|
124
149
|
RegisterClass(BaseArtifactViewerPluginComponent, 'VideoArtifactViewerPlugin')
|
|
@@ -134,7 +159,7 @@ export { VideoArtifactViewerComponent };
|
|
|
134
159
|
<span>{{ errorMessage }}</span>
|
|
135
160
|
</div>
|
|
136
161
|
} @else if (videoUrl) {
|
|
137
|
-
<
|
|
162
|
+
<mj-media-player class="video-viewer__player" [Tracks]="MediaTracks" (Ended)="onMediaEnded()"></mj-media-player>
|
|
138
163
|
} @else {
|
|
139
164
|
<div class="video-viewer__state">
|
|
140
165
|
<i class="fa-solid fa-spinner fa-spin"></i>
|
|
@@ -142,7 +167,7 @@ export { VideoArtifactViewerComponent };
|
|
|
142
167
|
</div>
|
|
143
168
|
}
|
|
144
169
|
</div>
|
|
145
|
-
`, styles: ["\n :host {\n display: block;\n height: 100%;\n }\n\n .video-viewer {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .video-
|
|
170
|
+
`, styles: ["\n :host {\n display: block;\n height: 100%;\n }\n\n .video-viewer {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .video-viewer__player {\n display: block;\n width: 100%;\n height: 100%;\n max-width: 100%;\n max-height: 100%;\n border-radius: 4px;\n background: var(--mj-bg-surface);\n }\n\n .video-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .video-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n "] }]
|
|
146
171
|
}], null, null); })();
|
|
147
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(VideoArtifactViewerComponent, { className: "VideoArtifactViewerComponent", filePath: "src/lib/components/plugins/video-artifact-viewer.component.ts", lineNumber:
|
|
172
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(VideoArtifactViewerComponent, { className: "VideoArtifactViewerComponent", filePath: "src/lib/components/plugins/video-artifact-viewer.component.ts", lineNumber: 81 }); })();
|
|
148
173
|
//# sourceMappingURL=video-artifact-viewer.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/video-artifact-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectorRef, Component, inject, OnInit, Type } from '@angular/core';\nimport { DataSnapshot } from '@memberjunction/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\nimport { ArtifactFileService } from '../../services/artifact-file.service';\nimport { IArtifactPreviewComponent } from '../../interfaces/artifact-viewer-plugin.interface';\nimport { VideoArtifactPreviewComponent } from '../previews/video-artifact-preview.component';\n\n/**\n * Minimal full-size viewer plugin for video artifacts. Renders a `<video controls>` player that\n * fills the panel. Supports both storage modes:\n * - `ContentMode === 'File'` — fetch a pre-auth URL from MJStorage via {@link ArtifactFileService}.\n * - `ContentMode === 'Text'` — `Content` is a `data:<mime>;base64,…` URI, bound directly.\n *\n * Deliberately minimal — the richer inline experience lives in {@link VideoArtifactPreviewComponent}\n * (exposed via {@link previewComponentType}); this just needs to satisfy the required `componentType`.\n */\n@Component({\n standalone: false,\n selector: 'mj-video-artifact-viewer',\n template: `\n <div class=\"video-viewer\" [ngClass]=\"cssClass\">\n @if (errorMessage) {\n <div class=\"video-viewer__state video-viewer__state--error\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n </div>\n } @else if (videoUrl) {\n <video class=\"video-viewer__video\" controls preload=\"metadata\" [src]=\"videoUrl\" (error)=\"onMediaError()\"></video>\n } @else {\n <div class=\"video-viewer__state\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading video…</span>\n </div>\n }\n </div>\n `,\n styles: [\n `\n :host {\n display: block;\n height: 100%;\n }\n\n .video-viewer {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .video-viewer__video {\n max-width: 100%;\n max-height: 100%;\n border-radius: 4px;\n background: var(--mj-bg-surface);\n }\n\n .video-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .video-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n `,\n ],\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'VideoArtifactViewerPlugin')\nexport class VideoArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit {\n private readonly fileService = inject(ArtifactFileService);\n private readonly cdr = inject(ChangeDetectorRef);\n\n public videoUrl = '';\n public errorMessage = '';\n\n /**\n * Inline-preview component for video artifacts ({@link IArtifactViewerPluginPreviewStatics}).\n * STATIC so the resolver reads it off the constructor without instantiating this DI-using component.\n */\n public static readonly PreviewComponentType: Type<IArtifactPreviewComponent> = VideoArtifactPreviewComponent;\n\n /** Matches video artifacts by type name or `video/*` MIME. STATIC — drives preview resolution. */\n public static CanHandlePreview(artifactTypeName: string, contentType?: string): boolean {\n const mime = (contentType ?? '').toLowerCase();\n if (mime.startsWith('video/')) {\n return true;\n }\n return (artifactTypeName ?? '').trim().toLowerCase() === 'video';\n }\n\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n async ngOnInit(): Promise<void> {\n try {\n if (this.artifactVersion?.ContentMode === 'File' && this.artifactVersion.ID) {\n this.videoUrl = await this.fileService.getDownloadUrl(this.artifactVersion.ID);\n } else {\n const content = this.artifactVersion?.Content;\n if (content) {\n this.videoUrl = content;\n } else {\n this.errorMessage = 'This artifact has no video content.';\n }\n }\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n this.errorMessage = `Could not load video: ${detail}`;\n }\n this.cdr.markForCheck();\n }\n\n public onMediaError(): void {\n this.errorMessage = 'The video could not be played. It may be corrupt or in an unsupported format.';\n this.videoUrl = '';\n this.cdr.markForCheck();\n }\n\n public override GetCurrentStateSnapshot(): DataSnapshot | null {\n if (!this.artifactVersion) {\n return null;\n }\n const snap = new DataSnapshot();\n snap.title = this.getDisplayTitle() ?? undefined;\n snap.interpretation = `Video (${this.artifactVersion.MimeType ?? 'video'}).`;\n snap.custom = {\n mimeType: this.artifactVersion.MimeType ?? undefined,\n fileName: this.artifactVersion.FileName ?? undefined,\n contentMode: this.artifactVersion.ContentMode,\n };\n return snap;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"video-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/video-artifact-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectorRef, Component, inject, OnInit, Type } from '@angular/core';\nimport { DataSnapshot } from '@memberjunction/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';\nimport { ArtifactFileService } from '../../services/artifact-file.service';\nimport { IArtifactPreviewComponent } from '../../interfaces/artifact-viewer-plugin.interface';\nimport { VideoArtifactPreviewComponent } from '../previews/video-artifact-preview.component';\nimport { MJMediaPlayerComponent, MediaTrack } from '@memberjunction/ng-media-player';\n\n/**\n * Minimal full-size viewer plugin for video artifacts. Renders a `<video controls>` player that\n * fills the panel. Supports both storage modes:\n * - `ContentMode === 'File'` — fetch a pre-auth URL from MJStorage via {@link ArtifactFileService}.\n * - `ContentMode === 'Text'` — `Content` is a `data:<mime>;base64,…` URI, bound directly.\n *\n * Deliberately minimal — the richer inline experience lives in {@link VideoArtifactPreviewComponent}\n * (exposed via {@link previewComponentType}); this just needs to satisfy the required `componentType`.\n */\n@Component({\n standalone: false,\n selector: 'mj-video-artifact-viewer',\n template: `\n <div class=\"video-viewer\" [ngClass]=\"cssClass\">\n @if (errorMessage) {\n <div class=\"video-viewer__state video-viewer__state--error\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n </div>\n } @else if (videoUrl) {\n <mj-media-player class=\"video-viewer__player\" [Tracks]=\"MediaTracks\" (Ended)=\"onMediaEnded()\"></mj-media-player>\n } @else {\n <div class=\"video-viewer__state\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading video…</span>\n </div>\n }\n </div>\n `,\n styles: [\n `\n :host {\n display: block;\n height: 100%;\n }\n\n .video-viewer {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n }\n\n .video-viewer__player {\n display: block;\n width: 100%;\n height: 100%;\n max-width: 100%;\n max-height: 100%;\n border-radius: 4px;\n background: var(--mj-bg-surface);\n }\n\n .video-viewer__state {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n }\n\n .video-viewer__state--error {\n color: var(--mj-status-error-text);\n }\n `,\n ],\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'VideoArtifactViewerPlugin')\nexport class VideoArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit {\n private readonly fileService = inject(ArtifactFileService);\n private readonly cdr = inject(ChangeDetectorRef);\n\n public videoUrl = '';\n public errorMessage = '';\n\n /**\n * Single-track input for the generic {@link MJMediaPlayerComponent}. Rebuilt whenever\n * {@link videoUrl} is (re)resolved via {@link setVideoUrl}; empty until a URL exists so the\n * player shows its own empty state.\n */\n public MediaTracks: MediaTrack[] = [];\n\n /** Set the resolved URL and recompute the single-element {@link MediaTracks} array in lockstep. */\n private setVideoUrl(url: string): void {\n this.videoUrl = url;\n this.MediaTracks = url\n ? [\n {\n Id: this.artifactVersion?.ID ?? 'video',\n Kind: 'video',\n Url: url,\n MimeType: this.artifactVersion?.MimeType ?? undefined,\n },\n ]\n : [];\n }\n\n /**\n * Inline-preview component for video artifacts ({@link IArtifactViewerPluginPreviewStatics}).\n * STATIC so the resolver reads it off the constructor without instantiating this DI-using component.\n */\n public static readonly PreviewComponentType: Type<IArtifactPreviewComponent> = VideoArtifactPreviewComponent;\n\n /** Matches video artifacts by type name or `video/*` MIME. STATIC — drives preview resolution. */\n public static CanHandlePreview(artifactTypeName: string, contentType?: string): boolean {\n const mime = (contentType ?? '').toLowerCase();\n if (mime.startsWith('video/')) {\n return true;\n }\n return (artifactTypeName ?? '').trim().toLowerCase() === 'video';\n }\n\n public override get hasDisplayContent(): boolean {\n return true;\n }\n\n async ngOnInit(): Promise<void> {\n try {\n if (this.artifactVersion?.ContentMode === 'File' && this.artifactVersion.ID) {\n this.setVideoUrl(await this.fileService.getDownloadUrl(this.artifactVersion.ID));\n } else {\n const content = this.artifactVersion?.Content;\n if (content) {\n this.setVideoUrl(content);\n } else {\n this.errorMessage = 'This artifact has no video content.';\n }\n }\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n this.errorMessage = `Could not load video: ${detail}`;\n }\n this.cdr.markForCheck();\n }\n\n public onMediaError(): void {\n this.errorMessage = 'The video could not be played. It may be corrupt or in an unsupported format.';\n this.setVideoUrl('');\n this.cdr.markForCheck();\n }\n\n /** Fired when the generic player reaches the end of the track. No-op affordance hook. */\n public onMediaEnded(): void {\n // Playback finished — nothing to persist for a one-shot artifact viewer.\n }\n\n public override GetCurrentStateSnapshot(): DataSnapshot | null {\n if (!this.artifactVersion) {\n return null;\n }\n const snap = new DataSnapshot();\n snap.title = this.getDisplayTitle() ?? undefined;\n snap.interpretation = `Video (${this.artifactVersion.MimeType ?? 'video'}).`;\n snap.custom = {\n mimeType: this.artifactVersion.MimeType ?? undefined,\n fileName: this.artifactVersion.FileName ?? undefined,\n contentMode: this.artifactVersion.ContentMode,\n };\n return snap;\n }\n}\n"]}
|
|
@@ -1,19 +1,33 @@
|
|
|
1
1
|
import { OnInit } from '@angular/core';
|
|
2
|
+
import { MediaTrack } from '@memberjunction/ng-media-player';
|
|
2
3
|
import { BaseArtifactPreviewComponent } from './base-artifact-preview.component';
|
|
3
4
|
import * as i0 from "@angular/core";
|
|
4
5
|
/**
|
|
5
|
-
* Inline preview for audio artifacts.
|
|
6
|
-
*
|
|
7
|
-
* controls does NOT open
|
|
6
|
+
* Inline preview for audio artifacts. Embeds the generic {@link MJMediaPlayerComponent}
|
|
7
|
+
* (`mj-media-player`) in a compact, thumbnail-sized configuration inside the conversation message
|
|
8
|
+
* card. Click events are stopped from propagating so using the transport controls does NOT open
|
|
9
|
+
* the full-size viewer.
|
|
10
|
+
*
|
|
11
|
+
* Compact gating: only play/pause + scrubber + time are shown. Transcript, waveform, speed,
|
|
12
|
+
* skip, volume and fullscreen chrome are turned OFF so the player reads cleanly at preview size.
|
|
8
13
|
*/
|
|
9
14
|
export declare class AudioArtifactPreviewComponent extends BaseArtifactPreviewComponent implements OnInit {
|
|
10
15
|
private readonly cdr;
|
|
11
|
-
/** Resolved URL
|
|
16
|
+
/** Resolved URL — data URI (inline) or pre-auth URL (file). Funneled through {@link setAudioUrl}. */
|
|
12
17
|
audioUrl: string;
|
|
13
18
|
/** Non-empty hides the player and shows a compact error line. */
|
|
14
19
|
errorMessage: string;
|
|
20
|
+
/**
|
|
21
|
+
* Single-track input for the generic {@link MJMediaPlayerComponent}. Rebuilt in lockstep with
|
|
22
|
+
* {@link audioUrl} via {@link setAudioUrl}; `[]` until a URL exists so the player shows its empty state.
|
|
23
|
+
*/
|
|
24
|
+
MediaTracks: MediaTrack[];
|
|
25
|
+
/** Set the resolved URL and recompute the single-element {@link MediaTracks} array in lockstep. */
|
|
26
|
+
private setAudioUrl;
|
|
15
27
|
ngOnInit(): Promise<void>;
|
|
16
28
|
onMediaError(): void;
|
|
29
|
+
/** Fired when the generic player reaches the end of the track. No-op affordance hook. */
|
|
30
|
+
onMediaEnded(): void;
|
|
17
31
|
static ɵfac: i0.ɵɵFactoryDeclaration<AudioArtifactPreviewComponent, never>;
|
|
18
32
|
static ɵcmp: i0.ɵɵComponentDeclaration<AudioArtifactPreviewComponent, "mj-audio-artifact-preview", never, {}, {}, never, never, false, never>;
|
|
19
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio-artifact-preview.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/previews/audio-artifact-preview.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,MAAM,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;;AAEjF
|
|
1
|
+
{"version":3,"file":"audio-artifact-preview.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/previews/audio-artifact-preview.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,MAAM,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;;AAEjF;;;;;;;;GAQG;AACH,qBAgDa,6BAA8B,SAAQ,4BAA6B,YAAW,MAAM;IAC7F,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IAEjD,qGAAqG;IAC9F,QAAQ,SAAM;IAErB,iEAAiE;IAC1D,YAAY,SAAM;IAEzB;;;OAGG;IACI,WAAW,EAAE,UAAU,EAAE,CAAM;IAEtC,mGAAmG;IACnG,OAAO,CAAC,WAAW;IAcb,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAcxB,YAAY,IAAI,IAAI;IAM3B,yFAAyF;IAClF,YAAY,IAAI,IAAI;yCAnDlB,6BAA6B;2CAA7B,6BAA6B;CAsDzC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ChangeDetectorRef, Component, inject } from '@angular/core';
|
|
2
2
|
import { BaseArtifactPreviewComponent } from './base-artifact-preview.component';
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "@memberjunction/ng-media-player";
|
|
4
5
|
function AudioArtifactPreviewComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
5
6
|
i0.ɵɵelementStart(0, "div", 0);
|
|
6
7
|
i0.ɵɵelement(1, "i", 2);
|
|
@@ -14,29 +15,52 @@ function AudioArtifactPreviewComponent_Conditional_0_Template(rf, ctx) { if (rf
|
|
|
14
15
|
} }
|
|
15
16
|
function AudioArtifactPreviewComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
16
17
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
17
|
-
i0.ɵɵelementStart(0, "
|
|
18
|
-
i0.ɵɵlistener("click", function
|
|
18
|
+
i0.ɵɵelementStart(0, "mj-media-player", 3);
|
|
19
|
+
i0.ɵɵlistener("click", function AudioArtifactPreviewComponent_Conditional_1_Template_mj_media_player_click_0_listener($event) { i0.ɵɵrestoreView(_r2); return i0.ɵɵresetView($event.stopPropagation()); })("Ended", function AudioArtifactPreviewComponent_Conditional_1_Template_mj_media_player_Ended_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onMediaEnded()); });
|
|
19
20
|
i0.ɵɵelementEnd();
|
|
20
21
|
} if (rf & 2) {
|
|
21
22
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
22
|
-
i0.ɵɵproperty("
|
|
23
|
+
i0.ɵɵproperty("Tracks", ctx_r0.MediaTracks)("ShowTranscript", false)("ShowTranscriptToggle", false)("ShowWaveform", false)("ShowSpeedControl", false)("ShowSkipControls", false)("ShowVolume", false)("ShowFullscreen", false);
|
|
23
24
|
} }
|
|
24
25
|
/**
|
|
25
|
-
* Inline preview for audio artifacts.
|
|
26
|
-
*
|
|
27
|
-
* controls does NOT open
|
|
26
|
+
* Inline preview for audio artifacts. Embeds the generic {@link MJMediaPlayerComponent}
|
|
27
|
+
* (`mj-media-player`) in a compact, thumbnail-sized configuration inside the conversation message
|
|
28
|
+
* card. Click events are stopped from propagating so using the transport controls does NOT open
|
|
29
|
+
* the full-size viewer.
|
|
30
|
+
*
|
|
31
|
+
* Compact gating: only play/pause + scrubber + time are shown. Transcript, waveform, speed,
|
|
32
|
+
* skip, volume and fullscreen chrome are turned OFF so the player reads cleanly at preview size.
|
|
28
33
|
*/
|
|
29
34
|
export class AudioArtifactPreviewComponent extends BaseArtifactPreviewComponent {
|
|
30
35
|
cdr = inject(ChangeDetectorRef);
|
|
31
|
-
/** Resolved URL
|
|
36
|
+
/** Resolved URL — data URI (inline) or pre-auth URL (file). Funneled through {@link setAudioUrl}. */
|
|
32
37
|
audioUrl = '';
|
|
33
38
|
/** Non-empty hides the player and shows a compact error line. */
|
|
34
39
|
errorMessage = '';
|
|
40
|
+
/**
|
|
41
|
+
* Single-track input for the generic {@link MJMediaPlayerComponent}. Rebuilt in lockstep with
|
|
42
|
+
* {@link audioUrl} via {@link setAudioUrl}; `[]` until a URL exists so the player shows its empty state.
|
|
43
|
+
*/
|
|
44
|
+
MediaTracks = [];
|
|
45
|
+
/** Set the resolved URL and recompute the single-element {@link MediaTracks} array in lockstep. */
|
|
46
|
+
setAudioUrl(url) {
|
|
47
|
+
this.audioUrl = url;
|
|
48
|
+
this.MediaTracks = url
|
|
49
|
+
? [
|
|
50
|
+
{
|
|
51
|
+
Id: this.artifactVersion?.ID ?? 'audio',
|
|
52
|
+
Kind: 'audio',
|
|
53
|
+
Url: url,
|
|
54
|
+
MimeType: this.artifactVersion?.MimeType ?? undefined,
|
|
55
|
+
},
|
|
56
|
+
]
|
|
57
|
+
: [];
|
|
58
|
+
}
|
|
35
59
|
async ngOnInit() {
|
|
36
60
|
try {
|
|
37
61
|
const url = await this.resolveContentUrl();
|
|
38
62
|
if (url) {
|
|
39
|
-
this.
|
|
63
|
+
this.setAudioUrl(url);
|
|
40
64
|
}
|
|
41
65
|
else {
|
|
42
66
|
this.errorMessage = 'No audio content.';
|
|
@@ -49,15 +73,19 @@ export class AudioArtifactPreviewComponent extends BaseArtifactPreviewComponent
|
|
|
49
73
|
}
|
|
50
74
|
onMediaError() {
|
|
51
75
|
this.errorMessage = 'Audio could not be played.';
|
|
52
|
-
this.
|
|
76
|
+
this.setAudioUrl('');
|
|
53
77
|
this.cdr.markForCheck();
|
|
54
78
|
}
|
|
79
|
+
/** Fired when the generic player reaches the end of the track. No-op affordance hook. */
|
|
80
|
+
onMediaEnded() {
|
|
81
|
+
// Playback finished — nothing to persist for an inline preview.
|
|
82
|
+
}
|
|
55
83
|
static ɵfac = /*@__PURE__*/ (() => { let ɵAudioArtifactPreviewComponent_BaseFactory; return function AudioArtifactPreviewComponent_Factory(__ngFactoryType__) { return (ɵAudioArtifactPreviewComponent_BaseFactory || (ɵAudioArtifactPreviewComponent_BaseFactory = i0.ɵɵgetInheritedFactory(AudioArtifactPreviewComponent)))(__ngFactoryType__ || AudioArtifactPreviewComponent); }; })();
|
|
56
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AudioArtifactPreviewComponent, selectors: [["mj-audio-artifact-preview"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 2, vars: 1, consts: [[1, "audio-preview", "audio-preview--error"], ["
|
|
57
|
-
i0.ɵɵconditionalCreate(0, AudioArtifactPreviewComponent_Conditional_0_Template, 4, 1, "div", 0)(1, AudioArtifactPreviewComponent_Conditional_1_Template, 1,
|
|
84
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AudioArtifactPreviewComponent, selectors: [["mj-audio-artifact-preview"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 2, vars: 1, consts: [[1, "audio-preview", "audio-preview--error"], [1, "audio-preview__player", 3, "Tracks", "ShowTranscript", "ShowTranscriptToggle", "ShowWaveform", "ShowSpeedControl", "ShowSkipControls", "ShowVolume", "ShowFullscreen"], [1, "fa-solid", "fa-music"], [1, "audio-preview__player", 3, "click", "Ended", "Tracks", "ShowTranscript", "ShowTranscriptToggle", "ShowWaveform", "ShowSpeedControl", "ShowSkipControls", "ShowVolume", "ShowFullscreen"]], template: function AudioArtifactPreviewComponent_Template(rf, ctx) { if (rf & 1) {
|
|
85
|
+
i0.ɵɵconditionalCreate(0, AudioArtifactPreviewComponent_Conditional_0_Template, 4, 1, "div", 0)(1, AudioArtifactPreviewComponent_Conditional_1_Template, 1, 8, "mj-media-player", 1);
|
|
58
86
|
} if (rf & 2) {
|
|
59
87
|
i0.ɵɵconditional(ctx.errorMessage ? 0 : ctx.audioUrl ? 1 : -1);
|
|
60
|
-
} }, styles: ["[_nghost-%COMP%] {\n display: block;\n }\n\n .audio-
|
|
88
|
+
} }, dependencies: [i1.MJMediaPlayerComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n }\n\n .audio-preview__player[_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n max-width: 100%;\n }\n\n .audio-preview--error[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n color: var(--mj-text-muted);\n font-size: 13px;\n }"] });
|
|
61
89
|
}
|
|
62
90
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AudioArtifactPreviewComponent, [{
|
|
63
91
|
type: Component,
|
|
@@ -68,16 +96,21 @@ export class AudioArtifactPreviewComponent extends BaseArtifactPreviewComponent
|
|
|
68
96
|
<span>{{ errorMessage }}</span>
|
|
69
97
|
</div>
|
|
70
98
|
} @else if (audioUrl) {
|
|
71
|
-
<
|
|
72
|
-
class="audio-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
[
|
|
99
|
+
<mj-media-player
|
|
100
|
+
class="audio-preview__player"
|
|
101
|
+
[Tracks]="MediaTracks"
|
|
102
|
+
[ShowTranscript]="false"
|
|
103
|
+
[ShowTranscriptToggle]="false"
|
|
104
|
+
[ShowWaveform]="false"
|
|
105
|
+
[ShowSpeedControl]="false"
|
|
106
|
+
[ShowSkipControls]="false"
|
|
107
|
+
[ShowVolume]="false"
|
|
108
|
+
[ShowFullscreen]="false"
|
|
76
109
|
(click)="$event.stopPropagation()"
|
|
77
|
-
(
|
|
78
|
-
></
|
|
110
|
+
(Ended)="onMediaEnded()"
|
|
111
|
+
></mj-media-player>
|
|
79
112
|
}
|
|
80
|
-
`, styles: ["\n :host {\n display: block;\n }\n\n .audio-
|
|
113
|
+
`, styles: ["\n :host {\n display: block;\n }\n\n .audio-preview__player {\n display: block;\n width: 100%;\n max-width: 100%;\n }\n\n .audio-preview--error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n color: var(--mj-text-muted);\n font-size: 13px;\n }\n "] }]
|
|
81
114
|
}], null, null); })();
|
|
82
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AudioArtifactPreviewComponent, { className: "AudioArtifactPreviewComponent", filePath: "src/lib/components/previews/audio-artifact-preview.component.ts", lineNumber:
|
|
115
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AudioArtifactPreviewComponent, { className: "AudioArtifactPreviewComponent", filePath: "src/lib/components/previews/audio-artifact-preview.component.ts", lineNumber: 62 }); })();
|
|
83
116
|
//# sourceMappingURL=audio-artifact-preview.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio-artifact-preview.component.js","sourceRoot":"","sources":["../../../../src/lib/components/previews/audio-artifact-preview.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,EAAU,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"audio-artifact-preview.component.js","sourceRoot":"","sources":["../../../../src/lib/components/previews/audio-artifact-preview.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,EAAU,MAAM,eAAe,CAAC;AAE7E,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;;;;IAgBrE,8BAAgD;IAC5C,uBAAiC;IACjC,4BAAM;IAAA,YAAkB;IAC5B,AAD4B,iBAAO,EAC7B;;;IADI,eAAkB;IAAlB,yCAAkB;;;;IAG5B,0CAYC;IADG,AADA,6KAAS,wBAAwB,KAAC,6LACzB,qBAAc,KAAC;IAC3B,iBAAkB;;;IAHf,AADA,AADA,AADA,AADA,AADA,AADA,AADA,2CAAsB,yBACE,+BACM,uBACR,2BACI,2BACA,qBACN,yBACI;;AA5BxC;;;;;;;;GAQG;AAiDH,MAAM,OAAO,6BAA8B,SAAQ,4BAA4B;IAC1D,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAEjD,qGAAqG;IAC9F,QAAQ,GAAG,EAAE,CAAC;IAErB,iEAAiE;IAC1D,YAAY,GAAG,EAAE,CAAC;IAEzB;;;OAGG;IACI,WAAW,GAAiB,EAAE,CAAC;IAEtC,mGAAmG;IAC3F,WAAW,CAAC,GAAW;QAC3B,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;QACpB,IAAI,CAAC,WAAW,GAAG,GAAG;YAClB,CAAC,CAAC;gBACI;oBACI,EAAE,EAAE,IAAI,CAAC,eAAe,EAAE,EAAE,IAAI,OAAO;oBACvC,IAAI,EAAE,OAAO;oBACb,GAAG,EAAE,GAAG;oBACR,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,IAAI,SAAS;iBACxD;aACJ;YACH,CAAC,CAAC,EAAE,CAAC;IACb,CAAC;IAED,KAAK,CAAC,QAAQ;QACV,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3C,IAAI,GAAG,EAAE,CAAC;gBACN,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACJ,IAAI,CAAC,YAAY,GAAG,mBAAmB,CAAC;YAC5C,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACL,IAAI,CAAC,YAAY,GAAG,uBAAuB,CAAC;QAChD,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC5B,CAAC;IAEM,YAAY;QACf,IAAI,CAAC,YAAY,GAAG,4BAA4B,CAAC;QACjD,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC5B,CAAC;IAED,yFAAyF;IAClF,YAAY;QACf,gEAAgE;IACpE,CAAC;iSArDQ,6BAA6B,yBAA7B,6BAA6B;6DAA7B,6BAA6B;YAvChC,AALF,+FAAoB,qFAKG;;YALvB,8DAmBC;;;iFAyBI,6BAA6B;cAhDzC,SAAS;6BACM,KAAK,YACP,2BAA2B,YAC3B;;;;;;;;;;;;;;;;;;;;;KAqBT;;kFAwBQ,6BAA6B","sourcesContent":["import { ChangeDetectorRef, Component, inject, OnInit } from '@angular/core';\nimport { MediaTrack } from '@memberjunction/ng-media-player';\nimport { BaseArtifactPreviewComponent } from './base-artifact-preview.component';\n\n/**\n * Inline preview for audio artifacts. Embeds the generic {@link MJMediaPlayerComponent}\n * (`mj-media-player`) in a compact, thumbnail-sized configuration inside the conversation message\n * card. Click events are stopped from propagating so using the transport controls does NOT open\n * the full-size viewer.\n *\n * Compact gating: only play/pause + scrubber + time are shown. Transcript, waveform, speed,\n * skip, volume and fullscreen chrome are turned OFF so the player reads cleanly at preview size.\n */\n@Component({\n standalone: false,\n selector: 'mj-audio-artifact-preview',\n template: `\n @if (errorMessage) {\n <div class=\"audio-preview audio-preview--error\">\n <i class=\"fa-solid fa-music\"></i>\n <span>{{ errorMessage }}</span>\n </div>\n } @else if (audioUrl) {\n <mj-media-player\n class=\"audio-preview__player\"\n [Tracks]=\"MediaTracks\"\n [ShowTranscript]=\"false\"\n [ShowTranscriptToggle]=\"false\"\n [ShowWaveform]=\"false\"\n [ShowSpeedControl]=\"false\"\n [ShowSkipControls]=\"false\"\n [ShowVolume]=\"false\"\n [ShowFullscreen]=\"false\"\n (click)=\"$event.stopPropagation()\"\n (Ended)=\"onMediaEnded()\"\n ></mj-media-player>\n }\n `,\n styles: [\n `\n :host {\n display: block;\n }\n\n .audio-preview__player {\n display: block;\n width: 100%;\n max-width: 100%;\n }\n\n .audio-preview--error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n color: var(--mj-text-muted);\n font-size: 13px;\n }\n `,\n ],\n})\nexport class AudioArtifactPreviewComponent extends BaseArtifactPreviewComponent implements OnInit {\n private readonly cdr = inject(ChangeDetectorRef);\n\n /** Resolved URL — data URI (inline) or pre-auth URL (file). Funneled through {@link setAudioUrl}. */\n public audioUrl = '';\n\n /** Non-empty hides the player and shows a compact error line. */\n public errorMessage = '';\n\n /**\n * Single-track input for the generic {@link MJMediaPlayerComponent}. Rebuilt in lockstep with\n * {@link audioUrl} via {@link setAudioUrl}; `[]` until a URL exists so the player shows its empty state.\n */\n public MediaTracks: MediaTrack[] = [];\n\n /** Set the resolved URL and recompute the single-element {@link MediaTracks} array in lockstep. */\n private setAudioUrl(url: string): void {\n this.audioUrl = url;\n this.MediaTracks = url\n ? [\n {\n Id: this.artifactVersion?.ID ?? 'audio',\n Kind: 'audio',\n Url: url,\n MimeType: this.artifactVersion?.MimeType ?? undefined,\n },\n ]\n : [];\n }\n\n async ngOnInit(): Promise<void> {\n try {\n const url = await this.resolveContentUrl();\n if (url) {\n this.setAudioUrl(url);\n } else {\n this.errorMessage = 'No audio content.';\n }\n } catch {\n this.errorMessage = 'Could not load audio.';\n }\n this.cdr.markForCheck();\n }\n\n public onMediaError(): void {\n this.errorMessage = 'Audio could not be played.';\n this.setAudioUrl('');\n this.cdr.markForCheck();\n }\n\n /** Fired when the generic player reaches the end of the track. No-op affordance hook. */\n public onMediaEnded(): void {\n // Playback finished — nothing to persist for an inline preview.\n }\n}\n"]}
|
|
@@ -1,20 +1,34 @@
|
|
|
1
1
|
import { OnInit } from '@angular/core';
|
|
2
|
+
import { MediaTrack } from '@memberjunction/ng-media-player';
|
|
2
3
|
import { BaseArtifactPreviewComponent } from './base-artifact-preview.component';
|
|
3
4
|
import * as i0 from "@angular/core";
|
|
4
5
|
/**
|
|
5
|
-
* Inline preview for video artifacts.
|
|
6
|
-
*
|
|
7
|
-
* propagating so scrubbing / play-pause does
|
|
8
|
-
* regions still open it).
|
|
6
|
+
* Inline preview for video artifacts. Embeds the generic {@link MJMediaPlayerComponent}
|
|
7
|
+
* (`mj-media-player`) in a compact, thumbnail-sized configuration inside the conversation message
|
|
8
|
+
* card. Click events on the player are stopped from propagating so scrubbing / play-pause does
|
|
9
|
+
* NOT open the full-size viewer (the card's other regions still open it).
|
|
10
|
+
*
|
|
11
|
+
* Compact gating: play/pause + scrubber + time (and fullscreen, which is handy for a tiny video
|
|
12
|
+
* surface) are shown. Transcript, waveform, speed, skip and volume chrome are turned OFF so the
|
|
13
|
+
* player reads cleanly at preview size and doesn't crowd the card.
|
|
9
14
|
*/
|
|
10
15
|
export declare class VideoArtifactPreviewComponent extends BaseArtifactPreviewComponent implements OnInit {
|
|
11
16
|
private readonly cdr;
|
|
12
|
-
/** Resolved URL
|
|
17
|
+
/** Resolved URL — data URI (inline) or pre-auth URL (file). Funneled through {@link setVideoUrl}. */
|
|
13
18
|
videoUrl: string;
|
|
14
19
|
/** Non-empty hides the player and shows a compact error line. */
|
|
15
20
|
errorMessage: string;
|
|
21
|
+
/**
|
|
22
|
+
* Single-track input for the generic {@link MJMediaPlayerComponent}. Rebuilt in lockstep with
|
|
23
|
+
* {@link videoUrl} via {@link setVideoUrl}; `[]` until a URL exists so the player shows its empty state.
|
|
24
|
+
*/
|
|
25
|
+
MediaTracks: MediaTrack[];
|
|
26
|
+
/** Set the resolved URL and recompute the single-element {@link MediaTracks} array in lockstep. */
|
|
27
|
+
private setVideoUrl;
|
|
16
28
|
ngOnInit(): Promise<void>;
|
|
17
29
|
onMediaError(): void;
|
|
30
|
+
/** Fired when the generic player reaches the end of the track. No-op affordance hook. */
|
|
31
|
+
onMediaEnded(): void;
|
|
18
32
|
static ɵfac: i0.ɵɵFactoryDeclaration<VideoArtifactPreviewComponent, never>;
|
|
19
33
|
static ɵcmp: i0.ɵɵComponentDeclaration<VideoArtifactPreviewComponent, "mj-video-artifact-preview", never, {}, {}, never, never, false, never>;
|
|
20
34
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video-artifact-preview.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/previews/video-artifact-preview.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,MAAM,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;;AAEjF
|
|
1
|
+
{"version":3,"file":"video-artifact-preview.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/previews/video-artifact-preview.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,MAAM,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;;AAEjF;;;;;;;;;GASG;AACH,qBAqDa,6BAA8B,SAAQ,4BAA6B,YAAW,MAAM;IAC7F,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IAEjD,qGAAqG;IAC9F,QAAQ,SAAM;IAErB,iEAAiE;IAC1D,YAAY,SAAM;IAEzB;;;OAGG;IACI,WAAW,EAAE,UAAU,EAAE,CAAM;IAEtC,mGAAmG;IACnG,OAAO,CAAC,WAAW;IAcb,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAcxB,YAAY,IAAI,IAAI;IAM3B,yFAAyF;IAClF,YAAY,IAAI,IAAI;yCAnDlB,6BAA6B;2CAA7B,6BAA6B;CAsDzC"}
|