feat(narratives): add config contract, static assets and lockfile - #439
feat(narratives): add config contract, static assets and lockfile#439ddebasmita-lab wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces configuration schemas, examples, and documentation for customizing Data Commons instances, including support for branding, metrics, and agent settings. It also updates the useBranding hook and its tests to support the new logo configuration key alongside its legacy alias. The review feedback suggests tightening the regex validation for fiscal_year_start in the agent configuration schema and adding a test case to cover the public-bucket fetching path in the branding hook tests.
| "fiscal_year_start": { | ||
| "description": "Month/day of fiscal-year start (e.g. '04-01' for India, '01-01' for calendar-year states).", | ||
| "type": "string", | ||
| "pattern": "^[0-9]{2}-[0-9]{2}$" | ||
| } |
There was a problem hiding this comment.
The current regex pattern ^[0-9]{2}-[0-9]{2}$ only validates that the value consists of two digits, a hyphen, and two digits. This allows invalid dates like 99-99 or 00-00 to pass schema validation. We can make this pattern more robust by strictly validating that the month is between 01 and 12 and the day is between 01 and 31.
| "fiscal_year_start": { | |
| "description": "Month/day of fiscal-year start (e.g. '04-01' for India, '01-01' for calendar-year states).", | |
| "type": "string", | |
| "pattern": "^[0-9]{2}-[0-9]{2}$" | |
| } | |
| "fiscal_year_start": { | |
| "description": "Month/day of fiscal-year start (e.g. '04-01' for India, '01-01' for calendar-year states).", | |
| "type": "string", | |
| "pattern": "^(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$" | |
| } |
| }); | ||
| }); |
There was a problem hiding this comment.
The test suite currently only covers the private-bucket path (where /agent/brand returns the branding object directly). The public-bucket path (where /agent/brand only returns brand_config_url and the browser must fetch branding.json directly from the GCS bucket) is currently untested. Adding a test case for this path would improve test coverage and ensure that the public-bucket fetching logic works as expected.
});
it("fetches branding.json from the bucket in the public-bucket path", async () => {
vi.stubGlobal(
"fetch",
vi.fn()
.mockResolvedValueOnce({
ok: true,
json: async () => ({ brand_config_url: BUCKET_URL }),
})
.mockResolvedValueOnce({
ok: true,
json: async () => ({ instance_name: "Public Example", logo: "assets/logo.png" }),
}),
);
const { result } = renderHook(() => useBranding());
await waitFor(() => expect(result.current.loaded).toBe(true));
expect(result.current.branding.logoUrl).toBe(BUCKET_URL + "/assets/logo.png");
expect(result.current.branding.instanceName).toBe("Public Example");
});
});Makes the narratives app deployable from a clean clone. Three related gaps:
- `package-lock.json` was never committed, so `npm ci` — used by the image
build — failed outright. All 25 dependencies float on `^` ranges, so pinning
the tree is what makes a clone reproduce the tested build.
- `public/` was missing entirely while four code paths referenced it:
`/send.svg` (view_initial, data_agent), `/loader.png` (block_reasoning) and
`/logo.png` (header, as a fallback). Those requests 404'd.
- `config/` documents the per-instance contract — the branding and agent
schemas plus fillable examples — which the agent and UI read from the
instance's config bucket at runtime. Instance-specific values stay out of the
repo: copy the `.example.json` files and edit them.
Also fixes the branding logo, which never loaded from config. The schema
publishes `logo`, but the UI read only `logo_url`, so `logoUrl` stayed empty and
the header always took the bundled fallback. `mapRawToBranding` now reads `logo`
and keeps `logo_url` as a legacy alias, matching how the same file already
accepts legacy aliases for colors, fonts and `suggestion_chips`. Covered by
tests that fail without the fix.
Overriding the logo stays optional: no logo ships in the config example, so a
fresh instance renders the bundled `public/logo.png`. An instance that wants its
own adds a `logo` key and uploads the image to its config bucket, which
`config/README.md` documents.
The branding schema previously declared eight keys with no consumer anywhere in
the UI — `favicon`, `logo_alt`, `extra_css`, `footer`, `splash_assets`,
`instance_id`, `domain_hint` and `analytics`. They are omitted here rather than
carried over, so every key in the schema is one the UI actually reads.
`template_vars` is kept but now says plainly that placeholder rendering is not
implemented; the previous wording claimed the agent already substituted
`{{instance.*}}`, which it does not.
67b1632 to
bef8ea0
Compare
Makes the narratives app deployable from a clean clone. Three related gaps:
package-lock.jsonwas never committed, sonpm ci— used by the image build — failed outright. All 25 dependencies float on^ranges, so pinning the tree is what makes a clone reproduce the tested build.public/was missing entirely while four code paths referenced it:/send.svg(view_initial, data_agent),/loader.png(block_reasoning) and/logo.png(header, as a fallback). Those requests 404'd.config/documents the per-instance contract — the branding and agent schemas plus fillable examples — which the agent and UI read from the instance's config bucket at runtime. Instance-specific values stay out of the repo: copy the.example.jsonfiles and edit them.template_varsis kept but now says plainly that placeholder rendering is not implemented; the previous wording claimed the agent already substituted{{instance.*}}, which it does not.