@openedx/frontend-app-admin-console 1.0.0-alpha.1 → 1.0.0-alpha.11
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/audit-user/index.js +6 -13
- package/dist/authz-module/audit-user/index.js.map +1 -1
- package/dist/authz-module/authz-home/index.js +21 -2
- 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/AuthZLayout.d.ts +7 -6
- package/dist/authz-module/components/AuthZLayout.js +9 -3
- package/dist/authz-module/components/AuthZLayout.js.map +1 -1
- package/dist/authz-module/components/AuthZTitle.d.ts +3 -2
- package/dist/authz-module/components/AuthZTitle.js +9 -7
- 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/PermissionTable.js +5 -1
- package/dist/authz-module/components/PermissionTable.js.map +1 -1
- package/dist/authz-module/components/TableCells.d.ts +5 -9
- package/dist/authz-module/components/TableCells.js +35 -65
- package/dist/authz-module/components/TableCells.js.map +1 -1
- package/dist/authz-module/components/TableControlBar/MultipleChoiceFilter.d.ts +1 -1
- package/dist/authz-module/components/TableControlBar/MultipleChoiceFilter.js +4 -3
- package/dist/authz-module/components/TableControlBar/MultipleChoiceFilter.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/SearchFilter.d.ts +2 -1
- package/dist/authz-module/components/TableControlBar/SearchFilter.js +2 -1
- package/dist/authz-module/components/TableControlBar/SearchFilter.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/TableControlBar/types.d.ts +1 -0
- package/dist/authz-module/components/TableControlBar/types.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 +18 -8
- package/dist/authz-module/constants.js +30 -11
- 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 +150 -13
- 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/AssignRoleWizard.js +1 -1
- package/dist/authz-module/role-assignation-wizard/AssignRoleWizard.js.map +1 -1
- package/dist/authz-module/role-assignation-wizard/AssignRoleWizardPage.js +4 -4
- package/dist/authz-module/role-assignation-wizard/AssignRoleWizardPage.js.map +1 -1
- package/dist/authz-module/role-assignation-wizard/components/ScopeFilterBar.js +1 -1
- package/dist/authz-module/role-assignation-wizard/components/ScopeFilterBar.js.map +1 -1
- package/dist/authz-module/role-assignation-wizard/hooks/useScopeListData.js.map +1 -1
- package/dist/authz-module/roles-permissions/RolesPermissions.js +3 -3
- package/dist/authz-module/roles-permissions/RolesPermissions.js.map +1 -1
- package/dist/authz-module/team-members/TeamMembersTable.js +102 -58
- 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 +6 -0
- package/dist/authz-module/utils.js +12 -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/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/routes.d.ts +3 -1
- package/dist/routes.js +17 -4
- package/dist/routes.js.map +1 -1
- package/dist/style.scss +19 -2
- package/dist/types.d.ts +29 -20
- package/dist/types.js.map +1 -1
- package/package.json +6 -3
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useScopeListData.js","sourceRoot":"","sources":["../../../../src/authz-module/role-assignation-wizard/hooks/useScopeListData.ts"],"names":[],"mappings":"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","sourcesContent":["import { useMemo } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Scope } from '@src/types';\nimport { useOrgs, useScopes } from '@src/authz-module/data/hooks';\nimport { useCourseAuthoringFlag } from '@src/authz-module/hooks/useCourseAuthoringFlag';\nimport { getOrgAggregateScopeKey, getPlatformAggregateScopeKey } from '@src/authz-module/constants';\nimport type { ContextType } from '@src/authz-module/constants';\nimport messages from '@src/authz-module/role-assignation-wizard/messages';\nimport useScopePermissions from './useScopePermissions';\n\ninterface UseScopeListDataParams {\n contextType: string | undefined;\n search: string;\n orgs: string[];\n}\n\nconst groupByOrg = (acc: Record<string, Scope[]>, scope: Scope): Record<string, Scope[]> => {\n const orgSlug = scope.org!.shortName;\n if (!acc[orgSlug]) acc[orgSlug] = [];\n acc[orgSlug].push(scope);\n return acc;\n};\n\nconst useScopeListData = ({ contextType, search, orgs }: UseScopeListDataParams) => {\n const intl = useIntl();\n const {\n data: scopesData,\n fetchNextPage,\n hasNextPage,\n isFetchingNextPage,\n isLoading,\n isError,\n } = useScopes({\n scopeType: contextType,\n search: search || undefined,\n orgs: orgs.length ? orgs : undefined,\n managementPermissionOnly: true,\n });\n\n const { data: orgsData } = useOrgs();\n const organizations = orgsData?.results;\n\n const { isCourseEnabled, isOrgAuthoringEnabled } = useCourseAuthoringFlag();\n\n const { allScopes, totalCount } = useMemo(\n () => {\n const scopes = scopesData?.pages.flatMap((page) => page.results) ?? [];\n const serverCount = scopesData?.pages[0]?.count ?? 0;\n // Course scopes are gated by the course-authoring flag; libraries always pass.\n if (contextType !== 'course') return { allScopes: scopes, totalCount: serverCount };\n const enabledScopes = scopes.filter((scope) => isCourseEnabled(scope.externalKey));\n // The server count includes authoring-disabled courses this filter hides; subtract\n // the ones already loaded so the reported total converges as pages arrive.\n return {\n allScopes: enabledScopes,\n totalCount: serverCount - (scopes.length - enabledScopes.length),\n };\n },\n [scopesData, contextType, isCourseEnabled],\n );\n\n const scopesByOrg = useMemo(\n () => allScopes\n .filter((s: Scope) => !!s.org)\n .reduce<Record<string, Scope[]>>(groupByOrg, {}),\n [allScopes],\n );\n\n const orderedOrgs = useMemo(() => {\n const orgSlugs = new Set(Object.keys(scopesByOrg));\n // Add orgs from the organizations list (respecting the active org filter)\n organizations?.forEach((org) => {\n if (!orgs.length || orgs.includes(org.shortName)) {\n orgSlugs.add(org.shortName);\n }\n });\n return [...orgSlugs].sort();\n }, [scopesByOrg, organizations, orgs]);\n\n const { hasPlatformPermission, orgHasPermission } = useScopePermissions({ contextType, orderedOrgs });\n\n const aggregateDescription = contextType === 'course'\n ? intl.formatMessage(messages['wizard.step2.scope.aggregate.description.course'])\n : intl.formatMessage(messages['wizard.step2.scope.aggregate.description.library']);\n\n const platformAggregateLabel = contextType === 'course'\n ? intl.formatMessage(messages['wizard.step2.scope.aggregate.platform.label.course'])\n : intl.formatMessage(messages['wizard.step2.scope.aggregate.platform.label.library']);\n\n const orgAggregateLabel = contextType === 'course'\n ? intl.formatMessage(messages['wizard.step2.scopeList.aggregate.label.course'])\n : intl.formatMessage(messages['wizard.step2.scopeList.aggregate.label.library']);\n\n const platformAggregateScopeItem: Scope | null = (contextType && hasPlatformPermission)\n ? {\n externalKey: getPlatformAggregateScopeKey(contextType as ContextType),\n displayName: platformAggregateLabel,\n description: aggregateDescription,\n org: null,\n }\n : null;\n\n /**\n * Builds a map of org-level aggregate scopes keyed by org slug.\n *\n * Each entry represents a wildcard scope that grants access to all courses or\n * libraries within an org (e.g. `course-v1:OrgSlug+*` or `lib:OrgSlug:*`).\n * Only orgs where the current user already holds permission are included.\n *\n * Returns an empty object when `contextType` is not yet defined.\n */\n const orgAggregateScopeItems = useMemo<Record<string, Scope>>(() => {\n if (!contextType) return {};\n return Object.fromEntries(\n orderedOrgs\n .filter((orgSlug) => orgHasPermission[orgSlug])\n // The org-wide aggregate is only offered when authoring is enabled for that org.\n .filter((orgSlug) => contextType !== 'course' || isOrgAuthoringEnabled(orgSlug))\n .map((orgSlug) => [\n orgSlug,\n {\n externalKey: getOrgAggregateScopeKey(contextType as ContextType, orgSlug),\n displayName: orgAggregateLabel,\n description: aggregateDescription,\n org: { id: '0', name: orgSlug, shortName: orgSlug },\n } satisfies Scope,\n ]),\n );\n }, [orderedOrgs, contextType, orgHasPermission, orgAggregateLabel, aggregateDescription, isOrgAuthoringEnabled]);\n\n return {\n organizations,\n orderedOrgs,\n scopesByOrg,\n allScopes,\n totalCount,\n queryState: {\n isLoading, isFetchingNextPage, hasNextPage, isError, fetchNextPage,\n },\n platformAggregateScopeItem,\n orgAggregateScopeItems,\n };\n};\n\nexport default useScopeListData;\n"]}
|
|
1
|
+
{"version":3,"file":"useScopeListData.js","sourceRoot":"","sources":["../../../../src/authz-module/role-assignation-wizard/hooks/useScopeListData.ts"],"names":[],"mappings":"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","sourcesContent":["import { useMemo } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Scope } from '@src/types';\nimport { useOrgs, useScopes } from '@src/authz-module/data/hooks';\nimport { useCourseAuthoringFlag } from '@src/authz-module/hooks/useCourseAuthoringFlag';\nimport { getOrgAggregateScopeKey, getPlatformAggregateScopeKey } from '@src/authz-module/constants';\nimport type { ContextType } from '@src/authz-module/constants';\nimport messages from '../messages';\nimport useScopePermissions from './useScopePermissions';\n\ninterface UseScopeListDataParams {\n contextType: string | undefined;\n search: string;\n orgs: string[];\n}\n\nconst groupByOrg = (acc: Record<string, Scope[]>, scope: Scope): Record<string, Scope[]> => {\n const orgSlug = scope.org!.shortName;\n if (!acc[orgSlug]) acc[orgSlug] = [];\n acc[orgSlug].push(scope);\n return acc;\n};\n\nconst useScopeListData = ({ contextType, search, orgs }: UseScopeListDataParams) => {\n const intl = useIntl();\n const {\n data: scopesData,\n fetchNextPage,\n hasNextPage,\n isFetchingNextPage,\n isLoading,\n isError,\n } = useScopes({\n scopeType: contextType,\n search: search || undefined,\n orgs: orgs.length ? orgs : undefined,\n managementPermissionOnly: true,\n });\n\n const { data: orgsData } = useOrgs();\n const organizations = orgsData?.results;\n\n const { isCourseEnabled, isOrgAuthoringEnabled } = useCourseAuthoringFlag();\n\n const { allScopes, totalCount } = useMemo(\n () => {\n const scopes = scopesData?.pages.flatMap((page) => page.results) ?? [];\n const serverCount = scopesData?.pages[0]?.count ?? 0;\n // Course scopes are gated by the course-authoring flag; libraries always pass.\n if (contextType !== 'course') return { allScopes: scopes, totalCount: serverCount };\n const enabledScopes = scopes.filter((scope) => isCourseEnabled(scope.externalKey));\n // The server count includes authoring-disabled courses this filter hides; subtract\n // the ones already loaded so the reported total converges as pages arrive.\n return {\n allScopes: enabledScopes,\n totalCount: serverCount - (scopes.length - enabledScopes.length),\n };\n },\n [scopesData, contextType, isCourseEnabled],\n );\n\n const scopesByOrg = useMemo(\n () => allScopes\n .filter((s: Scope) => !!s.org)\n .reduce<Record<string, Scope[]>>(groupByOrg, {}),\n [allScopes],\n );\n\n const orderedOrgs = useMemo(() => {\n const orgSlugs = new Set(Object.keys(scopesByOrg));\n // Add orgs from the organizations list (respecting the active org filter)\n organizations?.forEach((org) => {\n if (!orgs.length || orgs.includes(org.shortName)) {\n orgSlugs.add(org.shortName);\n }\n });\n return [...orgSlugs].sort();\n }, [scopesByOrg, organizations, orgs]);\n\n const { hasPlatformPermission, orgHasPermission } = useScopePermissions({ contextType, orderedOrgs });\n\n const aggregateDescription = contextType === 'course'\n ? intl.formatMessage(messages['wizard.step2.scope.aggregate.description.course'])\n : intl.formatMessage(messages['wizard.step2.scope.aggregate.description.library']);\n\n const platformAggregateLabel = contextType === 'course'\n ? intl.formatMessage(messages['wizard.step2.scope.aggregate.platform.label.course'])\n : intl.formatMessage(messages['wizard.step2.scope.aggregate.platform.label.library']);\n\n const orgAggregateLabel = contextType === 'course'\n ? intl.formatMessage(messages['wizard.step2.scopeList.aggregate.label.course'])\n : intl.formatMessage(messages['wizard.step2.scopeList.aggregate.label.library']);\n\n const platformAggregateScopeItem: Scope | null = (contextType && hasPlatformPermission)\n ? {\n externalKey: getPlatformAggregateScopeKey(contextType as ContextType),\n displayName: platformAggregateLabel,\n description: aggregateDescription,\n org: null,\n }\n : null;\n\n /**\n * Builds a map of org-level aggregate scopes keyed by org slug.\n *\n * Each entry represents a wildcard scope that grants access to all courses or\n * libraries within an org (e.g. `course-v1:OrgSlug+*` or `lib:OrgSlug:*`).\n * Only orgs where the current user already holds permission are included.\n *\n * Returns an empty object when `contextType` is not yet defined.\n */\n const orgAggregateScopeItems = useMemo<Record<string, Scope>>(() => {\n if (!contextType) return {};\n return Object.fromEntries(\n orderedOrgs\n .filter((orgSlug) => orgHasPermission[orgSlug])\n // The org-wide aggregate is only offered when authoring is enabled for that org.\n .filter((orgSlug) => contextType !== 'course' || isOrgAuthoringEnabled(orgSlug))\n .map((orgSlug) => [\n orgSlug,\n {\n externalKey: getOrgAggregateScopeKey(contextType as ContextType, orgSlug),\n displayName: orgAggregateLabel,\n description: aggregateDescription,\n org: { id: '0', name: orgSlug, shortName: orgSlug },\n } satisfies Scope,\n ]),\n );\n }, [orderedOrgs, contextType, orgHasPermission, orgAggregateLabel, aggregateDescription, isOrgAuthoringEnabled]);\n\n return {\n organizations,\n orderedOrgs,\n scopesByOrg,\n allScopes,\n totalCount,\n queryState: {\n isLoading, isFetchingNextPage, hasNextPage, isError, fetchNextPage,\n },\n platformAggregateScopeItem,\n orgAggregateScopeItems,\n };\n};\n\nexport default useScopeListData;\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo, useState } from 'react';
|
|
3
3
|
import { useIntl } from '@openedx/frontend-base';
|
|
4
|
-
import { Alert, Button, ButtonGroup,
|
|
4
|
+
import { Alert, Button, ButtonGroup, Card, Hyperlink, } from '@openedx/paragon';
|
|
5
5
|
import { coursePermissions, courseResourceTypes, courseRolesWithPermissions, } from './course/constants';
|
|
6
6
|
import { libraryRolesWithPermissions, libraryPermissions, libraryResourceTypes, } from './library/constants';
|
|
7
7
|
import AnchorButton from '../components/AnchorButton';
|
|
@@ -29,7 +29,7 @@ const RolesPermissions = () => {
|
|
|
29
29
|
});
|
|
30
30
|
return permissionsByResource;
|
|
31
31
|
}, [intl]);
|
|
32
|
-
return (_jsxs(
|
|
32
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Card, { className: "bg-light-200", children: [_jsx("div", { className: "px-3 py-4", children: _jsxs(ButtonGroup, { size: "md", children: [_jsx(Button, { onClick: () => setActive('courses'), variant: `${active === 'courses' ? 'primary' : 'outline-primary'}`, children: intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.tab']) }), _jsx(Button, { onClick: () => setActive('libraries'), variant: `${active === 'libraries' ? 'primary' : 'outline-primary'}`, children: intl.formatMessage(messages['authz.tabs.permissionsRoles.libraries.tab']) })] }) }), active === 'courses' && (_jsx("div", { className: "position-relative", children: _jsx(PermissionTable, { permissionsTable: coursePermissionsByResource, roles: courseRolesWithPermissions, title: intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.tab.title']) }) })), active === 'libraries' && (_jsx(PermissionTable, { permissionsTable: libraryPermissionsByResource, roles: libraryRolesWithPermissions, title: intl.formatMessage(messages['authz.tabs.permissionsRoles.libraries.tab.title']) }))] }), active === 'courses' && (_jsx(Alert, { variant: "info", className: "mt-5", children: _jsxs("div", { className: "row align-items-center", children: [_jsxs("div", { className: "col-12 col-md-7", children: [_jsx("p", { className: "text-primary font-weight-bold h4", children: intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.title']) }), _jsxs("span", { children: [_jsx("span", { className: "font-weight-bold", children: intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.note']) }), intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.description'])] })] }), _jsx("div", { className: "col-12 col-md-5 mt-3 mt-md-0", children: _jsx(Hyperlink, { className: "d-block text-right h5 font-weight-normal", destination: "https://docs.openedx.org/en/latest/educators/references/course_development/course_team_roles.html", target: "_blank", showLaunchIcon: false, isInline: true, children: intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.link']) }) })] }) })), _jsx(AnchorButton, {})] }));
|
|
33
33
|
};
|
|
34
34
|
export default RolesPermissions;
|
|
35
35
|
//# sourceMappingURL=RolesPermissions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RolesPermissions.js","sourceRoot":"","sources":["../../../src/authz-module/roles-permissions/RolesPermissions.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EACL,KAAK,EACL,MAAM,EACN,WAAW,EACX,
|
|
1
|
+
{"version":3,"file":"RolesPermissions.js","sourceRoot":"","sources":["../../../src/authz-module/roles-permissions/RolesPermissions.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useState } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport {\n Alert,\n Button,\n ButtonGroup,\n Card,\n Hyperlink,\n} from '@openedx/paragon';\n\nimport {\n coursePermissions,\n courseResourceTypes,\n courseRolesWithPermissions,\n} from './course/constants';\nimport {\n libraryRolesWithPermissions,\n libraryPermissions,\n libraryResourceTypes,\n} from './library/constants';\nimport AnchorButton from '@src/authz-module/components/AnchorButton';\nimport PermissionTable from '@src/authz-module/components/PermissionTable';\n\nimport { buildPermissionMatrixByResource } from './utils';\n\nimport messages from './messages';\n\nconst RolesPermissions = () => {\n const intl = useIntl();\n const [active, setActive] = useState('courses');\n\n const libraryPermissionsByResource = useMemo(() => {\n const permissionsByResource = buildPermissionMatrixByResource({\n roles: libraryRolesWithPermissions,\n permissions: libraryPermissions,\n resources: libraryResourceTypes,\n intl,\n });\n\n return permissionsByResource;\n }, [intl]);\n\n const coursePermissionsByResource = useMemo(() => {\n const permissionsByResource = buildPermissionMatrixByResource({\n roles: courseRolesWithPermissions,\n permissions: coursePermissions,\n resources: courseResourceTypes,\n intl,\n });\n\n return permissionsByResource;\n }, [intl]);\n\n return (\n <>\n <Card className=\"bg-light-200\">\n <div className=\"px-3 py-4\">\n <ButtonGroup size=\"md\">\n <Button\n onClick={() => setActive('courses')}\n variant={`${active === 'courses' ? 'primary' : 'outline-primary'}`}\n >\n {intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.tab'])}\n </Button>\n <Button\n onClick={() => setActive('libraries')}\n variant={`${active === 'libraries' ? 'primary' : 'outline-primary'}`}\n >\n {intl.formatMessage(messages['authz.tabs.permissionsRoles.libraries.tab'])}\n </Button>\n </ButtonGroup>\n </div>\n {/* Courses */}\n {active === 'courses' && (\n <div className=\"position-relative\">\n <PermissionTable\n permissionsTable={coursePermissionsByResource}\n roles={courseRolesWithPermissions}\n title={intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.tab.title'])}\n />\n </div>\n )}\n {/* Libraries */}\n {active === 'libraries' && (\n <PermissionTable\n permissionsTable={libraryPermissionsByResource}\n roles={libraryRolesWithPermissions}\n title={intl.formatMessage(messages['authz.tabs.permissionsRoles.libraries.tab.title'])}\n />\n )}\n </Card>\n {active === 'courses' && (\n <Alert\n variant=\"info\"\n className=\"mt-5\"\n >\n <div className=\"row align-items-center\">\n <div className=\"col-12 col-md-7\">\n <p className=\"text-primary font-weight-bold h4\">{intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.title'])}</p>\n <span>\n <span className=\"font-weight-bold\">{intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.note'])}</span>\n {intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.description'])}\n </span>\n </div>\n <div className=\"col-12 col-md-5 mt-3 mt-md-0\">\n <Hyperlink className=\"d-block text-right h5 font-weight-normal\" destination=\"https://docs.openedx.org/en/latest/educators/references/course_development/course_team_roles.html\" target=\"_blank\" showLaunchIcon={false} isInline>\n {intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.link'])}\n </Hyperlink>\n </div>\n </div>\n </Alert>\n )}\n <AnchorButton />\n </>\n );\n};\n\nexport default RolesPermissions;\n"]}
|
|
@@ -6,18 +6,36 @@ import { DataTable, TextFilter, } from '@openedx/paragon';
|
|
|
6
6
|
import { useToastManager } from '../../components/ToastManager/ToastManagerContext';
|
|
7
7
|
import { LIBRARY_ROLE_KEYS } from '../roles-permissions';
|
|
8
8
|
import { useViewTeamPermissions } from '../hooks/useViewTeamPermissions';
|
|
9
|
-
import { useCourseAuthoringFlag } from '../hooks/useCourseAuthoringFlag';
|
|
10
9
|
import { useQuerySettings } from '../hooks/useQuerySettings';
|
|
11
10
|
import OrgFilter from '../components/TableControlBar/OrgFilter';
|
|
12
11
|
import RolesFilter from '../components/TableControlBar/RolesFilter';
|
|
13
12
|
import ScopesFilter from '../components/TableControlBar/ScopesFilter';
|
|
14
13
|
import TableControlBar from '../components/TableControlBar/TableControlBar';
|
|
15
14
|
import { getCellHeader } from '../utils';
|
|
16
|
-
import {
|
|
17
|
-
import { useAllRoleAssignments } from '../data/hooks';
|
|
15
|
+
import { useTeamMembersAssignments } from '../data/hooks';
|
|
18
16
|
import { TABLE_DEFAULT_PAGE_SIZE } from '../constants';
|
|
19
17
|
import messages from './messages';
|
|
20
18
|
import TableFooter from '../components/TableFooter/TableFooter';
|
|
19
|
+
import AssignedRolesCell from './components/AssignedRolesCell';
|
|
20
|
+
import { EmailCell, NameCell } from './components/TeamMemberCells';
|
|
21
|
+
import MoreRolesToggle from './components/MoreRolesToggle';
|
|
22
|
+
import UserAssignmentsSubTable from './components/UserAssignmentsSubTable';
|
|
23
|
+
import TeamMemberViewActionCell from './components/TeamMemberViewActionCell';
|
|
24
|
+
const toastedErrors = new WeakSet();
|
|
25
|
+
/**
|
|
26
|
+
* Stable stand-in for a query that has not resolved. A fresh object literal here would
|
|
27
|
+
* hand `DataTable` a new `data` array on every render, and react-table resets its
|
|
28
|
+
* expanded-row state whenever `data` changes identity.
|
|
29
|
+
*/
|
|
30
|
+
const EMPTY_ASSIGNMENTS = {
|
|
31
|
+
results: [], count: 0, next: null, previous: null,
|
|
32
|
+
};
|
|
33
|
+
// Org, scope and role stay in the column set — TableControlBar derives its filter
|
|
34
|
+
// controls from the columns — but are hidden, since the design surfaces them inside
|
|
35
|
+
// each user's role breakdown instead of as top-level columns. They carry no accessor
|
|
36
|
+
// (a user row has no single org/scope/role), so each opts into filtering with
|
|
37
|
+
// `defaultCanFilter`, which react-table otherwise infers from the accessor.
|
|
38
|
+
const HIDDEN_FILTER_COLUMNS = ['org', 'scope', 'role'];
|
|
21
39
|
const TeamMembersTable = ({ presetScope }) => {
|
|
22
40
|
const intl = useIntl();
|
|
23
41
|
const { showErrorToast } = useToastManager();
|
|
@@ -34,74 +52,100 @@ const TeamMembersTable = ({ presetScope }) => {
|
|
|
34
52
|
} : undefined;
|
|
35
53
|
const { querySettings, handleTableFetch } = useQuerySettings(initialQuerySettings);
|
|
36
54
|
const { isCourseViewAllowed } = useViewTeamPermissions();
|
|
37
|
-
const { isCourseEnabled } = useCourseAuthoringFlag();
|
|
38
55
|
const effectiveQuerySettings = useMemo(() => {
|
|
39
56
|
if (isCourseViewAllowed || querySettings.roles)
|
|
40
57
|
return querySettings;
|
|
41
58
|
return Object.assign(Object.assign({}, querySettings), { roles: LIBRARY_ROLE_KEYS });
|
|
42
59
|
}, [isCourseViewAllowed, querySettings]);
|
|
43
|
-
const { data: { results:
|
|
44
|
-
const viewActionCell = useMemo(() => createViewActionCell({ isCourseEnabled }), [isCourseEnabled]);
|
|
60
|
+
const { data: { results: teamMembers, count } = EMPTY_ASSIGNMENTS, isLoading: isLoadingTeamMembers, error, refetch, } = useTeamMembersAssignments(effectiveQuerySettings);
|
|
45
61
|
const initialFilters = presetScope ? [{ id: 'scope', value: [presetScope] }] : [];
|
|
62
|
+
/**
|
|
63
|
+
* Only transient failures reach here.
|
|
64
|
+
*/
|
|
46
65
|
useEffect(() => {
|
|
47
|
-
if (error) {
|
|
66
|
+
if (error && !toastedErrors.has(error)) {
|
|
67
|
+
toastedErrors.add(error);
|
|
48
68
|
showErrorToast(error, refetch);
|
|
49
69
|
}
|
|
50
70
|
}, [error, showErrorToast, refetch]);
|
|
51
71
|
const pageCount = Math.ceil(count / TABLE_DEFAULT_PAGE_SIZE);
|
|
52
72
|
const fetchData = useMemo(() => debounce(handleTableFetch, 500), [handleTableFetch]);
|
|
53
73
|
useEffect(() => () => fetchData.cancel(), [fetchData]);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
74
|
+
const showingUsersLabel = intl.formatMessage(messages['authz.team.members.table.showing.users.text'], { pageSize: teamMembers.length, itemCount: count });
|
|
75
|
+
return (_jsxs(DataTable, { className: "team-members-table", isExpandable: true, isFilterable: true, isPaginated: true, isSortable: true, manualFilters: true, manualPagination: true, manualSortBy: true, numBreakoutFilters: 4, fetchData: fetchData, data: teamMembers, itemCount: count, pageCount: pageCount, initialState: {
|
|
76
|
+
pageSize: TABLE_DEFAULT_PAGE_SIZE,
|
|
77
|
+
filters: initialFilters,
|
|
78
|
+
hiddenColumns: HIDDEN_FILTER_COLUMNS,
|
|
79
|
+
}, isLoading: isLoadingTeamMembers, renderRowSubComponent: ({ row }) => (_jsx(UserAssignmentsSubTable, { row: row })), additionalColumns: [
|
|
80
|
+
{
|
|
81
|
+
id: 'moreRoles',
|
|
82
|
+
Header: '',
|
|
83
|
+
Cell: MoreRolesToggle,
|
|
84
|
+
headerClassName: 'authz-col-more-roles',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: 'action',
|
|
88
|
+
Header: intl.formatMessage(messages['authz.team.members.table.column.actions.title']),
|
|
89
|
+
Cell: TeamMemberViewActionCell,
|
|
90
|
+
cellClassName: 'text-center',
|
|
91
|
+
headerClassName: 'authz-col-actions justify-content-center',
|
|
92
|
+
},
|
|
93
|
+
], columns: [
|
|
94
|
+
{
|
|
95
|
+
id: 'username',
|
|
96
|
+
Header: intl.formatMessage(messages['authz.team.members.table.column.username.title']),
|
|
97
|
+
accessor: 'username',
|
|
98
|
+
Cell: NameCell,
|
|
99
|
+
headerClassName: 'authz-col-username',
|
|
100
|
+
filter: 'text',
|
|
101
|
+
Filter: TextFilter,
|
|
102
|
+
filterOrder: 1,
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
Header: intl.formatMessage(messages['authz.team.members.table.column.email.title']),
|
|
106
|
+
accessor: 'email',
|
|
107
|
+
Cell: EmailCell,
|
|
108
|
+
headerClassName: 'authz-col-email',
|
|
109
|
+
disableFilters: true,
|
|
110
|
+
filter: 'text',
|
|
111
|
+
Filter: TextFilter,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
id: 'assignedRoles',
|
|
115
|
+
Header: intl.formatMessage(messages['authz.team.members.table.column.assigned.roles.title']),
|
|
116
|
+
Cell: AssignedRolesCell,
|
|
117
|
+
headerClassName: 'authz-col-assigned-roles',
|
|
118
|
+
disableFilters: true,
|
|
119
|
+
disableSortBy: true,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: 'org',
|
|
123
|
+
Header: getCellHeader('org', intl.formatMessage(messages['authz.team.members.table.column.organization.title']), columnsWithFiltersApplied),
|
|
124
|
+
filter: 'includesValue',
|
|
125
|
+
defaultCanFilter: true,
|
|
126
|
+
Filter: OrgFilter,
|
|
127
|
+
filterButtonText: intl.formatMessage(messages['authz.team.members.table.column.organization.title']),
|
|
128
|
+
filterOrder: 2,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: 'scope',
|
|
132
|
+
Header: getCellHeader('scope', intl.formatMessage(messages['authz.team.members.table.column.scope.title']), columnsWithFiltersApplied),
|
|
133
|
+
filter: 'includesValue',
|
|
134
|
+
defaultCanFilter: true,
|
|
135
|
+
Filter: ScopesFilter,
|
|
136
|
+
filterButtonText: intl.formatMessage(messages['authz.team.members.table.column.scope.title']),
|
|
137
|
+
filterOrder: 4,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: 'role',
|
|
141
|
+
Header: getCellHeader('role', intl.formatMessage(messages['authz.team.members.table.column.role.title']), columnsWithFiltersApplied),
|
|
142
|
+
filter: 'includesValue',
|
|
143
|
+
defaultCanFilter: true,
|
|
144
|
+
Filter: RolesFilter,
|
|
145
|
+
filterButtonText: intl.formatMessage(messages['authz.team.members.table.column.role.title']),
|
|
146
|
+
filterOrder: 3,
|
|
147
|
+
},
|
|
148
|
+
], children: [_jsx(TableControlBar, { onFilterChange: setColumnsWithFiltersApplied, countLabel: showingUsersLabel }), _jsx(DataTable.Table, {}), _jsx(TableFooter, { showingMessage: messages['authz.team.members.table.showing.users.text'] })] }));
|
|
105
149
|
};
|
|
106
150
|
export default TeamMembersTable;
|
|
107
151
|
//# sourceMappingURL=TeamMembersTable.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamMembersTable.js","sourceRoot":"","sources":["../../../src/authz-module/team-members/TeamMembersTable.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACrD,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EACL,SAAS,EACT,UAAU,GACX,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,eAAe,EAAE,MAAM,kDAAkD,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAC;AACxF,OAAO,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,SAAS,MAAM,wDAAwD,CAAC;AAC/E,OAAO,WAAW,MAAM,0DAA0D,CAAC;AACnF,OAAO,YAAY,MAAM,2DAA2D,CAAC;AACrF,OAAO,eAAe,MAAM,8DAA8D,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EACL,oBAAoB,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,GAC7D,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,WAAW,MAAM,sDAAsD,CAAC;AAM/E,MAAM,gBAAgB,GAAG,CAAC,EAAE,WAAW,EAAyB,EAAE,EAAE;IAClE,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,EAAE,cAAc,EAAE,GAAG,eAAe,EAAE,CAAC;IAC7C,MAAM,CAAC,yBAAyB,EAAE,4BAA4B,CAAC,GAAG,QAAQ,CAAW,EAAE,CAAC,CAAC;IAEzF,MAAM,oBAAoB,GAAG,WAAW,CAAC,CAAC,CAAC;QACzC,MAAM,EAAE,WAAW;QACnB,QAAQ,EAAE,uBAAuB;QACjC,SAAS,EAAE,CAAC;QACZ,KAAK,EAAE,IAAI;QACX,aAAa,EAAE,IAAI;QACnB,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;KACb,CAAC,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,EAAE,aAAa,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,CAAC,oBAAoB,CAAC,CAAC;IAEnF,MAAM,EAAE,mBAAmB,EAAE,GAAG,sBAAsB,EAAE,CAAC;IACzD,MAAM,EAAE,eAAe,EAAE,GAAG,sBAAsB,EAAE,CAAC;IAErD,MAAM,sBAAsB,GAAG,OAAO,CAAC,GAAG,EAAE;QAC1C,IAAI,mBAAmB,IAAI,aAAa,CAAC,KAAK;YAAE,OAAO,aAAa,CAAC;QACrE,uCAAY,aAAa,KAAE,KAAK,EAAE,iBAAiB,IAAG;IACxD,CAAC,EAAE,CAAC,mBAAmB,EAAE,aAAa,CAAC,CAAC,CAAC;IAEzC,MAAM,EACJ,IAAI,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EACrE,SAAS,EAAE,2BAA2B,EACtC,KAAK,EACL,OAAO,GACR,GAAG,qBAAqB,CAAC,sBAAsB,CAAC,CAAC;IAElD,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;IAEnG,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAElF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,EAAE,CAAC;YACV,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;IAErC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,uBAAuB,CAAC,CAAC;IAE7D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,gBAAgB,EAAE,GAAG,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAErF,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEvD,OAAO,CACL,cAAK,SAAS,EAAC,cAAc,YAC3B,MAAC,SAAS,IACR,YAAY,QACZ,WAAW,QACX,UAAU,QACV,aAAa,QACb,gBAAgB,QAChB,YAAY,QACZ,kBAAkB,EAAE,CAAC,EACrB,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,eAAe,EACrB,SAAS,EAAE,KAAK,EAChB,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,EAAE,QAAQ,EAAE,uBAAuB,EAAE,OAAO,EAAE,cAAc,EAAE,EAC5E,SAAS,EAAE,2BAA2B,EACtC,iBAAiB,EAAE;gBACjB;oBACE,EAAE,EAAE,QAAQ;oBACZ,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,+CAA+C,CAAC,CAAC;oBACrF,IAAI,EAAE,cAAc;iBACrB;aACF,EACD,OAAO,EACL;gBACE;oBACE,EAAE,EAAE,UAAU;oBACd,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4CAA4C,CAAC,CAAC;oBAClF,QAAQ,EAAE,UAAU;oBACpB,IAAI,EAAE,QAAQ;oBACd,MAAM,EAAE,MAAM;oBACd,MAAM,EAAE,UAAU;oBAClB,WAAW,EAAE,CAAC;iBACf;gBACD;oBACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,6CAA6C,CAAC,CAAC;oBACnF,QAAQ,EAAE,OAAO;oBACjB,cAAc,EAAE,IAAI;oBACpB,MAAM,EAAE,MAAM;oBACd,MAAM,EAAE,UAAU;iBACnB;gBACD;oBACE,MAAM,EAAE,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oDAAoD,CAAC,CAAC,EAAE,yBAAyB,CAAC;oBAC3I,QAAQ,EAAE,KAAK;oBACf,IAAI,EAAE,OAAO;oBACb,MAAM,EAAE,eAAe;oBACvB,MAAM,EAAE,SAAS;oBACjB,gBAAgB,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oDAAoD,CAAC,CAAC;oBACpG,WAAW,EAAE,CAAC;iBACf;gBACD;oBACE,MAAM,EAAE,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,6CAA6C,CAAC,CAAC,EAAE,yBAAyB,CAAC;oBACtI,QAAQ,EAAE,OAAO;oBACjB,IAAI,EAAE,SAAS;oBACf,MAAM,EAAE,eAAe;oBACvB,MAAM,EAAE,YAAY;oBACpB,gBAAgB,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,6CAA6C,CAAC,CAAC;oBAC7F,WAAW,EAAE,CAAC;iBACf;gBACD;oBACE,MAAM,EAAE,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4CAA4C,CAAC,CAAC,EAAE,yBAAyB,CAAC;oBACpI,QAAQ,EAAE,MAAM;oBAChB,MAAM,EAAE,eAAe;oBACvB,IAAI,EAAE,QAAQ;oBACd,MAAM,EAAE,WAAW;oBACnB,gBAAgB,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4CAA4C,CAAC,CAAC;oBAC5F,WAAW,EAAE,CAAC;iBACf;aACF,aAGH,KAAC,eAAe,IAAC,cAAc,EAAE,4BAA4B,GAAI,EACjE,KAAC,SAAS,CAAC,KAAK,KAAG,EACnB,KAAC,WAAW,KAAG,IACL,GACR,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport debounce from 'lodash.debounce';\nimport { useIntl } from '@openedx/frontend-base';\nimport {\n DataTable,\n TextFilter,\n} from '@openedx/paragon';\n\nimport { useToastManager } from '@src/components/ToastManager/ToastManagerContext';\nimport { LIBRARY_ROLE_KEYS } from '@src/authz-module/roles-permissions';\nimport { useViewTeamPermissions } from '@src/authz-module/hooks/useViewTeamPermissions';\nimport { useCourseAuthoringFlag } from '@src/authz-module/hooks/useCourseAuthoringFlag';\nimport { useQuerySettings } from '@src/authz-module/hooks/useQuerySettings';\nimport OrgFilter from '@src/authz-module/components/TableControlBar/OrgFilter';\nimport RolesFilter from '@src/authz-module/components/TableControlBar/RolesFilter';\nimport ScopesFilter from '@src/authz-module/components/TableControlBar/ScopesFilter';\nimport TableControlBar from '@src/authz-module/components/TableControlBar/TableControlBar';\nimport { getCellHeader } from '@src/authz-module/utils';\nimport {\n createViewActionCell, NameCell, OrgCell, RoleCell, ScopeCell,\n} from '@src/authz-module/components/TableCells';\nimport { useAllRoleAssignments } from '@src/authz-module/data/hooks';\nimport { TABLE_DEFAULT_PAGE_SIZE } from '@src/authz-module/constants';\nimport messages from './messages';\nimport TableFooter from '@src/authz-module/components/TableFooter/TableFooter';\n\ninterface TeamMembersTableProps {\n presetScope?: string;\n}\n\nconst TeamMembersTable = ({ presetScope }: TeamMembersTableProps) => {\n const intl = useIntl();\n const { showErrorToast } = useToastManager();\n const [columnsWithFiltersApplied, setColumnsWithFiltersApplied] = useState<string[]>([]);\n\n const initialQuerySettings = presetScope ? {\n scopes: presetScope,\n pageSize: TABLE_DEFAULT_PAGE_SIZE,\n pageIndex: 0,\n roles: null,\n organizations: null,\n search: null,\n order: null,\n sortBy: null,\n } : undefined;\n\n const { querySettings, handleTableFetch } = useQuerySettings(initialQuerySettings);\n\n const { isCourseViewAllowed } = useViewTeamPermissions();\n const { isCourseEnabled } = useCourseAuthoringFlag();\n\n const effectiveQuerySettings = useMemo(() => {\n if (isCourseViewAllowed || querySettings.roles) return querySettings;\n return { ...querySettings, roles: LIBRARY_ROLE_KEYS };\n }, [isCourseViewAllowed, querySettings]);\n\n const {\n data: { results: roleAssignments, count } = { results: [], count: 0 },\n isLoading: isLoadingAllRoleAssignments,\n error,\n refetch,\n } = useAllRoleAssignments(effectiveQuerySettings);\n\n const viewActionCell = useMemo(() => createViewActionCell({ isCourseEnabled }), [isCourseEnabled]);\n\n const initialFilters = presetScope ? [{ id: 'scope', value: [presetScope] }] : [];\n\n useEffect(() => {\n if (error) {\n showErrorToast(error, refetch);\n }\n }, [error, showErrorToast, refetch]);\n\n const pageCount = Math.ceil(count / TABLE_DEFAULT_PAGE_SIZE);\n\n const fetchData = useMemo(() => debounce(handleTableFetch, 500), [handleTableFetch]);\n\n useEffect(() => () => fetchData.cancel(), [fetchData]);\n\n return (\n <div className=\"authz-module\">\n <DataTable\n isFilterable\n isPaginated\n isSortable\n manualFilters\n manualPagination\n manualSortBy\n numBreakoutFilters={4}\n fetchData={fetchData}\n data={roleAssignments}\n itemCount={count}\n pageCount={pageCount}\n initialState={{ pageSize: TABLE_DEFAULT_PAGE_SIZE, filters: initialFilters }}\n isLoading={isLoadingAllRoleAssignments}\n additionalColumns={[\n {\n id: 'action',\n Header: intl.formatMessage(messages['authz.team.members.table.column.actions.title']),\n Cell: viewActionCell,\n },\n ]}\n columns={\n [\n {\n id: 'username',\n Header: intl.formatMessage(messages['authz.team.members.table.column.name.title']),\n accessor: 'username',\n Cell: NameCell,\n filter: 'text',\n Filter: TextFilter,\n filterOrder: 1,\n },\n {\n Header: intl.formatMessage(messages['authz.team.members.table.column.email.title']),\n accessor: 'email',\n disableFilters: true,\n filter: 'text',\n Filter: TextFilter,\n },\n {\n Header: getCellHeader('org', intl.formatMessage(messages['authz.team.members.table.column.organization.title']), columnsWithFiltersApplied),\n accessor: 'org',\n Cell: OrgCell,\n filter: 'includesValue',\n Filter: OrgFilter,\n filterButtonText: intl.formatMessage(messages['authz.team.members.table.column.organization.title']),\n filterOrder: 2,\n },\n {\n Header: getCellHeader('scope', intl.formatMessage(messages['authz.team.members.table.column.scope.title']), columnsWithFiltersApplied),\n accessor: 'scope',\n Cell: ScopeCell,\n filter: 'includesValue',\n Filter: ScopesFilter,\n filterButtonText: intl.formatMessage(messages['authz.team.members.table.column.scope.title']),\n filterOrder: 4,\n },\n {\n Header: getCellHeader('role', intl.formatMessage(messages['authz.team.members.table.column.role.title']), columnsWithFiltersApplied),\n accessor: 'role',\n filter: 'includesValue',\n Cell: RoleCell,\n Filter: RolesFilter,\n filterButtonText: intl.formatMessage(messages['authz.team.members.table.column.role.title']),\n filterOrder: 3,\n },\n ]\n }\n >\n <TableControlBar onFilterChange={setColumnsWithFiltersApplied} />\n <DataTable.Table />\n <TableFooter />\n </DataTable>\n </div>\n );\n};\n\nexport default TeamMembersTable;\n"]}
|
|
1
|
+
{"version":3,"file":"TeamMembersTable.js","sourceRoot":"","sources":["../../../src/authz-module/team-members/TeamMembersTable.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport debounce from 'lodash.debounce';\nimport { useIntl } from '@openedx/frontend-base';\nimport {\n DataTable,\n TextFilter,\n} from '@openedx/paragon';\n\nimport { useToastManager } from '@src/components/ToastManager/ToastManagerContext';\nimport { LIBRARY_ROLE_KEYS } from '@src/authz-module/roles-permissions';\nimport { useViewTeamPermissions } from '@src/authz-module/hooks/useViewTeamPermissions';\nimport { useQuerySettings } from '@src/authz-module/hooks/useQuerySettings';\nimport OrgFilter from '@src/authz-module/components/TableControlBar/OrgFilter';\nimport RolesFilter from '@src/authz-module/components/TableControlBar/RolesFilter';\nimport ScopesFilter from '@src/authz-module/components/TableControlBar/ScopesFilter';\nimport TableControlBar from '@src/authz-module/components/TableControlBar/TableControlBar';\nimport { getCellHeader } from '@src/authz-module/utils';\n\nimport { useTeamMembersAssignments } from '@src/authz-module/data/hooks';\nimport type { GetTeamMembersAssignmentsResponse } from '@src/authz-module/data/api';\nimport { TABLE_DEFAULT_PAGE_SIZE } from '@src/authz-module/constants';\nimport messages from './messages';\nimport TableFooter from '@src/authz-module/components/TableFooter/TableFooter';\nimport AssignedRolesCell from './components/AssignedRolesCell';\nimport { EmailCell, NameCell } from './components/TeamMemberCells';\nimport MoreRolesToggle from './components/MoreRolesToggle';\nimport UserAssignmentsSubTable from './components/UserAssignmentsSubTable';\nimport TeamMemberViewActionCell from './components/TeamMemberViewActionCell';\n\ninterface TeamMembersTableProps {\n presetScope?: string;\n}\n\nconst toastedErrors = new WeakSet<Error>();\n\n/**\n * Stable stand-in for a query that has not resolved. A fresh object literal here would\n * hand `DataTable` a new `data` array on every render, and react-table resets its\n * expanded-row state whenever `data` changes identity.\n */\nconst EMPTY_ASSIGNMENTS: GetTeamMembersAssignmentsResponse = {\n results: [], count: 0, next: null, previous: null,\n};\n\n// Org, scope and role stay in the column set — TableControlBar derives its filter\n// controls from the columns — but are hidden, since the design surfaces them inside\n// each user's role breakdown instead of as top-level columns. They carry no accessor\n// (a user row has no single org/scope/role), so each opts into filtering with\n// `defaultCanFilter`, which react-table otherwise infers from the accessor.\nconst HIDDEN_FILTER_COLUMNS = ['org', 'scope', 'role'];\n\nconst TeamMembersTable = ({ presetScope }: TeamMembersTableProps) => {\n const intl = useIntl();\n const { showErrorToast } = useToastManager();\n const [columnsWithFiltersApplied, setColumnsWithFiltersApplied] = useState<string[]>([]);\n\n const initialQuerySettings = presetScope ? {\n scopes: presetScope,\n pageSize: TABLE_DEFAULT_PAGE_SIZE,\n pageIndex: 0,\n roles: null,\n organizations: null,\n search: null,\n order: null,\n sortBy: null,\n } : undefined;\n\n const { querySettings, handleTableFetch } = useQuerySettings(initialQuerySettings);\n\n const { isCourseViewAllowed } = useViewTeamPermissions();\n\n const effectiveQuerySettings = useMemo(() => {\n if (isCourseViewAllowed || querySettings.roles) return querySettings;\n return { ...querySettings, roles: LIBRARY_ROLE_KEYS };\n }, [isCourseViewAllowed, querySettings]);\n\n const {\n data: { results: teamMembers, count } = EMPTY_ASSIGNMENTS,\n isLoading: isLoadingTeamMembers,\n error,\n refetch,\n } = useTeamMembersAssignments(effectiveQuerySettings);\n\n const initialFilters = presetScope ? [{ id: 'scope', value: [presetScope] }] : [];\n\n /**\n * Only transient failures reach here.\n */\n useEffect(() => {\n if (error && !toastedErrors.has(error)) {\n toastedErrors.add(error);\n showErrorToast(error, refetch);\n }\n }, [error, showErrorToast, refetch]);\n\n const pageCount = Math.ceil(count / TABLE_DEFAULT_PAGE_SIZE);\n\n const fetchData = useMemo(() => debounce(handleTableFetch, 500), [handleTableFetch]);\n\n useEffect(() => () => fetchData.cancel(), [fetchData]);\n\n const showingUsersLabel = intl.formatMessage(\n messages['authz.team.members.table.showing.users.text'],\n { pageSize: teamMembers.length, itemCount: count },\n );\n\n return (\n <DataTable\n className=\"team-members-table\"\n isExpandable\n isFilterable\n isPaginated\n isSortable\n manualFilters\n manualPagination\n manualSortBy\n numBreakoutFilters={4}\n fetchData={fetchData}\n data={teamMembers}\n itemCount={count}\n pageCount={pageCount}\n initialState={{\n pageSize: TABLE_DEFAULT_PAGE_SIZE,\n filters: initialFilters,\n hiddenColumns: HIDDEN_FILTER_COLUMNS,\n }}\n isLoading={isLoadingTeamMembers}\n renderRowSubComponent={({ row }) => (\n <UserAssignmentsSubTable row={row} />\n )}\n additionalColumns={[\n {\n id: 'moreRoles',\n Header: '',\n Cell: MoreRolesToggle,\n headerClassName: 'authz-col-more-roles',\n },\n {\n id: 'action',\n Header: intl.formatMessage(messages['authz.team.members.table.column.actions.title']),\n Cell: TeamMemberViewActionCell,\n cellClassName: 'text-center',\n headerClassName: 'authz-col-actions justify-content-center',\n },\n ]}\n columns={\n [\n {\n id: 'username',\n Header: intl.formatMessage(messages['authz.team.members.table.column.username.title']),\n accessor: 'username',\n Cell: NameCell,\n headerClassName: 'authz-col-username',\n filter: 'text',\n Filter: TextFilter,\n filterOrder: 1,\n },\n {\n Header: intl.formatMessage(messages['authz.team.members.table.column.email.title']),\n accessor: 'email',\n Cell: EmailCell,\n headerClassName: 'authz-col-email',\n disableFilters: true,\n filter: 'text',\n Filter: TextFilter,\n },\n {\n id: 'assignedRoles',\n Header: intl.formatMessage(messages['authz.team.members.table.column.assigned.roles.title']),\n Cell: AssignedRolesCell,\n headerClassName: 'authz-col-assigned-roles',\n disableFilters: true,\n disableSortBy: true,\n },\n {\n id: 'org',\n Header: getCellHeader('org', intl.formatMessage(messages['authz.team.members.table.column.organization.title']), columnsWithFiltersApplied),\n filter: 'includesValue',\n defaultCanFilter: true,\n Filter: OrgFilter,\n filterButtonText: intl.formatMessage(messages['authz.team.members.table.column.organization.title']),\n filterOrder: 2,\n },\n {\n id: 'scope',\n Header: getCellHeader('scope', intl.formatMessage(messages['authz.team.members.table.column.scope.title']), columnsWithFiltersApplied),\n filter: 'includesValue',\n defaultCanFilter: true,\n Filter: ScopesFilter,\n filterButtonText: intl.formatMessage(messages['authz.team.members.table.column.scope.title']),\n filterOrder: 4,\n },\n {\n id: 'role',\n Header: getCellHeader('role', intl.formatMessage(messages['authz.team.members.table.column.role.title']), columnsWithFiltersApplied),\n filter: 'includesValue',\n defaultCanFilter: true,\n Filter: RolesFilter,\n filterButtonText: intl.formatMessage(messages['authz.team.members.table.column.role.title']),\n filterOrder: 3,\n },\n ]\n }\n >\n <TableControlBar onFilterChange={setColumnsWithFiltersApplied} countLabel={showingUsersLabel} />\n <DataTable.Table />\n <TableFooter showingMessage={messages['authz.team.members.table.showing.users.text']} />\n </DataTable>\n );\n};\n\nexport default TeamMembersTable;\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TeamMember } from '../../../types';
|
|
2
|
+
interface AssignedRolesCellProps {
|
|
3
|
+
row: {
|
|
4
|
+
original: TeamMember;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
/** The role pill: a light rounded block with the person icon, not a Paragon Chip. */
|
|
8
|
+
export declare const RoleBadge: ({ role }: {
|
|
9
|
+
role: string;
|
|
10
|
+
}) => import("react").JSX.Element;
|
|
11
|
+
/**
|
|
12
|
+
* Collapsed-row cell: the user's first assignment, as "[Role] In <scope>" with the
|
|
13
|
+
* organization on a subline.
|
|
14
|
+
*
|
|
15
|
+
* Renders `assignments[0]` exactly as the API returns it — the sub-table's first row must
|
|
16
|
+
* match it, so no client-side reordering happens here. The badge stays visible while the
|
|
17
|
+
* row is expanded, for visual continuity.
|
|
18
|
+
*/
|
|
19
|
+
declare const AssignedRolesCell: ({ row }: AssignedRolesCellProps) => import("react").JSX.Element | null;
|
|
20
|
+
export default AssignedRolesCell;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { FormattedMessage, useIntl } from '@openedx/frontend-base';
|
|
3
|
+
import { Icon } from '@openedx/paragon';
|
|
4
|
+
import { Person } from '@openedx/paragon/icons';
|
|
5
|
+
import { ALL_ORGS_KEY, getAggregateScopeType, MAP_ROLE_KEY_TO_LABEL, } from '../../constants';
|
|
6
|
+
import { getScopeResourceIcon } from '../../utils';
|
|
7
|
+
import componentMessages from '../../components/messages';
|
|
8
|
+
import { RESOURCE_ICONS } from '../../components/constants';
|
|
9
|
+
import messages from '../messages';
|
|
10
|
+
/** The role pill: a light rounded block with the person icon, not a Paragon Chip. */
|
|
11
|
+
export const RoleBadge = ({ role }) => (_jsxs("div", { className: "authz-role-badge d-inline-flex align-items-center flex-shrink-0 text-nowrap rounded bg-light-300 text-gray-700 mr-3 px-2 py-1", children: [_jsx(Icon, { src: Person, size: "xs", className: "mr-1" }), MAP_ROLE_KEY_TO_LABEL[role] || role] }));
|
|
12
|
+
/**
|
|
13
|
+
* Collapsed-row cell: the user's first assignment, as "[Role] In <scope>" with the
|
|
14
|
+
* organization on a subline.
|
|
15
|
+
*
|
|
16
|
+
* Renders `assignments[0]` exactly as the API returns it — the sub-table's first row must
|
|
17
|
+
* match it, so no client-side reordering happens here. The badge stays visible while the
|
|
18
|
+
* row is expanded, for visual continuity.
|
|
19
|
+
*/
|
|
20
|
+
const AssignedRolesCell = ({ row }) => {
|
|
21
|
+
var _a;
|
|
22
|
+
const { formatMessage } = useIntl();
|
|
23
|
+
const [assignment] = (_a = row.original.assignments) !== null && _a !== void 0 ? _a : [];
|
|
24
|
+
if (!assignment) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const { role, scope, scopeDisplayName, org, } = assignment;
|
|
28
|
+
/*
|
|
29
|
+
* A wildcard scope names no single resource, so the row summarises it by reach alone:
|
|
30
|
+
* the organization it covers, or the whole platform. The kind of resource ("All
|
|
31
|
+
* courses in this organization") is left to the breakdown, and the organization line
|
|
32
|
+
* is dropped since the scope line already says it.
|
|
33
|
+
*/
|
|
34
|
+
const aggregateType = getAggregateScopeType(scope, org);
|
|
35
|
+
let scopeIcon = getScopeResourceIcon(scope);
|
|
36
|
+
let scopeText = scopeDisplayName || scope;
|
|
37
|
+
if (aggregateType === 'platform') {
|
|
38
|
+
scopeIcon = RESOURCE_ICONS.GLOBAL;
|
|
39
|
+
scopeText = formatMessage(componentMessages['authz.user.table.org.all.organizations.label']);
|
|
40
|
+
}
|
|
41
|
+
else if (aggregateType === 'org') {
|
|
42
|
+
scopeIcon = RESOURCE_ICONS.ORGANIZATION;
|
|
43
|
+
scopeText = org;
|
|
44
|
+
}
|
|
45
|
+
const orgText = org === ALL_ORGS_KEY
|
|
46
|
+
? formatMessage(componentMessages['authz.user.table.org.all.organizations.label'])
|
|
47
|
+
: org;
|
|
48
|
+
return (_jsx("div", { className: "authz-assigned-roles d-flex align-items-center text-gray-500", children: _jsx(FormattedMessage, Object.assign({}, messages['authz.team.members.table.assigned.roles'], { values: {
|
|
49
|
+
role: _jsx(RoleBadge, { role: role }),
|
|
50
|
+
scope: (_jsxs("div", { className: "authz-scope-cell ml-3", children: [_jsxs("span", { className: "d-flex align-items-center", children: [_jsx(Icon, { src: scopeIcon, className: "mr-2 flex-shrink-0 text-primary", size: "xs" }), _jsx("span", { className: "text-truncate text-gray-700 authz-scope-cell__name", title: scopeText, children: scopeText })] }), !aggregateType && (_jsxs("span", { className: "d-flex align-items-center small text-gray-500 authz-scope-cell__org ml-4", children: [_jsx(Icon, { src: RESOURCE_ICONS.ORGANIZATION, className: "mr-2 flex-shrink-0", size: "xs" }), _jsx("span", { className: "text-truncate", title: orgText, children: orgText })] }))] })),
|
|
51
|
+
} })) }));
|
|
52
|
+
};
|
|
53
|
+
export default AssignedRolesCell;
|
|
54
|
+
//# sourceMappingURL=AssignedRolesCell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssignedRolesCell.js","sourceRoot":"","sources":["../../../../src/authz-module/team-members/components/AssignedRolesCell.tsx"],"names":[],"mappings":"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","sourcesContent":["import { FormattedMessage, useIntl } from '@openedx/frontend-base';\nimport { Icon } from '@openedx/paragon';\nimport { Person } from '@openedx/paragon/icons';\nimport {\n ALL_ORGS_KEY, getAggregateScopeType, MAP_ROLE_KEY_TO_LABEL,\n} from '@src/authz-module/constants';\nimport { getScopeResourceIcon } from '@src/authz-module/utils';\nimport componentMessages from '@src/authz-module/components/messages';\nimport { RESOURCE_ICONS } from '@src/authz-module/components/constants';\nimport type { TeamMember } from '@src/types';\nimport messages from '../messages';\n\ninterface AssignedRolesCellProps {\n row: { original: TeamMember };\n}\n\n/** The role pill: a light rounded block with the person icon, not a Paragon Chip. */\nexport const RoleBadge = ({ role }: { role: string }) => (\n <div className=\"authz-role-badge d-inline-flex align-items-center flex-shrink-0 text-nowrap rounded bg-light-300 text-gray-700 mr-3 px-2 py-1\">\n <Icon src={Person} size=\"xs\" className=\"mr-1\" />\n {MAP_ROLE_KEY_TO_LABEL[role] || role}\n </div>\n);\n\n/**\n * Collapsed-row cell: the user's first assignment, as \"[Role] In <scope>\" with the\n * organization on a subline.\n *\n * Renders `assignments[0]` exactly as the API returns it — the sub-table's first row must\n * match it, so no client-side reordering happens here. The badge stays visible while the\n * row is expanded, for visual continuity.\n */\nconst AssignedRolesCell = ({ row }: AssignedRolesCellProps) => {\n const { formatMessage } = useIntl();\n const [assignment] = row.original.assignments ?? [];\n\n if (!assignment) {\n return null;\n }\n\n const {\n role, scope, scopeDisplayName, org,\n } = assignment;\n /*\n * A wildcard scope names no single resource, so the row summarises it by reach alone:\n * the organization it covers, or the whole platform. The kind of resource (\"All\n * courses in this organization\") is left to the breakdown, and the organization line\n * is dropped since the scope line already says it.\n */\n const aggregateType = getAggregateScopeType(scope, org);\n let scopeIcon = getScopeResourceIcon(scope);\n let scopeText = scopeDisplayName || scope;\n if (aggregateType === 'platform') {\n scopeIcon = RESOURCE_ICONS.GLOBAL;\n scopeText = formatMessage(componentMessages['authz.user.table.org.all.organizations.label']);\n } else if (aggregateType === 'org') {\n scopeIcon = RESOURCE_ICONS.ORGANIZATION;\n scopeText = org;\n }\n\n const orgText = org === ALL_ORGS_KEY\n ? formatMessage(componentMessages['authz.user.table.org.all.organizations.label'])\n : org;\n\n return (\n <div className=\"authz-assigned-roles d-flex align-items-center text-gray-500\">\n <FormattedMessage\n {...messages['authz.team.members.table.assigned.roles']}\n values={{\n role: <RoleBadge role={role} />,\n scope: (\n <div className=\"authz-scope-cell ml-3\">\n <span className=\"d-flex align-items-center\">\n <Icon src={scopeIcon} className=\"mr-2 flex-shrink-0 text-primary\" size=\"xs\" />\n <span className=\"text-truncate text-gray-700 authz-scope-cell__name\" title={scopeText}>{scopeText}</span>\n </span>\n {!aggregateType && (\n <span className=\"d-flex align-items-center small text-gray-500 authz-scope-cell__org ml-4\">\n <Icon src={RESOURCE_ICONS.ORGANIZATION} className=\"mr-2 flex-shrink-0\" size=\"xs\" />\n <span className=\"text-truncate\" title={orgText}>{orgText}</span>\n </span>\n )}\n </div>\n ),\n }}\n />\n </div>\n );\n};\n\nexport default AssignedRolesCell;\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DataTableRow } from '@openedx/paragon';
|
|
2
|
+
import type { TeamMember } from '../../../types';
|
|
3
|
+
interface MoreRolesToggleProps {
|
|
4
|
+
row: DataTableRow<TeamMember>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Expands a team member row to reveal their full role breakdown.
|
|
8
|
+
*
|
|
9
|
+
* The count is `assignmentCount - 1`: the collapsed row already shows the first role, so
|
|
10
|
+
* only the remaining ones are "more". Renders nothing when the user has a single role,
|
|
11
|
+
* since there is nothing further to reveal.
|
|
12
|
+
*/
|
|
13
|
+
declare const MoreRolesToggle: ({ row }: MoreRolesToggleProps) => import("react").JSX.Element | null;
|
|
14
|
+
export default MoreRolesToggle;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
3
|
+
import ExpandableButton from '../../components/ExpandableButton';
|
|
4
|
+
import { useExclusiveRowExpansion } from '../../hooks/useExclusiveRowExpansion';
|
|
5
|
+
import messages from '../messages';
|
|
6
|
+
/**
|
|
7
|
+
* Expands a team member row to reveal their full role breakdown.
|
|
8
|
+
*
|
|
9
|
+
* The count is `assignmentCount - 1`: the collapsed row already shows the first role, so
|
|
10
|
+
* only the remaining ones are "more". Renders nothing when the user has a single role,
|
|
11
|
+
* since there is nothing further to reveal.
|
|
12
|
+
*/
|
|
13
|
+
const MoreRolesToggle = ({ row }) => {
|
|
14
|
+
const { formatMessage } = useIntl();
|
|
15
|
+
const toggleExpanded = useExclusiveRowExpansion(row);
|
|
16
|
+
const { assignmentCount } = row.original;
|
|
17
|
+
if (!assignmentCount || assignmentCount <= 1) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
return (_jsx(ExpandableButton, { label: row.isExpanded
|
|
21
|
+
? formatMessage(messages['authz.team.members.table.hide.roles'])
|
|
22
|
+
: formatMessage(messages['authz.team.members.table.more.roles'], { count: assignmentCount - 1 }), onClick: toggleExpanded, isExpanded: !!row.isExpanded }));
|
|
23
|
+
};
|
|
24
|
+
export default MoreRolesToggle;
|
|
25
|
+
//# sourceMappingURL=MoreRolesToggle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MoreRolesToggle.js","sourceRoot":"","sources":["../../../../src/authz-module/team-members/components/MoreRolesToggle.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,gBAAgB,MAAM,+CAA+C,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,kDAAkD,CAAC;AAE5F,OAAO,QAAQ,MAAM,aAAa,CAAC;AAMnC;;;;;;GAMG;AACH,MAAM,eAAe,GAAG,CAAC,EAAE,GAAG,EAAwB,EAAE,EAAE;IACxD,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,MAAM,cAAc,GAAG,wBAAwB,CAAC,GAAG,CAAC,CAAC;IACrD,MAAM,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,QAAQ,CAAC;IAEzC,IAAI,CAAC,eAAe,IAAI,eAAe,IAAI,CAAC,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CACL,KAAC,gBAAgB,IACf,KAAK,EAAE,GAAG,CAAC,UAAU;YACnB,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,qCAAqC,CAAC,CAAC;YAChE,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,qCAAqC,CAAC,EAAE,EAAE,KAAK,EAAE,eAAe,GAAG,CAAC,EAAE,CAAC,EAClG,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,GAC5B,CACH,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,eAAe,CAAC","sourcesContent":["import { useIntl } from '@openedx/frontend-base';\nimport type { DataTableRow } from '@openedx/paragon';\nimport ExpandableButton from '@src/authz-module/components/ExpandableButton';\nimport { useExclusiveRowExpansion } from '@src/authz-module/hooks/useExclusiveRowExpansion';\nimport type { TeamMember } from '@src/types';\nimport messages from '../messages';\n\ninterface MoreRolesToggleProps {\n row: DataTableRow<TeamMember>;\n}\n\n/**\n * Expands a team member row to reveal their full role breakdown.\n *\n * The count is `assignmentCount - 1`: the collapsed row already shows the first role, so\n * only the remaining ones are \"more\". Renders nothing when the user has a single role,\n * since there is nothing further to reveal.\n */\nconst MoreRolesToggle = ({ row }: MoreRolesToggleProps) => {\n const { formatMessage } = useIntl();\n const toggleExpanded = useExclusiveRowExpansion(row);\n const { assignmentCount } = row.original;\n\n if (!assignmentCount || assignmentCount <= 1) {\n return null;\n }\n\n return (\n <ExpandableButton\n label={row.isExpanded\n ? formatMessage(messages['authz.team.members.table.hide.roles'])\n : formatMessage(messages['authz.team.members.table.more.roles'], { count: assignmentCount - 1 })}\n onClick={toggleExpanded}\n isExpanded={!!row.isExpanded}\n />\n );\n};\n\nexport default MoreRolesToggle;\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TeamMember } from '../../../types';
|
|
2
|
+
interface NameCellProps {
|
|
3
|
+
row: {
|
|
4
|
+
original: TeamMember;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
interface EmailCellProps {
|
|
8
|
+
value: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Username column. Shows the username verbatim — the API also sends `fullName`, but this
|
|
12
|
+
* column is headed "Username" and is what the table sorts and searches on. The row for the
|
|
13
|
+
* signed-in user is marked so they can find themselves in the list.
|
|
14
|
+
*/
|
|
15
|
+
export declare const NameCell: ({ row }: NameCellProps) => import("react").JSX.Element;
|
|
16
|
+
export declare const EmailCell: ({ value }: EmailCellProps) => import("react").JSX.Element;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useContext } from 'react';
|
|
3
|
+
import { FormattedMessage, SiteContext } from '@openedx/frontend-base';
|
|
4
|
+
import messages from '../messages';
|
|
5
|
+
/**
|
|
6
|
+
* Username column. Shows the username verbatim — the API also sends `fullName`, but this
|
|
7
|
+
* column is headed "Username" and is what the table sorts and searches on. The row for the
|
|
8
|
+
* signed-in user is marked so they can find themselves in the list.
|
|
9
|
+
*/
|
|
10
|
+
export const NameCell = ({ row }) => {
|
|
11
|
+
const { authenticatedUser } = useContext(SiteContext);
|
|
12
|
+
const { username = '' } = row.original;
|
|
13
|
+
const isCurrentUser = username === (authenticatedUser === null || authenticatedUser === void 0 ? void 0 : authenticatedUser.username);
|
|
14
|
+
// The cell is muted so the bare "(Me)" reads as a marker; the username is content.
|
|
15
|
+
const name = _jsx("span", { className: "text-gray-700", children: username });
|
|
16
|
+
return (_jsx("span", { className: "d-block text-truncate authz-cell-username text-gray-500", title: username, children: isCurrentUser
|
|
17
|
+
? (_jsx(FormattedMessage, Object.assign({}, messages['authz.team.members.table.username.current'], { values: { username: name } })))
|
|
18
|
+
: name }));
|
|
19
|
+
};
|
|
20
|
+
export const EmailCell = ({ value }) => (_jsx("span", { className: "d-block text-truncate authz-cell-email", title: value, children: value }));
|
|
21
|
+
//# sourceMappingURL=TeamMemberCells.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamMemberCells.js","sourceRoot":"","sources":["../../../../src/authz-module/team-members/components/TeamMemberCells.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAEvE,OAAO,QAAQ,MAAM,aAAa,CAAC;AAUnC;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,EAAE,GAAG,EAAiB,EAAE,EAAE;IACjD,MAAM,EAAE,iBAAiB,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,EAAE,QAAQ,GAAG,EAAE,EAAE,GAAG,GAAG,CAAC,QAAQ,CAAC;IACvC,MAAM,aAAa,GAAG,QAAQ,MAAK,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAE,QAAQ,CAAA,CAAC;IAC/D,mFAAmF;IACnF,MAAM,IAAI,GAAG,eAAM,SAAS,EAAC,eAAe,YAAE,QAAQ,GAAQ,CAAC;IAE/D,OAAO,CACL,eAAM,SAAS,EAAC,yDAAyD,EAAC,KAAK,EAAE,QAAQ,YACtF,aAAa;YACZ,CAAC,CAAC,CACE,KAAC,gBAAgB,oBACX,QAAQ,CAAC,2CAA2C,CAAC,IACzD,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAC1B,CACH;YACH,CAAC,CAAC,IAAI,GACH,CACR,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,EAAE,KAAK,EAAkB,EAAE,EAAE,CAAC,CACtD,eAAM,SAAS,EAAC,wCAAwC,EAAC,KAAK,EAAE,KAAK,YAAG,KAAK,GAAQ,CACtF,CAAC","sourcesContent":["import { useContext } from 'react';\nimport { FormattedMessage, SiteContext } from '@openedx/frontend-base';\nimport type { TeamMember } from '@src/types';\nimport messages from '../messages';\n\ninterface NameCellProps {\n row: { original: TeamMember };\n}\n\ninterface EmailCellProps {\n value: string;\n}\n\n/**\n * Username column. Shows the username verbatim — the API also sends `fullName`, but this\n * column is headed \"Username\" and is what the table sorts and searches on. The row for the\n * signed-in user is marked so they can find themselves in the list.\n */\nexport const NameCell = ({ row }: NameCellProps) => {\n const { authenticatedUser } = useContext(SiteContext);\n const { username = '' } = row.original;\n const isCurrentUser = username === authenticatedUser?.username;\n // The cell is muted so the bare \"(Me)\" reads as a marker; the username is content.\n const name = <span className=\"text-gray-700\">{username}</span>;\n\n return (\n <span className=\"d-block text-truncate authz-cell-username text-gray-500\" title={username}>\n {isCurrentUser\n ? (\n <FormattedMessage\n {...messages['authz.team.members.table.username.current']}\n values={{ username: name }}\n />\n )\n : name}\n </span>\n );\n};\n\nexport const EmailCell = ({ value }: EmailCellProps) => (\n <span className=\"d-block text-truncate authz-cell-email\" title={value}>{value}</span>\n);\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TeamMember } from '../../../types';
|
|
2
|
+
interface TeamMemberViewActionCellProps {
|
|
3
|
+
row: {
|
|
4
|
+
original: TeamMember;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Opens a team member's audit page.
|
|
9
|
+
*
|
|
10
|
+
* Rows are users rather than single assignments, so the course-authoring flag is evaluated
|
|
11
|
+
* across the user's assignments: the action stays enabled while at least one of them is
|
|
12
|
+
* viewable, and is only disabled when every one sits in a course that hasn't moved to the
|
|
13
|
+
* new roles experience. `assignments` is capped by `assignments_limit`, so a user whose
|
|
14
|
+
* total exceeds the returned slice may hold viewable roles it does not contain; those rows
|
|
15
|
+
* stay enabled rather than being blocked on incomplete evidence.
|
|
16
|
+
*/
|
|
17
|
+
declare const TeamMemberViewActionCell: ({ row }: TeamMemberViewActionCellProps) => import("react").JSX.Element;
|
|
18
|
+
export default TeamMemberViewActionCell;
|