@emeryld/rrroutes-export 1.0.15 → 1.0.16

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@emeryld/rrroutes-export",
3
3
  "description": "Finalized leaves export helpers and CLI for RRRoutes",
4
- "version": "1.0.15",
4
+ "version": "1.0.16",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "main": "dist/index.cjs",
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>RRRoutes Export Viewer</title>
6
+ <title>RRRoutes Leaves Viewer</title>
7
7
  <style>
8
8
  :root {
9
9
  --bg: #212121;
@@ -170,6 +170,10 @@
170
170
  color: var(--accent);
171
171
  }
172
172
 
173
+ .route-changelog-summary-gray {
174
+ color: #c6c6c6;
175
+ }
176
+
173
177
  .leaf-content {
174
178
  display: grid;
175
179
  gap: 4px;
@@ -358,6 +362,18 @@
358
362
  font-family: inherit;
359
363
  }
360
364
 
365
+ .changelog-lines {
366
+ display: grid;
367
+ gap: 10px;
368
+ }
369
+
370
+ .changelog-line-item {
371
+ border-top: 1px solid var(--border);
372
+ padding: 10px 2px;
373
+ display: grid;
374
+ gap: 4px;
375
+ }
376
+
361
377
  .schema-block {
362
378
  border-top: 1px solid var(--border);
363
379
  padding: 8px 0 2px;
@@ -472,7 +488,7 @@
472
488
  </head>
473
489
  <body>
474
490
  <div class="wrap">
475
- <h1>RRRoutes Export Viewer</h1>
491
+ <h1 id="viewerHeading">RRRoutes Leaves Viewer</h1>
476
492
  <div class="card controls">
477
493
  <div class="primary-row">
478
494
  <label class="control-block">
@@ -746,6 +762,27 @@
746
762
  changelogSource: 'changelogSource',
747
763
  }
748
764
 
