Skip to content

Commit e2a71c0

Browse files
committed
feat: enhance Assign Role Wizard with initial user handling and permission constants
1 parent f27222d commit e2a71c0

6 files changed

Lines changed: 74 additions & 57 deletions

File tree

.eslintrc.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
// eslint-disable-next-line import/no-extraneous-dependencies
22
const { createConfig } = require('@openedx/frontend-build');
33

4-
module.exports = createConfig('eslint');
4+
module.exports = createConfig('eslint', {
5+
rules: {
6+
'react/jsx-filename-extension': [1, { extensions: ['.jsx', '.tsx'] }],
7+
},
8+
});

src/authz-module/constants.ts

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,52 @@ export const libraryPermissions = [
7171
{ key: CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, resource: 'library_team', description: 'Add, remove, and assign roles to users within the library.' },
7272
];
7373

74+
// Course Permission Keys
75+
export const COURSE_PERMISSIONS = {
76+
// View permissions (Course Auditor)
77+
VIEW_COURSE: 'courses.view_course',
78+
VIEW_COURSE_UPDATES: 'courses.view_course_updates',
79+
VIEW_PAGES_AND_RESOURCES: 'courses.view_pages_and_resources',
80+
VIEW_FILES: 'courses.view_files',
81+
VIEW_GRADING_SETTINGS: 'courses.view_grading_settings',
82+
VIEW_CHECKLISTS: 'courses.view_checklists',
83+
VIEW_COURSE_TEAM: 'courses.view_course_team',
84+
VIEW_SCHEDULE_AND_DETAILS: 'courses.view_schedule_and_details',
85+
86+
// Edit permissions (Course Editor)
87+
EDIT_COURSE_CONTENT: 'courses.edit_course_content',
88+
MANAGE_LIBRARY_UPDATES: 'courses.manage_library_updates',
89+
MANAGE_COURSE_UPDATES: 'courses.manage_course_updates',
90+
MANAGE_PAGES_AND_RESOURCES: 'courses.manage_pages_and_resources',
91+
CREATE_FILES: 'courses.create_files',
92+
EDIT_FILES: 'courses.edit_files',
93+
EDIT_GRADING_SETTINGS: 'courses.edit_grading_settings',
94+
MANAGE_GROUP_CONFIGURATIONS: 'courses.manage_group_configurations',
95+
EDIT_DETAILS: 'courses.edit_details',
96+
MANAGE_TAGS: 'courses.manage_tags',
97+
98+
// Publish & lifecycle permissions (Course Staff)
99+
PUBLISH_COURSE_CONTENT: 'courses.publish_course_content',
100+
DELETE_FILES: 'courses.delete_files',
101+
EDIT_SCHEDULE: 'courses.edit_schedule',
102+
MANAGE_ADVANCED_SETTINGS: 'courses.manage_advanced_settings',
103+
MANAGE_CERTIFICATES: 'courses.manage_certificates',
104+
IMPORT_COURSE: 'courses.import_course',
105+
EXPORT_COURSE: 'courses.export_course',
106+
EXPORT_TAGS: 'courses.export_tags',
107+
108+
// Team & taxonomy permissions (Course Admin only)
109+
MANAGE_COURSE_TEAM: 'courses.manage_course_team',
110+
MANAGE_TAXONOMIES: 'courses.manage_taxonomies',
111+
112+
// Legacy role permissions
113+
LEGACY_STAFF_ROLE_PERMISSIONS: 'courses.legacy_staff_role_permissions',
114+
LEGACY_INSTRUCTOR_ROLE_PERMISSIONS: 'courses.legacy_instructor_role_permissions',
115+
LEGACY_LIMITED_STAFF_ROLE_PERMISSIONS: 'courses.legacy_limited_staff_role_permissions',
116+
LEGACY_DATA_RESEARCHER_PERMISSIONS: 'courses.legacy_data_researcher_permissions',
117+
LEGACY_BETA_TESTER_PERMISSIONS: 'courses.legacy_beta_tester_permissions',
118+
};
119+
74120
// Resource Type Definitions
75121
export const RESOURCE_TYPES = {
76122
LIBRARY: 'library',
@@ -94,16 +140,13 @@ export const courseRolesMetadata = [
94140
},
95141
];
96142

