-
[OPIK-6040] [FE/BE] Deployment-level default rows-per-page for Experiments tables (#6463)
发布于
2026-04-28 10:18:09 +00:00 - [OPIK-6040] docs: add design spec for deployment-level default page size
Design for exposing a deployment-configurable default rows-per-page value
to the v2 Experiments tables via a new /v1/private/ui-config endpoint and
UIConfigProvider. User in-session overrides flow through the URL query
param only; no localStorage persistence (per customer requirement).Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] docs: clarify ui-config cache scope in design spec
Deployment-level config is identical across workspaces; clarify that the
React Query cache key is global, not workspace-scoped.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] docs: add implementation plan for deployment default page size
13 bite-sized tasks covering backend config class + resource + test,
frontend API hook + provider + test + wiring, three v2 Experiments
consumers, Helm values entry, and a manual verification gate.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] feat(backend): add UIConfig with defaultPageSize
Introduce a Dropwizard UIConfig class that holds deployment-level UI
defaults. Field defaultPageSize (validated @Min(1), default 100) lets
admins lower the global default rows-per-page for table views.- [OPIK-6040] refactor(backend): bound defaultPageSize with @Max(1000)
Defense-in-depth cap against misconfigured deployments; the UI dropdown
caps at 100 today and 1000 is a generous ceiling. Also splits @Min onto
its own line to match plan style.- [OPIK-6040] feat(backend): expose UIConfig via /v1/private/ui-config
Add UIConfigResource mirroring ServiceTogglesResource. The endpoint is
auto-discovered by Guicey (enableAutoConfig) and serves the uiConfig
block from OpikConfiguration.- [OPIK-6040] docs(plan): use snake_case wire format for UIConfig
Backend ObjectMapper applies SnakeCaseStrategy globally, so
defaultPageSize serializes as default_page_size on the wire. Update the
frontend type, provider default, test fixtures, curl expectation, and
consumers to match, aligning with the rest of the codebase's
snake_case API types.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] test(backend): unit test UIConfigResource returns config value
Cover the custom-value and default-value paths. Kept as a unit test to
avoid booting ClickHouse/MySQL/Redis for a read-only config endpoint.- [OPIK-6040] test(backend): add @Max(1000) bounds test for UIConfig
Closes Task 3 code review gap: exercises both @Min(1) and @Max(1000)
bean validation constraints using a local Validator, ensuring a
silent removal of @Max(1000) would break the build. Also drops the
redundant assertion in returnsConfiguredDefaultPageSize.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] feat(backend): wire UI_DEFAULT_PAGE_SIZE env var
Add uiConfig block to config.yml with env var substitution so
operators can override the default rows-per-page at deploy time
without a rebuild.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] feat(frontend): add UIConfig type, endpoint, and fetch hook
Cache key is global ("ui-config") because the value is deployment-wide
and does not vary per workspace. The second query-key element is an
empty params object to satisfy the project's QueryConfig tuple shape
([string, Record<string, unknown>, ...string[]]).Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] feat(frontend): add UIConfigProvider context
Exposes deployment UI config to the component tree with a 100-default
fallback so consumers always have a valid number during fetch / on
error.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] test(frontend): cover UIConfigProvider success and fallback paths
Verifies the provider exposes fetched data and falls back to
default_page_size=100 when the query is loading or errors.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] feat(frontend): mount UIConfigProvider in v2 WorkspaceGuard
Provider is nested inside FeatureTogglesProvider since the UI config
fetch is independent of feature toggles and should cover the same set
of workspace-scoped layouts.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] feat(frontend): use deployment default in v2 experiments list
Replace useQueryParamAndLocalStorageState with useQueryParam for the
page-size state. The deployment default comes from UIConfigProvider and
is no longer persisted to localStorage; in-session override lives only
on the URL query param per customer requirement.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] feat(frontend): use deployment default in experiment items viewer
Only the page-size state drops localStorage persistence; row height,
sorting, and other items-viewer state remain in localStorage per the
existing UX contract.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] feat(frontend): use deployment default in prompt experiments tab
Replace useQueryParamAndLocalStorageState with useQueryParam for the
page-size state so the v2 prompt experiments tab honors the deployment
default and drops stale localStorage dependency.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] feat(helm): expose UI_DEFAULT_PAGE_SIZE as a backend env var
Operators can lower the default rows-per-page (e.g. to 25) without
rebuilding, and the backend substitutes the value into config.yml at
startup.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] refactor(frontend): simplify useUIConfig to a stable singleton key
Drop the unused options parameter and the object-padded tuple key so the
hook mirrors useIsAlive: a single-element queryKey (["ui-config"]) for a
deployment-wide value that never varies by caller. Avoids confusion
around passing an empty params object only to satisfy QueryConfig's
tuple shape.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] [BE] test: add HTTP integration test + boundary cases for UIConfig
- Add wireFormatIsSnakeCase test using ResourceExtension to verify
the API serializes default_page_size as snake_case end-to-end.
This catches Jackson naming-strategy drift regardless of
annotation style on the config class. - Extend the bean-validation test to cover boundaries (1 and 1000)
and a typical in-range value (500), not just out-of-bounds cases.
Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] [DEPLOY] docs: cross-reference dual UI_DEFAULT_PAGE_SIZE defaults
Both apps/opik-backend/config.yml and deployment/helm_chart/opik/values.yaml
carry a literal fallback of 100 for UI_DEFAULT_PAGE_SIZE. Add reciprocal
comments in each file so anyone changing one default is prompted to
update the other, preventing silent drift between the backend fallback
and the Helm default.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] [FE] test: verify ?size URL param overrides UIConfig default
Add an integration test that exercises the exact coercion pattern used
by v2 Experiments tables (GeneralDatasetsTab, PromptPage/ExperimentsTab,
useExperimentItemsState):const size = sizeParam ?? defaultPageSize;
Two cases under real use-query-params + UIConfigProvider:
- No ?size in URL → provider default_page_size wins
- ?size=50 in URL → URL value wins over provider default
This guards the documented override semantics so later refactors
cannot silently invert the precedence.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] refactor: reuse ServiceTogglesConfig + shared hook for page-size default
Addresses PR review: drop the parallel /v1/private/ui-config/ endpoint in
favor of ServiceTogglesConfig (consumed through the existing feature-toggles
provider), and wire the deployment default into both v1 and v2 experiment
tables.Backend
- ServiceTogglesConfig gains
@Min(1) @Max(1000) int defaultPageSize = 100 - config.yml binds it to UI_DEFAULT_PAGE_SIZE with a cross-ref to Helm
- Remove UIConfig, UIConfigResource, and UIConfigResourceTest
Frontend
- FeatureTogglesProvider exposes useDefaultPageSize(), reading the
snake_case default_page_size field from /v1/private/toggles/ - New shared hook useTablePageSize() centralizes URL + fallback wiring and
hardens against malformed ?size= input (NaN, 0, negative, fractional) - v2 experiment call sites adopt useTablePageSize() directly
- v1 experiment call sites pass useDefaultPageSize() as the
useQueryParamAndLocalStorageState defaultValue (preserves localStorage) - Remove UIConfigProvider, useUIConfig, ui-config types, and related tests
Docs / deploy
- Delete internal planning docs from docs/superpowers/
- Update Helm cross-reference comment to serviceToggles.defaultPageSize
Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] fix: fold v1 tables into shared useTablePageSize hook
Baz review flagged a race in v1 pagination:
useQueryParamAndLocalStorageState
readsdefaultValueonly at first render, so before the feature-toggles fetch
resolves the hook seeds localStorage with the fallback (100). When the
deployment value arrives later, localStorage already holds 100 and the new
default is never reflected.Fix: drop localStorage persistence for the page-size on v1 and adopt the same
useTablePageSize()hook v2 uses. URL?size=still wins; otherwise each
render resolves the current deployment default. This also collapses the
three duplicateduseQueryParamAndLocalStorageStateblocks.Also regenerates deployment/helm_chart/opik/README.md (helm-docs v1.14.2) to
include the newUI_DEFAULT_PAGE_SIZEenv var row, unblocking the
update-readmeCI check.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] [BE] address review: drop java default, tighten bounds, sync configs
- ServiceTogglesConfig: drop = 100 default (sourced from YAML), bounds 5..100
to match the UI's existing min and current max. - config.yml: remove cross-reference NOTE.
- config-test.yml: bring comments in line with prod (convention: identical
except for env vars). - values.yaml: drop comments (config.yml is the source of truth).
Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] [FE] restore v1 cross-session page-size persistence
The previous v1 fold onto useTablePageSize traded localStorage persistence
to dodge the init race against the toggles fetch. v1 users (the actual
target of this PR) lost their cross-session page-size preference.Add useTablePageSizeWithStorage(localStorageKey) variant: URL → localStorage
→ deployment default. Pass NO defaultValue to useLocalStorageState so the
FE fallback (100) is never seeded into storage on first render — only
user-picked values get written. That avoids the race the previous commit
was working around.v2 keeps the URL-only useTablePageSize.
Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] address final review: widen bounds, lock wire format, fold v2 keys
- BE: ServiceTogglesConfig.defaultPageSize bounds widened to @Min(10)
@Max(1000) to match documented operator surface (was @Min(5) @Max(100),
which left zero headroom above the 100 Helm default). - BE: add ServiceTogglesConfigTest pinning the default_page_size snake_case
wire format - guards against silent FE fallback if the field is renamed
or the global SnakeCaseStrategy regresses. - FE: extend FeatureToggles type with default_page_size?: number; drop the
load-bearing (data as unknown) cast in feature-toggles-provider. - FE: tighten provider guard to Number.isInteger(raw) && raw >= 10 to
match the new backend floor. - FE: collapse useTablePageSize / useTablePageSizeWithStorage into a
single useTablePageSize(localStorageKey) export; restore the v2
pagination-size localStorage keys (experiments-pagination-size,
prompt-experiments-pagination-size, ${storagePrefix}-pagination-size)
that an earlier iteration dropped, so v2 users keep cross-session
page-size persistence at parity with v1. - FE: comment the in-flight-fetch race in useTablePageSize so the
no-defaultValue-to-useLocalStorageState pattern is not naively
"simplified" away.
Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
- [OPIK-6040] address review: clamp FE upper bound + sync helm-docs
- feature-toggles-provider: enforce raw <= 1000 to mirror BE bounds; out-of-range
values fall through to the 100 fallback (baz-reviewer Low). - helm_chart README: regenerate via helm-docs v1.14.2 to pick up Chart.yaml 2.0.15
(unblocks update-readme CI).
- [OPIK-6040] address review: revert bounds to 5..100, drop snake_case test
- ServiceTogglesConfig: bounds back to @Min(5) @Max(100) per the originally
agreed UI min/max; the 10..1000 widening was unnecessary. - feature-toggles-provider: tighten guard to raw >= 5 && raw <= 100 so the
FE mirrors the BE bounds. - Drop ServiceTogglesConfigTest (snake_case wire-format pin) per review -
low-value coverage.
Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com
Co-authored-by: Claude Opus 4.7 noreply@anthropic.com
下载附件