@mintplayer/ng-spark 22.23.0 → 22.25.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.
Files changed (71) hide show
  1. package/README.md +196 -0
  2. package/fesm2022/mintplayer-ng-spark-attribute-description.mjs +100 -47
  3. package/fesm2022/mintplayer-ng-spark-attribute-description.mjs.map +1 -1
  4. package/fesm2022/mintplayer-ng-spark-client-operations.mjs +310 -329
  5. package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
  6. package/fesm2022/mintplayer-ng-spark-column-filter.mjs +175 -135
  7. package/fesm2022/mintplayer-ng-spark-column-filter.mjs.map +1 -1
  8. package/fesm2022/mintplayer-ng-spark-contributions.mjs +721 -0
  9. package/fesm2022/mintplayer-ng-spark-contributions.mjs.map +1 -0
  10. package/fesm2022/mintplayer-ng-spark-grid.mjs +2385 -1118
  11. package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
  12. package/fesm2022/mintplayer-ng-spark-history.mjs +598 -0
  13. package/fesm2022/mintplayer-ng-spark-history.mjs.map +1 -0
  14. package/fesm2022/mintplayer-ng-spark-icon.mjs +64 -27
  15. package/fesm2022/mintplayer-ng-spark-icon.mjs.map +1 -1
  16. package/fesm2022/mintplayer-ng-spark-models.mjs +405 -762
  17. package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
  18. package/fesm2022/mintplayer-ng-spark-moderation.mjs +1212 -0
  19. package/fesm2022/mintplayer-ng-spark-moderation.mjs.map +1 -0
  20. package/fesm2022/mintplayer-ng-spark-panels.mjs +60 -0
  21. package/fesm2022/mintplayer-ng-spark-panels.mjs.map +1 -0
  22. package/fesm2022/mintplayer-ng-spark-pipes.mjs +1158 -765
  23. package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -1
  24. package/fesm2022/mintplayer-ng-spark-po-create.mjs +273 -169
  25. package/fesm2022/mintplayer-ng-spark-po-create.mjs.map +1 -1
  26. package/fesm2022/mintplayer-ng-spark-po-detail.mjs +795 -410
  27. package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
  28. package/fesm2022/mintplayer-ng-spark-po-edit.mjs +1196 -280
  29. package/fesm2022/mintplayer-ng-spark-po-edit.mjs.map +1 -1
  30. package/fesm2022/mintplayer-ng-spark-po-form.mjs +2244 -1224
  31. package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
  32. package/fesm2022/mintplayer-ng-spark-query-list.mjs +571 -303
  33. package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
  34. package/fesm2022/mintplayer-ng-spark-renderers.mjs +44 -55
  35. package/fesm2022/mintplayer-ng-spark-renderers.mjs.map +1 -1
  36. package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +216 -177
  37. package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs.map +1 -1
  38. package/fesm2022/mintplayer-ng-spark-routes.mjs +24 -28
  39. package/fesm2022/mintplayer-ng-spark-routes.mjs.map +1 -1
  40. package/fesm2022/mintplayer-ng-spark-services.mjs +625 -640
  41. package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
  42. package/fesm2022/mintplayer-ng-spark-shell.mjs +1031 -397
  43. package/fesm2022/mintplayer-ng-spark-shell.mjs.map +1 -1
  44. package/fesm2022/mintplayer-ng-spark-soft-delete.mjs +294 -0
  45. package/fesm2022/mintplayer-ng-spark-soft-delete.mjs.map +1 -0
  46. package/fesm2022/mintplayer-ng-spark.mjs +14 -48
  47. package/fesm2022/mintplayer-ng-spark.mjs.map +1 -1
  48. package/package.json +23 -2
  49. package/types/mintplayer-ng-spark-attribute-description.d.ts +25 -18
  50. package/types/mintplayer-ng-spark-client-operations.d.ts +139 -160
  51. package/types/mintplayer-ng-spark-column-filter.d.ts +73 -55
  52. package/types/mintplayer-ng-spark-contributions.d.ts +231 -0
  53. package/types/mintplayer-ng-spark-grid.d.ts +917 -448
  54. package/types/mintplayer-ng-spark-history.d.ts +216 -0
  55. package/types/mintplayer-ng-spark-icon.d.ts +15 -13
  56. package/types/mintplayer-ng-spark-models.d.ts +681 -573
  57. package/types/mintplayer-ng-spark-moderation.d.ts +402 -0
  58. package/types/mintplayer-ng-spark-panels.d.ts +143 -0
  59. package/types/mintplayer-ng-spark-pipes.d.ts +131 -149
  60. package/types/mintplayer-ng-spark-po-create.d.ts +46 -37
  61. package/types/mintplayer-ng-spark-po-detail.d.ts +180 -117
  62. package/types/mintplayer-ng-spark-po-edit.d.ts +367 -64
  63. package/types/mintplayer-ng-spark-po-form.d.ts +558 -373
  64. package/types/mintplayer-ng-spark-query-list.d.ts +143 -82
  65. package/types/mintplayer-ng-spark-renderers.d.ts +121 -85
  66. package/types/mintplayer-ng-spark-retry-action-modal.d.ts +31 -34
  67. package/types/mintplayer-ng-spark-routes.d.ts +7 -11
  68. package/types/mintplayer-ng-spark-services.d.ts +377 -261
  69. package/types/mintplayer-ng-spark-shell.d.ts +228 -132
  70. package/types/mintplayer-ng-spark-soft-delete.d.ts +90 -0
  71. package/types/mintplayer-ng-spark.d.ts +19 -12
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mintplayer-ng-spark-contributions.mjs","names":[],"sources":["../../contributions/src/line-diff.ts","../../contributions/src/spark-line-diff.component.ts","../../contributions/src/spark-contribution-attribution.component.ts","../../contributions/src/spark-revert-contribution.ts","../../contributions/src/provide-spark-contributions.ts"],"sourcesContent":["/** One line of a line diff: unchanged, only in the new text, or only in the old one. */\nexport interface SparkDiffLine {\n kind: 'same' | 'added' | 'removed';\n text: string;\n}\n\n/** Above this many cells (old lines × new lines) the LCS table is not built; see {@link lineDiff}. */\nconst MAX_CELLS = 4_000_000;\n\n/** Splits a text into lines (`\\r\\n`, `\\r` and `\\n` alike); an empty or absent text has none. */\nexport function splitLines(text: string | null | undefined): string[] {\n if (text === null || text === undefined || text === '') return [];\n return String(text).split(/\\r\\n|\\r|\\n/);\n}\n\n/**\n * A line diff of `newText` against `oldText`: the longest common subsequence of their lines kept as\n * `same`, everything else `removed` (old) or `added` (new), in reading order — at a change, the old\n * lines come before the new ones. Pure, no dependency.\n *\n * Beyond {@link MAX_CELLS} cells (thousands of lines on both sides) the common prefix and suffix are\n * still matched, and the middle is reported as removed-then-added rather than building a huge table.\n */\nexport function lineDiff(oldText: string | null | undefined, newText: string | null | undefined): SparkDiffLine[] {\n const a = splitLines(oldText);\n const b = splitLines(newText);\n\n // Common prefix and suffix first: most edits touch a few lines, and this keeps the table small.\n let start = 0;\n while (start < a.length && start < b.length && a[start] === b[start]) start++;\n let endA = a.length;\n let endB = b.length;\n while (endA > start && endB > start && a[endA - 1] === b[endB - 1]) { endA--; endB--; }\n\n const head: SparkDiffLine[] = a.slice(0, start).map(text => ({ kind: 'same', text }));\n const tail: SparkDiffLine[] = a.slice(endA).map(text => ({ kind: 'same', text }));\n const midA = a.slice(start, endA);\n const midB = b.slice(start, endB);\n\n return [...head, ...diffMiddle(midA, midB), ...tail];\n}\n\nfunction diffMiddle(a: string[], b: string[]): SparkDiffLine[] {\n const n = a.length;\n const m = b.length;\n if (n === 0) return b.map(text => ({ kind: 'added', text }));\n if (m === 0) return a.map(text => ({ kind: 'removed', text }));\n if (n * m > MAX_CELLS) {\n return [...a.map(text => ({ kind: 'removed' as const, text })), ...b.map(text => ({ kind: 'added' as const, text }))];\n }\n\n // lcs[i][j] = LCS length of a[i..] and b[j..], flattened row-major with a (m+1) stride.\n const stride = m + 1;\n const lcs = new Uint32Array((n + 1) * stride);\n for (let i = n - 1; i >= 0; i--) {\n for (let j = m - 1; j >= 0; j--) {\n lcs[i * stride + j] = a[i] === b[j]\n ? lcs[(i + 1) * stride + j + 1] + 1\n : Math.max(lcs[(i + 1) * stride + j], lcs[i * stride + j + 1]);\n }\n }\n\n const result: SparkDiffLine[] = [];\n let i = 0;\n let j = 0;\n while (i < n && j < m) {\n if (a[i] === b[j]) {\n result.push({ kind: 'same', text: a[i] });\n i++; j++;\n } else if (lcs[(i + 1) * stride + j] >= lcs[i * stride + j + 1]) {\n result.push({ kind: 'removed', text: a[i++] });\n } else {\n result.push({ kind: 'added', text: b[j++] });\n }\n }\n while (i < n) result.push({ kind: 'removed', text: a[i++] });\n while (j < m) result.push({ kind: 'added', text: b[j++] });\n return result;\n}\n\n/** Whether a diff changes anything. */\nexport function diffHasChanges(lines: readonly SparkDiffLine[]): boolean {\n return lines.some(l => l.kind !== 'same');\n}\n","import { ChangeDetectionStrategy, Component, computed, effect, inject, input, signal, untracked } from '@angular/core';\nimport { EntityAttributeDefinition, PersistentObject, PersistentObjectAttribute } from '@mintplayer/ng-spark/models';\nimport { SparkService } from '@mintplayer/ng-spark/services';\nimport { TranslateKeyPipe } from '@mintplayer/ng-spark/pipes';\nimport { SparkDiffLine, diffHasChanges, lineDiff } from './line-diff';\n\n/**\n * Where the `lineDiff` renderer finds the text to compare with — its `rendererOptions`:\n *\n * - `compareType`: the model name (or alias, or id) of the object to load;\n * - its id: `compareIdAttribute` (an attribute of this object holding it), or\n * `compareIdPattern` + `compareIdReplacement` (a regular expression and replacement applied to this\n * object's id);\n * - `compareAttribute`: the attribute of that object holding the text — or, for an AsDetail list, the\n * list, with `compareRowKeyPattern` + `compareRowKeyReplacement` (deriving the row key from this\n * object's id) and `compareRowAttribute` (the text on the row); for a single AsDetail object,\n * `compareRowAttribute` alone.\n *\n * Contributions seeds these on a generated contribution type's text values, comparing against the\n * target's row of the same slot (the current version).\n */\nexport interface SparkLineDiffSource {\n type: string;\n id: string;\n attribute: string;\n rowKey?: string;\n rowAttribute?: string;\n}\n\n/** The comparison source for `item`, or null when the options do not describe one. */\nexport function lineDiffSourceOf(options: Record<string, any> | null | undefined, item: PersistentObject | null | undefined): SparkLineDiffSource | null {\n if (!options || !item) return null;\n const type = asText(options['compareType']);\n const attribute = asText(options['compareAttribute']);\n if (!type || !attribute) return null;\n\n const idAttribute = asText(options['compareIdAttribute']);\n const id = idAttribute\n ? asText(item.attributes?.find(a => a.name === idAttribute)?.value)\n : derive(item.id, options['compareIdPattern'], options['compareIdReplacement']);\n if (!id) return null;\n\n const rowKeyPattern = options['compareRowKeyPattern'];\n const rowKey = rowKeyPattern !== undefined ? derive(item.id, rowKeyPattern, options['compareRowKeyReplacement']) : undefined;\n if (rowKeyPattern !== undefined && rowKey === null) return null;\n const rowAttribute = asText(options['compareRowAttribute']) ?? undefined;\n return { type, id, attribute, ...(rowKey !== undefined && rowKey !== null ? { rowKey } : {}), ...(rowAttribute ? { rowAttribute } : {}) };\n}\n\n/** The text at `source` in the loaded object, or null when it is not there (or not readable). */\nexport function lineDiffTextOf(po: PersistentObject | null | undefined, source: SparkLineDiffSource): string | null {\n const attribute = po?.attributes?.find(a => a.name === source.attribute);\n if (!attribute) return null;\n if (source.rowKey !== undefined) {\n const row = attribute.objects?.find(o => o.id === source.rowKey);\n // No row for the slot: there is no current version (all hidden) — compare with nothing.\n if (!row) return '';\n return valueText(row.attributes?.find(a => a.name === source.rowAttribute));\n }\n if (source.rowAttribute && attribute.object !== undefined) {\n return attribute.object ? valueText(attribute.object.attributes?.find(a => a.name === source.rowAttribute)) : '';\n }\n return valueText(attribute);\n}\n\nfunction valueText(attribute: PersistentObjectAttribute | undefined): string | null {\n if (!attribute) return null;\n const value = attribute.value;\n return value === null || value === undefined ? '' : String(value);\n}\n\nfunction asText(value: unknown): string | null {\n return typeof value === 'string' && value !== '' ? value : null;\n}\n\nfunction derive(id: string | undefined, pattern: unknown, replacement: unknown): string | null {\n if (!id || typeof pattern !== 'string') return null;\n let regex: RegExp;\n try { regex = new RegExp(pattern); } catch { return null; }\n if (!regex.test(id)) return null;\n return id.replace(regex, typeof replacement === 'string' ? replacement : '');\n}\n\n/**\n * The generic `lineDiff` detail renderer: this attribute's text, diffed line by line against a text\n * elsewhere ({@link SparkLineDiffSource}) — added lines marked `+`, removed ones `−`. When the other\n * object cannot be read (no right, gone), the text is shown as it is, with a note.\n *\n * Register through `sparkContributionRenderers` (or on its own: `{ name: 'lineDiff', detailComponent:\n * SparkLineDiffComponent }`).\n */\n@Component({\n selector: 'spark-line-diff',\n imports: [TranslateKeyPipe],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @switch (state()) {\n @case ('loading') {\n <pre class=\"spark-line-diff-plain mb-0\">{{ text() }}</pre>\n }\n @case ('diff') {\n @if (changed()) {\n <div class=\"spark-line-diff\" role=\"table\" [attr.aria-label]=\"attribute()?.name\">\n @for (line of lines(); track $index) {\n <div role=\"row\" [class]=\"'spark-line-diff-line spark-line-diff-' + line.kind\">\n <span class=\"spark-line-diff-marker\" role=\"cell\"\n [attr.aria-label]=\"line.kind === 'added' ? ('common.diffAdded' | t) : line.kind === 'removed' ? ('common.diffRemoved' | t) : null\">{{ marker(line) }}</span>\n <span class=\"spark-line-diff-text\" role=\"cell\">{{ line.text }}</span>\n </div>\n }\n </div>\n } @else {\n <pre class=\"spark-line-diff-plain mb-1\">{{ text() }}</pre>\n <div class=\"small text-muted spark-line-diff-identical\">{{ 'common.diffIdentical' | t }}</div>\n }\n }\n @default {\n <pre class=\"spark-line-diff-plain mb-1\">{{ text() }}</pre>\n <div class=\"small text-muted spark-line-diff-unavailable\">{{ 'common.diffUnavailable' | t }}</div>\n }\n }\n `,\n styles: [`\n :host { display: block; }\n .spark-line-diff-plain { white-space: pre-wrap; font-family: inherit; }\n .spark-line-diff { font-family: var(--bs-font-monospace, monospace); font-size: .875em; border: 1px solid var(--bs-border-color, #dee2e6); border-radius: var(--bs-border-radius, .375rem); overflow-x: auto; }\n .spark-line-diff-line { display: flex; white-space: pre-wrap; }\n .spark-line-diff-marker { flex: 0 0 1.5rem; text-align: center; user-select: none; color: var(--bs-secondary-color, #6c757d); }\n .spark-line-diff-text { flex: 1 1 auto; min-width: 0; padding-right: .5rem; }\n .spark-line-diff-added { background: var(--bs-success-bg-subtle, #d1e7dd); color: var(--bs-success-text-emphasis, #0a3622); }\n .spark-line-diff-removed { background: var(--bs-danger-bg-subtle, #f8d7da); color: var(--bs-danger-text-emphasis, #58151c); text-decoration: line-through; }\n `],\n})\nexport class SparkLineDiffComponent {\n private readonly spark = inject(SparkService);\n\n value = input<any>();\n attribute = input<EntityAttributeDefinition | undefined>();\n options = input<Record<string, any> | undefined>();\n item = input<PersistentObject | undefined>();\n\n protected readonly text = computed(() => {\n const value = this.value();\n return value === null || value === undefined ? '' : String(value);\n });\n\n /** The compared text: undefined while loading, null when it could not be read. */\n private readonly compared = signal<string | null | undefined>(undefined);\n\n protected readonly state = computed<'loading' | 'diff' | 'unavailable'>(() => {\n const compared = this.compared();\n return compared === undefined ? 'loading' : compared === null ? 'unavailable' : 'diff';\n });\n\n protected readonly lines = computed<SparkDiffLine[]>(() => lineDiff(this.compared() ?? '', this.text()));\n protected readonly changed = computed(() => diffHasChanges(this.lines()));\n\n private generation = 0;\n\n constructor() {\n effect(() => {\n const source = lineDiffSourceOf(this.options(), this.item());\n untracked(() => void this.load(source));\n });\n }\n\n protected marker(line: SparkDiffLine): string {\n return line.kind === 'added' ? '+' : line.kind === 'removed' ? '−' : ' ';\n }\n\n private async load(source: SparkLineDiffSource | null): Promise<void> {\n const generation = ++this.generation;\n if (!source) { this.compared.set(null); return; }\n this.compared.set(undefined);\n try {\n const type = await this.typeIdOf(source.type);\n const po = await this.spark.get(type, source.id);\n if (generation === this.generation) this.compared.set(lineDiffTextOf(po, source));\n } catch {\n if (generation === this.generation) this.compared.set(null);\n }\n }\n\n /** The entity type id for a model name or alias (the load endpoint is keyed by the type's id). */\n private async typeIdOf(type: string): Promise<string> {\n const types = await this.spark.getEntityTypes();\n return types.find(t => t.name === type || t.alias === type || t.id === type)?.id ?? type;\n }\n}\n","import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { RouterLink } from '@angular/router';\nimport { SparkLanguageService } from '@mintplayer/ng-spark/services';\n\n/** The `rendererOptions` Contributions writes on each attribution attribute (library README, \"Client contract\"). */\nexport interface SparkContributionAttributionOptions {\n /** The generated contributions query's alias (`songlyricscontributions`). */\n contributionsQuery: string;\n /** The target's model name: the query's `parentType` (`Song`). */\n targetType: string;\n /** The `[Contribution]` property (`Lyrics`). */\n property: string;\n /** The slot attributes, in id order: one column filter each (`Language`, `Script`). */\n slots: string[];\n /** The attribution attributes the row carries: `ContributorName`, `UpdatedAt`, `ContributionCount`. */\n attribution: string[];\n}\n\n/** The History link of a row: `/query/{contributionsQuery}?parentId=…&parentType=…&{slot}=…`. */\nexport interface SparkContributionHistoryLink {\n commands: string[];\n queryParams: Record<string, string>;\n}\n\n/** The History link for `row` of the object `ownerId`, or null when either is missing. */\nexport function contributionHistoryLink(\n options: Partial<SparkContributionAttributionOptions> | null | undefined,\n row: Record<string, any> | null | undefined,\n ownerId: string | null | undefined,\n): SparkContributionHistoryLink | null {\n if (!options?.contributionsQuery || !options.targetType || !ownerId || !row) return null;\n const queryParams: Record<string, string> = { parentId: ownerId, parentType: options.targetType };\n for (const slot of options.slots ?? []) {\n const value = row[slot];\n if (value === null || value === undefined || value === '') return null; // an unsaved row has no history yet\n queryParams[slot] = String(value);\n }\n return { commands: ['/query', options.contributionsQuery], queryParams };\n}\n\n/** \"3 days ago\" in `language`, from an ISO instant; null when it does not parse. */\nexport function relativeTime(value: unknown, language: string, now: number = Date.now()): string | null {\n if (typeof value !== 'string' && !(value instanceof Date)) return null;\n const time = new Date(value).getTime();\n if (Number.isNaN(time)) return null;\n const seconds = Math.round((time - now) / 1000);\n const units: [Intl.RelativeTimeFormatUnit, number][] = [\n ['year', 365 * 24 * 3600], ['month', 30 * 24 * 3600], ['week', 7 * 24 * 3600],\n ['day', 24 * 3600], ['hour', 3600], ['minute', 60],\n ];\n let format: Intl.RelativeTimeFormat;\n try { format = new Intl.RelativeTimeFormat(language, { numeric: 'auto' }); }\n catch { format = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }); }\n for (const [unit, size] of units) {\n if (Math.abs(seconds) >= size) return format.format(Math.round(seconds / size), unit);\n }\n return format.format(seconds, 'second');\n}\n\n/**\n * The `contributionAttribution` AsDetail **row** renderer (contributions PRD Q6): one line under a\n * row — \"by Alice · 3 days ago · History (4)\" — instead of three columns. Only the parts the\n * declaration asked for (`rendererOptions.attribution`) and that the row has; History links to the\n * slot's contributions query (`/query/{contributionsQuery}` with the parent and one filter per slot).\n */\n@Component({\n selector: 'spark-contribution-attribution',\n imports: [RouterLink],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @if (parts().length) {\n <span class=\"spark-contribution-attribution small text-muted\">\n @for (part of parts(); track part.kind; let last = $last) {\n @switch (part.kind) {\n @case ('by') { <span class=\"spark-contribution-by\">{{ part.text }}</span> }\n @case ('at') { <time class=\"spark-contribution-at\" [attr.datetime]=\"part.iso\" [attr.title]=\"part.title\">{{ part.text }}</time> }\n @case ('history') {\n @if (historyLink(); as link) {\n <a class=\"spark-contribution-history\" [routerLink]=\"link.commands\" [queryParams]=\"link.queryParams\">{{ part.text }}</a>\n } @else {\n <span class=\"spark-contribution-history\">{{ part.text }}</span>\n }\n }\n }\n @if (!last) { <span aria-hidden=\"true\"> · </span> }\n }\n </span>\n }\n `,\n})\nexport class SparkContributionAttributionComponent {\n private readonly lang = inject(SparkLanguageService);\n\n row = input<Record<string, any>>({});\n options = input<Record<string, any> | undefined>();\n ownerId = input<string | undefined>();\n\n private readonly asked = computed(() => new Set<string>(this.options()?.['attribution'] ?? ['ContributorName', 'UpdatedAt', 'ContributionCount']));\n\n protected readonly historyLink = computed(() =>\n contributionHistoryLink(this.options() as Partial<SparkContributionAttributionOptions> | undefined, this.row(), this.ownerId()));\n\n protected readonly parts = computed(() => {\n const row = this.row() ?? {};\n const asked = this.asked();\n const language = this.lang.language();\n const parts: { kind: 'by' | 'at' | 'history'; text: string; iso?: string; title?: string }[] = [];\n\n const name = row['ContributorName'];\n if (asked.has('ContributorName') && typeof name === 'string' && name.trim() !== '')\n parts.push({ kind: 'by', text: this.lang.t('contributions.by').replace('{name}', name) });\n\n const at = row['UpdatedAt'];\n const relative = asked.has('UpdatedAt') ? relativeTime(at, language) : null;\n if (relative) {\n const date = new Date(at);\n parts.push({ kind: 'at', text: relative, iso: date.toISOString(), title: date.toLocaleString(language) });\n }\n\n const count = row['ContributionCount'];\n if (asked.has('ContributionCount') && typeof count === 'number')\n parts.push({ kind: 'history', text: this.lang.t('contributions.history').replace('{count}', String(count)) });\n\n return parts;\n });\n}\n","import { ChangeDetectionStrategy, Component, computed, effect, inject, input, signal, untracked } from '@angular/core';\nimport { HttpErrorResponse } from '@angular/common/http';\nimport { SparkQuery } from '@mintplayer/ng-spark/models';\nimport { SparkLanguageService, SparkService } from '@mintplayer/ng-spark/services';\nimport { TranslateKeyPipe } from '@mintplayer/ng-spark/pipes';\nimport { SparkDetailContext, SparkQueryRowAction } from '@mintplayer/ng-spark/panels';\n\n/** The source of every generated `{Target}{Property}Contributions` query (`ContributionDescriptor.ContributionsQueryMethod`). */\nexport const SPARK_CONTRIBUTIONS_QUERY_SOURCE = 'Custom.SparkContributionsOfTarget';\n\n/** `POST /spark/po/revert-contribution` (the Contributions server package). */\nexport const SPARK_REVERT_CONTRIBUTION_PATH = '/po/revert-contribution';\n\n/** Whether `query` is a generated contributions query (its rows are contributions). */\nexport function isContributionsQuery(query: Pick<SparkQuery, 'source'> | null | undefined): boolean {\n return query?.source === SPARK_CONTRIBUTIONS_QUERY_SOURCE;\n}\n\n/**\n * Makes a contribution current again: every newer visible version of its slot is hidden (reason\n * `reverted`), atomically, by the server. The response's notice (\"…newer version(s) were hidden\") is\n * dispatched like every operation. Rejects with the server's error (400 \"restore it first\" for a\n * hidden one, 404 without the right).\n */\nexport async function revertContribution(spark: SparkService, objectTypeId: string, id: string): Promise<void> {\n await spark.postEnvelope(SPARK_REVERT_CONTRIBUTION_PATH, { objectTypeId, id });\n}\n\n/**\n * \"Revert to this version\" in the row menu of a contributions query — for holders of\n * `RevertContribution/{type}`, outside the recycle bin. Asks first; refreshes the list afterwards.\n */\nexport const sparkRevertContributionRowAction: SparkQueryRowAction = {\n id: 'spark-revert-contribution',\n labelKey: 'contributions.revert',\n priority: 20,\n isOffered: scope => scope.permissions?.canRevertContribution === true\n && isContributionsQuery(scope.query)\n && scope.deleted !== 'only',\n run: async context => {\n const spark = inject(SparkService);\n const lang = inject(SparkLanguageService);\n if (!confirm(lang.t('contributions.confirmRevert'))) return;\n await revertContribution(spark, context.entityType.id, context.row.id);\n context.reload();\n },\n};\n\n/**\n * \"Revert to this version\" on a contribution's detail page (a `SPARK_DETAIL_ACTIONS` entry): shown for\n * `RevertContribution/{type}` holders on a generated contribution type (one that has the generated\n * contributions query), outside the recycle bin. Reloads the page afterwards.\n */\n@Component({\n selector: 'spark-revert-contribution',\n imports: [TranslateKeyPipe],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @if (offered()) {\n <span class=\"d-inline-flex gap-2 align-items-center\">\n <button type=\"button\" class=\"btn btn-outline-primary spark-revert-contribution\" [disabled]=\"busy()\" (click)=\"revert()\">\n {{ 'contributions.revert' | t }}\n </button>\n @if (error(); as message) {\n <span class=\"text-danger small spark-revert-contribution-error\" role=\"alert\">{{ message }}</span>\n }\n </span>\n }\n `,\n})\nexport class SparkRevertContributionComponent {\n private readonly spark = inject(SparkService);\n private readonly lang = inject(SparkLanguageService);\n\n context = input.required<SparkDetailContext>();\n\n /** Whether the type is a generated contribution type: it has the generated contributions query. */\n private readonly isContributionType = signal(false);\n\n protected readonly offered = computed(() => {\n const ctx = this.context();\n return this.isContributionType() && ctx.permissions?.canRevertContribution === true && ctx.deleted !== 'only';\n });\n\n protected readonly busy = signal(false);\n protected readonly error = signal<string | null>(null);\n\n constructor() {\n effect(() => {\n const ctx = this.context();\n // Asked only of a caller who holds the right — everyone else never sees the button anyway.\n if (ctx.permissions?.canRevertContribution !== true || !ctx.entityType?.name) {\n untracked(() => this.isContributionType.set(false));\n return;\n }\n const name = ctx.entityType.name;\n untracked(() => void this.spark.getQueryByName(`${name}s`)\n .then(query => this.isContributionType.set(isContributionsQuery(query) && query?.entityType === name))\n .catch(() => this.isContributionType.set(false)));\n });\n }\n\n async revert(): Promise<void> {\n if (this.busy()) return;\n if (!confirm(this.lang.t('contributions.confirmRevert'))) return;\n const ctx = this.context();\n this.busy.set(true);\n this.error.set(null);\n try {\n await revertContribution(this.spark, ctx.entityType.id, ctx.id);\n await ctx.reload();\n } catch (e) {\n const err = e as HttpErrorResponse;\n const first = err?.error?.result?.errors?.[0];\n const validation = typeof first?.errorMessage === 'string' ? first.errorMessage\n : first?.errorMessage ? this.lang.resolve(first.errorMessage) : '';\n this.error.set(validation || err?.error?.result?.error || err?.error?.error || this.lang.t('common.actionFailed'));\n } finally {\n this.busy.set(false);\n }\n }\n}\n","import { Provider } from '@angular/core';\nimport { SparkAttributeRendererRegistration } from '@mintplayer/ng-spark/renderers';\nimport { provideSparkDetailActions, provideSparkQueryRowActions } from '@mintplayer/ng-spark/panels';\nimport { SparkContributionAttributionComponent } from './spark-contribution-attribution.component';\nimport { SparkLineDiffComponent } from './spark-line-diff.component';\nimport { SparkRevertContributionComponent, sparkRevertContributionRowAction } from './spark-revert-contribution';\n\n/**\n * Adds the Contributions UI to the pages `sparkRoutes()` routes to — no routes of its own (PRD Q7):\n * \"Revert to this version\" in the contributions query's row menu and on a contribution's detail page.\n * Needs the server package `MintPlayer.Spark.Contributions`.\n *\n * ```ts\n * providers: [\n * provideSpark(...),\n * provideSparkContributions(),\n * provideSparkAttributeRenderers([...sparkContributionRenderers, ...yourRenderers]),\n * ]\n * ```\n *\n * The renderers are registered with the app's own, because `provideSparkAttributeRenderers` takes one\n * list: see {@link sparkContributionRenderers}.\n */\nexport function provideSparkContributions(options?: { detailActionPriority?: number }): Provider[] {\n return [\n ...provideSparkQueryRowActions(sparkRevertContributionRowAction),\n ...provideSparkDetailActions({ id: 'spark-revert-contribution', component: SparkRevertContributionComponent, priority: options?.detailActionPriority ?? 6 }),\n ];\n}\n\n/**\n * The two renderers the Contributions model names:\n *\n * - `contributionAttribution` — an AsDetail **row** renderer: \"by Alice · 3 days ago · History (4)\"\n * once per row, in place of the `ContributorName`/`UpdatedAt`/`ContributionCount` columns;\n * - `lineDiff` — a detail renderer, generic: a text diffed line by line against a text of another\n * object (Contributions seeds it on a contribution's text values, against the current version).\n */\nexport const sparkContributionRenderers: SparkAttributeRendererRegistration[] = [\n { name: 'contributionAttribution', rowComponent: SparkContributionAttributionComponent },\n { name: 'lineDiff', detailComponent: SparkLineDiffComponent },\n];\n"],"mappings":"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"}