Repository navigation
Commit bf74607
feat(plugin-detail)!: a tab row under the record header; an open panel face is the active tab (#28394)
domain:ui#2 · os-tesla · session_01L9qibzGCEznLfiQm2T5icF
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoFyFEfkhs8RW6bDg2qQg8D2)_
Part of #27524
Clause-②: yes (narrowing)
Metadata-protocol: none
Skills-docs: none — the narrowing retires a ui component export and an
i18n key, not an author-writable metadata surface; `git grep` finds
neither `ArrangedRelatedTab` nor `detail.relatedEnlargedBack` under
`skills/`, `content/` or `docs/`.
## 维护者速读
-
改了什么:记录页头部底边多了一行常驻标签:「概览」、动态,再按读者的排列顺序列出每个关联面板,各带条数。能放几个由这一行自己的宽度算(窗口、侧栏、分屏拖宽都会重算),放不下的收进「+N
▾」,隐藏面板排在下拉末尾;当前标签永远在行上。放大视图就是当前标签:整宽列表画在标签行下面,头部不动,地址仍是
`?related=对象.字段`(动态是 `?related=timeline`),「概览」或 Esc 返回。
- 为什么改:#27524 的 Target 8、9(画布 60 定稿),四个串行 PR 中的第三个;顶栏在 PR ④。
- 风险与回滚:只动 ui 包(plugin-detail、app-shell、十个语言包)和文档。开页时现在给所有关联面板取条数,包括隐藏的和
⊟ 关掉时的(标签要显示条数),同一个计数缓存去重。退役了 `ArrangedRelatedTab` 导出和
`detail.relatedEnlargedBack` 一个键,只有控制台自己用过。回滚即 revert 本 PR。
- 先看:`ui/packages/plugin-detail/src/RecordTabRow.tsx` 与
`synth/recordTabRow.ts`(标签行和放几个的规则);`RecordPageColumns.tsx`(标签从哪来、当前标签面);app-shell
`RecordDetailView.tsx` 的 `openEnlargedRelated`(标签间切换替换历史)。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/plugin-detail/src/synth/__tests__/recordTabRow-27524.test.ts
packages/plugin-detail/src/__tests__/RecordTabRow-27524.test.tsx
packages/plugin-detail/src/__tests__/RecordPageColumns.tabRow-27524.test.tsx
packages/app-shell/src/views/RecordDetailView.recordTabRowUrl-27524.test.tsx`,预期
4 个文件、26 个测试全绿。
- 需要你做的:无,席位落地。
## What changes
Record page v4, Target items 8 and 9, PR ③ of the four serial PRs for
#27524. It is cut from `main` after PR ② (#28116, `3d2da4fd1a`) and
leaves `main` coherent on its own. The top bar (Target 7) is PR ④.
| Target item | Where |
|---|---|
| 1, 2, 3, 10, 11, 12 | PR ① (merged) |
| 4, 5, 6 | PR ② #28116 (merged) |
| 8 the tab row | **this PR** |
| 9 enlarged = the active tab | **this PR** |
| 7 the top bar (and ⊟ moving to it) | PR ④ |
**8. The tab row** (`RecordTabRow.tsx`, `synth/recordTabRow.ts`,
`RecordPageColumns.tsx`). A row at the bottom edge of the record header,
on every face the record is drawn in: the page, the split pane, the
overlay drawer, the maximized pane and a phone.
- The tabs are 「概览」, then 动态, then one tab per related panel in
`record.related.arrangement` order (`resolveRelatedArrangement`, the
order the right column draws). Each tab carries its count: 动态 the
stream's size, a related tab its list's count.
- The counts are one set. The page asks `useRelatedCounts` once for
every panel, hidden ones included, and hands the same counts to the
right column (`RelatedCardStack` takes a new optional `counts` prop and
then asks for none itself). 动态's count is the stream's own, reported by
the `record:activity` block through `RecordTimelinePanel`'s new `count`
/ `onCount` props in the peek face, and through
`RecordTimelineCountContext` on the 动态 tab while its chip is 全部.
- How many tabs show is computed from the row's own width. A
`ResizeObserver` on the row re-measures on every resize (window,
sidebar, a pane dragged wider), against a hidden measuring copy of every
tab and of the widest 「+N ▾」. The rule is the pure `layoutRecordTabRow`:
- every tab fits and no panel is hidden: all of them, no dropdown;
- otherwise the budget is the row less the trigger and one gap. 「概览」 and
the active tab are reserved, then tabs are taken in order until the
first that does not fit;
- 「概览」 and at least one more tab always show;
- the active tab is always on the row. When it would have folded it
takes the last slot, and the tab it displaced folds.
- 「+N ▾」 is a dropdown listing the folded tabs with their counts, then a
「已隐藏」 heading and the hidden panels' tabs. Choosing one opens it, and it
becomes the active tab.
- The row is a `tablist` named 「记录页签」 and a single tab stop: ← → Home
End move between the shown tabs, Enter or Space opens one.
- A body table opened in place (its ⤢ in the details) gets a tab of its
own while it is open.
- No row is drawn where the view gives no way to open a face
(`onEnlargeRelated` absent), or where there is nothing but 「概览」.
**9. The enlarged face is the active tab** (`RecordPageColumns.tsx`,
app-shell `RecordDetailView.tsx`).
- Choosing a tab, a panel's header or 「查看全部 N 条」 draws that panel's
whole face below the tab row at the page's full width. The header stays
as it is: no compaction, no modal, no drill-down, no path in the top
bar.
- The face is a `role="tabpanel"`. The ‹ back line and its own `h2` are
gone, because the tab names it. Esc (window capture, as in PR ②) and
「概览」 return to the page.
- The URL stays `?related=object.field`, `?related=timeline` for 动态.
Leaving 「概览」 pushes one history entry. Moving from tab to tab now
replaces that entry, keeping its state, so one Back, Esc or 「概览」 always
returns to the page. A deep link to a tab opens it as the active tab,
and 「概览」 then replaces the address, since there is nothing to pop.
- In the pane the face fills the pane body under the same row (no change
to `recordDrawerStack.tsx`; the pane draws the same view).
**Retired.**
- `ArrangedRelatedTab` (plugin-detail entry): it laid the reader's
arrangement over the 关联 tab of the tabbed tier that PR ② retired, and
only the console's record view imported it. Its full-face chrome path in
`RelatedList` (`arrangedFull`) and its scope branch in the
`record:related-list` renderer go with it. A page still drawn as its
strip is drawn as written.
- `detail.relatedEnlargedBack` leaves all ten packs.
**Arrives in ten packs:** `detail.recordTabs`,
`detail.recordTabOverview` (概览 · Overview · 概要 · 개요 · Übersicht · Aperçu
· Resumen · Visão geral · Обзор · نظرة عامة), `detail.recordTabsMore`
(with each pack's plural forms) and `detail.recordTabsHidden`.
**Declared.** `Clause-②: yes (narrowing)` (the claim said no; measured
on the diff, the retired export and the retired key narrow two published
surfaces). Two changesets:
- `27524-record-page-tab-row.md` (plugin-detail, app-shell):
`ArrangedRelatedTab` under `not-required (runtime-export-retired …)`
with its FROM → TO line.
- `27524-record-page-tab-row-i18n.md` (i18n): `TranslationKeys` loses
one key, under `not-required (runtime-interface-only
…#TranslationKeys)`, as PR ① and ② did.
**Reads at open.** A record open now counts every related panel, the
hidden ones and those behind ⊟ off included (before, only the panels on
screen), because their tabs show the counts. The requests are the same
`RelatedCountStore` count requests, deduplicated with the panels' own.
Nothing else a record open fetches changes. (Seat 2's #27627 / #28321
touches the data adapter; this PR does not.)
**File surface beyond the order.** `RelatedList.tsx` (the dead
`arrangedFull` path), `renderers/record-related-list.tsx` (the retired
scope branch), `index.tsx` (the export), `recordTimelineStream.ts` and
`renderers/record-activity.tsx` (动态's count, for its tab),
`RelatedCardStack.tsx` and `RecordTimelinePanel.tsx` (shared counts),
the plugin-detail README and `content/docs/ui/pages.mdx`.
`navigation-overlay.tsx` (#28294), the top bar (④) and #27545's split /
overlay / maximize mechanics are untouched.
## Tests
New:
- `plugin-detail/src/synth/__tests__/recordTabRow-27524.test.ts` (6):
the layout rule at a wide, a medium and a narrow width; the active tab
displacing the last tab, fitting beside them, or keeping its place; 「概览」
and the active tab at the narrowest; hidden panels forcing the dropdown
and taking the trigger's width.
- `plugin-detail/src/__tests__/RecordTabRow-27524.test.tsx` (7), with
given widths and a stub `ResizeObserver`: the shown count follows the
width and is recomputed on resize; the active tab is always on the row;
the count chips; 「+N ▾」 lists the folded tabs with counts, then the
hidden ones, and choosing one selects it; a hidden panel makes the
dropdown on a wide row; clicking; the keyboard (one tab stop, ← → Home
End).
- `plugin-detail/src/__tests__/RecordPageColumns.tabRow-27524.test.tsx`
(10), the real `RecordPageColumns`: the tabs in arrangement order with
hidden panels in the dropdown; counts for every panel from one request
each (hidden ones included) and 动态's from the stream; selecting a tab
and 「概览」; no row without a way to open; the stack tier; the enlarged
face keeps the header, is a `tabpanel` and draws no back line or title;
the 动态 face; a body table's tab; Esc.
- `app-shell/src/views/RecordDetailView.recordTabRowUrl-27524.test.tsx`
(3), a real `RecordDetailView` on the browser's own history: a tab
pushes one entry and tab to tab replaces it (three tabs visited, one
entry), 「概览」 returns; Esc and the browser's Back return in one step at
720; a deep link opens its tab and 「概览」 replaces the address without
growing history.
Rewritten to the new anatomy:
- `RecordDetailView.recordPageTiers-26678` (6): the page's only tablist
is its tab row on every tier and embedded (`overview, timeline,
showcase_task.project, showcase_note.project`), 「概览」 active;
`?related=timeline` makes 动态 the active tab.
- `RelatedCardStack-27055`: the enlarged face's back-button case reads
「概览」 and Esc; the `ArrangedRelatedTab` cases leave with the component.
- `RecordPageColumns.enlargedEscapeInPane-27524`: Esc is pressed on the
face, which no longer draws a back button to focus.
- `RelatedPanel.header-27524`: the case for the arranged full face (the
retired tabbed tier's 关联 tab) leaves with that face.
<details><summary>Ablations (each through <code>node
scripts/ablation-replace.mjs</code>, restore proven blob ==
HEAD)</summary>
- A1, the active tab's reservation removed from `layoutRecordTabRow`
(`chosen.add(active)`): `Tests 2 failed | 11 passed (13)`, the rule's
and the drawn row's "active tab always shown" cases.
- A2, hidden panels dropped from the page's count targets: `Tests 1
failed | 9 passed (10)`, "each panel tab carries its count — the hidden
ones counted too".
- A3, `openEnlargedRelated` pushing on every tab change (the replace
branch removed): `Tests 2 failed | 1 passed (3)`, the one-entry history
case and the Esc / Back case.
</details>
## Acceptance notes
- Target 8: the row is on every face (page, pane, drawer, phone), 「概览」
then 动态 then the panels in arrangement order with counts; the count of
shown tabs comes from the row's width with a `ResizeObserver`; the rest
in 「+N ▾」 with counts; the active tab always shown, in the last slot
when it would fold; 「概览」 plus at least one more always; hidden panels at
the dropdown's end.
- Target 9: the enlarged state is the active tab, the full-width list
under the row; `?related=object.field` / `?related=timeline`; Esc or
「概览」 returns; not a modal, not a drill-down, no top-bar path, the header
not compacted; in the pane it fills the pane body.
- Screenshots on `examples/app-crm`, not HotCRM, as in ① and ②. Ten
shots `*.png` in
`/mnt/project-files/ui-seat-2/r2026-10-31/out/27524-pr3-shots/` (project
files, not a repository branch), zh, through the console's dev server on
this branch:
- `page-1440` and `page-1200`: six tabs, no dropdown (概览 · 动态 · 活动列表 2 ·
联系人列表 1 · 线索列表 1 · 商机列表 4).
- `page-390`: 概览 · 动态 · 活动列表 · 联系人列表, then 「+2」; `page-390-more-open`:
the dropdown lists 线索列表 1 and 商机列表 4; `page-390-folded-active`: 商机列表
chosen from it takes the last slot (联系人列表 folds, still 「+2」) and its
list draws below.
- `page-1440-enlarged` (联系人列表 active), `page-1200-enlarged` (商机列表
active, every column), `page-1440-timeline` (`?related=timeline`, the
full stream with its chips).
- `pane-720` and `pane-720-enlarged`: the split pane beside the list
(row 623 px wide), all six tabs; switching tabs replaced the URL, Esc
returned to 「概览」 with the pane still open, and Back then closed the
pane.
- Proxy preview review against the v4 boards at `a7825499aa`
(RecordPageV4Enlarged, RecordDrawerV4Enlarged, and the rows on
RecordPageV4Panels / TwoCol / RecordDrawerV4Peek):
- Matches: the row's place (under the highlights, above the body),
height 36 px, 13 px labels, the active tab's primary underline, the 10.5
px count chip, 「+N ▾」 at the row's end, no title or back line on the
enlarged face, the header unchanged above it.
- Differs, noted and not changed here: the enlarged list keeps
`RelatedList`'s own card header (title, count, 新建) and its 查看全部 foot,
where the board draws a bare toolbar (filter, 全部 / 我的 / 逾期, 新建, 导出) over
a table filling the rest of the height. That toolbar is not something
the related list has today.
- On a deep link to another tab (`page-1440-enlarged`), 动态's tab has no
count until the stream is drawn once: its count is the stream's own
size, which only the stream reads.
- The 动态 count reads 0 in the shots because app-crm's Acme Corp has no
activity; the chip is drawn for a known 0.
## Known gaps
- The enlarged related list keeps `RelatedList`'s own card header
(title, count, 新建) and its 查看全部 foot. The v4 board (RecordPageV4Enlarged
/ RecordDrawerV4Enlarged at `a7825499aa`) draws a bare toolbar there
(filter, 全部 / 我的 / 逾期, 新建, 导出) over a table that fills the rest of the
height. The related list has no such toolbar today; this PR does not add
one.
- On a deep link to another tab, 动态's tab has no count until the stream
is drawn once (its count is the stream's own size).
## Verification
<details><summary>Tests, type-check and the derived gates on
572d6b1</summary>
Head `572d6b18fb`, change set vs the merge base `a878ff6c26`: 36 paths,
1,816 (+1,478 / −338) changed lines.
- Under the verify lock: `pnpm --dir ui exec vitest run
packages/plugin-detail packages/i18n` plus 226 test files across `ui/`
that name a module, test id or key this PR changes (`RecordDetailView`,
`RecordPageColumns`, `RelatedCardStack`, `ArrangedRelatedTab`,
`relatedEnlargedBack`, `data-related-enlarged`,
`RECORD_RELATED_ENLARGE`, `record-tab`; derived by `git grep`) → `Test
Files 672 passed | 1 skipped (673)`, `Tests 6395 passed | 31 skipped
(6426)`, VERDICT command-exit 0 (on `7a0555e2`; `572d6b18fb` only adds
`objectName` to one pin's record context, and that file then ran `Tests
10 passed (10)`). A first broad run found the six
`recordPageTiers-26678` cases (they asserted no tablist) and the retired
full-face case in `RelatedPanel.header-27524`, both rewritten above.
- `type-check` (`tsc --noEmit` + `tsc -p tsconfig.test.json`) of
`@object-ui/i18n`, `@object-ui/plugin-detail` and
`@object-ui/app-shell`, under the lock: each exit 0 on `572d6b18fb`. The
first plugin-detail run was exit 2 on the new pin's missing `objectName`
(TS2741), fixed in `572d6b18fb`.
- eslint on the 31 added or modified `ts`/`tsx` files under `ui/`: 0
errors. `pnpm --dir ui run check:i18n-drift`: exit 0.
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` → 66 commands, the same list on `c1734bc8`
and on `572d6b18fb`. Each was run on `572d6b18fb` with its exit code
captured before any pipe (the three heavy ones under the lock); all 66
are `:: exit 0`, `node scripts/check-sdui-manifest.mjs` among them.
`--ran` reconcile: `66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN`.
- Dogfood (the title has `!`), once on `572d6b18fb` under the lock:
`pnpm --filter @objectstack/dogfood test` → VERDICT command-exit 0,
`Test Files 361 passed | 3 skipped (364)`, `Tests 2917 passed | 28
skipped (2945)`.
- CI on `572d6b18fb`: all 59 check-runs concluded success, or skipped by
path filter or opt-in; `Test UI` (16/16), `Type Check UI`, `Lint UI`,
`Live E2E UI` and `Build & E2E UI` among them.
- `main` has moved 8 commits past the merge base; `git merge-tree
--write-tree origin/main HEAD` is clean, and no merge was pushed.
- Not run locally, CI's own: the whole `ui/` suite (Test UI; `app-shell`
alone is 1,379 test files), the other type-check lanes, the repo-wide
scans.
```
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-adr-links.mjs :: exit 0
node scripts/check-adr-links.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-doc-route-spelling.mjs --advisory :: exit 0
node scripts/check-doc-route-spelling.mjs --self-test :: exit 0
node scripts/check-docs-section-name.mjs :: exit 0
node scripts/check-docs-section-name.mjs --self-test :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
node scripts/check-section-landing-index.mjs :: exit 0
node scripts/check-section-landing-index.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm --filter @objectstack/lint run check:doc-security-posture :: exit 0
pnpm --filter @objectstack/spec run check:docs :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm --filter @objectstack/spec run check:empty-state :: exit 0
pnpm --filter @objectstack/spec run check:liveness :: exit 0
pnpm --filter @objectstack/spec run check:skill-examples :: exit 0
pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0
pnpm --filter @objectstack/spec run check:variant-docs :: exit 0
pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:corpus-claim-drift :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:doc-anchors :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:doc-frontmatter :: exit 0
pnpm check:docs-audit-scope :: exit 0
pnpm check:docs-redirects :: exit 0
pnpm check:docs-single-h1 :: exit 0
pnpm check:docs-spec-enumerations :: exit 0
pnpm check:docs-transcript-drift :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-changeset-deadline-census :: exit 0
pnpm check:published-files :: exit 0
pnpm check:published-readme-links :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:react-page-adapter-contract :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:role-word :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:vendor-version-stamps :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
pnpm --dir ui run check:i18n-drift :: exit 0
```
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L9qibzGCEznLfiQm2T5icF)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent a9f1452 commit bf74607
36 files changed
Lines changed: 1478 additions & 338 deletions
File tree
- .changeset
- content/docs/ui
- ui/packages
- app-shell/src/views
- i18n/src/locales
- plugin-detail
- src
- __tests__
- renderers
- synth
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
190 | 190 | | |
191 | 191 | | |
192 | 192 | | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
193 | 197 | | |
194 | 198 | | |
195 | 199 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
25 | 27 | | |
26 | 28 | | |
27 | | - | |
28 | | - | |
| 29 | + | |
| 30 | + | |
29 | 31 | | |
30 | 32 | | |
31 | 33 | | |
| |||
218 | 220 | | |
219 | 221 | | |
220 | 222 | | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
221 | 241 | | |
222 | 242 | | |
223 | 243 | | |
| |||
226 | 246 | | |
227 | 247 | | |
228 | 248 | | |
229 | | - | |
| 249 | + | |
230 | 250 | | |
231 | 251 | | |
232 | 252 | | |
| |||
253 | 273 | | |
254 | 274 | | |
255 | 275 | | |
256 | | - | |
| 276 | + | |
257 | 277 | | |
258 | 278 | | |
259 | 279 | | |
260 | 280 | | |
261 | 281 | | |
262 | | - | |
| 282 | + | |
263 | 283 | | |
264 | 284 | | |
265 | 285 | | |
266 | 286 | | |
267 | 287 | | |
268 | | - | |
| 288 | + | |
269 | 289 | | |
270 | 290 | | |
271 | 291 | | |
| |||
284 | 304 | | |
285 | 305 | | |
286 | 306 | | |
287 | | - | |
| 307 | + | |
288 | 308 | | |
289 | 309 | | |
290 | 310 | | |
291 | 311 | | |
292 | 312 | | |
293 | 313 | | |
294 | | - | |
| 314 | + | |
295 | 315 | | |
296 | 316 | | |
297 | 317 | | |
| |||
307 | 327 | | |
308 | 328 | | |
309 | 329 | | |
| 330 | + | |
310 | 331 | | |
311 | 332 | | |
312 | 333 | | |
| |||
0 commit comments