765
+ const VIEWER_MODE = {
766
+ leaves: 'leaves',
767
+ bundle: 'bundle',
768
+ changelog: 'changelog',
769
+ }
770
+
771
+ const VIEWER_MODE_META = {
772
+ [VIEWER_MODE.leaves]: {
773
+ title: 'RRRoutes Leaves Viewer',
774
+ heading: 'RRRoutes Leaves Viewer',
775
+ },
776
+ [VIEWER_MODE.bundle]: {
777
+ title: 'RRRoutes Bundle Viewer',
778
+ heading: 'RRRoutes Bundle Viewer',
779
+ },
780
+ [VIEWER_MODE.changelog]: {
781
+ title: 'RRRoutes Changelog Viewer',
782
+ heading: 'RRRoutes Changelog Viewer',
783
+ },
784
+ }
785
+
749
786
  const TAB_CONFIG = {
750
787
  [VIEW_IDS.leaves]: {
751
788
  fieldDefs: SEARCH_FIELDS,
@@ -767,6 +804,7 @@
767
804
  changelogPayload: null,
768
805
  leaves: [],
769
806
  activeTab: VIEW_IDS.leaves,
807
+ viewerMode: VIEWER_MODE.leaves,
770
808
  availableTabs: new Set([VIEW_IDS.leaves]),
771
809
  selectedFieldIdsByTab: {
772
810
  [VIEW_IDS.leaves]: new Set(TAB_CONFIG[VIEW_IDS.leaves].defaultSelected),
@@ -791,6 +829,7 @@
791
829
  const resetFiltersBtn = document.getElementById('resetFilters')
792
830
  const statusEl = document.getElementById('status')
793
831
  const resultsEl = document.getElementById('results')
832
+ const viewerHeadingEl = document.getElementById('viewerHeading')
794
833
  const controlsEl = document.querySelector('.controls')
795
834
  const tabLeavesBtn = document.getElementById('tabLeaves')
796
835
  const tabChangelogBtn = document.getElementById('tabChangelog')
@@ -799,6 +838,19 @@
799
838
  const URL_PARAM_KEY = 'filters'
800
839
  let isHydratingFromUrl = false
801
840
 
841
+ function resolveViewerMode(payload) {
842
+ if (isBundlePayload(payload)) return VIEWER_MODE.bundle
843
+ if (isChangelogPayload(payload)) return VIEWER_MODE.changelog
844
+ if (payload && Array.isArray(payload.leaves)) return VIEWER_MODE.leaves
845
+ return VIEWER_MODE.leaves
846
+ }
847
+
848
+ function applyViewerModeMeta() {
849
+ const meta = VIEWER_MODE_META[state.viewerMode] || VIEWER_MODE_META[VIEWER_MODE.leaves]
850
+ document.title = meta.title
851
+ if (viewerHeadingEl) viewerHeadingEl.textContent = meta.heading
852
+ }
853
+
802
854
  function escapeHtml(value) {
803
855
  return String(value)
804
856
  .replace(/&/g, '&amp;')
@@ -1442,6 +1494,9 @@
1442
1494
  '',
1443
1495
  `Route Changelog (${routeHistory.length} event${routeHistory.length === 1 ? '' : 's'})`,
1444
1496
  )
1497
+ if (state.viewerMode === VIEWER_MODE.bundle) {
1498
+ routeChangelogSummary.classList.add('route-changelog-summary-gray')
1499
+ }
1445
1500
  routeChangelogDetails.appendChild(routeChangelogSummary)
1446
1501
 
1447
1502
  const routeChangelogBody = el('div', 'leaf-content')
@@ -1559,6 +1614,47 @@
1559
1614
  return card
1560
1615
  }
1561
1616
 
1617
+ function buildCommitMetaLine(event, commitBySha) {
1618
+ const commit = commitBySha.get(event.commitSha)
1619
+ const commitDateTime = formatCommitDateTime(commit?.authorDate)
1620
+ return [
1621
+ event.commitSha.slice(0, 12),
1622
+ commitDateTime,
1623
+ commit?.authorName || null,
1624
+ commit?.subject || null,
1625
+ ]
1626
+ .filter(Boolean)
1627
+ .join(' - ')
1628
+ }
1629
+
1630
+ function renderChangelogEventLines(event, commitBySha, contextLabel) {
1631
+ const row = el('div', 'changelog-line-item')
1632
+ row.appendChild(el('div', 'meta', buildCommitMetaLine(event, commitBySha)))
1633
+ row.appendChild(el('div', 'mono', `${contextLabel} (${event.type})`))
1634
+
1635
+ if (Array.isArray(event.schemaDiff) && event.schemaDiff.length > 0) {
1636
+ event.schemaDiff.forEach((delta) => {
1637
+ const line = formatSchemaDiffLine(delta)
1638
+ if (!line) return
1639
+ row.appendChild(el('div', 'meta mono', line))
1640
+ })
1641
+ }
1642
+ if (Array.isArray(event.cfgDiff) && event.cfgDiff.length > 0) {
1643
+ event.cfgDiff.forEach((diff) => {
1644
+ const line = formatCfgDiffLine(diff)
1645
+ if (!line) return
1646
+ row.appendChild(el('div', 'meta mono', line))
1647
+ })
1648
+ }
1649
+ if (Array.isArray(event.impactedRoutes) && event.impactedRoutes.length > 0) {
1650
+ row.appendChild(
1651
+ el('div', 'meta mono', `impacted routes: ${event.impactedRoutes.join(', ')}`),
1652
+ )
1653
+ }
1654
+
1655
+ return row
1656
+ }
1657
+
1562
1658
  function buildChronologicalEvents(payload) {
1563
1659
  if (!payload) return []
1564
1660
  const commitBySha = new Map((payload.commits || []).map((commit) => [commit.sha, commit]))
@@ -1687,24 +1783,52 @@
1687
1783
  const commitBySha = new Map(
1688
1784
  (state.changelogPayload?.commits || []).map((commit) => [commit.sha, commit]),
1689
1785
  )
1690
- renderCollection(
1691
- filtered,
1692
- (item) => {
1693
- const details = el('details', 'leaf')
1694
- const title =
1695
- state.activeTab === VIEW_IDS.changelog
1696
- ? `${item.eventKind === 'route' ? `Route: ${item.routeKey}` : `Source: ${item.displayName || item.sourceObjectId}`} (${item.event.type})`
1697
- : `${item.displayName} (${item.events.length})`
1698
- details.appendChild(el('summary', '', title))
1699
- if (state.activeTab === VIEW_IDS.changelog) {
1700
- details.appendChild(renderEventCard(item.event, commitBySha))
1701
- } else {
1702
- item.events.forEach((event) => details.appendChild(renderEventCard(event, commitBySha)))
1703
- }
1704
- return details
1705
- },
1706
- 'No matches.',
1707
- )
1786
+ if (state.viewerMode === VIEWER_MODE.changelog) {
1787
+ renderCollection(
1788
+ filtered,
1789
+ (item) => {
1790
+ if (state.activeTab === VIEW_IDS.changelog) {
1791
+ const contextLabel =
1792
+ item.eventKind === 'route'
1793
+ ? `Route: ${item.routeKey}`
1794
+ : `Source: ${item.displayName || item.sourceObjectId}`
1795
+ return renderChangelogEventLines(item.event, commitBySha, contextLabel)
1796
+ }
1797
+
1798
+ const lines = el('div', 'changelog-lines')
1799
+ ;(item.events || []).forEach((event) => {
1800
+ lines.appendChild(
1801
+ renderChangelogEventLines(
1802
+ event,
1803
+ commitBySha,
1804
+ `Source: ${item.displayName || item.sourceId}`,
1805
+ ),
1806
+ )
1807
+ })
1808
+ return lines
1809
+ },
1810
+ 'No matches.',
1811
+ )
1812
+ } else {
1813
+ renderCollection(
1814
+ filtered,
1815
+ (item) => {
1816
+ const details = el('details', 'leaf')
1817
+ const title =
1818
+ state.activeTab === VIEW_IDS.changelog
1819
+ ? `${item.eventKind === 'route' ? `Route: ${item.routeKey}` : `Source: ${item.displayName || item.sourceObjectId}`} (${item.event.type})`
1820
+ : `${item.displayName} (${item.events.length})`
1821
+ details.appendChild(el('summary', '', title))
1822
+ if (state.activeTab === VIEW_IDS.changelog) {
1823
+ details.appendChild(renderEventCard(item.event, commitBySha))
1824
+ } else {
1825
+ item.events.forEach((event) => details.appendChild(renderEventCard(event, commitBySha)))
1826
+ }
1827
+ return details
1828
+ },
1829
+ 'No matches.',
1830
+ )
1831
+ }
1708
1832
  }
1709
1833
  syncFilterStateToUrl()
1710
1834
  }
@@ -1949,6 +2073,8 @@
1949
2073
  }
1950
2074
 
1951
2075
  function applyLoadedPayload(payload) {
2076
+ state.viewerMode = resolveViewerMode(payload)
2077
+ applyViewerModeMeta()
1952
2078
  state.payload = payload
1953
2079
  state.availableTabs = new Set()
1954
2080
  state.leavesPayload = null
@@ -2052,6 +2178,7 @@
2052
2178
  renderFieldChips()
2053
2179
  hydrateFilterStateFromUrl()
2054
2180
  initializeFromBakedPayload()
2181
+ applyViewerModeMeta()
2055
2182
  renderResults()
2056
2183
  </script>
2057
2184
  </body>