Observation-class finding from PR #4388 (#4330). Nothing a user hits today — both copies call the same helpers and are pinned to the same behaviour on both surfaces. Filing so the duplication is retired deliberately rather than discovered later as drift.
What is duplicated, and what is not
The resolution rules are not duplicated: both surfaces call the same @object-ui/core helpers, which is the "one channel, no second dialect" property #4324 established and #4330 kept —
resolveDimensionFieldMeta → localizeFieldOptions / buildDimensionLabelMap → relabelDimensions
with the translator bound to useSafeFieldLabel().fieldOptionLabel.
What is written twice is the React glue around them — read the object schema through SchemaRendererContext.apiFetch (falling back to the global fetch), keep the fetched metadata locale-free in state, derive the label maps in a render memo so a language switch relabels in place instead of refetching:
packages/plugin-dashboard/src/DatasetWidget.tsx — the resolution effect plus its { categoryColors, dimensionLabels, categoryOrder } memo;
packages/plugin-report/src/useDatasetDimensionLabels.ts — the same shape, minus the chart-only colour/order wiring.
Why it was written twice
packages/core was held by #4040 tranche 5 while #4330 was in flight, and #4330's surface was the two plugin packages. The hook's file header says this and points here.
Suggested direction (for triage, not a decision)
Once tranche 5 lands, lift the glue into @object-ui/core beside the helpers it calls — one hook both plugins consume, with the dashboard keeping its extra colour/order derivation on top. Two details a mover should not lose, both of them bug fixes that are currently expressed twice:
Both are pinned on the dashboard side; the report side would inherit them from the shared hook instead of restating them.
Observation-class finding from PR #4388 (#4330). Nothing a user hits today — both copies call the same helpers and are pinned to the same behaviour on both surfaces. Filing so the duplication is retired deliberately rather than discovered later as drift.
What is duplicated, and what is not
The resolution rules are not duplicated: both surfaces call the same
@object-ui/corehelpers, which is the "one channel, no second dialect" property #4324 established and #4330 kept —with the translator bound to
useSafeFieldLabel().fieldOptionLabel.What is written twice is the React glue around them — read the object schema through
SchemaRendererContext.apiFetch(falling back to the globalfetch), keep the fetched metadata locale-free in state, derive the label maps in a render memo so a language switch relabels in place instead of refetching:packages/plugin-dashboard/src/DatasetWidget.tsx— the resolution effect plus its{ categoryColors, dimensionLabels, categoryOrder }memo;packages/plugin-report/src/useDatasetDimensionLabels.ts— the same shape, minus the chart-only colour/order wiring.Why it was written twice
packages/corewas held by #4040 tranche 5 while #4330 was in flight, and #4330's surface was the two plugin packages. The hook's file header says this and points here.Suggested direction (for triage, not a decision)
Once tranche 5 lands, lift the glue into
@object-ui/corebeside the helpers it calls — one hook both plugins consume, with the dashboard keeping its extra colour/order derivation on top. Two details a mover should not lose, both of them bug fixes that are currently expressed twice:apiFetch(DatasetWidget's option-color / dimension-label probe reads the globalfetch, bypassing the host'sapiFetchchannel (the plugin-dashboard twin of #4114) #4121), not the globalfetch;Both are pinned on the dashboard side; the report side would inherit them from the shared hook instead of restating them.