[Devportal] Restructure the admin UI - #2574
Conversation
📝 WalkthroughWalkthroughThis PR moves developer portal settings to ChangesSettings restructure
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Admin
participant SettingsPage
participant ViewSelector
participant SettingsAPI
participant ThemeService
Admin->>SettingsPage: Open org settings
SettingsPage->>ViewSelector: Render available views
Admin->>ViewSelector: Select view
ViewSelector->>SettingsPage: Update view query and panel
Admin->>SettingsAPI: Save view-scoped configuration
Admin->>ThemeService: Apply or reset theme
ThemeService-->>SettingsPage: Return operation status
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
🧹 Nitpick comments (1)
portals/developer-portal/src/pages/settings/partials/view-combo.hbs (1)
35-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueARIA roles mismatch: this is a listbox/combobox, not a menu.
role="menu"/role="menuitem"imply an action menu, but this is a single-select, type-to-filter view switcher. Screen readers may announce this incorrectly (e.g., not communicating selection state). Considerrole="listbox"/role="option"witharia-selectedon.selected, andaria-controls/aria-ownswiring on the trigger.🤖 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 `@portals/developer-portal/src/pages/settings/partials/view-combo.hbs` around lines 35 - 50, Update the view switcher in view-combo.hbs to use combobox/listbox semantics instead of menu semantics: replace the current role="menu" on the container and role="menuitem" on each item with the appropriate listbox/option roles, and ensure the selected view is exposed via aria-selected on the item marked with the selected class. Also wire the trigger/input behavior to the popup with the correct aria-controls/aria-owns pattern so the filterable single-select control is announced correctly by assistive tech.
🤖 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 `@portals/developer-portal/src/controllers/viewConfigureController.js`:
- Around line 62-65: The settings page flow is currently trusting
req.params.orgName, so an admin can access another organization’s settings by
changing the URL. Update the access check in requireAdmin and the org lookup
path used by viewConfigureController.loadSettingsPage to verify the caller’s
organization from req.user before calling orgDao.getId and orgDao.get, and
reject requests where the URL orgName does not match the authenticated user’s
org membership.
In `@portals/developer-portal/src/dao/organizationDao.js`:
- Around line 369-379: The hasThemeContent helper in organizationDao has the
same missing-viewId bug as deleteThemeContent: if viewDao.getId(orgId, viewName)
returns a falsy value, the OrgContent.count query is no longer scoped to the
intended view and can incorrectly report a theme exists. Add the same guard used
in deleteThemeContent by checking viewId immediately after lookup and returning
false or throwing before calling OrgContent.count, keeping the fix localized to
hasThemeContent and referencing viewDao.getId plus OrgContent.count.
In `@portals/developer-portal/src/pages/settings/page.hbs`:
- Around line 667-670: The business owner email field is only relying on native
email input validation, so malformed values can still be submitted. Update the
settings save flow in the page’s submit handler to validate the org-owner-email
value with the same emailRe check used for wz-tech-email and wz-biz-email, and
block submission with a clear error if it fails. Use the org-owner-email input
and the existing save handler in page.hbs to keep validation consistent before
sending currentOrg.businessOwnerEmail to the backend.
- Around line 667-679: The settings form in page.hbs exposes the internal org
reference fields for idpRefId and cpRefId as editable inputs, which can
accidentally break org linkage when saved. Update the form sections for
org-idp-ref and org-cp-ref so they are read-only or otherwise protected behind
an explicit confirmation flow, and make sure the save path in the settings page
JS does not blindly submit these values unless the user has intentionally
confirmed the change.
- Around line 954-958: The view handle input in the settings page is missing the
same auto-slug and lowercase/hyphen validation used by the label, webhook, and
key manager handle fields. Update the view modal flow around the view-handle
field and the cfg-view-modal-save handler to slugify the entered display name
and reject invalid characters/patterns before saving, matching the existing
handle validation behavior (for example the wz-handle regex pattern).
- Around line 726-736: Add a server-side protection for deleting the default
view: the UI guard in page.hbs is not enough because
apiMetadataService.deleteView still reaches viewDao.deleteView, which currently
calls View.destroy unconditionally. Update the delete flow in
apiMetadataService.deleteView and/or viewDao.deleteView to reject requests where
the target view id or name is "default" before any destroy call, and return an
appropriate error so crafted DELETE requests cannot remove it.
- Around line 18-19: The JSON blobs embedded by the page.hbs script tags are
using raw JSON from the json helper, which can be broken by values containing
script terminators. Update the settings template around the cfg-views-data and
cfg-orglabels-data blocks to use a script-safe serialization approach instead of
plain JSON.stringify output, ensuring the existing views and orgLabels data
remains available without allowing premature </script> termination.
In `@portals/developer-portal/src/pages/settings/partials/theming.hbs`:
- Around line 1-3: The inline JSON in the themingContext script block is
currently rendered with raw triple-stache output, which can allow
script-breaking content from org-sourced fields. Update the theming.hbs template
to use a script-safe serialization approach instead of the json helper from
handlebarsHelpers, and make sure the themingContext payload is escaped so it
cannot contain a closing script tag or similar unsafe sequences.
In `@portals/developer-portal/src/services/adminService.js`:
- Line 444: The temp extraction path in adminService should not include the
user-controlled viewName from req.params.viewId, because it can produce unsafe
filesystem paths. Update the logic around the extractPath creation to use a
process-generated temp directory name instead, such as crypto.randomUUID() or
mkdtemp, and keep viewName out of the path construction entirely.
---
Nitpick comments:
In `@portals/developer-portal/src/pages/settings/partials/view-combo.hbs`:
- Around line 35-50: Update the view switcher in view-combo.hbs to use
combobox/listbox semantics instead of menu semantics: replace the current
role="menu" on the container and role="menuitem" on each item with the
appropriate listbox/option roles, and ensure the selected view is exposed via
aria-selected on the item marked with the selected class. Also wire the
trigger/input behavior to the popup with the correct aria-controls/aria-owns
pattern so the filterable single-select control is announced correctly by
assistive tech.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3842af83-0f78-48c8-b9ee-ee0996beef00
📒 Files selected for processing (18)
portals/developer-portal/docs/administer/llm-instructions.mdportals/developer-portal/src/controllers/viewConfigureController.jsportals/developer-portal/src/dao/organizationDao.jsportals/developer-portal/src/defaultContent/pages/api-workflows/page.hbsportals/developer-portal/src/defaultContent/partials/sidebar.hbsportals/developer-portal/src/middlewares/registerPartials.jsportals/developer-portal/src/pages/settings/page.hbsportals/developer-portal/src/pages/settings/partials/api-workflows.hbsportals/developer-portal/src/pages/settings/partials/llms-config.hbsportals/developer-portal/src/pages/settings/partials/theming.hbsportals/developer-portal/src/pages/settings/partials/view-combo.hbsportals/developer-portal/src/routes/pages/designModeRoute.jsportals/developer-portal/src/routes/pages/settingsRoute.jsportals/developer-portal/src/scripts/filter.jsportals/developer-portal/src/scripts/manage-api-workflows.jsportals/developer-portal/src/services/adminService.jsportals/developer-portal/src/styles/settings-layout.cssportals/developer-portal/src/utils/constants.js
There was a problem hiding this comment.
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 `@portals/developer-portal/src/middlewares/ensureAuthenticated.js`:
- Around line 188-206: Align the cross-organization authorization logic in the
local-auth and token/OAuth2 branches of the authentication middleware: both must
compare the token organization claim with orgDetails.idp_ref_id and allow
authorizedOrgs membership consistently. Review the orgIdentifier falsy case and
explicitly enforce the intended behavior, avoiding an unintended fail-open
bypass; update both branches and preserve the 403 response for unauthorized
access.
- Around line 193-194: Update the glob matching in the authentication middleware
around isDevportalRoot and the AUTHENTICATED_PAGES/AUTHORIZED_PAGES checks to
use the request pathname without query parameters instead of req.originalUrl.
Derive the pathname from the request URL while preserving the existing minimatch
patterns and ensure all related route checks use this normalized value.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7b2e0112-99ff-407c-a533-8eb98ff502eb
📒 Files selected for processing (6)
portals/developer-portal/src/helpers/handlebarsHelpers.jsportals/developer-portal/src/middlewares/ensureAuthenticated.jsportals/developer-portal/src/pages/settings/page.hbsportals/developer-portal/src/pages/settings/partials/view-combo.hbsportals/developer-portal/src/services/adminService.jsportals/developer-portal/src/services/apiMetadataService.js
🚧 Files skipped from review as they are similar to previous changes (3)
- portals/developer-portal/src/pages/settings/partials/view-combo.hbs
- portals/developer-portal/src/services/adminService.js
- portals/developer-portal/src/pages/settings/page.hbs
Purpose
Fix #2569
Approach
Samples
View specific settings:

Theme config page + settings navbar ordering:
