Skip to content

Feature flagging moved over to redesign#1139

Closed
corypride wants to merge 119 commits into
mainfrom
cpride/feature_flagging
Closed

Feature flagging moved over to redesign#1139
corypride wants to merge 119 commits into
mainfrom
cpride/feature_flagging

Conversation

@corypride
Copy link
Copy Markdown
Contributor

@corypride corypride commented May 26, 2026

Description of the change

Ports the Feature Control (feature flagging) admin page from the original frontend to the redesign. System admins can now toggle platform-wide features on and off directly from the redesigned UI.

Changes include:

  • New FeatureControl.tsx page under /feature-control, accessible only to SystemAdmin role

  • Toggle support for top-level features (Knowledge Center, Program Hub & Tracking) and Knowledge Center sub-features (Request Content Button, Helpful Links, Videos)

  • Confirmation dialog before applying any toggle, with a statewide impact warning when disabling resident-facing features

  • Sub-features are visually disabled (opacity + Switch disabled) when their parent feature is off

  • "Feature Control" nav link added to Sidebar.tsx admin nav, visible only to system admins, using AdjustmentsHorizontalIcon

  • systemAdminRoutes route group added to app-routes.tsx gating the route to UserRole.SystemAdmin

  • Related issues: https://app.asana.com/1/1201607307149189/project/1209460078641109/task/1214641676425184

Screenshot(s)

image image image image image

Additional context

The API calls (PUT auth/features/:key and PUT auth/page-features/:key) were already in place from the original frontend — this commit only brings the UI into the redesign. No backend changes were made.

@corypride corypride requested a review from a team as a code owner May 26, 2026 21:39
@corypride corypride requested review from CK-7vn and removed request for a team May 26, 2026 21:39
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds FeatureControl.tsx, a new admin page for managing feature access toggles. The component reads the authenticated user, derives enabled states, and provides UI to toggle features with confirmation dialogs. On confirmation, it issues API requests to update access, refreshes user state, and emits success/error notifications. Sub-features can be disabled when their parent is off.

Changes

Feature Control Admin Page

Layer / File(s) Summary
Type definitions and state shape
frontend/src/pages/admin/FeatureControl.tsx
Local types define toggle targets (feature vs page-feature) and a PendingToggle state object carrying the target, display label, and desired next boolean value.
State management and API handlers
frontend/src/pages/admin/FeatureControl.tsx
FeatureControl component derives enabled flags from user.feature_access, defines requestToggle to store pending intent, and defines async confirmToggle that performs API update via API.put, refreshes user via fetchUser, emits toasts, and manages loading state.
Main UI rendering and confirmation dialog
frontend/src/pages/admin/FeatureControl.tsx
Renders feature toggles including "Knowledge Center" parent switch with dependent sub-feature rows and "Program Hub & Tracking" section. Confirmation Dialog driven by pending state shows dynamic enable/disable messaging, disabling warnings, and wired Cancel/Confirm buttons.
SubFeatureRow component
frontend/src/pages/admin/FeatureControl.tsx
Reusable presentational component rendering a labeled toggle with description, visually dimmed and disabled when parentEnabled is false to enforce parent-child feature dependencies.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: porting the feature flagging admin page from the original frontend to the redesigned UI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description clearly explains that it ports the Feature Control admin page from the original frontend to the redesign, including specific features like toggle support, confirmation dialogs, navigation updates, and routing restrictions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

