|
@@ -1,5 +1,5 @@
|
|
|
-import { capitalize, get, set } from "lodash";
|
|
|
|
|
-import React, { useCallback, useContext, useEffect } from "react";
|
|
|
|
|
|
|
+import _, { capitalize, get, set } from "lodash";
|
|
|
|
|
+import React, { useContext, useEffect, useRef } from "react";
|
|
|
import api from "shared/api";
|
|
import api from "shared/api";
|
|
|
import {
|
|
import {
|
|
|
POLICY_HIERARCHY_TREE,
|
|
POLICY_HIERARCHY_TREE,
|
|
@@ -30,8 +30,28 @@ const PolicyDocumentRenderer = ({
|
|
|
onChange: (data: PolicyDocType) => void;
|
|
onChange: (data: PolicyDocType) => void;
|
|
|
readOnly?: boolean;
|
|
readOnly?: boolean;
|
|
|
}) => {
|
|
}) => {
|
|
|
- const { currentProject } = useContext(Context);
|
|
|
|
|
|
|
+ const { currentProject, setCurrentOverlay } = useContext(Context);
|
|
|
const [scopeHierarchy, setScopeHierarchy] = React.useState<any>(null);
|
|
const [scopeHierarchy, setScopeHierarchy] = React.useState<any>(null);
|
|
|
|
|
+ const emptyPolicyDoc = useRef(
|
|
|
|
|
+ populatePolicy({
|
|
|
|
|
+ scope: "project",
|
|
|
|
|
+ verbs: [],
|
|
|
|
|
+ })
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ if (!scopeHierarchy) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ emptyPolicyDoc.current = populatePolicy(
|
|
|
|
|
+ {
|
|
|
|
|
+ scope: "project",
|
|
|
|
|
+ verbs: [],
|
|
|
|
|
+ },
|
|
|
|
|
+ scopeHierarchy
|
|
|
|
|
+ );
|
|
|
|
|
+ }, [scopeHierarchy]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
api
|
|
api
|
|
@@ -44,12 +64,41 @@ const PolicyDocumentRenderer = ({
|
|
|
});
|
|
});
|
|
|
}, [currentProject?.id]);
|
|
}, [currentProject?.id]);
|
|
|
|
|
|
|
|
- const handleChangeVerbs = (dataPath: string, verbs: Verbs[]) => {
|
|
|
|
|
|
|
+ const handleChangeVerbs = (verbsPath: string, verbs: Verbs[]) => {
|
|
|
const newPolicyDoc = structuredClone(value) as PolicyDocType;
|
|
const newPolicyDoc = structuredClone(value) as PolicyDocType;
|
|
|
|
|
+ const pathToChildren = verbsPath
|
|
|
|
|
+ .split(".")
|
|
|
|
|
+ .slice(0, -1)
|
|
|
|
|
+ .concat(["children"])
|
|
|
|
|
+ .join(".");
|
|
|
|
|
+
|
|
|
|
|
+ const isReadRemovedTransitive =
|
|
|
|
|
+ !verbs.includes("get") &&
|
|
|
|
|
+ Object.keys(_.get(newPolicyDoc, pathToChildren, {})).length;
|
|
|
|
|
+
|
|
|
|
|
+ if (isReadRemovedTransitive) {
|
|
|
|
|
+ const emptyPolicyDocumentForChildren = get(
|
|
|
|
|
+ emptyPolicyDoc.current,
|
|
|
|
|
+ pathToChildren
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ set(newPolicyDoc, pathToChildren, emptyPolicyDocumentForChildren);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- set(newPolicyDoc, dataPath, verbs);
|
|
|
|
|
|
|
+ set(newPolicyDoc, verbsPath, verbs);
|
|
|
|
|
|
|
|
- onChange(newPolicyDoc);
|
|
|
|
|
|
|
+ if (isReadRemovedTransitive) {
|
|
|
|
|
+ setCurrentOverlay({
|
|
|
|
|
+ message: `Dummy text?`,
|
|
|
|
|
+ onYes: () => {
|
|
|
|
|
+ onChange(newPolicyDoc);
|
|
|
|
|
+ setCurrentOverlay(null);
|
|
|
|
|
+ },
|
|
|
|
|
+ onNo: () => setCurrentOverlay(null),
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ onChange(newPolicyDoc);
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
if (!scopeHierarchy) {
|
|
if (!scopeHierarchy) {
|
|
@@ -111,13 +160,13 @@ const RenderComponents = (
|
|
|
|
|
|
|
|
const Component = (
|
|
const Component = (
|
|
|
<>
|
|
<>
|
|
|
- <Card anidationLevel={anidationLevel}>
|
|
|
|
|
- <ScopePermissionsHandler
|
|
|
|
|
- name={scope}
|
|
|
|
|
- dataPath={verbsPath}
|
|
|
|
|
- readOnly={readOnly}
|
|
|
|
|
- />
|
|
|
|
|
- </Card>
|
|
|
|
|
|
|
+ <ScopePermissionsHandler
|
|
|
|
|
+ name={scope}
|
|
|
|
|
+ parent={dataPath.split(".").slice(0, -1).join(".")}
|
|
|
|
|
+ dataPath={verbsPath}
|
|
|
|
|
+ readOnly={readOnly}
|
|
|
|
|
+ anidationLevel={anidationLevel}
|
|
|
|
|
+ />
|
|
|
{components.map((c) => c)}
|
|
{components.map((c) => c)}
|
|
|
</>
|
|
</>
|
|
|
);
|
|
);
|
|
@@ -135,28 +184,48 @@ const Card = styled.div<{ anidationLevel: number }>`
|
|
|
`;
|
|
`;
|
|
|
|
|
|
|
|
const ScopePermissionsHandler = ({
|
|
const ScopePermissionsHandler = ({
|
|
|
|
|
+ anidationLevel,
|
|
|
|
|
+ parent,
|
|
|
name,
|
|
name,
|
|
|
dataPath,
|
|
dataPath,
|
|
|
readOnly,
|
|
readOnly,
|
|
|
}: {
|
|
}: {
|
|
|
|
|
+ anidationLevel: number;
|
|
|
|
|
+ parent: string;
|
|
|
name: string;
|
|
name: string;
|
|
|
dataPath: string;
|
|
dataPath: string;
|
|
|
readOnly: boolean;
|
|
readOnly: boolean;
|
|
|
}) => {
|
|
}) => {
|
|
|
const { handleChangeVerbs, data } = React.useContext(Store);
|
|
const { handleChangeVerbs, data } = React.useContext(Store);
|
|
|
|
|
+ const { setCurrentError } = React.useContext(Context);
|
|
|
|
|
|
|
|
const verbs = get(data, dataPath);
|
|
const verbs = get(data, dataPath);
|
|
|
|
|
|
|
|
|
|
+ const onChange = (newVerbs: Verbs[]) => {
|
|
|
|
|
+ const pathToParentsVerbs = parent.split(".").concat("verbs").join(".");
|
|
|
|
|
+
|
|
|
|
|
+ const isActionAllowed =
|
|
|
|
|
+ anidationLevel === 0
|
|
|
|
|
+ ? true
|
|
|
|
|
+ : get(data, pathToParentsVerbs, []).includes("get");
|
|
|
|
|
+
|
|
|
|
|
+ if (isActionAllowed) {
|
|
|
|
|
+ handleChangeVerbs(dataPath, newVerbs);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ setCurrentError(
|
|
|
|
|
+ "This action is not allowed since the parent does not have read permissions enabled."
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // show something to tell user
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
- <>
|
|
|
|
|
|
|
+ <Card anidationLevel={anidationLevel}>
|
|
|
{name}
|
|
{name}
|
|
|
- {readOnly ? null : (
|
|
|
|
|
- <Select
|
|
|
|
|
- values={verbs}
|
|
|
|
|
- onChange={(newVerbs) => handleChangeVerbs(dataPath, newVerbs)}
|
|
|
|
|
- />
|
|
|
|
|
- )}
|
|
|
|
|
- </>
|
|
|
|
|
|
|
+ {readOnly ? null : <Select values={verbs} onChange={onChange} />}
|
|
|
|
|
+ </Card>
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|
|
|
|
|
|