studiokit-scaffolding-js 4.3.20 → 4.4.0-next.1.1

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.
@@ -1,16 +1,16 @@
1
1
  import { Component } from 'react';
2
- import { RoleDescription } from '../../types';
2
+ import { RoleDescriptions } from '../../types';
3
3
  export interface UserRolesAddProps {
4
4
  id: string;
5
+ disabled?: boolean;
5
6
  entityName?: string;
6
- addUsersToRole: any;
7
- shouldReset: boolean;
8
- isAddingUsersToRole: boolean;
9
7
  defaultRole: string;
10
- roleDescriptions: RoleDescription;
8
+ roleDescriptions: RoleDescriptions;
11
9
  renderAddDescription?: (entityName?: string) => JSX.Element;
12
- disabled?: boolean;
13
10
  textForRole?: (role: string) => string;
11
+ isAddingUsersToRole: boolean;
12
+ shouldReset: boolean;
13
+ addUserRoles: (identifiers: string[], role: string) => void;
14
14
  }
15
15
  interface UserRolesAddState {
16
16
  identifiers: string;
@@ -20,7 +20,7 @@ interface UserRolesAddState {
20
20
  }
21
21
  export default class UserRolesAdd extends Component<UserRolesAddProps, UserRolesAddState> {
22
22
  constructor(props: UserRolesAddProps);
23
- updateRole: (e: any) => void;
23
+ updateRole: (role: string) => void;
24
24
  componentDidUpdate(prevProps: UserRolesAddProps): void;
25
25
  handleSubmit: () => void;
26
26
  closeErrorAlert: () => void;
@@ -42,7 +42,7 @@ var react_1 = __importStar(require("react"));
42
42
  var react_bootstrap_1 = require("react-bootstrap");
43
43
  var AlertDialog_1 = __importDefault(require("../../components/AlertDialog"));
44
44
  var Inline_1 = __importDefault(require("../../components/RefreshIndicator/Inline"));
45
- var Select_1 = __importDefault(require("../../components/UserRoles/Select"));
45
+ var Select_1 = require("../../components/UserRoles/Select");
46
46
  var baseRole_1 = __importDefault(require("../../constants/baseRole"));
47
47
  var configuration_1 = require("../../constants/configuration");
48
48
  var domainIdentifier_1 = require("../../utils/domainIdentifier");
@@ -54,9 +54,9 @@ var UserRolesAdd = /** @class */ (function (_super) {
54
54
  __extends(UserRolesAdd, _super);
55
55
  function UserRolesAdd(props) {
56
56
  var _this = _super.call(this, props) || this;
57
- _this.updateRole = function (e) {
57
+ _this.updateRole = function (role) {
58
58
  _this.setState({
59
- role: e.target.value
59
+ role: role
60
60
  });
61
61
  };
62
62
  _this.handleSubmit = function () {
@@ -73,7 +73,7 @@ var UserRolesAdd = /** @class */ (function (_super) {
73
73
  });
74
74
  }
75
75
  else {
76
- _this.props.addUsersToRole(identifiersArray, role);
76
+ _this.props.addUserRoles(identifiersArray, role);
77
77
  }
78
78
  };
79
79
  _this.closeErrorAlert = function () {
@@ -140,7 +140,7 @@ var UserRolesAdd = /** @class */ (function (_super) {
140
140
  " (separated by a new line)"),
141
141
  react_1.default.createElement(react_bootstrap_1.FormControl, { type: "text", as: "textarea", name: "account", "aria-label": "The account names to add", onChange: this.updateIdentifiers, value: identifiers, placeholder: domainIdentifier_1.getDomainIdentifierTypeString(), disabled: disabled }))),
142
142
  react_1.default.createElement(react_bootstrap_1.Col, { xs: 12, sm: 4 },
143
- react_1.default.createElement(Select_1.default, { options: roles, value: role, onChange: this.updateRole, labelVisible: true, popoverContentComponent: rolePopover, textForRole: textForRole })),
143
+ react_1.default.createElement(Select_1.RoleSelect, { options: roles, value: role, onChange: this.updateRole, labelVisible: true, popoverContentComponent: rolePopover, textForRole: textForRole })),
144
144
  react_1.default.createElement(react_bootstrap_1.Col, { xs: 12, sm: 2, className: "mt3-ns pt2-ns" },
145
145
  isAddingUsersToRole && react_1.default.createElement(Inline_1.default, { className: "mr3" }),
146
146
  !isAddingUsersToRole && (react_1.default.createElement(Button_1.default, { id: "userRolesAddButton", className: "btn btn-primary w-100-lt-xs", disabled: !identifiers || disabled, color: "primary", onClick: this.handleSubmit },
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import { UserRole } from '../../types';
3
+ export interface UserRolesContextType {
4
+ /** disable all user role select dropdowns, if any */
5
+ isUpdateDisabled?: boolean;
6
+ /** disable all user role delete buttons */
7
+ isDeleteDisabled?: boolean;
8
+ /** Is the current user allowed to add, update, and delete user roles? */
9
+ canModify?: boolean;
10
+ /** Is the current user allowed to delete their own user role? */
11
+ canDeleteSelf?: boolean;
12
+ /** If multiple roles allowed, each role is displayed per user, otherwise a select dropdown is displayed. */
13
+ allowMultipleRoles?: boolean;
14
+ roles: string[];
15
+ /** (Optional) If provided, the last user role with the required role will be prevented from being removed. */
16
+ requiredRole?: string;
17
+ /** (Optional) Provide custom user-friendly names for displayed roles */
18
+ textForRole?: (role: string) => string;
19
+ /** The user role being updated */
20
+ userRoleToUpdate?: UserRole;
21
+ /** If a user role is being updated */
22
+ isUpdating: boolean;
23
+ /** Method to update a user role */
24
+ updateUserRole: (userRoleToUpdate: UserRole, newRole: string) => void;
25
+ /** The user role being removed */
26
+ userRoleToRemove?: UserRole;
27
+ /** If a user role is being removed */
28
+ isRemoving: boolean;
29
+ /** Method to remove a user role */
30
+ removeUserRole: (userRoleToRemove: UserRole) => void;
31
+ }
32
+ export declare const UserRolesContext: React.Context<UserRolesContextType>;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.UserRolesContext = void 0;
7
+ var react_1 = __importDefault(require("react"));
8
+ /*
9
+ * Context provided to the children of UserRoles. Default values should be initialized
10
+ * by the context provider.
11
+ */
12
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
13
+ exports.UserRolesContext = react_1.default.createContext(undefined);
@@ -1,21 +1,7 @@
1
- import React, { FunctionComponent } from 'react';
2
- import { BaseReduxState } from '../../types/BaseReduxState';
1
+ import { FunctionComponent } from 'react';
3
2
  import { UserWithRoles } from '../../types/UserRole';
4
- export interface RoleCellOwnProps {
3
+ export interface RoleCellProps {
5
4
  user: UserWithRoles;
6
- readOnly?: boolean;
7
- canModifySelf?: boolean;
8
- textForRole?: (role: string) => string;
9
- removeUserFromRole?: (user: UserWithRoles, role: string) => void;
10
- roles: string[];
11
- entityOwnerRole: string;
12
- }
13
- export interface RoleCellReduxProps {
14
- currentUserId: string;
15
- }
16
- export interface RoleCellProps extends RoleCellOwnProps, RoleCellReduxProps {
5
+ requiredRoleCount?: number;
17
6
  }
18
7
  export declare const RoleCell: FunctionComponent<RoleCellProps>;
19
- export declare const mapStateToProps: (state: BaseReduxState) => RoleCellReduxProps;
20
- declare const _default: import("react-redux").ConnectedComponent<React.FunctionComponent<RoleCellProps>, Pick<RoleCellProps, "user" | "readOnly" | "textForRole" | "canModifySelf" | "removeUserFromRole" | "roles" | "entityOwnerRole">>;
21
- export default _default;
@@ -1,34 +1,97 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
2
21
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
22
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
23
  };
5
24
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.mapStateToProps = exports.RoleCell = void 0;
25
+ exports.RoleCell = void 0;
7
26
  var core_1 = require("@material-ui/core");
8
27
  var Delete_1 = __importDefault(require("@material-ui/icons/Delete"));
9
- var react_1 = __importDefault(require("react"));
28
+ var react_1 = __importStar(require("react"));
10
29
  var react_bootstrap_1 = require("react-bootstrap");
11
30
  var react_redux_1 = require("react-redux");
12
31
  var userRole_1 = require("../../utils/userRole");
13
32
  var IconExternalUser_1 = require("../Icons/IconExternalUser");
33
+ var Inline_1 = __importDefault(require("../RefreshIndicator/Inline"));
34
+ var Context_1 = require("./Context");
35
+ var Select_1 = require("./Select");
14
36
  var RoleCell = function (_a) {
15
- var user = _a.user, currentUserId = _a.currentUserId, readOnly = _a.readOnly, canModifySelf = _a.canModifySelf, textForRole = _a.textForRole, removeUserFromRole = _a.removeUserFromRole, roles = _a.roles, entityOwnerRole = _a.entityOwnerRole;
37
+ var user = _a.user, requiredRoleCount = _a.requiredRoleCount;
38
+ var _b = react_1.useContext(Context_1.UserRolesContext), isUpdateDisabled = _b.isUpdateDisabled, isDeleteDisabled = _b.isDeleteDisabled, canModify = _b.canModify, canDeleteSelf = _b.canDeleteSelf, allowMultipleRoles = _b.allowMultipleRoles, roles = _b.roles, requiredRole = _b.requiredRole, textForRole = _b.textForRole, userRoleToUpdate = _b.userRoleToUpdate, isUpdating = _b.isUpdating, updateUserRole = _b.updateUserRole, userRoleToRemove = _b.userRoleToRemove, isRemoving = _b.isRemoving, removeUserRole = _b.removeUserRole;
39
+ var currentUserId = react_redux_1.useSelector(function (state) {
40
+ if (!state.models.user || !state.models.user.userInfo) {
41
+ throw new Error('Current user id is not stored in redux');
42
+ }
43
+ return state.models.user.userInfo.id;
44
+ });
16
45
  return (react_1.default.createElement("ul", { className: "mb0 list pa0 tr" }, user.roles.sort(userRole_1.sortByRole(roles)).map(function (userRole) {
17
46
  var roleText = userRole_1.getRoleText(textForRole)(userRole);
18
47
  var isUserRoleExternal = userRole_1.isExternal(userRole);
19
- var popover = (react_1.default.createElement(react_bootstrap_1.Popover, { id: "is-external-popover-" + userRole.userId + "-" + userRole.role },
48
+ var userId = userRole_1.getUserId(userRole);
49
+ var canUpdate =
50
+ // current user has modify access
51
+ canModify &&
52
+ // in single role mode (multiple roles are not allowed)
53
+ !allowMultipleRoles &&
54
+ // the userRole is not external (roster synced)
55
+ !isUserRoleExternal &&
56
+ // update is not disabled
57
+ !isUpdateDisabled &&
58
+ // there is more than one possible role
59
+ roles.length > 1 &&
60
+ // the user role is not the last remaining required role user
61
+ (!requiredRole || userRole.role !== requiredRole || !requiredRoleCount || requiredRoleCount > 1);
62
+ var canDelete =
63
+ // the userRole is not external (roster synced)
64
+ !isUserRoleExternal &&
65
+ // delete is not disabled, e.g. course is ended
66
+ !isDeleteDisabled &&
67
+ // the role is not the last required role
68
+ (!requiredRole || userRole.role !== requiredRole || !requiredRoleCount || requiredRoleCount > 1) &&
69
+ // the current user can delete the role for another user, or the current user can delete themselves
70
+ ((canModify && user.id !== currentUserId) || (canDeleteSelf && user.id === currentUserId));
71
+ var shouldDisplayRightAligned =
72
+ // in multiple role mode
73
+ allowMultipleRoles ||
74
+ // only one role option
75
+ roles.length === 1 ||
76
+ // no access to update
77
+ !canModify ||
78
+ // update is disabled
79
+ isUpdateDisabled;
80
+ var isExternalPopover = (react_1.default.createElement(react_bootstrap_1.Popover, { id: "is-external-popover-" + userId + "-" + userRole.role },
20
81
  react_1.default.createElement("h3", null, "Added via Roster Sync"),
21
82
  react_1.default.createElement("p", { className: "mb2" }, "This person was added automatically via roster sync and cannot be manually removed.")));
22
- return (react_1.default.createElement("li", { key: user.id + "-" + roleText, className: "nowrap" },
23
- react_1.default.createElement("span", null, roleText),
24
- !isUserRoleExternal &&
25
- !readOnly &&
26
- (user.id !== currentUserId || canModifySelf || userRole.role !== entityOwnerRole) ? (react_1.default.createElement(core_1.IconButton, { className: "remove-user-button", "aria-label": "Remove " + roleText, onClick: function () {
27
- if (removeUserFromRole) {
28
- removeUserFromRole(user, userRole.role);
29
- }
30
- } },
31
- react_1.default.createElement(Delete_1.default, { color: "error" }))) : isUserRoleExternal ? (react_1.default.createElement(react_bootstrap_1.OverlayTrigger, { placement: "auto", trigger: ['click', 'hover', 'focus'], overlay: popover },
83
+ var isUserRoleUpdating = isUpdating && (userRoleToUpdate === null || userRoleToUpdate === void 0 ? void 0 : userRoleToUpdate.id) === userRole.id;
84
+ var isUserRoleRemoving = isRemoving && (userRoleToRemove === null || userRoleToRemove === void 0 ? void 0 : userRoleToRemove.id) === userRole.id;
85
+ return (react_1.default.createElement("li", { key: user.id + "-" + roleText, className: "nowrap flex items-center" + (shouldDisplayRightAligned ? ' justify-end' : '') },
86
+ isUserRoleUpdating ? (react_1.default.createElement("div", { className: "flex justify-start flex-grow-1 pl3" },
87
+ react_1.default.createElement(Inline_1.default, { size: 20 }))) : canUpdate ? (react_1.default.createElement(Select_1.RoleSelectControl, { options: roles, value: userRole.role, onChange: function (role) {
88
+ updateUserRole(userRole, role);
89
+ }, textForRole: textForRole, disabled: isUpdating || isRemoving })) : (react_1.default.createElement("span", { className: shouldDisplayRightAligned ? '' : 'pl3' }, roleText)),
90
+ isUserRoleRemoving ? (react_1.default.createElement("div", { className: "flex items-center" },
91
+ react_1.default.createElement(Inline_1.default, { size: 20, className: "ma3" }))) : canDelete ? (react_1.default.createElement(core_1.IconButton, { className: "remove-user-button", "aria-label": "Remove " + roleText, onClick: function () {
92
+ removeUserRole(userRole);
93
+ }, disabled: isUpdating || isRemoving },
94
+ react_1.default.createElement(Delete_1.default, { color: "error" }))) : isUserRoleExternal ? (react_1.default.createElement(react_bootstrap_1.OverlayTrigger, { placement: "auto", trigger: ['click', 'hover', 'focus'], overlay: isExternalPopover },
32
95
  react_1.default.createElement(IconExternalUser_1.IconExternalUser, { tabIndex: 0, style: { margin: '12px', opacity: 0.5 }, className: "external-icon" }))) : (
33
96
  // dummy spacer to keep items aligned
34
97
  react_1.default.createElement("span", { style: {
@@ -41,13 +104,3 @@ var RoleCell = function (_a) {
41
104
  })));
42
105
  };
43
106
  exports.RoleCell = RoleCell;
44
- var mapStateToProps = function (state) {
45
- if (!state.models.user || !state.models.user.userInfo) {
46
- throw new Error('Current user id is not stored in redux');
47
- }
48
- return {
49
- currentUserId: state.models.user.userInfo.id
50
- };
51
- };
52
- exports.mapStateToProps = mapStateToProps;
53
- exports.default = react_redux_1.connect(exports.mapStateToProps)(exports.RoleCell);
@@ -1,27 +1,26 @@
1
- import { ReactElement } from 'react';
1
+ import { FunctionComponent, ReactElement } from 'react';
2
2
  import { OverlayInjectedProps } from 'react-bootstrap/Overlay';
3
- export interface RoleSelectProps {
3
+ export interface RoleSelectControlProps {
4
+ /** CSS class passed to the selector FormControl component */
4
5
  className?: string;
6
+ /** Array of options the user can choose from */
5
7
  options: string[];
8
+ /** Currently selected value */
6
9
  value: string;
7
- onChange: any;
10
+ /** Function that is called when the value changes */
11
+ onChange: (option: string) => void;
12
+ /** (Optional) Provide custom user-friendly names for displayed roles */
13
+ textForRole?: (role: string) => string;
14
+ /** (Optional) Is the control disabled? */
15
+ disabled?: boolean;
16
+ }
17
+ export declare const RoleSelectControl: FunctionComponent<RoleSelectControlProps>;
18
+ export interface RoleSelectProps extends RoleSelectControlProps {
19
+ /** Id for the 'select' form control, defaults to 'RoleSelect' */
8
20
  controlId?: string;
21
+ /** Whether the label text should be visible */
9
22
  labelVisible?: boolean;
23
+ /** (Optional) Content of the popover tooltip */
10
24
  popoverContentComponent?: ReactElement<OverlayInjectedProps>;
11
- textForRole?: (role: string) => string;
12
25
  }
13
- /**
14
- * Create a selector which will be properly labeled based on the number of options and provided content.
15
- *
16
- * @param {string} props.className - CSS class passed to the selector FormControl component
17
- * @param {string[]} props.options - Array of options the user can choose from
18
- * @param {string} props.value - Currently selected value
19
- * @param {function} props.onChange - Function that is called when the value changes
20
- * @param {string} props.controlId - Id for the selector
21
- * @param {boolean} props.labelVisible - Whether the label text should be visible
22
- * @param {ReactNode} props.popoverContentComponent - Content of the popover tooltip
23
- *
24
- * @returns {ReactElement} Selector and label component
25
- */
26
- declare const RoleSelect: (props: RoleSelectProps) => JSX.Element;
27
- export default RoleSelect;
26
+ export declare const RoleSelect: FunctionComponent<RoleSelectProps>;
@@ -1,8 +1,31 @@
1
1
  "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __rest = (this && this.__rest) || function (s, e) {
14
+ var t = {};
15
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
16
+ t[p] = s[p];
17
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
18
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
19
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
20
+ t[p[i]] = s[p[i]];
21
+ }
22
+ return t;
23
+ };
2
24
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
25
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
26
  };
5
27
  Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.RoleSelect = exports.RoleSelectControl = void 0;
6
29
  var Help_1 = __importDefault(require("@material-ui/icons/Help"));
7
30
  var react_1 = __importDefault(require("react"));
8
31
  var react_bootstrap_1 = require("react-bootstrap");
@@ -18,27 +41,18 @@ var overlay = function (hasMultipleOptions, labelVisible, rolePopover) {
18
41
  if (labelVisible === void 0) { labelVisible = false; }
19
42
  return rolePopover ? (react_1.default.createElement(react_bootstrap_1.OverlayTrigger, { placement: "right", trigger: ['click', 'hover', 'focus'], overlay: rolePopover }, label(hasMultipleOptions, labelVisible, true))) : (label(hasMultipleOptions, labelVisible, false));
20
43
  };
21
- var selector = function (options, value, onChange, textForRole, className) {
22
- return options.length > 1 ? (react_1.default.createElement(react_bootstrap_1.FormControl, { className: className ? className : '', "aria-label": "Role", as: "select", placeholder: "select", onChange: onChange, value: value }, options.map(function (role, i) { return (react_1.default.createElement("option", { value: role, key: role }, textForRole ? textForRole(role) : baseRole_1.textForBaseRole(role))); }))) : (react_1.default.createElement("div", null, textForRole ? textForRole(options[0]) : baseRole_1.textForBaseRole(options[0])));
44
+ var RoleSelectControl = function (_a) {
45
+ var className = _a.className, options = _a.options, value = _a.value, onChange = _a.onChange, textForRole = _a.textForRole, disabled = _a.disabled;
46
+ return options.length > 1 ? (react_1.default.createElement(react_bootstrap_1.FormControl, { className: className ? className : '', "aria-label": "Role", as: "select", placeholder: "select", onChange: function (e) {
47
+ onChange(e.target.value);
48
+ }, value: value, disabled: disabled }, options.map(function (role, i) { return (react_1.default.createElement("option", { value: role, key: role }, textForRole ? textForRole(role) : baseRole_1.textForBaseRole(role))); }))) : (react_1.default.createElement("div", null, textForRole ? textForRole(options[0]) : baseRole_1.textForBaseRole(options[0])));
23
49
  };
24
- /**
25
- * Create a selector which will be properly labeled based on the number of options and provided content.
26
- *
27
- * @param {string} props.className - CSS class passed to the selector FormControl component
28
- * @param {string[]} props.options - Array of options the user can choose from
29
- * @param {string} props.value - Currently selected value
30
- * @param {function} props.onChange - Function that is called when the value changes
31
- * @param {string} props.controlId - Id for the selector
32
- * @param {boolean} props.labelVisible - Whether the label text should be visible
33
- * @param {ReactNode} props.popoverContentComponent - Content of the popover tooltip
34
- *
35
- * @returns {ReactElement} Selector and label component
36
- */
37
- var RoleSelect = function (props) {
38
- var className = props.className, options = props.options, value = props.value, onChange = props.onChange, controlId = props.controlId, labelVisible = props.labelVisible, popoverContentComponent = props.popoverContentComponent, textForRole = props.textForRole;
50
+ exports.RoleSelectControl = RoleSelectControl;
51
+ var RoleSelect = function (_a) {
52
+ var controlId = _a.controlId, labelVisible = _a.labelVisible, popoverContentComponent = _a.popoverContentComponent, options = _a.options, controlProps = __rest(_a, ["controlId", "labelVisible", "popoverContentComponent", "options"]);
39
53
  var content = (react_1.default.createElement(react_1.default.Fragment, null,
40
54
  overlay(options.length > 1, !!labelVisible, popoverContentComponent),
41
- selector(options, value, onChange, textForRole, className)));
55
+ react_1.default.createElement(exports.RoleSelectControl, __assign({ options: options }, controlProps))));
42
56
  return options.length > 1 ? (react_1.default.createElement(react_bootstrap_1.FormGroup, { controlId: controlId ? controlId : 'RoleSelect' }, content)) : (react_1.default.createElement("span", null, content));
43
57
  };
44
- exports.default = RoleSelect;
58
+ exports.RoleSelect = RoleSelect;
@@ -3,14 +3,5 @@ import { UserWithRoles } from '../../types';
3
3
  export interface UserRolesTableProps {
4
4
  id?: string;
5
5
  users: UserWithRoles[];
6
- readOnly?: boolean;
7
- canModifySelf?: boolean;
8
- removeUserFromRole?: (user: UserWithRoles, role: string) => void;
9
- textForRole?: (role: string) => string;
10
- roles: string[];
11
- /** The role for the owner of the entity, i.e. GroupOwner, RubricOwner, ProblemOwner etc.
12
- ** The current user cannot be removed from an ownership role unless they are an admin.
13
- **/
14
- entityOwnerRole: string;
15
6
  }
16
7
  export declare const UserRolesTable: React.NamedExoticComponent<UserRolesTableProps>;
@@ -29,9 +29,11 @@ var react_table_1 = __importDefault(require("react-table"));
29
29
  var userRole_1 = require("../../utils/userRole");
30
30
  var RoleFilter_1 = require("../Tables/RoleFilter");
31
31
  var TextFilter_1 = require("../Tables/TextFilter");
32
- var RoleCell_1 = __importDefault(require("./RoleCell"));
32
+ var Context_1 = require("./Context");
33
+ var RoleCell_1 = require("./RoleCell");
33
34
  var UserRolesTableComponent = function (_a) {
34
- var id = _a.id, users = _a.users, roles = _a.roles, readOnly = _a.readOnly, canModifySelf = _a.canModifySelf, textForRole = _a.textForRole, removeUserFromRole = _a.removeUserFromRole, entityOwnerRole = _a.entityOwnerRole;
35
+ var id = _a.id, users = _a.users;
36
+ var _b = react_1.useContext(Context_1.UserRolesContext), roles = _b.roles, requiredRole = _b.requiredRole, textForRole = _b.textForRole;
35
37
  var hasExternal = users.some(function (r) { return r.roles.some(function (r) { return userRole_1.isExternal(r); }); });
36
38
  var columns = [
37
39
  {
@@ -60,7 +62,9 @@ var UserRolesTableComponent = function (_a) {
60
62
  accessor: function (u) { return u; },
61
63
  Cell: function (cell) {
62
64
  var user = cell.value;
63
- return (react_1.default.createElement(RoleCell_1.default, { user: user, readOnly: readOnly, canModifySelf: canModifySelf, textForRole: textForRole, removeUserFromRole: removeUserFromRole, roles: roles, entityOwnerRole: entityOwnerRole }));
65
+ return (react_1.default.createElement(RoleCell_1.RoleCell, { user: user, requiredRoleCount: requiredRole
66
+ ? users.filter(function (u) { return u.roles.some(function (r) { return r.role === requiredRole; }); }).length
67
+ : undefined }));
64
68
  },
65
69
  filterMethod: RoleFilter_1.roleFilterMethod,
66
70
  Filter: RoleFilter_1.RoleFilter(roles, textForRole, hasExternal),
@@ -68,21 +72,27 @@ var UserRolesTableComponent = function (_a) {
68
72
  style: { padding: '4px' }
69
73
  });
70
74
  }
71
- var _b = react_1.useState(users), usersState = _b[0], setUsersState = _b[1];
75
+ var _c = react_1.useState(users), usersState = _c[0], setUsersState = _c[1];
76
+ var _d = react_1.useState(), roleFilter = _d[0], setRoleFilter = _d[1];
72
77
  var onFilteredChange = function (newFiltering, column, value) {
78
+ var newRoleFilter = newFiltering.find(function (f) { return f.id === 'role'; });
79
+ setRoleFilter(newRoleFilter);
80
+ };
81
+ // update `usersState` when `users` or `roleFilter` changes
82
+ react_1.useEffect(function () {
83
+ var usersToDisplay = users;
73
84
  // when the role filter is set, only show the matching userRoles in the table
74
- var roleFilter = newFiltering.find(function (f) { return f.id === 'role'; });
75
85
  if (roleFilter) {
76
- setUsersState(users.map(function (u) {
86
+ usersToDisplay = users.map(function (u) {
77
87
  var newUser = lodash_1.merge({}, u);
78
88
  newUser.roles = u.roles.filter(function (r) { return RoleFilter_1.roleUserRoleFilterMethod(roleFilter, r); });
79
89
  return newUser;
80
- }));
90
+ });
81
91
  }
82
- else if (!lodash_1.isEqual(users, usersState)) {
83
- setUsersState(users);
92
+ if (!lodash_1.isEqual(usersToDisplay, usersState)) {
93
+ setUsersState(usersToDisplay);
84
94
  }
85
- };
95
+ }, [users, roleFilter, usersState]);
86
96
  return (react_1.default.createElement("div", { id: id, className: "table-container" },
87
97
  react_1.default.createElement(react_table_1.default, { className: "-striped", columns: columns, data: usersState, resizable: false, filterable: true, onFilteredChange: onFilteredChange, defaultSorted: [
88
98
  {
@@ -93,7 +103,7 @@ var UserRolesTableComponent = function (_a) {
93
103
  id: 'firstName',
94
104
  desc: false
95
105
  }
96
- ], defaultPageSize: Object.keys(usersState).length, showPagination: false })));
106
+ ], pageSize: Object.keys(usersState).length, showPagination: false })));
97
107
  };
98
108
  // similar to "shouldComponentUpdate", prevent unnecessary renders
99
- exports.UserRolesTable = react_1.default.memo(UserRolesTableComponent, function (prevProps, nextProps) { return !lodash_1.isEqual(prevProps, nextProps); });
109
+ exports.UserRolesTable = react_1.default.memo(UserRolesTableComponent, function (prevProps, nextProps) { return lodash_1.isEqual(prevProps, nextProps); });
@@ -1,53 +1,79 @@
1
1
  import React, { Component } from 'react';
2
2
  import { FetchError, Model, ModelCollection } from 'studiokit-net-js';
3
- import BASE_ROLE from '../../constants/baseRole';
4
- import { BaseReduxState, ExternalProvider, RoleDescription, User, UserWithRoles } from '../../types';
3
+ import { BaseReduxState, ExternalProvider, RoleDescriptions, UserRole, UserWithRoles } from '../../types';
5
4
  import { CollectionComponentWrappedProps } from '../HOC/CollectionComponent';
6
5
  export interface UserRolesReduxProps {
7
- canModifySelf?: boolean;
6
+ /** Is the current user allowed to add, update, and delete user roles? */
8
7
  canModify?: boolean;
8
+ /** Is the current user allowed to delete their own user role? */
9
+ canDeleteSelf?: boolean;
9
10
  }
10
- export interface UserRolesOwnProps extends CollectionComponentWrappedProps<UserWithRoles> {
11
+ export interface UserRolesOwnProps extends CollectionComponentWrappedProps<UserRole> {
12
+ /** Is the current user allowed to delete their own user role? Overrides the value from redux. */
13
+ canDeleteSelf?: boolean;
14
+ /** If multiple roles allowed, each role is displayed per user, otherwise a select dropdown is displayed. */
15
+ allowMultipleRoles?: boolean;
16
+ /** disable adding new user roles */
17
+ isAddDisabled?: boolean;
18
+ /** disable all user role select dropdowns, if any */
19
+ isUpdateDisabled?: boolean;
20
+ /** disable all user role delete buttons */
21
+ isDeleteDisabled?: boolean;
22
+ /** The activity the current user must have in order to add, update, or delete user roles. */
11
23
  modifyUserRoleActivityName: string;
12
- filterUsers: (userRoles: UserWithRoles[]) => UserWithRoles[];
13
- /** The role that will be shown first in the list of available roles. Currently assumes that this is the entity owner role, groupOwner, assignmentOwner, rubricOwner, problemOwner etc. */
24
+ /** (Optional) The activity the current user must have in order to delete their own user roles, if they cannot modify all. */
25
+ deleteOwnUserRoleActivityName?: string;
26
+ /** The role that will be shown first in the list of available roles. */
14
27
  defaultRole: string;
28
+ /** (Optional) If provided, the last user role with the required role will be prevented from being removed. */
29
+ requiredRole?: string;
15
30
  /** A dictionary of all possible roles and their descriptions. */
16
- roleDescriptions: RoleDescription;
17
- /** An optional blacklist of roles that should be excluded from the add options. */
18
- addRoleBlacklist?: string[];
19
- canModifySelf?: boolean;
20
- renderTableDescription?: (canModify?: boolean) => JSX.Element;
31
+ roleDescriptions: RoleDescriptions;
32
+ /** (Optional) list of roles that should be excluded from the add options. */
33
+ addRoleExcludeList?: string[];
34
+ /** (Optional) The entity that owns the user roles, when targeting EntityUserRoles */
21
35
  entity?: Model;
36
+ /** (Optional) A user-friendly name for the entity type, when targeting EntityUserRoles */
22
37
  entityName?: string;
38
+ /** (Optional) set if `renderRemoveUserRoleDescription` should check for roster sync */
39
+ externalProviders?: ModelCollection<ExternalProvider>;
40
+ /** (Optional) Allow users to be excluded from being displayed in the table */
41
+ filterUsers?: (users: UserWithRoles[]) => UserWithRoles[];
42
+ /** (Optional) Callback that is called after any change is made */
23
43
  onChange?: () => void;
44
+ /** (Optional) Render custom components between the Add and Table components */
45
+ renderTableDescription?: (canModify?: boolean) => JSX.Element;
46
+ /** (Optional) Render custom components at the start of the Add component */
24
47
  renderAddDescription?: (entityName?: string) => JSX.Element;
25
- disabled?: boolean;
48
+ /** (Optional) Provide custom user-friendly names for displayed roles */
26
49
  textForRole?: (role: string) => string;
50
+ /** (Optional) Provide custom user-friendly articles ("a" vs. "an") for displayed roles */
27
51
  singularArticleForRole?: (role: string) => string;
28
- isDeleteDisabled?: boolean;
29
- /** An optional parameter for `renderRemoveUserDescription` */
30
- externalProviders?: ModelCollection<ExternalProvider>;
31
52
  }
32
53
  export interface UserRolesProps extends UserRolesReduxProps, UserRolesOwnProps {
33
54
  }
34
55
  interface UserRolesState {
35
56
  sortedUsers: UserWithRoles[];
36
57
  addUsersHookId: any;
37
- isAddingUsers: boolean;
58
+ isAdding: boolean;
38
59
  identifiersToAdd?: string[];
39
60
  roleForAdd?: string;
40
61
  shouldResetAddForm: boolean;
62
+ userRoleToUpdate?: UserRole;
63
+ roleForUpdate?: string;
64
+ isUpdating: boolean;
41
65
  shouldShowRemoveDialog: boolean;
42
- userToRemove: UserWithRoles | undefined;
43
- roleForRemove?: string;
66
+ userRoleToRemove?: UserRole;
67
+ isRemoving: boolean;
44
68
  successMessage?: string;
45
- existingUsersMessage?: string;
69
+ existingMessage?: string;
70
+ blockedMessage?: string;
46
71
  failMessage?: string;
47
72
  }
48
73
  export interface AddBusinessModel {
49
- addedUsers: UserWithRoles[];
50
- existingUsers: UserWithRoles[];
74
+ addedUserRoles: UserRole[];
75
+ existingUserRoles: UserRole[];
76
+ blockedUserRoles?: UserRole[];
51
77
  invalidIdentifiers: string[];
52
78
  allowedDomains: string;
53
79
  invalidDomainIdentifiers: string[];
@@ -62,15 +88,17 @@ export declare class UserRoles extends Component<UserRolesProps, UserRolesState>
62
88
  setStateFromProps: (props: UserRolesProps) => void;
63
89
  textForRole: (role: string) => string;
64
90
  singularArticleForRole: (role: string) => string;
65
- addUsers: (ids: string[], role: BASE_ROLE) => void;
91
+ addUserRoles: (identifiers: string[], role: string) => void;
66
92
  didAdd: (data?: FetchError | AddBusinessModel | undefined) => void;
67
- alertRemoveUser: (userToRemove: UserWithRoles, roleForRemove: string) => void;
68
- removeUserTitle: (roleForRemove: string) => string;
69
- renderRemoveUserDescription: (userToRemove: User, role: string, warning?: JSX.Element | undefined) => JSX.Element;
70
- removeUser: (shouldRemove: boolean) => void;
93
+ updateUserRole: (userRoleToUpdate: UserRole, newRole: string) => void;
94
+ didUpdate: (isSuccess: boolean) => void;
95
+ alertRemoveUserRole: (userRoleToRemove: UserRole) => void;
96
+ removeUserRoleTitle: (roleForRemove: string) => string;
97
+ renderRemoveUserRoleDescription: (userRoleToRemove: UserRole, warning?: JSX.Element | undefined) => JSX.Element;
98
+ removeUserRole: (shouldRemove: boolean) => void;
71
99
  didRemove: (isSuccess: boolean) => void;
72
100
  render(): JSX.Element;
73
101
  }
74
102
  export declare const mapStateToProps: (state: BaseReduxState, ownProps: UserRolesOwnProps) => UserRolesReduxProps;
75
- declare const _default: import("react-redux").ConnectedComponent<typeof UserRoles, Pick<React.ClassAttributes<UserRoles> & UserRolesProps, "externalProviders" | "model" | "ref" | "onChange" | "key" | "disabled" | "guid" | "load" | "modelName" | "pathParams" | "modelStatus" | "queryParams" | "disableAutoLoad" | "modelArray" | "stopPeriodicLoad" | "create" | "update" | "delete" | "previousModelStatus" | "fetchingId" | "textForRole" | "entityName" | "defaultRole" | "roleDescriptions" | "renderAddDescription" | "modifyUserRoleActivityName" | "filterUsers" | "addRoleBlacklist" | "renderTableDescription" | "entity" | "singularArticleForRole" | "isDeleteDisabled"> & UserRolesOwnProps>;
103
+ declare const _default: import("react-redux").ConnectedComponent<typeof UserRoles, Pick<React.ClassAttributes<UserRoles> & UserRolesProps, "externalProviders" | "model" | "ref" | "onChange" | "key" | "guid" | "load" | "modelName" | "pathParams" | "modelStatus" | "queryParams" | "disableAutoLoad" | "modelArray" | "stopPeriodicLoad" | "create" | "update" | "delete" | "previousModelStatus" | "fetchingId" | "textForRole" | "entityName" | "defaultRole" | "roleDescriptions" | "renderAddDescription" | "isUpdateDisabled" | "isDeleteDisabled" | "allowMultipleRoles" | "requiredRole" | "isAddDisabled" | "modifyUserRoleActivityName" | "deleteOwnUserRoleActivityName" | "addRoleExcludeList" | "entity" | "filterUsers" | "renderTableDescription" | "singularArticleForRole"> & UserRolesOwnProps>;
76
104
  export default _default;