mattrguerra/meridian-ops-boardmainPrivate on GitHub, published here in full

preview-own-list.ts

Language TypeScript3.1 KB88 lines

scripts/preview-own-list.ts

  1. /**
  2. * Render one person's board with their private list stamped in, to a file.
  3. *
  4. * `pnpm dashboard` writes the COMPANY_VIEWER page, which has no
  5. * My Day card and therefore no private list, so the one command that renders a
  6. * page without credentials cannot show this feature at all. Without something
  7. * like this, the only way to look at the card is to deploy.
  8. *
  9. * It is a preview, not a test. The numbers are fixtures and the lines below are
  10. * invented; nothing here reads or writes a real store, and it never touches D1.
  11. * The tests are what pin behaviour.
  12. *
  13. * pnpm preview:own-list [email] [state]
  14. * state: ok (default) | empty | failed | unconfigured
  15. */
  16. import { writeFile } from 'node:fs/promises'
  17. import { FIXTURE_SNAPSHOT } from '../apps/dashboard/src/fixtures.js'
  18. import { headline } from '../apps/dashboard/src/collect.js'
  19. import { render } from '../apps/dashboard/src/render.js'
  20. import { viewerFor } from '../apps/dashboard/src/viewer.js'
  21. import {
  22. ownListBlock,
  23. stampOwnList,
  24. type OwnItem,
  25. type OwnStore,
  26. } from '../apps/dashboard/src/own-list-view.js'
  27. const email = process.argv[2] ?? 'hello@meridiandisplay.example'
  28. const which = process.argv[3] ?? 'ok'
  29. const viewer = viewerFor(email)
  30. if (!viewer.person) {
  31. console.error(`${email} is not on the roster, so there is no private list to preview.`)
  32. process.exit(1)
  33. }
  34. const now = new Date()
  35. const day = (offset: number): string => {
  36. const d = new Date(now)
  37. d.setDate(d.getDate() + offset)
  38. return d.toISOString().slice(0, 10)
  39. }
  40. let id = 0
  41. const line = (over: Partial<OwnItem>): OwnItem => ({
  42. id: ++id,
  43. text: '',
  44. due: null,
  45. priority: 'normal',
  46. linkKey: null,
  47. createdAt: now.toISOString(),
  48. updatedAt: now.toISOString(),
  49. edits: 0,
  50. doneAt: null,
  51. ...over,
  52. })
  53. const sample: OwnStore = {
  54. state: 'ok',
  55. person: viewer.person.name,
  56. open: [
  57. line({ text: 'Call the school booster club back about the 10 ft feather flag', due: day(-4), priority: 'high', linkKey: 'order:MD2639582' }),
  58. line({ text: 'Send Rafael the revised backdrop dimensions', due: day(0) }),
  59. line({ text: 'Chase the vinyl supplier on the January quote', due: day(3), linkKey: 'task:41837' }),
  60. line({ text: 'Reorder the sample kit', priority: 'low' }),
  61. ],
  62. done: [line({ text: 'Approved the tabletop banner proof', doneAt: new Date(now.getTime() - 86_400_000).toISOString() })],
  63. truncated: false,
  64. doneHidden: 3,
  65. }
  66. const stores: Record<string, OwnStore> = {
  67. ok: sample,
  68. empty: { state: 'ok', person: viewer.person.name, open: [], done: [], truncated: false, doneHidden: 0 },
  69. failed: { state: 'failed', error: 'D1_ERROR: no such table: own_item' },
  70. unconfigured: { state: 'unconfigured' },
  71. }
  72. const store = stores[which]
  73. if (!store) {
  74. console.error(`unknown state "${which}": try ok, empty, failed or unconfigured`)
  75. process.exit(1)
  76. }
  77. const page = render(FIXTURE_SNAPSHOT, headline(FIXTURE_SNAPSHOT), [], day(0), null, viewer)
  78. const out = new URL('../own-list-preview.html', import.meta.url)
  79. await writeFile(out, stampOwnList(page, ownListBlock(viewer, store, now)), 'utf8')
  80. console.log(`Wrote ${out.pathname}: ${viewer.person.name}, store: ${which}`)