CK-7vn and others added 20 commits May 26, 2026 16:46
PageHeader, StatusBadge, EmptyState, SearchInput, ConfirmDialog,
FormModal, and DataTable components with consistent design system
theming and reusable patterns.
Split monolithic common.ts into 15 domain-specific type modules (auth,
user, facility, program, attendance, provider, content, insights,
events, server, reports, navigation, websocket, ui, global.d.ts).
Port API client with CSRF handling and credential passing. Add
formatters and cn() utility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port AuthProvider with Ory Kratos flow integration, RouteGuard for
role-based access control, useAuth with role helpers and session
management. Port BroadcastChannel tab session and WebSocket session.
Rewrite ThemeContext for next-themes, ToastContext for sonner. Port
Tour, Breadcrumb, and PageTitle contexts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port useUrlPagination, useSessionViewType, useCheckResponse (adapted
for shadcn Dialog controlled state), useBreadcrumbsFromRoutes. Port
all route loaders for data prefetching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port all 52 shadcn/ui components from the redesign. Components use
Radix UI primitives with forest green/olive/gold design tokens.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port AuthenticatedLayout with redesign top nav bar (bg-[#203622]),
role-based nav items, facility selector, user menu, theme toggle.
Port GuestLayout, TopNav, MobileNav, Breadcrumbs. Port TitleManager,
Loading, Brand, and UnlockEdTour components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Set up React Router v6 with route guards, loaders, and breadcrumbs.
Configure provider nesting order (PostHog, Tour, SWR, Theme). Define
all app routes (admin, program, provider, knowledge center). Add
globals.css with design tokens and dark mode support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port Login with Ory Kratos flow integration (rate limiting, lockout,
deactivation detection). Add ChangePasswordForm with validation and
first-login facility setup. Add ConsentForm for OAuth2. Port Welcome
landing page and StudentLayer0 greeting page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add AdminManagement with role-based CRUD and permission checks.
Add StudentManagement with deactivation support. Add FacilityManagement
with room and timezone configuration. Add ResidentProfile detail page.
Add ProviderPlatformManagement with OIDC registration and archive.
Add ProviderUserManagement with user import and Kolibri detection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ProgramManagementForm and ClassManagementForm for create/edit.
Add ProgramOverviewDashboard, ProgramClassManagement, ClassLayout,
ClassEnrollmentDetails, ClassEvents, and AddClassEnrollments.
Add decomposed EventAttendance page with grid and summary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ResidentHome with featured content and favorites. Add StudentDashboard
with weekly activity chart. Add MyCourses with tabs and grid/list toggle.
Add MyProgress with stats and sortable table. Add ResidentOverview and
CourseCatalog. Add WeeklyActivity, TopContentList, EnrolledCourseCard,
CatalogCourseCard, and ActivityHistoryCard components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add OpenContent tabbed container for admin/student views. Add
LibraryLayout, VideoManagement, HelpfulLinksManagement for admins.
Add StudentOpenContent, VideoContent, LibraryViewer (Kiwix iframe),
VideoViewer, HelpfulLinks, and Favorites for students. Add LibraryCard,
VideoCard, HelpfulLinkCard, FavoriteCard, and OpenContentItemAccordion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add OperationalInsights, KnowledgeInsights, and LearningInsights
with recharts visualizations. Add EngagementRateGraph and chart
components. Add Schedule with weekly calendar view. Add FAQs with
accordion and HelpCenter. Port Dashboard, ClassesPage, ProgramsPage,
TakeAttendance, Error page, and class-detail/program-detail modules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…me blocking

Add forwardRef to Input, Textarea, and Button for react-hook-form
compatibility. Move side effects (navigate, window.location.href) from
render bodies into useEffect in AuthProvider, RouteGuard, Login, and
ResidentProfile. Extract shared formatDate/formatDateTime into
formatters.ts to eliminate duplication. Fix LoginForm timer to use
derived state instead of synced useState. Fix X-Frame-Options to use
SAMEORIGIN for proxy routes so Kiwix content renders in iframes. Fix
inverted NATS cache condition in middleware that prevented library proxy
params from being cached.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
carddev81 and others added 24 commits May 26, 2026 16:46
…der (#1126)

* feat: add new redesign files to frontend folder and remove old v2 folder

* feat: add new redesign files to frontend folder and remove old v2 folder

* fix: add changes for linting errors
* fix: export sessionutil funcs

* fix: split 3 helpers to lib and session-utils

* fix: type linked_override_event nullable, type VideoViewer fetch

* refactor: split SessionDetailSheet into focused sub-components

* refactor: split SessionsTab into sub-components

* refactor: extract LoadingSkeleton and ClassNotFoundCard from class-detail

* refactor: dedupe buildFacilityEvent, tighten EnrollResidentModal cast

* fix: routes for top content and resident dashboard

* fix: scrollbars
* refactor: brand colors in globals

* refactor: sweep stragglers + add brand-gold-dark token

* refactor: focus rings

* refactor: consolidate more hex and extract reusable component classes

* refactor: extract more component classes

* refactor: more component class extractions and library viewer stretch fix

* refactor: css hex and badges

* fix: schedule tab click state color
@corypride corypride force-pushed the cpride/feature_flagging branch from 4d68085 to 77bbb8f Compare May 26, 2026 21:50
@corypride corypride requested a review from carddev81 May 26, 2026 22:07
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/pages/admin/FeatureControl.tsx`:
- Around line 48-67: handleConfirm currently sends a toggle because the API.put
call omits the desired state; change the request to send the intended state
(e.g., include { enabled: newValue } or similar payload) when calling API.put
for `auth/${urlSegment}/${target.key}`, then read the server-confirmed state
from the response (or re-fetch via fetchUser) and use that server-confirmed
value when calling setUser, setPending(null) and when composing toast
success/error messages so the UI reflects the server-side state rather than
assuming newValue.
- Around line 97-106: The Switch controls (e.g., the Switch component instance
that uses checked={kcEnabled} and onCheckedChange={()=>requestToggle({ type:
'feature', key: FeatureAccess.OpenContentAccess }, 'Knowledge Center',
kcEnabled)}) lack accessible names; add an aria-label or aria-labelledby prop to
each Switch (including the other instances for sub-features referenced) with a
clear, unique label such as "Toggle Knowledge Center feature" (or the
appropriate sub-feature name) so screen readers can identify them; update every
Switch usage in this component to include the prop while keeping existing
checked and onCheckedChange handlers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b3cb8218-7393-4873-a7df-784304b1c8d0

📥 Commits

Reviewing files that changed from the base of the PR and between edf64e4 and c52e1af.

📒 Files selected for processing (1)
  • frontend/src/pages/admin/FeatureControl.tsx

Comment on lines +48 to +67
const handleConfirm = async () => {
if (!pending) return;
setLoading(true);
try {
const { target, name, newValue } = pending;
const urlSegment =
target.type === 'feature' ? 'features' : 'page-features';
const resp = await API.put<string, void>(
`auth/${urlSegment}/${target.key}`,
undefined
);
if (!resp.success) {
toast.error(`Failed to ${newValue ? 'enable' : 'disable'} ${name}`);
return;
}
const updated = await fetchUser();
if (updated) setUser(updated);
toast.success(`${name} ${newValue ? 'enabled' : 'disabled'} successfully`);
setPending(null);
} catch {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Make this write idempotent; current toggle flow can apply the opposite state.

Line 55 sends no desired value, so this behaves like a toggle operation. Combined with retries/transient errors/concurrent admins, a second confirmation can flip the feature back while Line 65 still reports the client-intended state. Please move to a set-state contract (e.g., send enabled: newValue and use server-confirmed state in UI messaging).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/admin/FeatureControl.tsx` around lines 48 - 67,
handleConfirm currently sends a toggle because the API.put call omits the
desired state; change the request to send the intended state (e.g., include {
enabled: newValue } or similar payload) when calling API.put for
`auth/${urlSegment}/${target.key}`, then read the server-confirmed state from
the response (or re-fetch via fetchUser) and use that server-confirmed value
when calling setUser, setPending(null) and when composing toast success/error
messages so the UI reflects the server-side state rather than assuming newValue.

Comment on lines +97 to +106
<Switch
checked={kcEnabled}
onCheckedChange={() =>
requestToggle(
{ type: 'feature', key: FeatureAccess.OpenContentAccess },
'Knowledge Center',
kcEnabled
)
}
/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add accessible names to all Switch controls.

These switches do not expose an explicit accessible name, which makes them ambiguous in screen readers. Add aria-label (or aria-labelledby) for each control, including sub-features.

Suggested patch
                         <Switch
+                            aria-label="Toggle Knowledge Center"
                             checked={kcEnabled}
                             onCheckedChange={() =>
                                 requestToggle(
@@
                         <Switch
+                            aria-label="Toggle Program Hub & Tracking"
                             checked={isEnabled(FeatureAccess.ProgramAccess)}
                             onCheckedChange={() =>
                                 requestToggle(
@@
             <Switch
+                aria-label={`Toggle ${label}`}
                 checked={enabled}
                 onCheckedChange={onToggle}
                 disabled={!parentEnabled}
             />

Also applies to: 170-179, 274-278

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/admin/FeatureControl.tsx` around lines 97 - 106, The
Switch controls (e.g., the Switch component instance that uses
checked={kcEnabled} and onCheckedChange={()=>requestToggle({ type: 'feature',
key: FeatureAccess.OpenContentAccess }, 'Knowledge Center', kcEnabled)}) lack
accessible names; add an aria-label or aria-labelledby prop to each Switch
(including the other instances for sub-features referenced) with a clear, unique
label such as "Toggle Knowledge Center feature" (or the appropriate sub-feature
name) so screen readers can identify them; update every Switch usage in this
component to include the prop while keeping existing checked and onCheckedChange
handlers.

@corypride corypride closed this May 26, 2026
@corypride corypride deleted the cpride/feature_flagging branch May 26, 2026 22:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants