Skip to content

feat(report-issue): gate toolbar menu item behind FEATURE_FLAG_REPORT_ISSUE_ENABLED#35759

Open
fmontes wants to merge 2 commits into
mainfrom
fmontes/feature-request-flag
Open

feat(report-issue): gate toolbar menu item behind FEATURE_FLAG_REPORT_ISSUE_ENABLED#35759
fmontes wants to merge 2 commits into
mainfrom
fmontes/feature-request-flag

Conversation

@fmontes
Copy link
Copy Markdown
Member

@fmontes fmontes commented May 19, 2026

Summary

  • Adds FEATURE_FLAG_REPORT_ISSUE_ENABLED (default false) to gate the "Report an Issue" entry in the toolbar user menu added by Add report issue workflow to backend and toolbar UI #35717.
  • Whitelists the new key in ConfigurationResource and exposes it in the frontend FeaturedFlags enum so DotPropertiesService can read it.
  • Flag check intentionally lives in DotToolbarUserComponent (not the store) so it can be cleanly removed once the feature ships — see inline comment.

Closes #35758. Follow-up to #35717.

Test plan

  • With FEATURE_FLAG_REPORT_ISSUE_ENABLED unset or false: "Report an Issue" item is not visible in the user menu.
  • With FEATURE_FLAG_REPORT_ISSUE_ENABLED=true: item appears and opens the report issue dialog as before.
  • yarn nx test dotcms-ui --testPathPattern=dot-toolbar-user.component.spec passes.

🤖 Generated with Claude Code

@github-actions github-actions Bot added Area : Backend PR changes Java/Maven backend code Area : Frontend PR changes Angular/TypeScript frontend code labels May 19, 2026
@fmontes fmontes requested a review from Copilot May 19, 2026 22:03
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 19, 2026

Claude finished @fmontes's task in 3m 0s —— View job


Review

  • Read changed files on the branch
  • Inspect frontend gating logic + tests
  • Inspect backend whitelist + flag declarations
  • Post review

The PR is clean. Both copilot review comments were addressed properly and the defensive pipe is correctly composed. A few small notes below — none are blockers.

Worth a second look

1. The store still emits the report-issue item unconditionally — component filters it out
dot-toolbar-user.store.ts:135-139 builds the menu including the report-issue entry with no command. The component then either filters it out (flag off) or rebinds the command (flag on). That's intentional per the PR description ("easier to rip out from the component"), but it does mean:

  • If anyone else ever subscribes to store.vm$ directly (outside this component), they'll see a half-built item with no command — a latent footgun for the next reader.
  • A comment in the store noting "command is bound by DotToolbarUserComponent" would make this less surprising. Not necessary, just defensive.

2. getFeatureFlagWithDefault is not cached — combineLatest will trigger a fresh HTTP call on every new subscription to vm$
dot-properties.service.ts:121-132 — unlike getFeatureFlag which uses shareReplay(1) and a per-key cache, this overload pipes the result through map only. The template has one vm$ | async so it's fine today, but the unit test at dot-toolbar-user.component.spec.ts:268-287 actually demonstrates a second subscribe path (the vm$.pipe(filter…) block). In prod, anyone who copies that pattern would silently double-fire the config endpoint. You're already aware (cited YAGNI on shareReplay(1)); flagging because the service-level miss is the asymmetric one, not the component's.

3. Disabled-path test mutates the mock and creates a second fixture
dot-toolbar-user.component.spec.ts:289-307 calls TestBed.createComponent again after beforeEach already created one. The first fixture is just abandoned (no destroy()), and the mock is mutated via mockReturnValue after-the-fact. Functionally correct because beforeEach rebuilds the providers per test, but it's a smell — if someone adds a jest.useFakeTimers() or similar global setup later, the dangling first fixture could leak. Cleaner pattern would be to set the mock value before the component is built (e.g., move the override into a nested describe with its own beforeEach), but not worth blocking on.

4. startWith(false) is correctly placed but the order isn't obviously safe
At dot-toolbar-user.component.ts:58-61 the pipe is startWith(false), catchError(() => of(false)). This is the right order — startWith emits the synchronous false and catchError catches a downstream error. If they were reversed (catchError first), an error from the source would be caught and replaced by of(false), then startWith would prepend another false — still works but the chain would emit false, false. Worth a one-line comment, since the next person to touch this will think about swapping them.

5. Backend: no test asserts the new key is reachable through /api/v1/configuration/config
The whitelist addition at ConfigurationResource.java:76 is config-driven and trivial, but the only verification path right now is the frontend integration. If someone later regroups the literal-vs-constant entries and accidentally drops this one, nothing catches it. Probably acceptable given the trivial change, but worth knowing.

Net

Code is correct, comments explain intent, both copilot points and the prior review feedback are addressed. The component-side flag check is the right scope choice for something meant to be ripped out at launch. Ship it.
• Branch: fmontes/feature-request-flag

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new opt-in feature flag to control whether the “Report an Issue” menu item appears in the toolbar user menu, wiring it through backend configuration exposure and frontend consumption.

