@growth-labs/cms 0.7.0 → 0.8.1

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 (55) hide show
  1. package/dist/engine/fronts-publish-intent.d.ts +25 -1
  2. package/dist/engine/fronts-publish-intent.d.ts.map +1 -1
  3. package/dist/engine/fronts-publish-intent.js +64 -11
  4. package/dist/engine/fronts-publish-intent.js.map +1 -1
  5. package/dist/engine/index.d.ts +1 -0
  6. package/dist/engine/index.d.ts.map +1 -1
  7. package/dist/engine/index.js +1 -0
  8. package/dist/engine/index.js.map +1 -1
  9. package/dist/engine/video-source.d.ts +26 -0
  10. package/dist/engine/video-source.d.ts.map +1 -0
  11. package/dist/engine/video-source.js +31 -0
  12. package/dist/engine/video-source.js.map +1 -0
  13. package/dist/providers/types.d.ts +40 -3
  14. package/dist/providers/types.d.ts.map +1 -1
  15. package/dist/providers/types.js +17 -0
  16. package/dist/providers/types.js.map +1 -1
  17. package/dist/routes/calendar.d.ts +26 -0
  18. package/dist/routes/calendar.d.ts.map +1 -1
  19. package/dist/routes/calendar.js +41 -0
  20. package/dist/routes/calendar.js.map +1 -1
  21. package/dist/routes/content.d.ts +2 -0
  22. package/dist/routes/content.d.ts.map +1 -1
  23. package/dist/routes/content.js.map +1 -1
  24. package/dist/routes/fronts-publish.d.ts.map +1 -1
  25. package/dist/routes/fronts-publish.js +1 -0
  26. package/dist/routes/fronts-publish.js.map +1 -1
  27. package/dist/ui/api/_content-config.d.ts.map +1 -1
  28. package/dist/ui/api/_content-config.js +1 -0
  29. package/dist/ui/api/_content-config.js.map +1 -1
  30. package/dist/ui/api/calendar.d.ts.map +1 -1
  31. package/dist/ui/api/calendar.js +5 -1
  32. package/dist/ui/api/calendar.js.map +1 -1
  33. package/dist/ui/screens/CalendarScreen.d.ts.map +1 -1
  34. package/dist/ui/screens/CalendarScreen.js +10 -1
  35. package/dist/ui/screens/CalendarScreen.js.map +1 -1
  36. package/dist/ui/screens/calendar-data.d.ts +3 -0
  37. package/dist/ui/screens/calendar-data.d.ts.map +1 -1
  38. package/dist/ui/screens/calendar-data.js.map +1 -1
  39. package/dist/ui/screens/go-publish-badge.d.ts +11 -0
  40. package/dist/ui/screens/go-publish-badge.d.ts.map +1 -0
  41. package/dist/ui/screens/go-publish-badge.js +47 -0
  42. package/dist/ui/screens/go-publish-badge.js.map +1 -0
  43. package/package.json +1 -1
  44. package/src/engine/fronts-publish-intent.ts +104 -15
  45. package/src/engine/index.ts +5 -0
  46. package/src/engine/video-source.ts +45 -0
  47. package/src/providers/types.ts +51 -1
  48. package/src/routes/calendar.ts +72 -0
  49. package/src/routes/content.ts +2 -0
  50. package/src/routes/fronts-publish.ts +1 -0
  51. package/src/ui/api/_content-config.ts +2 -0
  52. package/src/ui/api/calendar.ts +5 -1
  53. package/src/ui/screens/CalendarScreen.tsx +22 -0
  54. package/src/ui/screens/calendar-data.ts +4 -0
  55. package/src/ui/screens/go-publish-badge.ts +55 -0
@@ -1,6 +1,7 @@
1
1
  // src/ui/api/calendar.ts — Astro endpoint adapter for GET /admin/api/calendar.
2
2
  // Maps the APIContext onto a RouteContext and delegates to createCalendarRoutes().month.
3
- // The calendar is first-party D1 (no provider injection needed).
3
+ // The calendar is first-party D1; the host's Foundry provider (locals.cmsHooks.foundryVideo)
4
+ // adds the Go publish badge state to scheduled media items when present (W1-08b).
4
5
 
5
6
  import type { APIContext } from 'astro'
6
7
  import { type CalendarRouteConfig, createCalendarRoutes } from '../../routes/calendar.js'
@@ -13,8 +14,11 @@ function toCtx(c: APIContext): RouteContext {
13
14
  }
14
15
 
15
16
  function calendarConfig(c: APIContext): CalendarRouteConfig {
17
+ const hooks = (c.locals as { cmsHooks?: { foundryVideo?: CalendarRouteConfig['foundryVideo'] } })
18
+ .cmsHooks
16
19
  return {
17
20
  authz: buildSiteAuthz(c),
21
+ foundryVideo: hooks?.foundryVideo,
18
22
  }
19
23
  }
20
24
 
@@ -18,6 +18,7 @@
18
18
  import { useCallback, useEffect, useReducer, useState } from 'react'
19
19
  import { Icon } from '../icons.js'
20
20
  import { buildCalendarMonth, type CalendarCell, type CalendarItem } from './calendar-data.js'
21
+ import { goPublishBadge } from './go-publish-badge.js'
21
22
 
22
23
  // ---------------------------------------------------------------------------
23
24
  // Props
