Permissions.tsx 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import * as React from "react";
  2. import { CommandBar, ContextualMenuItemType, ICommandBarItemProps } from "@fluentui/react";
  3. import { useConst } from "@fluentui/react-hooks";
  4. import { scopedLogger } from "@hpcc-js/util";
  5. import * as WsAccess from "src/ws_access";
  6. import nlsHPCC from "src/nlsHPCC";
  7. import { ShortVerticalDivider } from "./Common";
  8. import { useConfirm } from "../hooks/confirm";
  9. import { DojoGrid, selector, tree } from "./DojoGrid";
  10. import { AddPermissionForm } from "./forms/AddPermission";
  11. import { HolyGrail } from "../layouts/HolyGrail";
  12. import { pushUrl } from "../util/history";
  13. const logger = scopedLogger("src-react/components/Permissions.tsx");
  14. const defaultUIState = {
  15. canDelete: false,
  16. categorySelected: false,
  17. fileScope: false,
  18. hasSelection: false,
  19. repositoryModule: false,
  20. workunitScope: false
  21. };
  22. interface PermissionsProps {
  23. }
  24. export const Permissions: React.FunctionComponent<PermissionsProps> = ({
  25. }) => {
  26. const [grid, setGrid] = React.useState<any>(undefined);
  27. const [selection, setSelection] = React.useState([]);
  28. const [showAddPermission, setShowAddPermission] = React.useState(false);
  29. const [scopeScansEnabled, setScopeScansEnabled] = React.useState(false);
  30. const [modulesDn, setModulesDn] = React.useState("");
  31. const [selectedFileList, setSelectedFileList] = React.useState("");
  32. const [uiState, setUIState] = React.useState({ ...defaultUIState });
  33. // Grid ---
  34. const gridStore = useConst(WsAccess.CreatePermissionsStore(null, null));
  35. const gridSort = useConst([{ attribute: "name", "descending": false }]);
  36. const gridQuery = useConst({});
  37. const gridColumns = useConst({
  38. check: selector({
  39. width: 27,
  40. disabled: function (row) {
  41. if (row.name === "File Scopes" || row.name === "Workunit Scopes" || row.name === "Repository Modules") {
  42. return false;
  43. }
  44. return row.children ? true : false;
  45. }
  46. }, "checkbox"),
  47. name: tree({
  48. width: 360,
  49. label: nlsHPCC.Name,
  50. formatter: function (_name, idx) {
  51. if (idx.__hpcc_parent) {
  52. return `<a href="/#/security/permissions/${_name}/${idx.__hpcc_parent.name}">${_name}</a>`;
  53. } else {
  54. return _name;
  55. }
  56. }
  57. }),
  58. description: { label: nlsHPCC.Description },
  59. basedn: { label: "basedn" }
  60. });
  61. // Selection ---
  62. React.useEffect(() => {
  63. const state = { ...defaultUIState };
  64. if (selection.length) {
  65. state.hasSelection = true;
  66. if (!selection.filter(item => item.hasOwnProperty("children")).length) {
  67. state.canDelete = true;
  68. } else {
  69. state.categorySelected = true;
  70. }
  71. if (selection.filter(item => item.name === "File Scopes").length) {
  72. state.fileScope = true;
  73. }
  74. const _modules = selection.filter(item => item.name === "Repository Modules");
  75. if (_modules.length) {
  76. setModulesDn(_modules[0].basedn);
  77. state.repositoryModule = true;
  78. }
  79. if (selection.filter(item => item.name === "Workunit Scopes").length) {
  80. state.workunitScope = true;
  81. }
  82. }
  83. setSelectedFileList(selection.map(file => file.name).join("\n"));
  84. setUIState(state);
  85. }, [selection]);
  86. React.useEffect(() => {
  87. WsAccess.Resources({
  88. request: {
  89. name: "File Scopes"
  90. }
  91. })
  92. .then(({ ResourcesResponse }) => {
  93. setScopeScansEnabled(ResourcesResponse?.scopeScansStatus?.isEnabled || false);
  94. })
  95. .catch(logger.error)
  96. ;
  97. }, [setScopeScansEnabled]);
  98. const refreshTable = React.useCallback((clearSelection = false) => {
  99. grid?.set("query", gridQuery);
  100. if (clearSelection) {
  101. grid?.clearSelection();
  102. }
  103. }, [grid, gridQuery]);
  104. const [DeleteConfirm, setShowDeleteConfirm] = useConfirm({
  105. title: nlsHPCC.Delete,
  106. message: nlsHPCC.DeleteSelectedPermissions + "\n\n" + selectedFileList,
  107. onSubmit: React.useCallback(() => {
  108. const deleteRequests = {};
  109. const requests = [];
  110. selection.forEach((item, idx) => {
  111. if (!deleteRequests[item.__hpcc_id]) {
  112. deleteRequests[item.__hpcc_id] = {
  113. action: "Delete",
  114. BasednName: item.__hpcc_parent.name,
  115. rtype: item.__hpcc_parent.rtype,
  116. rtitle: item.__hpcc_parent.rtitle
  117. };
  118. }
  119. deleteRequests[item.__hpcc_id]["names_i" + idx] = item.name;
  120. });
  121. for (const key in deleteRequests) {
  122. requests.push(WsAccess.ResourceDelete({
  123. request: deleteRequests[key]
  124. }));
  125. }
  126. Promise.all(requests)
  127. .then(() => {
  128. refreshTable();
  129. })
  130. .catch(logger.error)
  131. ;
  132. }, [refreshTable, selection])
  133. });
  134. const [ClearPermissionsConfirm, setShowClearPermissionsConfirm] = useConfirm({
  135. title: nlsHPCC.ClearPermissionsCache,
  136. message: nlsHPCC.ClearPermissionsCacheConfirm,
  137. onSubmit: () => WsAccess.ClearPermissionsCache
  138. });
  139. const [EnableScopesConfirm, setShowEnableScopesConfirm] = useConfirm({
  140. title: nlsHPCC.EnableScopeScans,
  141. message: nlsHPCC.EnableScopeScansConfirm,
  142. onSubmit: () => WsAccess.EnableScopeScans
  143. });
  144. const [DisableScopesConfirm, setShowDisableScopesConfirm] = useConfirm({
  145. title: nlsHPCC.DisableScopeScans,
  146. message: nlsHPCC.DisableScopeScanConfirm,
  147. onSubmit: () => WsAccess.DisableScopeScans
  148. });
  149. // Command Bar ---
  150. const buttons = React.useMemo((): ICommandBarItemProps[] => [
  151. {
  152. key: "refresh", text: nlsHPCC.Refresh, iconProps: { iconName: "Refresh" },
  153. onClick: () => refreshTable()
  154. },
  155. { key: "divider_1", itemType: ContextualMenuItemType.Divider, onRender: () => <ShortVerticalDivider /> },
  156. {
  157. key: "add", text: nlsHPCC.Add,
  158. onClick: () => setShowAddPermission(true)
  159. },
  160. {
  161. key: "delete", text: nlsHPCC.Delete, disabled: !uiState.canDelete,
  162. onClick: () => setShowDeleteConfirm(true)
  163. },
  164. { key: "divider_2", itemType: ContextualMenuItemType.Divider, onRender: () => <ShortVerticalDivider /> },
  165. {
  166. key: "clearPermissions", text: nlsHPCC.ClearPermissionsCache,
  167. onClick: () => setShowClearPermissionsConfirm(true)
  168. },
  169. {
  170. key: "advanced", text: nlsHPCC.Advanced, disabled: !uiState.hasSelection || !uiState.categorySelected,
  171. subMenuProps: {
  172. items: [
  173. {
  174. key: "enableScopeScans",
  175. text: nlsHPCC.EnableScopeScans,
  176. onClick: () => setShowEnableScopesConfirm(true),
  177. disabled: scopeScansEnabled
  178. },
  179. {
  180. key: "disableScopeScans",
  181. text: nlsHPCC.DisableScopeScans,
  182. onClick: () => setShowDisableScopesConfirm(true),
  183. disabled: !scopeScansEnabled
  184. },
  185. { key: "fileScopeDefaults", text: nlsHPCC.FileScopeDefaultPermissions, onClick: (evt, item) => pushUrl("/security/permissions/_/File%20Scopes"), disabled: !uiState.fileScope },
  186. { key: "workunitScopeDefaults", text: nlsHPCC.WorkUnitScopeDefaultPermissions, onClick: (evt, item) => pushUrl("/security/permissions/_/Workunit%20Scopes"), disabled: !uiState.workunitScope },
  187. { key: "physicalFiles", text: nlsHPCC.PhysicalFiles, onClick: (evt, item) => pushUrl("/security/permissions/file/File%20Scopes"), disabled: !uiState.fileScope },
  188. { key: "checkFilePermissions", text: nlsHPCC.CheckFilePermissions, disabled: !uiState.fileScope },
  189. { key: "codeGenerator", text: nlsHPCC.CodeGenerator, onClick: (evt, item) => pushUrl(`/security/permissions/_/${modulesDn}`), disabled: !uiState.repositoryModule },
  190. ],
  191. },
  192. },
  193. ], [modulesDn, refreshTable, setShowClearPermissionsConfirm, setShowDeleteConfirm, setShowDisableScopesConfirm, setShowEnableScopesConfirm, scopeScansEnabled, uiState]);
  194. React.useEffect(() => {
  195. refreshTable();
  196. }, [grid?.data, refreshTable]);
  197. return <>
  198. <HolyGrail
  199. header={<CommandBar items={buttons} overflowButtonProps={{}} />}
  200. main={<DojoGrid store={gridStore} query={gridQuery} sort={gridSort} columns={gridColumns} setGrid={setGrid} setSelection={setSelection} />}
  201. />
  202. <DeleteConfirm />
  203. <ClearPermissionsConfirm />
  204. <EnableScopesConfirm />
  205. <DisableScopesConfirm />
  206. <AddPermissionForm showForm={showAddPermission} setShowForm={setShowAddPermission} refreshGrid={refreshTable} />
  207. </>;
  208. };