1. Overview
The data visibility feature within the access control page allows administrators to control what data different user roles can access based on various rules. The implementation ensures that each role has exactly one rule applied to prevent conflicts or gaps in data access permissions. The interface presents these permissions in a tabular format with checkbox controls for different user roles, enabling administrators to configure precise data visibility rules across the organization.
Integration Points:
- Settings - Parent settings management system
- Access Control - Permission management framework
- Users - User role assignment and management
- Sites - Location-based data visibility
- Departments - Department-level access control
2. Libraries and Dependencies
| Library | Purpose |
|---|---|
| React | Component-based UI development and state management |
| styled-components | Component styling with CSS-in-JS approach |
| clsx | Conditional class name construction |
| react-i18next | Internationalization of UI text |
| react-toastify | Displaying toast notifications for validation errors |
| @nimbly-technologies/nimbly-common | Common types shared across the Nimbly platform |
| Redux | State management (accessed via useSelector) |
3. Implementation Structure
3.1 Main Component: PermissionsContainer
The PermissionsContainer is the primary component responsible for rendering the access control interface, including the data visibility tab.
Key Props:
isNimbly- Boolean flag to determine if this is a Nimbly instanceisFetching/isBusy- Loading states for the componentpermissions- Restructured resource data that includes data visibility rulesselectedTab- The currently selected tab in the interfaceuserRoles- List of user roles available in the systemaccess- Current user’s permission valuesaccessLevel- Current user’s role levelonChangeValue- Handler for permission value changesonSave- Handler to persist changes to the databaseonReset- Handler to reset permissions to default values
3.2 Tab Navigation
The data visibility feature is accessed through a dedicated tab in the permission interface. The tab structure is defined in the TabsNav component:
{
label: 'data Visibility',
value: 'data-visibility',
text: 'label.settingPage.permissions.data-Visibility',
}3.3 Table Structure
The permission interface uses a table structure with:
- Header row: Shows user roles as column headers
- Feature rows: Groups permissions by features
- Permission rows: Individual permission items with checkboxes for each role
4. Data Visibility Rules and Validation
4.1 Rule Structure
Data visibility permissions are structured as follows:
{
'data-visibility': {
rules: {
all: {
permissions: {
view: {
admin: boolean,
manager: boolean,
// other roles...
}
}
},
'specific-dept': {
permissions: {
view: {
admin: boolean,
manager: boolean,
// other roles...
}
}
},
// other rules...
}
}
}4.2 Validation Logic
A key aspect of the data visibility implementation is the validation logic that ensures each role has exactly one rule applied:
const save = () => {
const dataVisibilityPermissions = props.permissions["data-visibility"];
let isError = false;
if (dataVisibilityPermissions) {
// Gets an array of all the roles
const roles = Object.keys(
dataVisibilityPermissions.rules.all.permissions.view ?? {}
);
// Keeps count of the number of rules selected for each role
let roleCount: Record<string, number> = {};
// Number of rules selected initialized to zero
roles.forEach((item) => {
roleCount[item] = 0;
});
// Iterate through each rule
Object.entries(dataVisibilityPermissions.rules).forEach(
([rule, permissions]) => {
// Iterate through permissions for each rule
Object.entries(permissions.permissions).forEach(
([permission, view]) => {
Object.entries(roleCount).forEach(([role, count]) => {
roleCount[role] = view?.[role]
? roleCount[role] + 1
: roleCount[role];
});
}
);
}
);
// Validate that each role has exactly one rule
Object.entries(roleCount).forEach(([role, count]) => {
if (count > 1) {
const roleObj = userRoles.find((item) => item.value === role);
toast.error(
`Error: Multiple permissions selected for '${roleObj?.label ?? ""}'`
);
isError = true;
} else if (count === 0) {
const roleObj = userRoles.find((item) => item.value === role);
toast.error(
`Error: No permission selected for '${roleObj?.label ?? ""}'`
);
isError = true;
}
});
}
// Only save if validation passes
if (!isError) {
handleSave();
}
};Validation ensures:
- No role has multiple conflicting data visibility rules
- Every role has at least one data visibility rule assigned
5. UI Components and Styling
5.1 Table Components
| Component | Purpose |
|---|---|
| SettingPermissionTable | Main table component with sticky headers and columns |
| TableWrapper | Container for the table with overflow handling |
| Column | Table cell component with conditional cursor styling based on permission status |
5.2 Permission Controls
- Checkbox: Custom checkbox component used for toggling permissions
- handleChangeValue: Function that updates permission values when checkboxes are clicked
5.3 Responsive Design
The interface includes responsive design elements:
- Desktop view: Full table layout with horizontal scrolling for many columns
- Mobile view: Placeholder for mobile-specific layout (marked as TODO in the code)
- FloatingButton: Fixed-position save button for mobile screens
6. State Management and Data Flow
6.1 Permission State Structure
The permissions data is structured as a nested object with specific paths for each permission:
[tabName, feature, access, 'permissions', permission, role]
Example:
['data-visibility', 'rules', 'all', 'permissions', 'view', 'admin']
6.2 State Updates
When a checkbox is clicked:
handleChangeValueis called with the path and new value- This triggers the
onChangeValueprop function, updating the permission state - Changes remain in memory until saved
6.3 Saving Changes
The save process involves:
- Validating the current permission state
- If valid, calling
handleSavewhich triggers theonSaveprop - The parent component then persists changes to the database
7. File Paths and Code References
| File | Path |
|---|---|
| Main Component | src/components/permissions/PermissionsContainer.tsx |
| Checkbox Component | src/components/permissions/components/Checkbox.tsx |
| Reset Modal | src/components/permissions/components/PermissionsResetConfirmationModal.tsx |
| Types | src/components/permissions/typings.ts |
8. Summary
The data visibility feature in the access control page provides a structured, rule-based approach to managing what data different roles can access within the organization.
Key aspects include:
- Rule-based permissions: Different visibility rules (all, specific-dept, specific-site, etc.)
- Role-specific controls: Permissions