@@ -483,6 +484,10 @@ function CalendarItemChip({
483
484
  const border = TYPE_COLOR[item.type] ?? 'var(--accent)'
484
485
  const statusIcon = STATUS_ICON[item.status]
485
486
  const statusColor = STATUS_ICON_COLOR[item.status] ?? 'var(--ink-faint)'
487
+ // W1-08b: the Go publish state of a scheduled media item, from the
488
+ // host's receipts (route: goPublish). Hover shows the receipt and the
489
+ // correlation id; the pill vocabulary is the Foundry tab's.
490
+ const badge = goPublishBadge(item.goPublish)
486
491
 
487
492
  return (
488
493
  <div
@@ -520,6 +525,23 @@ function CalendarItemChip({
520
525
  >
521
526
  {item.title || '(Untitled)'}
522
527
  </button>
528
+ {badge && (
529
+ <span
530
+ className={
531
+ badge.pill === 'ready'
532
+ ? 'pill published'
533
+ : badge.pill === 'failed'
534
+ ? 'pill review'
535
+ : 'pill processing'
536
+ }
537
+ title={badge.tooltip}
538
+ data-go-publish={item.goPublish?.state}
539
+ style={{ flex: 'none', fontSize: 9, padding: '1px 5px', whiteSpace: 'nowrap' }}
540
+ >
541
+ <span className="pdot" />
542
+ {badge.label}
543
+ </span>
544
+ )}
523
545
  {statusIcon &&
524
546
  (item.status === 'scheduled' ? (
525
547
  <button
@@ -13,6 +13,8 @@
13
13
  // Types
14
14
  // ---------------------------------------------------------------------------
15
15
 
16
+ import type { CalendarGoPublish } from '../../routes/calendar.js'
17
+
16
18
  /**
17
19
  * A dated content item as returned by the `/admin/api/calendar?from=&to=` route.
18
20
  * `date` is an ISO-8601 string (date-only or with time component, UTC-assumed).
@@ -24,6 +26,8 @@ export interface CalendarItem {
24
26
  slug: string
25
27
  title: string
26
28
  date: string
29
+ /** Go publish state of a scheduled video/podcast item (W1-08b); see go-publish-badge.ts. */
30
+ goPublish?: CalendarGoPublish | null
27
31
  }
28
32
 
29
33
  /** A leading blank cell before the first day of the month. */
@@ -0,0 +1,55 @@
1
+ // src/ui/screens/go-publish-badge.ts — pure badge model for a scheduled media
2
+ // item's Go publish state (W1-08b).
3
+ //
4
+ // goPublishBadge(goPublish) → { label, pill, tooltip } | null
5
+ // label — the word the chip shows ("Captured", "Processing", …)
6
+ // pill — the FoundryPillState bucket the broadsheet pill classes render
7
+ // (working / ready / failed), reused from foundry-stages
8
+ // tooltip — the hover text: label, the newest receipt and its time, the
9
+ // correlation id, and the blocked reason when there is one
10
+ //
11
+ // Pure — no DOM, no React, fully vitest-testable.
12
+
13
+ import type { CalendarGoPublish } from '../../routes/calendar.js'
14
+ import type { FoundryPillState } from '../inspector/foundry-stages.js'
15
+
16
+ export interface GoPublishBadge {
17
+ label: string
18
+ pill: FoundryPillState
19
+ tooltip: string
20
+ }
21
+
22
+ const LABELS: Record<string, { label: string; pill: FoundryPillState }> = {
23
+ pending: { label: 'Not captured', pill: 'working' },
24
+ captured: { label: 'Captured', pill: 'working' },
25
+ processing: { label: 'Processing', pill: 'working' },
26
+ media_ready: { label: 'Media ready', pill: 'ready' },
27
+ publishing: { label: 'Publishing', pill: 'working' },
28
+ published: { label: 'Published', pill: 'ready' },
29
+ late: { label: 'Late', pill: 'failed' },
30
+ failed: { label: 'Blocked', pill: 'failed' },
31
+ unavailable: { label: 'State unavailable', pill: 'failed' },
32
+ }
33
+
34
+ /** Format a unix-second receipt time for the tooltip (UTC, to the minute). */
35
+ export function formatReceiptTime(unixSeconds: number): string {
36
+ return `${new Date(unixSeconds * 1000).toISOString().slice(0, 16).replace('T', ' ')} UTC`
37
+ }
38
+
39
+ export function goPublishBadge(
40
+ goPublish: CalendarGoPublish | null | undefined,
41
+ ): GoPublishBadge | null {
42
+ if (!goPublish) return null
43
+ const entry = LABELS[goPublish.state] ?? { label: goPublish.state, pill: 'working' as const }
44
+ const lines = [`Go publish: ${entry.label}`]
45
+ if (goPublish.eventKind && goPublish.receiptAt !== null) {
46
+ lines.push(`Last receipt: ${goPublish.eventKind} at ${formatReceiptTime(goPublish.receiptAt)}`)
47
+ } else if (goPublish.eventKind) {
48
+ lines.push(`Last receipt: ${goPublish.eventKind}`)
49
+ } else {
50
+ lines.push('No receipt yet')
51
+ }
52
+ if (goPublish.correlationId) lines.push(`Correlation: ${goPublish.correlationId}`)
53
+ if (goPublish.blockedReason) lines.push(`Reason: ${goPublish.blockedReason}`)
54
+ return { label: entry.label, pill: entry.pill, tooltip: lines.join('\n') }
55
+ }