97-
// Course roles placeholder for future implementation
98-
export const COURSE_ROLES_METADATA = courseRolesMetadata;
99-
100143
// Get roles metadata by resource type
101144
export const getRolesMetadata = (resourceType: ResourceType) => {
102145
switch (resourceType) {
103146
case RESOURCE_TYPES.LIBRARY:
104147
return libraryRolesMetadata;
105148
case RESOURCE_TYPES.COURSE:
106-
return COURSE_ROLES_METADATA;
149+
return courseRolesMetadata;
107150
default:
108151
return [];
109152
}

src/authz-module/libraries-manager/LibrariesTeamManager.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const LibrariesTeamManager = () => {
6464
onClick={handleNavigateToWizard}
6565
key="add-new-role"
6666
>
67-
{intl.formatMessage(messages['library.authz.manage.add.role.button']) || 'New Role'}
67+
{intl.formatMessage(messages['library.authz.manage.add.role.button'])}
6868
</Button>,
6969
]
7070
: []

src/authz-module/wizard/AssignRoleWizard.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@ import { SpinnerSimple } from '@openedx/paragon/icons';
88
import SelectUsersAndRoleStep from './SelectUsersAndRoleStep';
99
import DefineApplicationScopeStep from './DefineApplicationScopeStep';
1010
import { useValidateUsers, useAssignTeamMembersRole } from '../data/hooks';
11-
import { courseRolesMetadata, libraryRolesMetadata } from '../constants';
11+
import {
12+
CONTENT_LIBRARY_PERMISSIONS, COURSE_PERMISSIONS, courseRolesMetadata, libraryRolesMetadata,
13+
} from '../constants';
1214
import { useToastManager } from '../libraries-manager/ToastManagerContext';
1315
import { useValidateUserPermissions } from '../../data/hooks';
1416

1517
const allRolesMetadata = [...courseRolesMetadata, ...libraryRolesMetadata];
1618

1719
const CONTEXT_BY_ACTION: Record<string, string> = {
18-
'content_libraries.manage_library_team': 'library',
19-
'courses.manage_course_team': 'course',
20+
[CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TEAM]: 'library',
21+
[COURSE_PERMISSIONS.MANAGE_COURSE_TEAM]: 'course',
2022
};
2123

2224
const STEPS = {
@@ -29,11 +31,12 @@ type StepKey = typeof STEPS[keyof typeof STEPS];
2931
interface AssignRoleWizardProps {
3032
onClose: () => void;
3133
scope: string;
34+
initialUsers?: string;
3235
}
3336

34-
const AssignRoleWizard = ({ onClose, scope }: AssignRoleWizardProps) => {
37+
const AssignRoleWizard = ({ onClose, scope, initialUsers = '' }: AssignRoleWizardProps) => {
3538
const [activeStep, setActiveStep] = useState<StepKey>(STEPS.SELECT_USERS_AND_ROLE);
36-
const [users, setUsers] = useState('');
39+
const [users, setUsers] = useState(initialUsers);
3740
const [selectedRole, setSelectedRole] = useState<string | null>(null);
3841
const [selectedScopes, setSelectedScopes] = useState<Set<string>>(new Set());
3942

@@ -46,8 +49,8 @@ const AssignRoleWizard = ({ onClose, scope }: AssignRoleWizardProps) => {
4649

4750
// Filter role groups based on what the current user is allowed to manage
4851
const permissionChecks = useMemo(() => [
49-
{ action: 'content_libraries.manage_library_team', scope },
50-
{ action: 'courses.manage_course_team', scope },
52+
{ action: CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TEAM, scope },
53+
{ action: COURSE_PERMISSIONS.MANAGE_COURSE_TEAM, scope },
5154
], [scope]);
5255

5356
const { data: permissionsData } = useValidateUserPermissions(permissionChecks);

src/authz-module/wizard/AssignRoleWizardPage.tsx

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { useNavigate, useSearchParams } from 'react-router-dom';
2-
import { Button } from '@openedx/paragon';
32
import AssignRoleWizard from './AssignRoleWizard';
43
import AuthZLayout from '../components/AuthZLayout';
54
import { useLibrary } from '../data/hooks';
@@ -9,23 +8,11 @@ const AssignRoleWizardPage = () => {
98
const navigate = useNavigate();
109
const [searchParams] = useSearchParams();
1110
const scope = searchParams.get('scope') || '';
11+
const initialUsers = searchParams.get('users') || '';
1212

13-
const { data: library, isLoading, error } = useLibrary(scope);
13+
const { data: library, isLoading } = useLibrary(scope);
1414

15-
if (isLoading) {
16-
return null;
17-
}
18-
19-
if (error || !library) {
20-
return (
21-
<div className="assign-role-wizard-page p-4">
22-
<p>Library not found. Please go back and try again.</p>
23-
<Button variant="secondary" onClick={() => navigate(-1)}>
24-
Go Back
25-
</Button>
26-
</div>
27-
);
28-
}
15+
if (isLoading) { return null; }
2916

3017
const teamMembersPath = `/authz${ROUTES.LIBRARIES_TEAM_PATH.replace(':libraryId', scope)}`;
3118

@@ -45,6 +32,7 @@ const AssignRoleWizardPage = () => {
4532
<AssignRoleWizard
4633
onClose={handleCancel}
4734
scope={scope}
35+
initialUsers={initialUsers}
4836
/>
4937
</AuthZLayout>
5038
);
Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,17 @@
11
interface DefineApplicationScopeStepProps {
2-
users: string;
32
selectedRole: string | null;
4-
onBack?: () => void;
3+
selectedScopes: Set<string>;
4+
onScopeToggle: (scopeId: string) => void;
55
}
66

7-
const DefineApplicationScopeStep = ({ users, selectedRole }: DefineApplicationScopeStepProps) => {
7+
const DefineApplicationScopeStep = (
8+
{ selectedRole, selectedScopes, onScopeToggle }: DefineApplicationScopeStepProps,
9+
) => {
810
// Placeholder for Step 2 - "Define Application Scope"
911
// This will be implemented in future iterations
12+
console.log(selectedRole, selectedScopes, onScopeToggle);
1013

11-
const usersList = users.split(',').map(u => u.trim()).filter(Boolean);
12-
13-
return (
14-
<div className="assign-role-step-2">
15-
<h4>Review and Confirm</h4>
16-
17-
<div className="mb-4">
18-
<h5>Selected Role</h5>
19-
<p>{selectedRole || 'No role selected'}</p>
20-
</div>
21-
22-
<div className="mb-4">
23-
<h5>Users ({usersList.length})</h5>
24-
<ul>
25-
{usersList.map((user, index) => (
26-
<li key={index}>{user}</li>
27-
))}
28-
</ul>
29-
</div>
30-
31-
<p className="text-muted">
32-
Step 2 content - "Define Application Scope" will be implemented in future iterations.
33-
</p>
34-
</div>
35-
);
14+
return <h1>Step 2</h1>;
3615
};
3716

3817
export default DefineApplicationScopeStep;

0 commit comments

Comments
 (0)