Repository navigation
feat: Re-land local flag overrides using dev server, with filter reset fix - #851
Merged
Merged
Conversation
The filter state stayed set after the last override went away. A new override then turned the filter on again and hid other flags. Two effects now reset each filter when its condition is false. Add tests for both filters. Co-authored-by: Ramon Niebla <nieblara@users.noreply.github.com>
nieblara
marked this pull request as ready for review
October 6, 2026 03:37
davidbrackbill
approved these changes
Oct 7, 2026
Merge origin/main to fix the conflicts with the UI analytics change in #855. Flags.tsx had one conflict in its imports. The merge keeps sortFlags for the local flags list and keeps the uiAnalytics imports from main. The override analytics calls and the local flag filters now work together. The merge rebuilds ui/dist/index.html from the merged source with npm ci and npm run build. Co-authored-by: Ramon Niebla <nieblara@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR re-lands #837. It also fixes the UI bug that caused the revert in #850. The branch also has a merge of
main.What changes
A local flag is an override for a flag key that is not in the source environment. Before this change, the dev server returned "flag not found" for such an override. Now the dev server accepts it and serves it to SDKs like a synced flag.
model.UpsertOverrideno longer returns an error when the flag is not in the project.GetFlagStateWithOverridesForProjectadds each active override for a flag that is not in the project.model.DeleteOverrideremoves a local flag, it sends a full sync event. The SDKs then drop the flag.UpdateProjectdeletes an override only if its flag was in the previous flag state and is not in the new one. A sync no longer deletes local flags.The UI shows local flags in the flag list with the synced flags. If local flags exist, an "Only show local flags" filter appears. If no overrides exist, the "Only show flags with overrides" filter is greyed out.
Commits
9244fe31: A revert of the revert commit9197f92from fix: Add local flag overrides using dev server (#837) #850. This brings back the full change from feat: Add local flag overrides using dev server #837.2e64a54a: A fix for the filter bug.54ae71c0: A merge ofmain.The bug
#837 removed the
useEffectthat reset the filter state ininternal/dev_server/ui/src/Flags.tsx. The checkbox showedonlyShowOverrides && overridesPresent, but the stored state did not reset. Only "Remove all overrides" cleared it.To see the bug:
The filter turned on again and hid the other flags. "Only show local flags" had the same problem.
The fix
Two effects in
Flags.tsxreset each filter when it no longer applies:onlyShowOverridesresets when no overrides exist.onlyShowLocalresets when no local flags exist. The effect skips this reset untilflagsloads.The effects watch the data, not one handler. They cover "Remove override", "Remove all overrides", and changes to
overridesfrom outside the component.Merge with main
The merge fixes the conflicts with the UI analytics change in #855.
Flags.tsxhad one conflict in its imports. The merge keepssortFlagsfrom this PR and theuiAnalyticsimports frommain.internal/dev_server/ui/dist/index.htmlis rebuilt from the merged source withnpm ciandnpm run build. It is not merged by hand.Local flags use the same
updateOverride,removeOverride, andremoveAllOverridesfunctions as synced flags. They send the same analytics events with the same property values. The allowlist ininternal/dev_server/ui_analytics.goaccepts all of these values, so this PR does not change it. The local filter sends no analytics event.FDv2 polling and streaming from #764 read flags through
GetFlagStateWithOverridesForProjectand the same override and sync events. FDv2 SDKs get local flags with no other change.Tests
db/sqlite_test.go,model/override_test.go, andmodel/project_test.gohave tests for local flags.src/__tests__/Flags.test.tsxhas eight tests. Four of them cover the filter bug with a stateful wrapper and a mockedfetch. Without the two effects, all four fail.What ran after the merge
internal/dev_server/ui:npm ci,npm test -- --run(20 passed),npm run lint,npx prettier --check src,npx tsc -b, andnpm run build. All passed. After the build,git statusshowed no changes.go build ./...,go vet ./internal/dev_server/..., andgo test ./...passed.golangci-lintv2.9.0 on./internal/dev_server/...reported 0 issues./sdk/latest-alland the FDv2/sdk/pollserved the local flag. After the override was removed, the payload no longer had the flag./ui-analyticsreturned HTTP 204 for each payload that local flag actions send.Verification video
The video compares three builds of the dev server:
mainat7f647177, the reverted #837 at9244fe31, and this PR at54ae71c0.mainrejects an override for a flag key that is not in the project. This PR accepts it, serves it to SDKs, keeps it after a project sync, and removes it with the override.In the video, "Remove all overrides" fails with HTTP 404, and the last override comes back. The same failure occurs on
main, so this PR does not cause it. The cause is inDeleteOverridesininternal/dev_server/model/override.go. It loops over all override rows, also the rows that "Remove override" made inactive. For an inactive row,DeactivateOverridereturns "not found", and the loop stops before the active rows.