@openedx/frontend-app-admin-console 1.0.0-alpha.6 → 1.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authz-module/authz-home/index.js +20 -1
- package/dist/authz-module/authz-home/index.js.map +1 -1
- package/dist/authz-module/components/AddRoleButton.js +1 -1
- package/dist/authz-module/components/AddRoleButton.js.map +1 -1
- package/dist/authz-module/components/AuthZTitle.js +5 -3
- package/dist/authz-module/components/AuthZTitle.js.map +1 -1
- package/dist/authz-module/components/ExpandableButton.d.ts +17 -0
- package/dist/authz-module/components/ExpandableButton.js +16 -0
- package/dist/authz-module/components/ExpandableButton.js.map +1 -0
- package/dist/authz-module/components/TableCells.d.ts +5 -8
- package/dist/authz-module/components/TableCells.js +26 -59
- package/dist/authz-module/components/TableCells.js.map +1 -1
- package/dist/authz-module/components/TableControlBar/OrgFilter.js +2 -2
- package/dist/authz-module/components/TableControlBar/OrgFilter.js.map +1 -1
- package/dist/authz-module/components/TableControlBar/TableControlBar.d.ts +4 -1
- package/dist/authz-module/components/TableControlBar/TableControlBar.js +24 -24
- package/dist/authz-module/components/TableControlBar/TableControlBar.js.map +1 -1
- package/dist/authz-module/components/TableFooter/TableFooter.d.ts +14 -1
- package/dist/authz-module/components/TableFooter/TableFooter.js +3 -2
- package/dist/authz-module/components/TableFooter/TableFooter.js.map +1 -1
- package/dist/authz-module/components/constants.d.ts +1 -0
- package/dist/authz-module/components/constants.js +2 -1
- package/dist/authz-module/components/constants.js.map +1 -1
- package/dist/authz-module/components/messages.d.ts +0 -5
- package/dist/authz-module/components/messages.js +2 -7
- package/dist/authz-module/components/messages.js.map +1 -1
- package/dist/authz-module/constants.d.ts +14 -6
- package/dist/authz-module/constants.js +23 -6
- package/dist/authz-module/constants.js.map +1 -1
- package/dist/authz-module/data/api.d.ts +12 -4
- package/dist/authz-module/data/api.js +11 -2
- package/dist/authz-module/data/api.js.map +1 -1
- package/dist/authz-module/data/hooks.d.ts +8 -8
- package/dist/authz-module/data/hooks.js +15 -20
- package/dist/authz-module/data/hooks.js.map +1 -1
- package/dist/authz-module/hooks/useExclusiveRowExpansion.d.ts +7 -0
- package/dist/authz-module/hooks/useExclusiveRowExpansion.js +24 -0
- package/dist/authz-module/hooks/useExclusiveRowExpansion.js.map +1 -0
- package/dist/authz-module/index.scss +120 -2
- package/dist/authz-module/messages.d.ts +23 -0
- package/dist/authz-module/messages.js +18 -0
- package/dist/authz-module/messages.js.map +1 -1
- package/dist/authz-module/role-assignation-wizard/hooks/useScopeListData.js.map +1 -1
- package/dist/authz-module/team-members/TeamMembersTable.js +55 -17
- package/dist/authz-module/team-members/TeamMembersTable.js.map +1 -1
- package/dist/authz-module/team-members/components/AssignedRolesCell.d.ts +20 -0
- package/dist/authz-module/team-members/components/AssignedRolesCell.js +54 -0
- package/dist/authz-module/team-members/components/AssignedRolesCell.js.map +1 -0
- package/dist/authz-module/team-members/components/MoreRolesToggle.d.ts +14 -0
- package/dist/authz-module/team-members/components/MoreRolesToggle.js +25 -0
- package/dist/authz-module/team-members/components/MoreRolesToggle.js.map +1 -0
- package/dist/authz-module/team-members/components/TeamMemberCells.d.ts +17 -0
- package/dist/authz-module/team-members/components/TeamMemberCells.js +21 -0
- package/dist/authz-module/team-members/components/TeamMemberCells.js.map +1 -0
- package/dist/authz-module/team-members/components/TeamMemberViewActionCell.d.ts +18 -0
- package/dist/authz-module/team-members/components/TeamMemberViewActionCell.js +42 -0
- package/dist/authz-module/team-members/components/TeamMemberViewActionCell.js.map +1 -0
- package/dist/authz-module/team-members/components/UserAssignmentsSubTable.d.ts +16 -0
- package/dist/authz-module/team-members/components/UserAssignmentsSubTable.js +74 -0
- package/dist/authz-module/team-members/components/UserAssignmentsSubTable.js.map +1 -0
- package/dist/authz-module/team-members/index.d.ts +1 -0
- package/dist/authz-module/team-members/index.js +2 -0
- package/dist/authz-module/team-members/index.js.map +1 -0
- package/dist/authz-module/team-members/messages.d.ts +56 -1
- package/dist/authz-module/team-members/messages.js +59 -4
- package/dist/authz-module/team-members/messages.js.map +1 -1
- package/dist/authz-module/utils.d.ts +5 -0
- package/dist/authz-module/utils.js +10 -10
- package/dist/authz-module/utils.js.map +1 -1
- package/dist/components/LoadingPage.d.ts +3 -0
- package/dist/components/LoadingPage.js +9 -1
- package/dist/components/LoadingPage.js.map +1 -1
- package/dist/components/messages.d.ts +8 -0
- package/dist/components/messages.js +10 -0
- package/dist/components/messages.js.map +1 -0
- package/dist/types.d.ts +29 -20
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/dist/authz-module/components/ViewMoreLink.d.ts +0 -8
- package/dist/authz-module/components/ViewMoreLink.js +0 -8
- package/dist/authz-module/components/ViewMoreLink.js.map +0 -1
|
@@ -2,8 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useIntl } from '@openedx/frontend-base';
|
|
3
3
|
import { Tab, Tabs } from '@openedx/paragon';
|
|
4
4
|
import { useLocation, useSearchParams } from 'react-router-dom';
|
|
5
|
-
import TeamMembersTable from '../team-members
|
|
5
|
+
import { TeamMembersTable } from '../team-members';
|
|
6
6
|
import AddRoleButton from '../components/AddRoleButton';
|
|
7
|
+
import { useViewTeamPermissions } from '../hooks/useViewTeamPermissions';
|
|
8
|
+
import { CustomErrors } from '../../constants';
|
|
9
|
+
import LoadingPage from '../../components/LoadingPage';
|
|
7
10
|
import RolesPermissions from '../roles-permissions/RolesPermissions';
|
|
8
11
|
import AuthZLayout from '../components/AuthZLayout';
|
|
9
12
|
import messages from './messages';
|
|
@@ -17,6 +20,22 @@ const AuthzHome = () => {
|
|
|
17
20
|
*/
|
|
18
21
|
const presetScope = ((_a = searchParams.get('scope')) === null || _a === void 0 ? void 0 : _a.replace(/\s/g, '+')) || undefined;
|
|
19
22
|
const pageTitle = intl.formatMessage(messages['authz.manage.page.title']);
|
|
23
|
+
const { isCourseViewAllowed, isLibraryViewAllowed, isLoading: isLoadingPermissions, } = useViewTeamPermissions();
|
|
24
|
+
/**
|
|
25
|
+
* It gates the whole page whether the user is allowed to view the team members. If
|
|
26
|
+
* the user is not allowed, an error is thrown to display the access denied message.
|
|
27
|
+
*
|
|
28
|
+
* Rendering is held until the check settles rather than started optimistically, so a
|
|
29
|
+
* user who turns out to be denied never fires the listing and filter requests behind
|
|
30
|
+
* the page. Both flags read false while it is in flight, which would otherwise deny
|
|
31
|
+
* everyone for a frame.
|
|
32
|
+
*/
|
|
33
|
+
if (isLoadingPermissions) {
|
|
34
|
+
return _jsx(LoadingPage, {});
|
|
35
|
+
}
|
|
36
|
+
if (!isCourseViewAllowed && !isLibraryViewAllowed) {
|
|
37
|
+
throw new Error(CustomErrors.NO_ACCESS);
|
|
38
|
+
}
|
|
20
39
|
return (_jsx(AuthZLayout, { pageTitle: pageTitle, actions: [_jsx(AddRoleButton, {}, "add-role-button")], children: _jsxs(Tabs, { variant: "tabs", defaultActiveKey: hash ? 'permissionsRoles' : 'team', className: "page-band bg-light-100", children: [_jsx(Tab, { eventKey: "team", title: intl.formatMessage(messages['authz.tabs.team']), className: "page-band py-5", children: _jsx(TeamMembersTable, { presetScope: presetScope }) }), _jsx(Tab, { id: "libraries-permissions-roles-tab", eventKey: "permissionsRoles", title: intl.formatMessage(messages['authz.tabs.permissionsRoles']), className: "page-band py-5", children: _jsx(RolesPermissions, {}) })] }) }));
|
|
21
40
|
};
|
|
22
41
|
export default AuthzHome;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/authz-module/authz-home/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,gBAAgB,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/authz-module/authz-home/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,aAAa,MAAM,4CAA4C,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAC;AACxF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,WAAW,MAAM,6BAA6B,CAAC;AACtD,OAAO,gBAAgB,MAAM,sDAAsD,CAAC;AACpF,OAAO,WAAW,MAAM,0CAA0C,CAAC;AAEnE,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,SAAS,GAAG,GAAG,EAAE;;IACrB,MAAM,EAAE,IAAI,EAAE,GAAG,WAAW,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,YAAY,CAAC,GAAG,eAAe,EAAE,CAAC;IAEzC;;MAEE;IACF,MAAM,WAAW,GAAG,CAAA,MAAA,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,0CAAE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,KAAI,SAAS,CAAC;IAEhF,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,CAAC;IAE1E,MAAM,EACJ,mBAAmB,EAAE,oBAAoB,EAAE,SAAS,EAAE,oBAAoB,GAC3E,GAAG,sBAAsB,EAAE,CAAC;IAE7B;;;;;;;;OAQG;IACH,IAAI,oBAAoB,EAAE,CAAC;QACzB,OAAO,KAAC,WAAW,KAAG,CAAC;IACzB,CAAC;IAED,IAAI,CAAC,mBAAmB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,CACL,KAAC,WAAW,IACV,SAAS,EAAE,SAAS,EACpB,OAAO,EACL,CAAC,KAAC,aAAa,MAAK,iBAAiB,CAAG,CAAC,YAG3C,MAAC,IAAI,IACH,OAAO,EAAC,MAAM,EACd,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,EACpD,SAAS,EAAC,wBAAwB,aAElC,KAAC,GAAG,IAAC,QAAQ,EAAC,MAAM,EAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,EAAE,SAAS,EAAC,gBAAgB,YACrG,KAAC,gBAAgB,IAAC,WAAW,EAAE,WAAW,GAAI,GAC1C,EACN,KAAC,GAAG,IAAC,EAAE,EAAC,iCAAiC,EAAC,QAAQ,EAAC,kBAAkB,EAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,6BAA6B,CAAC,CAAC,EAAE,SAAS,EAAC,gBAAgB,YAClK,KAAC,gBAAgB,KAAG,GAChB,IACD,GACK,CACf,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,SAAS,CAAC","sourcesContent":["import { useIntl } from '@openedx/frontend-base';\nimport { Tab, Tabs } from '@openedx/paragon';\nimport { useLocation, useSearchParams } from 'react-router-dom';\nimport { TeamMembersTable } from '@src/authz-module/team-members';\nimport AddRoleButton from '@src/authz-module/components/AddRoleButton';\nimport { useViewTeamPermissions } from '@src/authz-module/hooks/useViewTeamPermissions';\nimport { CustomErrors } from '@src/constants';\nimport LoadingPage from '@src/components/LoadingPage';\nimport RolesPermissions from '@src/authz-module/roles-permissions/RolesPermissions';\nimport AuthZLayout from '@src/authz-module/components/AuthZLayout';\n\nimport messages from './messages';\n\nconst AuthzHome = () => {\n const { hash } = useLocation();\n const intl = useIntl();\n const [searchParams] = useSearchParams();\n\n /* In the authoring repository the scope is encoded but this is to Replace spaces with '+'\n to match URL encoding format in case the 'scope' parameter is provided with spaces instead of '+'\n */\n const presetScope = searchParams.get('scope')?.replace(/\\s/g, '+') || undefined;\n\n const pageTitle = intl.formatMessage(messages['authz.manage.page.title']);\n\n const {\n isCourseViewAllowed, isLibraryViewAllowed, isLoading: isLoadingPermissions,\n } = useViewTeamPermissions();\n\n /**\n * It gates the whole page whether the user is allowed to view the team members. If\n * the user is not allowed, an error is thrown to display the access denied message.\n *\n * Rendering is held until the check settles rather than started optimistically, so a\n * user who turns out to be denied never fires the listing and filter requests behind\n * the page. Both flags read false while it is in flight, which would otherwise deny\n * everyone for a frame.\n */\n if (isLoadingPermissions) {\n return <LoadingPage />;\n }\n\n if (!isCourseViewAllowed && !isLibraryViewAllowed) {\n throw new Error(CustomErrors.NO_ACCESS);\n }\n\n return (\n <AuthZLayout\n pageTitle={pageTitle}\n actions={\n [<AddRoleButton key=\"add-role-button\" />]\n }\n >\n <Tabs\n variant=\"tabs\"\n defaultActiveKey={hash ? 'permissionsRoles' : 'team'}\n className=\"page-band bg-light-100\"\n >\n <Tab eventKey=\"team\" title={intl.formatMessage(messages['authz.tabs.team'])} className=\"page-band py-5\">\n <TeamMembersTable presetScope={presetScope} />\n </Tab>\n <Tab id=\"libraries-permissions-roles-tab\" eventKey=\"permissionsRoles\" title={intl.formatMessage(messages['authz.tabs.permissionsRoles'])} className=\"page-band py-5\">\n <RolesPermissions />\n </Tab>\n </Tabs>\n </AuthZLayout>\n );\n};\n\nexport default AuthzHome;\n"]}
|
|
@@ -16,7 +16,7 @@ const AddRoleButton = ({ presetUsername, from }) => {
|
|
|
16
16
|
const path = buildWizardPath({ from, users: presetUsername });
|
|
17
17
|
navigate(path);
|
|
18
18
|
};
|
|
19
|
-
return (canAssignRole ? (_jsx(Button, { iconBefore: Plus, onClick: handleClick, children: intl.formatMessage(baseMessages['authz.management.assign.role.title']) })) : null);
|
|
19
|
+
return (canAssignRole ? (_jsx(Button, { size: "sm", iconBefore: Plus, onClick: handleClick, children: intl.formatMessage(baseMessages['authz.management.assign.role.title']) })) : null);
|
|
20
20
|
};
|
|
21
21
|
export default AddRoleButton;
|
|
22
22
|
//# sourceMappingURL=AddRoleButton.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AddRoleButton.js","sourceRoot":"","sources":["../../../src/authz-module/components/AddRoleButton.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,YAAY,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,qCAAqC,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAO9E,MAAM,aAAa,GAAG,CAAC,EAAE,cAAc,EAAE,IAAI,EAAsB,EAAE,EAAE;IACrE,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,MAAM,EAAE,IAAI,EAAE,4BAA4B,EAAE,GAAG,qCAAqC,CAAC,uBAAuB,CAAC,CAAC;IAC9G,MAAM,aAAa,GAAG,4BAA4B,aAA5B,4BAA4B,uBAA5B,4BAA4B,CAAE,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAE7F,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,MAAM,IAAI,GAAG,eAAe,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;QAC9D,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO,CACL,aAAa,CAAC,CAAC,CAAC,CACd,KAAC,MAAM,IACL,UAAU,EAAE,IAAI,EAChB,OAAO,EAAE,WAAW,YAEnB,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,oCAAoC,CAAC,CAAC,GAChE,CACV,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACd,CAAC,CAAC;AAEF,eAAe,aAAa,CAAC","sourcesContent":["import { useIntl } from '@openedx/frontend-base';\nimport { Button } from '@openedx/paragon';\nimport { Plus } from '@openedx/paragon/icons';\nimport { useNavigate } from 'react-router-dom';\n\nimport baseMessages from '@src/authz-module/messages';\nimport { buildWizardPath } from '@src/authz-module/constants';\nimport { useValidateUserPermissionsNonSuspense } from '@src/data/hooks';\nimport { MANAGE_TEAM_PERMISSIONS } from '@src/authz-module/roles-permissions';\n\ninterface AddRoleButtonProps {\n presetUsername?: string;\n from?: string;\n}\n\nconst AddRoleButton = ({ presetUsername, from }: AddRoleButtonProps) => {\n const intl = useIntl();\n const navigate = useNavigate();\n\n const { data: permissionValidationResponse } = useValidateUserPermissionsNonSuspense(MANAGE_TEAM_PERMISSIONS);\n const canAssignRole = permissionValidationResponse?.some((permission) => permission.allowed);\n\n const handleClick = () => {\n const path = buildWizardPath({ from, users: presetUsername });\n navigate(path);\n };\n\n return (\n canAssignRole ? (\n <Button\n iconBefore={Plus}\n onClick={handleClick}\n >\n {intl.formatMessage(baseMessages['authz.management.assign.role.title'])}\n </Button>\n ) : null);\n};\n\nexport default AddRoleButton;\n"]}
|
|
1
|
+
{"version":3,"file":"AddRoleButton.js","sourceRoot":"","sources":["../../../src/authz-module/components/AddRoleButton.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,YAAY,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,qCAAqC,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAO9E,MAAM,aAAa,GAAG,CAAC,EAAE,cAAc,EAAE,IAAI,EAAsB,EAAE,EAAE;IACrE,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,MAAM,EAAE,IAAI,EAAE,4BAA4B,EAAE,GAAG,qCAAqC,CAAC,uBAAuB,CAAC,CAAC;IAC9G,MAAM,aAAa,GAAG,4BAA4B,aAA5B,4BAA4B,uBAA5B,4BAA4B,CAAE,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAE7F,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,MAAM,IAAI,GAAG,eAAe,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;QAC9D,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO,CACL,aAAa,CAAC,CAAC,CAAC,CACd,KAAC,MAAM,IACL,IAAI,EAAC,IAAI,EACT,UAAU,EAAE,IAAI,EAChB,OAAO,EAAE,WAAW,YAEnB,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,oCAAoC,CAAC,CAAC,GAChE,CACV,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACd,CAAC,CAAC;AAEF,eAAe,aAAa,CAAC","sourcesContent":["import { useIntl } from '@openedx/frontend-base';\nimport { Button } from '@openedx/paragon';\nimport { Plus } from '@openedx/paragon/icons';\nimport { useNavigate } from 'react-router-dom';\n\nimport baseMessages from '@src/authz-module/messages';\nimport { buildWizardPath } from '@src/authz-module/constants';\nimport { useValidateUserPermissionsNonSuspense } from '@src/data/hooks';\nimport { MANAGE_TEAM_PERMISSIONS } from '@src/authz-module/roles-permissions';\n\ninterface AddRoleButtonProps {\n presetUsername?: string;\n from?: string;\n}\n\nconst AddRoleButton = ({ presetUsername, from }: AddRoleButtonProps) => {\n const intl = useIntl();\n const navigate = useNavigate();\n\n const { data: permissionValidationResponse } = useValidateUserPermissionsNonSuspense(MANAGE_TEAM_PERMISSIONS);\n const canAssignRole = permissionValidationResponse?.some((permission) => permission.allowed);\n\n const handleClick = () => {\n const path = buildWizardPath({ from, users: presetUsername });\n navigate(path);\n };\n\n return (\n canAssignRole ? (\n <Button\n size=\"sm\"\n iconBefore={Plus}\n onClick={handleClick}\n >\n {intl.formatMessage(baseMessages['authz.management.assign.role.title'])}\n </Button>\n ) : null);\n};\n\nexport default AddRoleButton;\n"]}
|
|
@@ -2,11 +2,13 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
2
2
|
import { isValidElement, Fragment, } from 'react';
|
|
3
3
|
import { Link } from 'react-router-dom';
|
|
4
4
|
import { Breadcrumb, Col, Row, Button, Stack, useMediaQuery, breakpoints, } from '@openedx/paragon';
|
|
5
|
-
export const ActionButton = ({ label, icon, onClick }) => (_jsx(Button, { iconBefore: icon, onClick: onClick, children: label }));
|
|
5
|
+
export const ActionButton = ({ label, icon, onClick }) => (_jsx(Button, { size: "sm", iconBefore: icon, onClick: onClick, children: label }));
|
|
6
6
|
const AuthZTitle = ({ activeLabel, navLinks = [], pageTitle, pageSubtitle, actions = [], }) => {
|
|
7
|
+
const shouldRenderBreadcrumb = activeLabel || (navLinks === null || navLinks === void 0 ? void 0 : navLinks.length) > 0;
|
|
7
8
|
const isDesktop = useMediaQuery({ minWidth: breakpoints.large.minWidth });
|
|
8
|
-
return (_jsxs("div", { className: "page-band py-
|
|
9
|
-
|
|
9
|
+
return (_jsxs("div", { className: "page-band py-4 bg-light-100", children: [shouldRenderBreadcrumb
|
|
10
|
+
&& (_jsx(Breadcrumb, { linkAs: Link, links: navLinks, activeLabel: activeLabel })), _jsxs(Row, { children: [_jsx(Col, { xs: 12, md: 7, children: _jsxs("div", { className: "d-flex align-items-center flex-column-sm mb-3 mb-md-0", children: [_jsx("h2", { className: "text-primary mb-0", children: pageTitle }), pageSubtitle && (_jsxs(_Fragment, { children: [_jsx("hr", { className: "authz-action-divider mx-lg-3 my-md-0 mx-md-3" }), typeof pageSubtitle === 'string'
|
|
11
|
+
? _jsx("h3", { className: "mb-0 font-weight-light text-gray-700", children: pageSubtitle })
|
|
10
12
|
: _jsx("div", { className: "mb-0", children: pageSubtitle })] }))] }) }), _jsx(Col, { xs: 12, md: 5, children: _jsx(Stack, { className: "justify-content-end", direction: isDesktop ? 'horizontal' : 'vertical', children: actions.map((action, index) => {
|
|
11
13
|
const content = isValidElement(action)
|
|
12
14
|
? action
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthZTitle.js","sourceRoot":"","sources":["../../../src/authz-module/components/AuthZTitle.tsx"],"names":[],"mappings":";AAAA,OAAO,EACU,cAAc,EAAa,QAAQ,GACnD,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EACL,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAC5B,KAAK,EACL,aAAa,EACb,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAqB1B,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAU,EAAE,EAAE,CAAC,CAChE,KAAC,MAAM,IACL,UAAU,EAAE,IAAI,EAChB,OAAO,EAAE,OAAO,YAEf,KAAK,GACC,CACV,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,EAClB,WAAW,EAAE,QAAQ,GAAG,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,GAAG,EAAE,GACjD,EAAE,EAAE;IACpB,MAAM,SAAS,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC1E,OAAO,CACL,eAAK,SAAS,EAAC,6BAA6B,
|
|
1
|
+
{"version":3,"file":"AuthZTitle.js","sourceRoot":"","sources":["../../../src/authz-module/components/AuthZTitle.tsx"],"names":[],"mappings":";AAAA,OAAO,EACU,cAAc,EAAa,QAAQ,GACnD,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EACL,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAC5B,KAAK,EACL,aAAa,EACb,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAqB1B,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAU,EAAE,EAAE,CAAC,CAChE,KAAC,MAAM,IACL,IAAI,EAAC,IAAI,EACT,UAAU,EAAE,IAAI,EAChB,OAAO,EAAE,OAAO,YAEf,KAAK,GACC,CACV,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,EAClB,WAAW,EAAE,QAAQ,GAAG,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,GAAG,EAAE,GACjD,EAAE,EAAE;IACpB,MAAM,sBAAsB,GAAG,WAAW,IAAI,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,MAAM,IAAG,CAAC,CAAC;IACnE,MAAM,SAAS,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC1E,OAAO,CACL,eAAK,SAAS,EAAC,6BAA6B,aACxC,sBAAsB;mBACrB,CACD,KAAC,UAAU,IACT,MAAM,EAAE,IAAI,EACZ,KAAK,EAAE,QAAQ,EACf,WAAW,EAAE,WAAW,GACxB,CACH,EACD,MAAC,GAAG,eACF,KAAC,GAAG,IAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,YAChB,eAAK,SAAS,EAAC,uDAAuD,aACpE,aAAI,SAAS,EAAC,mBAAmB,YAAE,SAAS,GAAM,EACjD,YAAY,IAAI,CACf,8BACE,aAAI,SAAS,EAAC,8CAA8C,GAAG,EAC9D,OAAO,YAAY,KAAK,QAAQ;4CAC/B,CAAC,CAAC,aAAI,SAAS,EAAC,sCAAsC,YAAE,YAAY,GAAM;4CAC1E,CAAC,CAAC,cAAK,SAAS,EAAC,MAAM,YAAE,YAAY,GAAO,IAC7C,CACJ,IAEG,GACF,EACN,KAAC,GAAG,IAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,YAChB,KAAC,KAAK,IAAC,SAAS,EAAC,qBAAqB,EAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,YAEnF,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;gCAC5B,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC;oCACpC,CAAC,CAAC,MAAM;oCACR,CAAC,CAAC,KAAC,YAAY,oBAAK,MAAgB,EAAI,CAAC;gCAC3C,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,CAAC;oCAChC,CAAC,CAAC,MAAM,CAAC,GAAG;oCACZ,CAAC,CAAE,MAAiB,CAAC,KAAK,CAAC;gCAC7B,OAAO,CACL,MAAC,QAAQ,eACN,OAAO,EACP,CAAC,KAAK,KAAK,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;4CACpC,CAAC,CAAC,CAAC,aAAI,SAAS,EAAC,8BAA8B,GAAG,CAAC,KAHxC,uBAAuB,GAAG,EAAE,CAIhC,CACZ,CAAC;4BACJ,CAAC,CAAC,GAEE,GACJ,IACF,IACF,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["import {\n ComponentType, isValidElement, ReactNode, Fragment,\n} from 'react';\nimport { Link } from 'react-router-dom';\nimport {\n Breadcrumb, Col, Row, Button,\n Stack,\n useMediaQuery,\n breakpoints,\n} from '@openedx/paragon';\n\ninterface BreadcrumbLink {\n label: string;\n to?: string;\n}\n\ninterface Action {\n label: string;\n icon?: ComponentType;\n onClick: () => void;\n}\n\nexport interface AuthZTitleProps {\n activeLabel?: string;\n pageTitle: string;\n pageSubtitle?: string | ReactNode;\n navLinks?: BreadcrumbLink[];\n actions?: (Action | ReactNode)[];\n}\n\nexport const ActionButton = ({ label, icon, onClick }: Action) => (\n <Button\n size=\"sm\"\n iconBefore={icon}\n onClick={onClick}\n >\n {label}\n </Button>\n);\n\nconst AuthZTitle = ({\n activeLabel, navLinks = [], pageTitle, pageSubtitle, actions = [],\n}: AuthZTitleProps) => {\n const shouldRenderBreadcrumb = activeLabel || navLinks?.length > 0;\n const isDesktop = useMediaQuery({ minWidth: breakpoints.large.minWidth });\n return (\n <div className=\"page-band py-4 bg-light-100\">\n { shouldRenderBreadcrumb\n && (\n <Breadcrumb\n linkAs={Link}\n links={navLinks}\n activeLabel={activeLabel}\n />\n )}\n <Row>\n <Col xs={12} md={7}>\n <div className=\"d-flex align-items-center flex-column-sm mb-3 mb-md-0\">\n <h2 className=\"text-primary mb-0\">{pageTitle}</h2>\n {pageSubtitle && (\n <>\n <hr className=\"authz-action-divider mx-lg-3 my-md-0 mx-md-3\" />\n {typeof pageSubtitle === 'string'\n ? <h3 className=\"mb-0 font-weight-light text-gray-700\">{pageSubtitle}</h3>\n : <div className=\"mb-0\">{pageSubtitle}</div>}\n </>\n )}\n\n </div>\n </Col>\n <Col xs={12} md={5}>\n <Stack className=\"justify-content-end\" direction={isDesktop ? 'horizontal' : 'vertical'}>\n {\n actions.map((action, index) => {\n const content = isValidElement(action)\n ? action\n : <ActionButton {...action as Action} />;\n const key = isValidElement(action)\n ? action.key\n : (action as Action).label;\n return (\n <Fragment key={`authz-header-action-${key}`}>\n {content}\n {(index === actions.length - 1) ? null\n : (<hr className=\"authz-action-divider mx-lg-5\" />)}\n </Fragment>\n );\n })\n }\n </Stack>\n </Col>\n </Row>\n </div>\n );\n};\n\nexport default AuthZTitle;\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface ExpandableButtonProps {
|
|
2
|
+
label: string;
|
|
3
|
+
onClick: () => void;
|
|
4
|
+
isExpanded: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Link-styled trigger that expands something in place: a table row, a list of items.
|
|
8
|
+
*
|
|
9
|
+
* A real `<button>` rather than an anchor — it navigates nowhere, and an anchor with no
|
|
10
|
+
* `href` is neither focusable nor activatable from the keyboard. `size="inline"` drops the
|
|
11
|
+
* button padding so it keeps sitting on the text baseline inside a table cell.
|
|
12
|
+
*
|
|
13
|
+
* `isExpanded` drives both halves of the state report, which have to agree: the chevron
|
|
14
|
+
* for sighted users and `aria-expanded` for a screen reader.
|
|
15
|
+
*/
|
|
16
|
+
declare const ExpandableButton: ({ label, onClick, isExpanded }: ExpandableButtonProps) => import("react").JSX.Element;
|
|
17
|
+
export default ExpandableButton;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '@openedx/paragon';
|
|
3
|
+
import { ExpandLess, ExpandMore } from '@openedx/paragon/icons';
|
|
4
|
+
/**
|
|
5
|
+
* Link-styled trigger that expands something in place: a table row, a list of items.
|
|
6
|
+
*
|
|
7
|
+
* A real `<button>` rather than an anchor — it navigates nowhere, and an anchor with no
|
|
8
|
+
* `href` is neither focusable nor activatable from the keyboard. `size="inline"` drops the
|
|
9
|
+
* button padding so it keeps sitting on the text baseline inside a table cell.
|
|
10
|
+
*
|
|
11
|
+
* `isExpanded` drives both halves of the state report, which have to agree: the chevron
|
|
12
|
+
* for sighted users and `aria-expanded` for a screen reader.
|
|
13
|
+
*/
|
|
14
|
+
const ExpandableButton = ({ label, onClick, isExpanded }) => (_jsx(Button, { variant: "link", size: "inline", onClick: onClick, iconAfter: isExpanded ? ExpandLess : ExpandMore, "aria-expanded": isExpanded, children: label }));
|
|
15
|
+
export default ExpandableButton;
|
|
16
|
+
//# sourceMappingURL=ExpandableButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpandableButton.js","sourceRoot":"","sources":["../../../src/authz-module/components/ExpandableButton.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAQhE;;;;;;;;;GASG;AACH,MAAM,gBAAgB,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAyB,EAAE,EAAE,CAAC,CAClF,KAAC,MAAM,IACL,OAAO,EAAC,MAAM,EACd,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,mBAChC,UAAU,YAExB,KAAK,GACC,CACV,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["import { Button } from '@openedx/paragon';\nimport { ExpandLess, ExpandMore } from '@openedx/paragon/icons';\n\ninterface ExpandableButtonProps {\n label: string;\n onClick: () => void;\n isExpanded: boolean;\n}\n\n/**\n * Link-styled trigger that expands something in place: a table row, a list of items.\n *\n * A real `<button>` rather than an anchor — it navigates nowhere, and an anchor with no\n * `href` is neither focusable nor activatable from the keyboard. `size=\"inline\"` drops the\n * button padding so it keeps sitting on the text baseline inside a table cell.\n *\n * `isExpanded` drives both halves of the state report, which have to agree: the chevron\n * for sighted users and `aria-expanded` for a screen reader.\n */\nconst ExpandableButton = ({ label, onClick, isExpanded }: ExpandableButtonProps) => (\n <Button\n variant=\"link\"\n size=\"inline\"\n onClick={onClick}\n iconAfter={isExpanded ? ExpandLess : ExpandMore}\n aria-expanded={isExpanded}\n >\n {label}\n </Button>\n);\n\nexport default ExpandableButton;\n"]}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { UserRoleWithPermissions, RoleToDelete } from '../../types';
|
|
2
|
-
import { type
|
|
3
|
-
|
|
4
|
-
isCourseEnabled: (scope: string) => boolean;
|
|
5
|
-
}
|
|
2
|
+
import { type ComponentProps } from 'react';
|
|
3
|
+
import { IconButton, type DataTableCellProps } from '@openedx/paragon';
|
|
6
4
|
type CellProps = DataTableCellProps<UserRoleWithPermissions>;
|
|
7
5
|
type CellPropsWithValue = CellProps & {
|
|
8
6
|
value: string;
|
|
@@ -17,13 +15,12 @@ interface ActionsCellExtraProps {
|
|
|
17
15
|
isUserAuthenticatedPage: boolean;
|
|
18
16
|
isCourseEnabled?: (scope: string) => boolean;
|
|
19
17
|
}
|
|
20
|
-
|
|
21
|
-
declare const
|
|
22
|
-
declare const createViewActionCell: (extraProps: ViewActionCellExtraProps) => (cellProps: any) => import("react").JSX.Element;
|
|
18
|
+
type DisabledCourseActionButtonProps = Pick<ComponentProps<typeof IconButton>, 'src' | 'alt' | 'size' | 'variant'>;
|
|
19
|
+
export declare const DisabledCourseActionButton: ({ src, alt, size, variant, }: DisabledCourseActionButtonProps) => import("react").JSX.Element;
|
|
23
20
|
declare const OrgCell: ({ value, row }: CellPropsWithValue) => import("react").JSX.Element;
|
|
24
21
|
declare const ScopeCell: ({ row }: CellProps) => import("react").JSX.Element;
|
|
25
22
|
declare const RoleCell: ({ value, cell }: ExtendedCellProps) => import("react").JSX.Element;
|
|
26
23
|
declare const PermissionsCell: ({ row }: CellProps) => import("react").JSX.Element;
|
|
27
24
|
declare const ViewAllPermissionsCell: ({ row }: CellProps) => import("react").JSX.Element;
|
|
28
25
|
declare const createActionsCell: (extraProps: ActionsCellExtraProps) => (cellProps: any) => import("react").JSX.Element;
|
|
29
|
-
export {
|
|
26
|
+
export { RoleCell, OrgCell, ScopeCell, PermissionsCell, ViewAllPermissionsCell, createActionsCell, };
|
|
@@ -10,65 +10,47 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
13
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
14
|
+
import { Delete, Info, } from '@openedx/paragon/icons';
|
|
15
|
+
import { useMemo } from 'react';
|
|
16
|
+
import { ADMIN_ROLES, ALL_ORGS_KEY, DJANGO_MANAGED_ROLES, getAggregateScopeType, getScopeContextType, MAP_ROLE_KEY_TO_LABEL, } from '../constants';
|
|
17
|
+
import { Icon, IconButton, OverlayTrigger, Tooltip, } from '@openedx/paragon';
|
|
18
|
+
import { useExclusiveRowExpansion } from '../hooks/useExclusiveRowExpansion';
|
|
19
|
+
import { getScopeResourceIcon } from '../utils';
|
|
20
|
+
import { AGGREGATE_SCOPE_LABELS } from '../messages';
|
|
19
21
|
import { RESOURCE_ICONS } from './constants';
|
|
20
22
|
import messages from './messages';
|
|
21
|
-
import
|
|
23
|
+
import ExpandableButton from './ExpandableButton';
|
|
22
24
|
// A disabled button can't trigger its own tooltip (Paragon sets pointer-events: none on it),
|
|
23
25
|
// so the OverlayTrigger must live on a wrapper element that still receives hover events.
|
|
24
|
-
const DisabledCourseActionButton = ({ src, alt, size, variant, }) => {
|
|
26
|
+
export const DisabledCourseActionButton = ({ src, alt, size, variant, }) => {
|
|
25
27
|
const { formatMessage } = useIntl();
|
|
26
28
|
return (_jsx(OverlayTrigger, { placement: "left", overlay: (_jsx(Tooltip, { variant: "light", id: "tooltip-left", children: formatMessage(messages['authz.table.actions.course.disabled.tooltip']) })), children: _jsx("span", { className: "d-inline-block", children: _jsx(IconButton, { src: src, alt: alt, size: size, variant: variant, disabled: true }) }) }));
|
|
27
29
|
};
|
|
28
|
-
const NameCell = ({ row }) => {
|
|
29
|
-
const intl = useIntl();
|
|
30
|
-
const { authenticatedUser } = useContext(SiteContext);
|
|
31
|
-
const username = authenticatedUser === null || authenticatedUser === void 0 ? void 0 : authenticatedUser.username;
|
|
32
|
-
if (row.original.username === username) {
|
|
33
|
-
return (_jsxs("span", { children: [row.original.fullName || row.original.username, _jsx("span", { className: "text-gray-500", children: intl.formatMessage(messages['authz.table.username.current']) })] }));
|
|
34
|
-
}
|
|
35
|
-
return _jsx("span", { children: row.original.fullName || row.original.username || '' });
|
|
36
|
-
};
|
|
37
|
-
const ViewActionCell = ({ row, isCourseEnabled }) => {
|
|
38
|
-
var _a, _b;
|
|
39
|
-
const { formatMessage } = useIntl();
|
|
40
|
-
const navigate = useNavigate();
|
|
41
|
-
const viewPath = buildAuditUserPath((_a = row.original.username) !== null && _a !== void 0 ? _a : '');
|
|
42
|
-
const isCourseScope = !((_b = row.original.role) === null || _b === void 0 ? void 0 : _b.startsWith('lib')) && !DJANGO_MANAGED_ROLES.includes(row.original.role);
|
|
43
|
-
const isDisabled = isCourseEnabled !== undefined && isCourseScope && !isCourseEnabled(row.original.scope);
|
|
44
|
-
if (isDisabled) {
|
|
45
|
-
return (_jsx(DisabledCourseActionButton, { src: RemoveRedEye, alt: formatMessage(messages['authz.table.column.actions.view.title']), size: "sm" }));
|
|
46
|
-
}
|
|
47
|
-
return (_jsx(IconButton, { src: RemoveRedEye, alt: formatMessage(messages['authz.table.column.actions.view.title']), size: "sm", onClick: () => navigate(viewPath) }));
|
|
48
|
-
};
|
|
49
|
-
const createViewActionCell = (extraProps) => function customViewActionCell(cellProps) {
|
|
50
|
-
return _jsx(ViewActionCell, Object.assign({}, cellProps, extraProps));
|
|
51
|
-
};
|
|
52
30
|
const OrgCell = ({ value, row }) => {
|
|
53
31
|
const { formatMessage } = useIntl();
|
|
54
|
-
|
|
32
|
+
// The backend returns '*' as the org wildcard, meaning the role spans every organization.
|
|
33
|
+
const isAllOrgs = DJANGO_MANAGED_ROLES.includes(row.original.role) || value === ALL_ORGS_KEY;
|
|
34
|
+
return (_jsx("span", { children: isAllOrgs ? formatMessage(messages['authz.user.table.org.all.organizations.label']) : value }));
|
|
55
35
|
};
|
|
56
36
|
const ScopeCell = ({ row }) => {
|
|
57
37
|
const { formatMessage } = useIntl();
|
|
58
38
|
const { scopeText, iconSrc } = useMemo(() => {
|
|
59
|
-
|
|
60
|
-
if (DJANGO_MANAGED_ROLES.includes(
|
|
39
|
+
const { role, scope, org } = row.original;
|
|
40
|
+
if (DJANGO_MANAGED_ROLES.includes(role)) {
|
|
61
41
|
return {
|
|
62
42
|
scopeText: formatMessage(messages['authz.user.table.scope.global.label']),
|
|
63
43
|
iconSrc: RESOURCE_ICONS.GLOBAL,
|
|
64
44
|
};
|
|
65
45
|
}
|
|
66
|
-
const
|
|
46
|
+
const aggregateType = getAggregateScopeType(scope, org);
|
|
67
47
|
return {
|
|
68
|
-
scopeText:
|
|
69
|
-
|
|
48
|
+
scopeText: aggregateType
|
|
49
|
+
? formatMessage(AGGREGATE_SCOPE_LABELS[getScopeContextType(scope)])
|
|
50
|
+
: scope,
|
|
51
|
+
iconSrc: getScopeResourceIcon(scope),
|
|
70
52
|
};
|
|
71
|
-
}, [row.original
|
|
53
|
+
}, [row.original, formatMessage]);
|
|
72
54
|
return (_jsxs("span", { className: "d-flex align-items-center", children: [iconSrc && _jsx(Icon, { color: "primary", src: iconSrc, className: "mr-2", size: "xs" }), scopeText] }));
|
|
73
55
|
};
|
|
74
56
|
const RoleCell = ({ value, cell }) => {
|
|
@@ -85,25 +67,10 @@ const PermissionsCell = ({ row }) => {
|
|
|
85
67
|
};
|
|
86
68
|
const ViewAllPermissionsCell = ({ row }) => {
|
|
87
69
|
const { formatMessage } = useIntl();
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// Close all other expanded rows first
|
|
93
|
-
const expanded = ((_a = instance.state) === null || _a === void 0 ? void 0 : _a.expanded) || {};
|
|
94
|
-
Object.keys(expanded).forEach(rowId => {
|
|
95
|
-
var _a;
|
|
96
|
-
if (rowId !== row.id && expanded[rowId]) {
|
|
97
|
-
(_a = instance.toggleRowExpanded) === null || _a === void 0 ? void 0 : _a.call(instance, rowId, false);
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
// Toggle the current row
|
|
102
|
-
(_b = row.toggleRowExpanded) === null || _b === void 0 ? void 0 : _b.call(row);
|
|
103
|
-
};
|
|
104
|
-
return (_jsx("div", { role: "button", children: _jsx(ViewMoreLink, { label: formatMessage(row.isExpanded
|
|
105
|
-
? messages['authz.user.table.view_all_permissions.link.text.close']
|
|
106
|
-
: messages['authz.user.table.view_all_permissions.link.text.open']), onClick: handleToggleExpanded, iconSrc: ExpandMore }) }));
|
|
70
|
+
const toggleExpanded = useExclusiveRowExpansion(row);
|
|
71
|
+
return (_jsx(ExpandableButton, { label: formatMessage(row.isExpanded
|
|
72
|
+
? messages['authz.user.table.view_all_permissions.link.text.close']
|
|
73
|
+
: messages['authz.user.table.view_all_permissions.link.text.open']), onClick: toggleExpanded, isExpanded: !!row.isExpanded }));
|
|
107
74
|
};
|
|
108
75
|
const ActionsCell = ({ row, onClickDeleteButton, isUserAuthenticatedPage, isCourseEnabled, }) => {
|
|
109
76
|
const { formatMessage } = useIntl();
|
|
@@ -133,5 +100,5 @@ const ActionsCell = ({ row, onClickDeleteButton, isUserAuthenticatedPage, isCour
|
|
|
133
100
|
const createActionsCell = (extraProps) => function customActionsCell(cellProps) {
|
|
134
101
|
return _jsx(ActionsCell, Object.assign({}, cellProps, extraProps));
|
|
135
102
|
};
|
|
136
|
-
export {
|
|
103
|
+
export { RoleCell, OrgCell, ScopeCell, PermissionsCell, ViewAllPermissionsCell, createActionsCell, };
|
|
137
104
|
//# sourceMappingURL=TableCells.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableCells.js","sourceRoot":"","sources":["../../../src/authz-module/components/TableCells.tsx"],"names":[],"mappings":"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","sourcesContent":["import { SiteContext, useIntl } from '@openedx/frontend-base';\nimport {\n RemoveRedEye,\n Delete, ExpandMore,\n Info,\n} from '@openedx/paragon/icons';\nimport { UserRoleWithPermissions, RoleToDelete } from '@src/types';\nimport { useNavigate } from 'react-router-dom';\nimport { useContext, useMemo, type ComponentProps } from 'react';\nimport {\n ADMIN_ROLES, buildAuditUserPath, DJANGO_MANAGED_ROLES, MAP_ROLE_KEY_TO_LABEL,\n} from '@src/authz-module/constants';\nimport {\n Icon, IconButton, OverlayTrigger, Tooltip, DataTableContext,\n type DataTableCellProps,\n} from '@openedx/paragon';\nimport { RESOURCE_ICONS } from './constants';\nimport messages from './messages';\nimport ViewMoreLink from './ViewMoreLink';\n\ninterface ViewActionCellExtraProps {\n isCourseEnabled: (scope: string) => boolean;\n}\n\ninterface DataTableInstance {\n state?: {\n expanded?: Record<string, boolean>;\n };\n toggleRowExpanded?: (rowId: string, expanded: boolean) => void;\n}\n\ntype CellProps = DataTableCellProps<UserRoleWithPermissions>;\ntype CellPropsWithValue = CellProps & {\n value: string;\n};\ntype ExtendedCellProps = CellPropsWithValue & {\n cell: {\n getCellProps: (props?: Record<string, string>) => Record<string, string>;\n };\n};\n\ninterface ActionsCellExtraProps {\n onClickDeleteButton: (role: RoleToDelete) => void;\n isUserAuthenticatedPage: boolean;\n isCourseEnabled?: (scope: string) => boolean;\n}\n\ntype ActionsCellProps = CellProps & ActionsCellExtraProps;\n\ntype DisabledCourseActionButtonProps = Pick<ComponentProps<typeof IconButton>, 'src' | 'alt' | 'size' | 'variant'>;\n\n// A disabled button can't trigger its own tooltip (Paragon sets pointer-events: none on it),\n// so the OverlayTrigger must live on a wrapper element that still receives hover events.\nconst DisabledCourseActionButton = ({\n src, alt, size, variant,\n}: DisabledCourseActionButtonProps) => {\n const { formatMessage } = useIntl();\n return (\n <OverlayTrigger\n placement=\"left\"\n overlay={(\n <Tooltip variant=\"light\" id=\"tooltip-left\">\n {formatMessage(messages['authz.table.actions.course.disabled.tooltip'])}\n </Tooltip>\n )}\n >\n <span className=\"d-inline-block\">\n <IconButton\n src={src}\n alt={alt}\n size={size}\n variant={variant}\n disabled\n />\n </span>\n </OverlayTrigger>\n );\n};\n\nconst NameCell = ({ row }: CellProps) => {\n const intl = useIntl();\n const { authenticatedUser } = useContext(SiteContext);\n const username = authenticatedUser?.username;\n\n if (row.original.username === username) {\n return (\n <span>\n {row.original.fullName || row.original.username}\n <span className=\"text-gray-500\">{intl.formatMessage(messages['authz.table.username.current'])}</span>\n </span>\n );\n }\n return <span>{row.original.fullName || row.original.username || ''}</span>;\n};\n\nconst ViewActionCell = ({ row, isCourseEnabled }: CellProps & Partial<ViewActionCellExtraProps>) => {\n const { formatMessage } = useIntl();\n const navigate = useNavigate();\n const viewPath = buildAuditUserPath(row.original.username ?? '');\n const isCourseScope = !row.original.role?.startsWith('lib') && !DJANGO_MANAGED_ROLES.includes(row.original.role);\n const isDisabled = isCourseEnabled !== undefined && isCourseScope && !isCourseEnabled(row.original.scope);\n\n if (isDisabled) {\n return (\n <DisabledCourseActionButton\n src={RemoveRedEye}\n alt={formatMessage(messages['authz.table.column.actions.view.title'])}\n size=\"sm\"\n />\n );\n }\n\n return (\n <IconButton\n src={RemoveRedEye}\n alt={formatMessage(messages['authz.table.column.actions.view.title'])}\n size=\"sm\"\n onClick={() => navigate(viewPath)}\n />\n );\n};\n\nconst createViewActionCell = (extraProps: ViewActionCellExtraProps) => function customViewActionCell(cellProps) {\n return <ViewActionCell {...cellProps} {...extraProps} />;\n};\n\nconst OrgCell = ({ value, row }: CellPropsWithValue) => {\n const { formatMessage } = useIntl();\n return (\n <span>\n {DJANGO_MANAGED_ROLES.includes(row.original.role) ? formatMessage(messages['authz.user.table.org.all.organizations.label']) : value}\n </span>\n );\n};\n\nconst ScopeCell = ({ row }: CellProps) => {\n const { formatMessage } = useIntl();\n\n const { scopeText, iconSrc } = useMemo(() => {\n if (DJANGO_MANAGED_ROLES.includes(row.original.role)) {\n return {\n scopeText: formatMessage(messages['authz.user.table.scope.global.label']),\n iconSrc: RESOURCE_ICONS.GLOBAL,\n };\n }\n const scopeIcon = row.original.role?.startsWith('lib') ? RESOURCE_ICONS.LIBRARY : RESOURCE_ICONS.COURSE;\n return {\n scopeText: row.original.scope,\n iconSrc: scopeIcon,\n };\n }, [row.original.role, row.original.scope, formatMessage]);\n\n return (\n <span className=\"d-flex align-items-center\">\n {iconSrc && <Icon color=\"primary\" src={iconSrc} className=\"mr-2\" size=\"xs\" />}\n {scopeText}\n </span>\n );\n};\n\nconst RoleCell = ({ value, cell }: ExtendedCellProps) => {\n const { key, ...cellProps } = cell.getCellProps({ 'data-role': MAP_ROLE_KEY_TO_LABEL[value] || '' });\n return (\n <span key={key} {...cellProps}>\n {MAP_ROLE_KEY_TO_LABEL[value] || ''}\n </span>\n );\n};\n\nconst PermissionsCell = ({ row }: CellProps) => {\n const { formatMessage } = useIntl();\n const { role, permissionCount: count } = row.original;\n const isDjangoRole = DJANGO_MANAGED_ROLES.includes(role);\n return (\n <span>\n { isDjangoRole\n ? formatMessage(\n messages['authz.user.table.permissions.access.label'],\n { accessType: role === 'django.superuser' ? 'total' : 'partial' },\n )\n : formatMessage(messages['authz.user.table.permissions.available.count'], { count })}\n </span>\n );\n};\n\nconst ViewAllPermissionsCell = ({ row }: CellProps) => {\n const { formatMessage } = useIntl();\n const instance = useContext(DataTableContext) as DataTableInstance;\n const handleToggleExpanded = () => {\n if (!row.isExpanded && instance) {\n // Close all other expanded rows first\n const expanded = instance.state?.expanded || {};\n Object.keys(expanded).forEach(rowId => {\n if (rowId !== row.id && expanded[rowId]) {\n instance.toggleRowExpanded?.(rowId, false);\n }\n });\n }\n // Toggle the current row\n row.toggleRowExpanded?.();\n };\n\n return (\n <div role=\"button\">\n <ViewMoreLink\n label={formatMessage(\n row.isExpanded\n ? messages['authz.user.table.view_all_permissions.link.text.close']\n : messages['authz.user.table.view_all_permissions.link.text.open'],\n )}\n onClick={handleToggleExpanded}\n iconSrc={ExpandMore}\n />\n </div>\n );\n};\n\nconst ActionsCell = ({\n row, onClickDeleteButton, isUserAuthenticatedPage, isCourseEnabled,\n}: ActionsCellProps) => {\n const { formatMessage } = useIntl();\n const { role, canManageScope } = row.original;\n\n const handleDelete = () => {\n const roleToDelete = {\n role,\n scope: row.original.scope,\n name: MAP_ROLE_KEY_TO_LABEL[role] || '',\n } as RoleToDelete;\n onClickDeleteButton(roleToDelete);\n };\n\n if (DJANGO_MANAGED_ROLES.includes(role)) {\n return (\n <OverlayTrigger\n placement=\"left\"\n overlay={(\n <Tooltip variant=\"light\" id=\"tooltip-left\">\n {formatMessage(messages['authz.user.table.delete.action.djangorole.tooltip'])}\n </Tooltip>\n )}\n >\n <Icon\n className=\"mx-2 pl-1\"\n src={Info}\n />\n </OverlayTrigger>\n );\n }\n\n if (ADMIN_ROLES.includes(role) && isUserAuthenticatedPage) {\n return (\n <OverlayTrigger\n placement=\"left\"\n overlay={(\n <Tooltip variant=\"light\" id=\"tooltip-left\">\n {formatMessage(messages['authz.user.table.delete.action.adminrole.tooltip'])}\n </Tooltip>\n )}\n >\n <Icon\n className=\"mx-2 pl-1 text-light-500\"\n src={Delete}\n />\n </OverlayTrigger>\n );\n }\n\n const isCourseScope = !role?.startsWith('lib');\n const isCourseAuthoringDisabled = isCourseEnabled !== undefined\n && isCourseScope && !isCourseEnabled(row.original.scope);\n\n if (isCourseAuthoringDisabled) {\n return (\n <DisabledCourseActionButton\n src={Delete}\n alt={formatMessage(messages['authz.user.table.delete.action.alt'])}\n variant=\"light\"\n />\n );\n }\n\n return (\n <IconButton\n disabled={!canManageScope}\n variant={canManageScope ? 'danger' : 'light'}\n onClick={handleDelete}\n alt={formatMessage(messages['authz.user.table.delete.action.alt'])}\n src={Delete}\n />\n );\n};\n\nconst createActionsCell = (extraProps: ActionsCellExtraProps) => function customActionsCell(cellProps) {\n return <ActionsCell {...cellProps} {...extraProps} />;\n};\n\nexport {\n NameCell,\n ViewActionCell,\n RoleCell,\n OrgCell,\n ScopeCell,\n PermissionsCell,\n ViewAllPermissionsCell,\n createActionsCell,\n createViewActionCell,\n};\n"]}
|
|
1
|
+
{"version":3,"file":"TableCells.js","sourceRoot":"","sources":["../../../src/authz-module/components/TableCells.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useIntl } from '@openedx/frontend-base';\nimport {\n Delete,\n Info,\n} from '@openedx/paragon/icons';\nimport { UserRoleWithPermissions, RoleToDelete } from '@src/types';\nimport { useMemo, type ComponentProps } from 'react';\nimport {\n ADMIN_ROLES, ALL_ORGS_KEY, DJANGO_MANAGED_ROLES, getAggregateScopeType,\n getScopeContextType, MAP_ROLE_KEY_TO_LABEL,\n} from '@src/authz-module/constants';\nimport {\n Icon, IconButton, OverlayTrigger, Tooltip,\n type DataTableCellProps,\n} from '@openedx/paragon';\nimport { useExclusiveRowExpansion } from '@src/authz-module/hooks/useExclusiveRowExpansion';\nimport { getScopeResourceIcon } from '@src/authz-module/utils';\nimport { AGGREGATE_SCOPE_LABELS } from '@src/authz-module/messages';\nimport { RESOURCE_ICONS } from './constants';\nimport messages from './messages';\nimport ExpandableButton from './ExpandableButton';\n\ntype CellProps = DataTableCellProps<UserRoleWithPermissions>;\ntype CellPropsWithValue = CellProps & {\n value: string;\n};\ntype ExtendedCellProps = CellPropsWithValue & {\n cell: {\n getCellProps: (props?: Record<string, string>) => Record<string, string>;\n };\n};\n\ninterface ActionsCellExtraProps {\n onClickDeleteButton: (role: RoleToDelete) => void;\n isUserAuthenticatedPage: boolean;\n isCourseEnabled?: (scope: string) => boolean;\n}\n\ntype ActionsCellProps = CellProps & ActionsCellExtraProps;\n\ntype DisabledCourseActionButtonProps = Pick<ComponentProps<typeof IconButton>, 'src' | 'alt' | 'size' | 'variant'>;\n\n// A disabled button can't trigger its own tooltip (Paragon sets pointer-events: none on it),\n// so the OverlayTrigger must live on a wrapper element that still receives hover events.\nexport const DisabledCourseActionButton = ({\n src, alt, size, variant,\n}: DisabledCourseActionButtonProps) => {\n const { formatMessage } = useIntl();\n return (\n <OverlayTrigger\n placement=\"left\"\n overlay={(\n <Tooltip variant=\"light\" id=\"tooltip-left\">\n {formatMessage(messages['authz.table.actions.course.disabled.tooltip'])}\n </Tooltip>\n )}\n >\n <span className=\"d-inline-block\">\n <IconButton\n src={src}\n alt={alt}\n size={size}\n variant={variant}\n disabled\n />\n </span>\n </OverlayTrigger>\n );\n};\n\nconst OrgCell = ({ value, row }: CellPropsWithValue) => {\n const { formatMessage } = useIntl();\n // The backend returns '*' as the org wildcard, meaning the role spans every organization.\n const isAllOrgs = DJANGO_MANAGED_ROLES.includes(row.original.role) || value === ALL_ORGS_KEY;\n return (\n <span>\n {isAllOrgs ? formatMessage(messages['authz.user.table.org.all.organizations.label']) : value}\n </span>\n );\n};\n\nconst ScopeCell = ({ row }: CellProps) => {\n const { formatMessage } = useIntl();\n\n const { scopeText, iconSrc } = useMemo(() => {\n const { role, scope, org } = row.original;\n if (DJANGO_MANAGED_ROLES.includes(role)) {\n return {\n scopeText: formatMessage(messages['authz.user.table.scope.global.label']),\n iconSrc: RESOURCE_ICONS.GLOBAL,\n };\n }\n const aggregateType = getAggregateScopeType(scope, org);\n return {\n scopeText: aggregateType\n ? formatMessage(AGGREGATE_SCOPE_LABELS[getScopeContextType(scope)])\n : scope,\n iconSrc: getScopeResourceIcon(scope),\n };\n }, [row.original, formatMessage]);\n\n return (\n <span className=\"d-flex align-items-center\">\n {iconSrc && <Icon color=\"primary\" src={iconSrc} className=\"mr-2\" size=\"xs\" />}\n {scopeText}\n </span>\n );\n};\n\nconst RoleCell = ({ value, cell }: ExtendedCellProps) => {\n const { key, ...cellProps } = cell.getCellProps({ 'data-role': MAP_ROLE_KEY_TO_LABEL[value] || '' });\n return (\n <span key={key} {...cellProps}>\n {MAP_ROLE_KEY_TO_LABEL[value] || ''}\n </span>\n );\n};\n\nconst PermissionsCell = ({ row }: CellProps) => {\n const { formatMessage } = useIntl();\n const { role, permissionCount: count } = row.original;\n const isDjangoRole = DJANGO_MANAGED_ROLES.includes(role);\n return (\n <span>\n { isDjangoRole\n ? formatMessage(\n messages['authz.user.table.permissions.access.label'],\n { accessType: role === 'django.superuser' ? 'total' : 'partial' },\n )\n : formatMessage(messages['authz.user.table.permissions.available.count'], { count })}\n </span>\n );\n};\n\nconst ViewAllPermissionsCell = ({ row }: CellProps) => {\n const { formatMessage } = useIntl();\n const toggleExpanded = useExclusiveRowExpansion(row);\n\n return (\n <ExpandableButton\n label={formatMessage(\n row.isExpanded\n ? messages['authz.user.table.view_all_permissions.link.text.close']\n : messages['authz.user.table.view_all_permissions.link.text.open'],\n )}\n onClick={toggleExpanded}\n isExpanded={!!row.isExpanded}\n />\n );\n};\n\nconst ActionsCell = ({\n row, onClickDeleteButton, isUserAuthenticatedPage, isCourseEnabled,\n}: ActionsCellProps) => {\n const { formatMessage } = useIntl();\n const { role, canManageScope } = row.original;\n\n const handleDelete = () => {\n const roleToDelete = {\n role,\n scope: row.original.scope,\n name: MAP_ROLE_KEY_TO_LABEL[role] || '',\n } as RoleToDelete;\n onClickDeleteButton(roleToDelete);\n };\n\n if (DJANGO_MANAGED_ROLES.includes(role)) {\n return (\n <OverlayTrigger\n placement=\"left\"\n overlay={(\n <Tooltip variant=\"light\" id=\"tooltip-left\">\n {formatMessage(messages['authz.user.table.delete.action.djangorole.tooltip'])}\n </Tooltip>\n )}\n >\n <Icon\n className=\"mx-2 pl-1\"\n src={Info}\n />\n </OverlayTrigger>\n );\n }\n\n if (ADMIN_ROLES.includes(role) && isUserAuthenticatedPage) {\n return (\n <OverlayTrigger\n placement=\"left\"\n overlay={(\n <Tooltip variant=\"light\" id=\"tooltip-left\">\n {formatMessage(messages['authz.user.table.delete.action.adminrole.tooltip'])}\n </Tooltip>\n )}\n >\n <Icon\n className=\"mx-2 pl-1 text-light-500\"\n src={Delete}\n />\n </OverlayTrigger>\n );\n }\n\n const isCourseScope = !role?.startsWith('lib');\n const isCourseAuthoringDisabled = isCourseEnabled !== undefined\n && isCourseScope && !isCourseEnabled(row.original.scope);\n\n if (isCourseAuthoringDisabled) {\n return (\n <DisabledCourseActionButton\n src={Delete}\n alt={formatMessage(messages['authz.user.table.delete.action.alt'])}\n variant=\"light\"\n />\n );\n }\n\n return (\n <IconButton\n disabled={!canManageScope}\n variant={canManageScope ? 'danger' : 'light'}\n onClick={handleDelete}\n alt={formatMessage(messages['authz.user.table.delete.action.alt'])}\n src={Delete}\n />\n );\n};\n\nconst createActionsCell = (extraProps: ActionsCellExtraProps) => function customActionsCell(cellProps) {\n return <ActionsCell {...cellProps} {...extraProps} />;\n};\n\nexport {\n RoleCell,\n OrgCell,\n ScopeCell,\n PermissionsCell,\n ViewAllPermissionsCell,\n createActionsCell,\n};\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import React, { useMemo } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { AccountBalance } from '@openedx/paragon/icons';
|
|
4
4
|
import { useOrgs } from '../../data/hooks';
|
|
5
5
|
import { useViewTeamPermissions } from '../../hooks/useViewTeamPermissions';
|
|
6
6
|
import { useCourseAuthoringFlag } from '../../hooks/useCourseAuthoringFlag';
|
|
@@ -30,7 +30,7 @@ const OrgFilter = ({ filterButtonText, filterValue, setFilter, disabled, }) => {
|
|
|
30
30
|
const handleSearchChange = (value) => {
|
|
31
31
|
setSearchValue(value);
|
|
32
32
|
};
|
|
33
|
-
return (_jsx(MultipleChoiceFilter, { filterButtonText: filterButtonText, filterChoices: filterChoices, filterValue: filterValue, setFilter: setFilter, isSearchable: true, onSearchChange: handleSearchChange, iconSrc:
|
|
33
|
+
return (_jsx(MultipleChoiceFilter, { filterButtonText: filterButtonText, filterChoices: filterChoices, filterValue: filterValue, setFilter: setFilter, isSearchable: true, onSearchChange: handleSearchChange, iconSrc: AccountBalance, disabled: disabled }));
|
|
34
34
|
};
|
|
35
35
|
export default OrgFilter;
|
|
36
36
|
//# sourceMappingURL=OrgFilter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrgFilter.js","sourceRoot":"","sources":["../../../../src/authz-module/components/TableControlBar/OrgFilter.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"OrgFilter.js","sourceRoot":"","sources":["../../../../src/authz-module/components/TableControlBar/OrgFilter.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAC;AACxF,OAAO,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAC;AACxF,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAEvE,OAAO,oBAAoB,MAAM,wBAAwB,CAAC;AAI1D,MAAM,SAAS,GAAG,CAAC,EACjB,gBAAgB,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,GACnC,EAAE,EAAE;IACnB,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAqB,SAAS,CAAC,CAAC;IACpF,MAAM,EAAE,oBAAoB,EAAE,SAAS,EAAE,GAAG,sBAAsB,EAAE,CAAC;IACrE,MAAM,EAAE,qBAAqB,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,sBAAsB,EAAE,CAAC;IACrF,MAAM,EACJ,IAAI,EAAE,QAAQ,GAAG;QACf,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;KAClD,GACF,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,wBAAwB,CAAC,CAAC;IAEtD,sFAAsF;IACtF,iFAAiF;IACjF,kFAAkF;IAClF,sFAAsF;IACtF,MAAM,qBAAqB,GAAG,CAAC,SAAS,IAAI,CAAC,aAAa,IAAI,CAAC,oBAAoB,CAAC;IAEpF,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,EAAE;;QAAC,OAAA,CAAC,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,OAAO,mCAAI,EAAE,CAAC;aAC1D,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,qBAAqB,IAAI,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;aAC/E,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACb,WAAW,EAAE,GAAG,CAAC,IAAI;YACrB,KAAK,EAAE,GAAG,CAAC,SAAS;SACrB,CAAC,CAAC,CAAA;KAAA,EAAE,CAAC,QAAQ,EAAE,qBAAqB,EAAE,qBAAqB,CAAC,CAAC,CAAC;IAEjE,MAAM,kBAAkB,GAAG,CAAC,KAAa,EAAE,EAAE;QAC3C,cAAc,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC,CAAC;IAEF,OAAO,CACL,KAAC,oBAAoB,IACnB,gBAAgB,EAAE,gBAAgB,EAClC,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,SAAS,EACpB,YAAY,QACZ,cAAc,EAAE,kBAAkB,EAClC,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,QAAQ,GAClB,CACH,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,SAAS,CAAC","sourcesContent":["import React, { useMemo } from 'react';\nimport { AccountBalance } from '@openedx/paragon/icons';\nimport { useOrgs } from '@src/authz-module/data/hooks';\nimport { useViewTeamPermissions } from '@src/authz-module/hooks/useViewTeamPermissions';\nimport { useCourseAuthoringFlag } from '@src/authz-module/hooks/useCourseAuthoringFlag';\nimport { DEFAULT_FILTER_PAGE_SIZE } from '@src/authz-module/constants';\nimport { MultipleChoiceFilterProps } from './types';\nimport MultipleChoiceFilter from './MultipleChoiceFilter';\n\ntype OrgFilterProps = Omit<MultipleChoiceFilterProps, 'filterChoices' | 'isSearchable' | 'onSearchChange'>;\n\nconst OrgFilter = ({\n filterButtonText, filterValue, setFilter, disabled,\n}: OrgFilterProps) => {\n const [searchValue, setSearchValue] = React.useState<string | undefined>(undefined);\n const { isLibraryViewAllowed, isLoading } = useViewTeamPermissions();\n const { isOrgAuthoringEnabled, isLoading: isFlagLoading } = useCourseAuthoringFlag();\n const {\n data: orgsData = {\n count: 0, next: null, previous: null, results: [],\n },\n } = useOrgs(searchValue, 1, DEFAULT_FILTER_PAGE_SIZE);\n\n // Users with library access (including those with both library and course roles) must\n // always see all orgs: library access is not gated by the course-authoring flag,\n // so the flag must never be used to filter orgs for them. Only filter orgs by the\n // flag for course-only users, and never while permissions or flag states are loading.\n const filterByAuthoringFlag = !isLoading && !isFlagLoading && !isLibraryViewAllowed;\n\n const filterChoices = useMemo(() => (orgsData?.results ?? [])\n .filter((org) => !filterByAuthoringFlag || isOrgAuthoringEnabled(org.shortName))\n .map((org) => ({\n displayName: org.name,\n value: org.shortName,\n })), [orgsData, filterByAuthoringFlag, isOrgAuthoringEnabled]);\n\n const handleSearchChange = (value: string) => {\n setSearchValue(value);\n };\n\n return (\n <MultipleChoiceFilter\n filterButtonText={filterButtonText}\n filterChoices={filterChoices}\n filterValue={filterValue}\n setFilter={setFilter}\n isSearchable\n onSearchChange={handleSearchChange}\n iconSrc={AccountBalance}\n disabled={disabled}\n />\n );\n};\n\nexport default OrgFilter;\n"]}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
1
2
|
interface TableControlBarProps {
|
|
2
3
|
onFilterChange?: (filters: string[]) => void;
|
|
4
|
+
/** Optional count rendered right-aligned on the filter row, e.g. "Showing 10 users of 100." */
|
|
5
|
+
countLabel?: ReactNode;
|
|
3
6
|
}
|
|
4
|
-
declare const TableControlBar: ({ onFilterChange }: TableControlBarProps) => import("react").JSX.Element;
|
|
7
|
+
declare const TableControlBar: ({ onFilterChange, countLabel }: TableControlBarProps) => import("react").JSX.Element;
|
|
5
8
|
export default TableControlBar;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useContext, useEffect, useState } from 'react';
|
|
2
|
+
import { useContext, useEffect, useState, } from 'react';
|
|
3
3
|
import { useIntl } from '@openedx/frontend-base';
|
|
4
4
|
import { DataTableContext, Stack, TextFilter, Button, Chip, Alert, Icon, } from '@openedx/paragon';
|
|
5
|
-
import {
|
|
5
|
+
import { AccountBalance, Close, LocationOn, Person, Warning, } from '@openedx/paragon/icons';
|
|
6
6
|
import { MAX_TABLE_FILTERS_APPLIED } from '../../constants';
|
|
7
7
|
import MultipleChoiceFilter from './MultipleChoiceFilter';
|
|
8
8
|
import SearchFilter from './SearchFilter';
|
|
@@ -12,7 +12,7 @@ import OrgFilter from './OrgFilter';
|
|
|
12
12
|
import ScopesFilter from './ScopesFilter';
|
|
13
13
|
const FILTER_CHIPS_ICONS = {
|
|
14
14
|
role: Person,
|
|
15
|
-
organization:
|
|
15
|
+
organization: AccountBalance,
|
|
16
16
|
scope: LocationOn,
|
|
17
17
|
};
|
|
18
18
|
const FILTER_GROUP_TO_ID = {
|
|
@@ -20,7 +20,7 @@ const FILTER_GROUP_TO_ID = {
|
|
|
20
20
|
organization: 'org',
|
|
21
21
|
scope: 'scope',
|
|
22
22
|
};
|
|
23
|
-
const TableControlBar = ({ onFilterChange }) => {
|
|
23
|
+
const TableControlBar = ({ onFilterChange, countLabel }) => {
|
|
24
24
|
const intl = useIntl();
|
|
25
25
|
// applied filters in the order they were selected by the user, to display on the control bar as chips
|
|
26
26
|
const [chronologicalFilters, setChronologicalFilters] = useState([]);
|
|
@@ -74,26 +74,26 @@ const TableControlBar = ({ onFilterChange }) => {
|
|
|
74
74
|
setAllFilters([]);
|
|
75
75
|
setChronologicalFilters([]);
|
|
76
76
|
};
|
|
77
|
-
return (_jsxs("div", { className: "authz-table-control-bar pgn__data-table-status-bar", children: [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
77
|
+
return (_jsxs("div", { className: "authz-table-control-bar pgn__data-table-status-bar", children: [_jsxs(Stack, { className: "mb-2 flex-wrap", gap: 2, direction: "horizontal", children: [availableFilters.map((column) => {
|
|
78
|
+
var _a;
|
|
79
|
+
const { Filter } = column;
|
|
80
|
+
if (Filter === RolesFilter) {
|
|
81
|
+
return (_jsx(RolesFilter, Object.assign({}, column, { setFilter: handleSetFilters(column.setFilter), disabled: filtersLimitReached }), column.id || column.accessor));
|
|
82
|
+
}
|
|
83
|
+
if (Filter === OrgFilter) {
|
|
84
|
+
return (_jsx(OrgFilter, Object.assign({}, column, { setFilter: handleSetFilters(column.setFilter), disabled: filtersLimitReached }), column.id || column.accessor));
|
|
85
|
+
}
|
|
86
|
+
if (Filter === MultipleChoiceFilter) {
|
|
87
|
+
return (_jsx(MultipleChoiceFilter, Object.assign({}, column, { setFilter: handleSetFilters(column.setFilter), disabled: filtersLimitReached }), column.id || column.accessor));
|
|
88
|
+
}
|
|
89
|
+
if (Filter === ScopesFilter) {
|
|
90
|
+
return (_jsx(ScopesFilter, Object.assign({}, column, { setFilter: handleSetFilters(column.setFilter), disabled: filtersLimitReached, filterValue: ((_a = state.filters.find(filter => filter.id === 'scope')) === null || _a === void 0 ? void 0 : _a.value) || null }), column.id || column.accessor));
|
|
91
|
+
}
|
|
92
|
+
if (Filter === TextFilter) {
|
|
93
|
+
return (_jsx(SearchFilter, { filterValue: column.filterValue, setFilter: column.setFilter, placeholder: getSearchPlaceholder() }, column.id || column.accessor));
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}), countLabel && _jsx("span", { className: "ml-auto text-gray-500", children: countLabel })] }), chronologicalFilters.length > 0 && (_jsxs(Stack, { gap: 1, direction: "horizontal", className: "flex-wrap mb-2", children: [_jsx("span", { children: intl.formatMessage(messages['authz.table.controlbar.filterby.label']) }), chronologicalFilters.map((filter) => (_jsx(Chip, { iconBefore: FILTER_CHIPS_ICONS[filter.groupName || ''], iconAfter: Close, onIconAfterClick: () => handleCloseFilter(filter.groupName, filter.value), children: filter.displayName }, filter.value))), chronologicalFilters.length > 1 && (_jsx(Button, { className: "py-0", variant: "link", onClick: clearAllFilters, children: intl.formatMessage(messages['authz.table.controlbar.clearFilters']) }))] })), filtersLimitReached && (_jsx(Alert, { variant: "warning", className: "mb-2", children: _jsxs("span", { className: "d-flex flex-row", children: [_jsx(Icon, { src: Warning, className: "text-warning-400 mr-2" }), intl.formatMessage(messages['authz.table.controlbar.filters.limit.reached'])] }) }))] }));
|
|
97
97
|
};
|
|
98
98
|
export default TableControlBar;
|
|
99
99
|
//# sourceMappingURL=TableControlBar.js.map
|