Changes:

  • Introduces FEATURE_FLAG_REPORT_ISSUE_ENABLED (default false) and exposes it via the configuration whitelist.
  • Exposes the new flag in the frontend FeaturedFlags enum and gates the toolbar user-menu entry in DotToolbarUserComponent.
  • Updates the component test setup to provide DotPropertiesService for the new flag lookup.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
dotCMS/src/main/resources/dotmarketing-config.properties Adds the new feature flag with a default false value.
dotCMS/src/main/java/com/dotcms/rest/api/v1/system/ConfigurationResource.java Whitelists the new feature flag for /api/v1/configuration/config access.
dotCMS/src/main/java/com/dotcms/featureflag/FeatureFlagName.java Declares the new backend feature flag constant.
core-web/libs/dotcms-models/src/lib/shared-models.ts Adds the new flag to the frontend FeaturedFlags enum.
core-web/apps/dotcms-ui/src/app/view/components/dot-toolbar/components/dot-toolbar-user/dot-toolbar-user.component.ts Fetches the flag and removes/binds the report-issue menu item accordingly.
core-web/apps/dotcms-ui/src/app/view/components/dot-toolbar/components/dot-toolbar-user/dot-toolbar-user.component.spec.ts Mocks DotPropertiesService.getFeatureFlagWithDefault for component tests.

Comment thread dotCMS/src/main/java/com/dotcms/rest/api/v1/system/ConfigurationResource.java Outdated
@fmontes
Copy link
Copy Markdown
Member Author

fmontes commented May 19, 2026

Thanks for the review @claude — addressed in the latest force-push:

1. combineLatest regression ✅ Fixed
Wrapped the flag observable in catchError(() => of(false)) so a failed /api/v1/configuration/config call degrades to "flag off" instead of taking the whole toolbar down with it.

2. Disabled-path test coverage ✅ Fixed
Added should hide the report issue menu item when the feature flag is disabled — overrides the DotPropertiesService mock to return of(false) and asserts the item is absent from vm.items. Now both default-production and enabled states are exercised.

3. shareReplay(1) to future-proof double-subscription ⏭️ Skipped
Only one vm$ | async subscriber today. Adding it preemptively for a hypothetical second subscriber felt like YAGNI, especially since the whole flag check is meant to be ripped out after launch.

4. Extract menu-item id constant ⏭️ Skipped
The duplication already existed in the store before this PR — the cleanup belongs in its own change rather than bundled here.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 19, 2026

Claude finished @fmontes's task in 1m 40s —— View job


Verifying the latest changes

  • Read the current state of the changed files on the branch
  • Verify fix update with latest SVN #1 (catchError resilience) is in place
  • Verify fix Test Branch and Commit #2 (disabled-path test) is in place
  • Cross-check the third original review point about the REPORT_ISSUE_INCLUDE_USER_PII constant on ConfigurationResource
  • Post review summary

Verification

Fix #1catchError resilience ✅ Confirmed at dot-toolbar-user.component.ts:51-57. The flag observable is now .pipe(catchError(() => of(false))) and the inline comment clearly states the intent ("Degrade to 'flag off' on fetch errors so the whole toolbar doesn't disappear.").

One minor thing worth surfacing: you went with catchError alone, not startWith(false) + catchError. That means errored requests are now handled, but a slow /api/v1/configuration/config will still gate the whole vm$ | async template (no avatar/menu until the call emits). In practice this is probably fine — the endpoint is fast on a healthy backend — but if you ever see toolbar flicker on cold starts, that's the knob to turn.

Fix #2 — Disabled-path test ✅ Confirmed at dot-toolbar-user.component.spec.ts:268-286. The new spec re-mocks getFeatureFlagWithDefault to of(false), rebuilds the component so the new value flows through combineLatest, and asserts the report-issue item is undefined in vm.items. The default-true setup at lines 70-75 keeps the enabled path covered. 👍

Skipped #3/#4 — YAGNI calls and scope hygiene both look fine to me. shareReplay(1) can wait until there's an actual second subscriber, and the menu-item id constant cleanup is genuinely pre-existing churn that's better in its own PR.

One copilot point that didn't get a response

The copilot reviewer's third comment about ConfigurationResource.java:75 still applies on the current HEAD — the whitelist uses the literal "REPORT_ISSUE_INCLUDE_USER_PII" even though REPORT_ISSUE_INCLUDE_USER_PII is declared as a constant one line above (L61) and is already used at L144 for the default-value lookup. It's a trivial swap to remove the duplication. Up to you whether to fold it into this PR or leave it — same scope argument as #4 applies. Fix this →

Net

The two fixes you committed look correct and the test coverage matches what was asked for. From my side this is good to go once the lint/test job comes back green.
• Branch: fmontes/feature-request-flag

…_ISSUE_ENABLED (#35758)

Adds an opt-in feature flag that hides the Report Issue user-menu entry
by default. The check lives in the toolbar component (not the store) so
it can be cleanly removed once the feature ships.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nicobytes nicobytes added this pull request to the merge queue May 20, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Safe To Rollback Area : Backend PR changes Java/Maven backend code Area : Frontend PR changes Angular/TypeScript frontend code

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Add FEATURE_FLAG_REPORT_ISSUE_ENABLED to gate Report Issue menu item

4 participants