Add read-only indicators and access guards for declarative resources#3033
Add read-only indicators and access guards for declarative resources#3033rajithacharith wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughThis pull request adds read-only resource protection across the console. It introduces an ChangesRead-Only Resource Protection
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
frontend/apps/console/src/features/agents/components/AgentsList.tsxESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox. frontend/apps/console/src/features/agents/models/agent.tsESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox. frontend/apps/console/src/features/agents/pages/AgentEditPage.tsxESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.
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 |
84aa0f5 to
8ef4c0f
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/packages/configure-organization-units/src/components/OrganizationUnitsTreeView.tsx (1)
430-436:⚠️ Potential issue | 🟠 Major | ⚡ Quick winRead-only OUs still expose an add-child action path.
fetchChildItemsalways prepends the synthetic add-child node, so expanding a read-only OU still allows creating children via that row. This bypasses the read-only access guard.Suggested fix
const result = await fetchChildPage(parentId, 0); const childOUs = result.organizationUnits; const parentItem = findTreeItem(treeItemsRef.current, parentId); - const addChildItem = buildAddChildItem(parentId, parentItem?.label ?? '', parentItem?.handle ?? ''); - const items = childOUs.length > 0 ? [addChildItem, ...buildTreeItems(childOUs)] : [addChildItem]; + const canAddChild = !parentItem?.isReadOnly; + const items = buildTreeItems(childOUs); + + if (canAddChild) { + items.unshift(buildAddChildItem(parentId, parentItem?.label ?? '', parentItem?.handle ?? '')); + }🤖 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/packages/configure-organization-units/src/components/OrganizationUnitsTreeView.tsx` around lines 430 - 436, The code always prepends the synthetic add-child node (via buildAddChildItem) which lets users create children on read-only OUs; change the logic after finding parentItem (findTreeItem/ treeItemsRef.current) to only create/prepend addChildItem when the parent item is present and not read-only (e.g., check parentItem?.readOnly === false or parentItem?.isReadOnly === false / or a capability flag like parentItem?.canCreateChildren), then construct items as [addChildItem, ...buildTreeItems(childOUs)] only when that check passes, otherwise return only buildTreeItems(childOUs) (or [ ] if none).
🤖 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/apps/console/src/features/agents/components/AgentsList.tsx`:
- Around line 127-133: The row click handler is firing even for read-only rows;
update the onRowClick logic in AgentsList (where onRowClick currently always
navigates) to first check params.row.isReadOnly and return early if true, and
modify the Lock IconButton (the small IconButton rendered when
params.row.isReadOnly is true) to call event.stopPropagation() in its click
handler so clicks on the lock do not bubble to the row; ensure you reference
params.row.isReadOnly, the onRowClick function, and the IconButton/Lock render
branch when making the changes.
In
`@frontend/apps/console/src/features/applications/components/ApplicationsList.tsx`:
- Around line 135-139: The row click handler in ApplicationsList.tsx currently
navigates unconditionally and bypasses the read-only guard; update the handler
(e.g., the onRowClick or handleRowClick function that calls navigate) to check
params.row.isReadOnly and return/do nothing when true, mirroring the existing
isReadOnly check used for action buttons (where params.row.isReadOnly is used);
ensure this same guard is applied wherever navigation on row click occurs so
read-only applications cannot be opened by clicking the row.
In `@frontend/apps/console/src/features/groups/components/GroupsList.tsx`:
- Around line 113-119: The row click handler in GroupsList.tsx currently
navigates for every row and bypasses the lock icon's read-only intent; update
the row click handler (the onRowClick/handleRowClick function used for DataGrid
rows) to check params.row.isReadOnly and return early (no navigation) when true,
preserving the lock-only UI behavior; ensure you reference the same params.row
object used in the render cell (the isReadOnly property) so read-only rows are
not navigable.
In `@frontend/apps/console/src/features/roles/components/RolesList.tsx`:
- Around line 113-119: The row click handler currently navigates even for
read-only roles; update the onRowClick (or the function handling row activation)
to check params.row.isReadOnly and return early (no-op) when true so clicks on
locked rows do nothing; apply the same guard to the second occurrence referenced
(the other row click handler around the 174-181 block) and ensure any navigation
calls (e.g., history.push or navigate) are skipped for read-only rows.
---
Outside diff comments:
In
`@frontend/packages/configure-organization-units/src/components/OrganizationUnitsTreeView.tsx`:
- Around line 430-436: The code always prepends the synthetic add-child node
(via buildAddChildItem) which lets users create children on read-only OUs;
change the logic after finding parentItem (findTreeItem/ treeItemsRef.current)
to only create/prepend addChildItem when the parent item is present and not
read-only (e.g., check parentItem?.readOnly === false or parentItem?.isReadOnly
=== false / or a capability flag like parentItem?.canCreateChildren), then
construct items as [addChildItem, ...buildTreeItems(childOUs)] only when that
check passes, otherwise return only buildTreeItems(childOUs) (or [ ] if none).
🪄 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 Plus
Run ID: b03f7718-be0a-4d9d-a01c-03439509c467
📒 Files selected for processing (37)
frontend/apps/console/src/features/agents/components/AgentsList.tsxfrontend/apps/console/src/features/agents/models/agent.tsfrontend/apps/console/src/features/agents/pages/AgentEditPage.tsxfrontend/apps/console/src/features/applications/components/ApplicationsList.tsxfrontend/apps/console/src/features/applications/components/edit-application/general-settings/EditGeneralSettings.tsxfrontend/apps/console/src/features/applications/models/application.tsfrontend/apps/console/src/features/applications/pages/ApplicationEditPage.tsxfrontend/apps/console/src/features/design/components/common/ItemCard.tsxfrontend/apps/console/src/features/design/pages/DesignPage.tsxfrontend/apps/console/src/features/flows/components/FlowsList.tsxfrontend/apps/console/src/features/flows/components/visual-flow/DecoratedVisualFlow.tsxfrontend/apps/console/src/features/flows/models/responses.tsfrontend/apps/console/src/features/groups/components/GroupsList.tsxfrontend/apps/console/src/features/groups/components/edit-group/general-settings/EditGeneralSettings.tsxfrontend/apps/console/src/features/groups/models/group.tsfrontend/apps/console/src/features/groups/pages/GroupEditPage.tsxfrontend/apps/console/src/features/integrations/models/identity-provider.tsfrontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsxfrontend/apps/console/src/features/roles/components/RolesList.tsxfrontend/apps/console/src/features/roles/components/edit-role/general-settings/EditGeneralSettings.tsxfrontend/apps/console/src/features/roles/models/role.tsfrontend/apps/console/src/features/roles/pages/RoleEditPage.tsxfrontend/apps/console/src/features/user-types/components/UserTypesList.tsxfrontend/apps/console/src/features/user-types/components/edit-user-type/general-settings/EditGeneralSettings.tsxfrontend/apps/console/src/features/user-types/pages/ViewUserTypePage.tsxfrontend/apps/console/src/features/user-types/types/user-types.tsfrontend/packages/configure-organization-units/src/components/OrganizationUnitsTreeView.tsxfrontend/packages/configure-organization-units/src/components/edit-organization-unit/general-settings/EditGeneralSettings.tsxfrontend/packages/configure-organization-units/src/models/organization-unit-tree.tsfrontend/packages/configure-organization-units/src/models/organization-unit.tsfrontend/packages/configure-organization-units/src/pages/OrganizationUnitEditPage.tsxfrontend/packages/configure-organization-units/src/utils/buildTreeItems.tsfrontend/packages/configure-users/src/components/UsersList.tsxfrontend/packages/configure-users/src/pages/UserEditPage.tsxfrontend/packages/design/src/models/responses.tsfrontend/packages/i18n/src/locales/en-US.tsfrontend/packages/types/src/concepts/user.ts
| {params.row.isReadOnly ? ( | ||
| <Tooltip title={t('common:status.readOnly', 'Read Only')}> | ||
| <IconButton size="small" disableRipple sx={{cursor: 'default'}}> | ||
| <Lock size={16} /> | ||
| </IconButton> | ||
| </Tooltip> | ||
| ) : ( |
There was a problem hiding this comment.
Read-only rows are still navigable via row click.
Line 188 always navigates, so a read-only row (including clicking the lock icon) still opens edit. Gate onRowClick with isReadOnly and stop propagation on the lock button.
Suggested fix
onRowClick={(params) => {
- handleEditClick((params.row as BasicAgent).id);
+ if (!(params.row as BasicAgent).isReadOnly) {
+ handleEditClick((params.row as BasicAgent).id);
+ }
}} {params.row.isReadOnly ? (
<Tooltip title={t('common:status.readOnly', 'Read Only')}>
- <IconButton size="small" disableRipple sx={{cursor: 'default'}}>
+ <IconButton
+ size="small"
+ disableRipple
+ sx={{cursor: 'default'}}
+ onClick={(e) => e.stopPropagation()}
+ >
<Lock size={16} />
</IconButton>
</Tooltip>Also applies to: 188-190
🤖 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/apps/console/src/features/agents/components/AgentsList.tsx` around
lines 127 - 133, The row click handler is firing even for read-only rows; update
the onRowClick logic in AgentsList (where onRowClick currently always navigates)
to first check params.row.isReadOnly and return early if true, and modify the
Lock IconButton (the small IconButton rendered when params.row.isReadOnly is
true) to call event.stopPropagation() in its click handler so clicks on the lock
do not bubble to the row; ensure you reference params.row.isReadOnly, the
onRowClick function, and the IconButton/Lock render branch when making the
changes.
| {params.row.isReadOnly ? ( | ||
| <Tooltip title={t('common:status.readOnly', 'Read Only')}> | ||
| <IconButton size="small" disableRipple sx={{cursor: 'default'}}> | ||
| <Lock size={16} /> | ||
| </IconButton> |
There was a problem hiding this comment.
Row-click bypasses the read-only guard.
Line 198 navigates unconditionally, so read-only applications can still be opened from row click. Add the same isReadOnly check used in actions.
Suggested fix
onRowClick={(params) => {
- handleEditClick((params.row as BasicApplication).id);
+ if (!(params.row as BasicApplication).isReadOnly) {
+ handleEditClick((params.row as BasicApplication).id);
+ }
}}Also applies to: 198-200
🤖 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/apps/console/src/features/applications/components/ApplicationsList.tsx`
around lines 135 - 139, The row click handler in ApplicationsList.tsx currently
navigates unconditionally and bypasses the read-only guard; update the handler
(e.g., the onRowClick or handleRowClick function that calls navigate) to check
params.row.isReadOnly and return/do nothing when true, mirroring the existing
isReadOnly check used for action buttons (where params.row.isReadOnly is used);
ensure this same guard is applied wherever navigation on row click occurs so
read-only applications cannot be opened by clicking the row.
| {params.row.isReadOnly ? ( | ||
| <Tooltip title={t('common:status.readOnly', 'Read Only')}> | ||
| <IconButton size="small" disableRipple sx={{cursor: 'default'}}> | ||
| <Lock size={16} /> | ||
| </IconButton> | ||
| </Tooltip> | ||
| ) : ( |
There was a problem hiding this comment.
Read-only groups can still be opened via row click.
The row handler (Line 174 onward) navigates without checking isReadOnly, so the lock-only action state is bypassed.
Suggested fix
onRowClick={(params) => {
- const groupId = (params.row as GroupBasic).id;
+ if ((params.row as GroupBasic).isReadOnly) {
+ return;
+ }
+ const groupId = (params.row as GroupBasic).id;
(async (): Promise<void> => {
await navigate(`/groups/${groupId}`);
})().catch((_error: unknown) => {
logger.error('Failed to navigate to group', {error: _error, groupId});
});
}}Also applies to: 174-181
🤖 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/apps/console/src/features/groups/components/GroupsList.tsx` around
lines 113 - 119, The row click handler in GroupsList.tsx currently navigates for
every row and bypasses the lock icon's read-only intent; update the row click
handler (the onRowClick/handleRowClick function used for DataGrid rows) to check
params.row.isReadOnly and return early (no navigation) when true, preserving the
lock-only UI behavior; ensure you reference the same params.row object used in
the render cell (the isReadOnly property) so read-only rows are not navigable.
| {params.row.isReadOnly ? ( | ||
| <Tooltip title={t('common:status.readOnly', 'Read Only')}> | ||
| <IconButton size="small" disableRipple sx={{cursor: 'default'}}> | ||
| <Lock size={16} /> | ||
| </IconButton> | ||
| </Tooltip> | ||
| ) : ( |
There was a problem hiding this comment.
Read-only role guard is bypassed on row click.
The row click path still navigates regardless of isReadOnly, which undermines the lock-only action rendering.
Suggested fix
onRowClick={(params) => {
+ if ((params.row as RoleSummary).isReadOnly) {
+ return;
+ }
const roleId = (params.row as RoleSummary).id;
(async (): Promise<void> => {
await navigate(`/roles/${roleId}`);
})().catch((_error: unknown) => {
logger.error('Failed to navigate to role', {error: _error, roleId});
});
}}Also applies to: 174-181
🤖 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/apps/console/src/features/roles/components/RolesList.tsx` around
lines 113 - 119, The row click handler currently navigates even for read-only
roles; update the onRowClick (or the function handling row activation) to check
params.row.isReadOnly and return early (no-op) when true so clicks on locked
rows do nothing; apply the same guard to the second occurrence referenced (the
other row click handler around the 174-181 block) and ensure any navigation
calls (e.g., history.push or navigate) are skipped for read-only rows.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Purpose
Backend API list endpoints return an
isReadOnlyflag for declarative (file-based) resources. This PR wires up the frontend to visually indicate when a resource is read-only and prevent any mutation actions on those resources.Affected resources: Applications, Agents, Groups, Roles, User Types, Users, Flows, Organization Units, Themes
Approach
List views
Lockicon button in the actions column (DataGrid lists) — clicking is disabled and hovering shows a "Read Only" tooltip.Organization Units (tree view)
RichTreeViewrather than a DataGrid. For read-only items the Plus/Edit/Delete icon buttons in each tree node are replaced by a single Lock icon with a tooltip.isReadOnlyis propagated throughbuildTreeItems→OrganizationUnitTreeItem→buildItemMap→CustomTreeItem.Themes (card grid)
ItemCard) instead of a table. For read-only themes:isReadOnlyadded toThemeListItemmodel.Edit pages
isReadOnlyis true.ResourceAvatarmade non-editable, inline name/description edit buttons hidden, delete section hidden,UnsavedChangesBarsave button disabled.onSave={undefined}when the flow is read-only.Bug fixes
BoxandChipimports inFlowsList.tsxandRolesList.tsxthat caused render failures.Related Issues
Related PRs
Checklist
breaking changelabel added.Security checks
Summary by CodeRabbit
Release Notes