Files
rowy/src/components/TableSettings/SuggestedRules.tsx
2021-10-29 11:47:12 +11:00

143 lines
4.2 KiB
TypeScript

import { useState } from "react";
import { useWatch } from "react-hook-form";
import {
InputLabel,
Collapse,
FormControlLabel,
Checkbox,
Grid,
Button,
} from "@mui/material";
import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon";
import { IFieldComponentProps } from "@rowy/form-builder";
import { useAppContext } from "@src/contexts/AppContext";
type customizationOptions = "allRead" | "authRead" | "subcollections" | "user";
export interface ISuggestedRulesProps extends IFieldComponentProps {}
export default function SuggestedRules({
useFormMethods: { control },
label,
}: ISuggestedRulesProps) {
const { projectId } = useAppContext();
const watched = useWatch({ control, name: ["collection", "roles"] } as any);
const [collection, roles] = Array.isArray(watched) ? watched : [];
const [customized, setCustomized] = useState<boolean>(false);
const [customizations, setCustomizations] = useState<customizationOptions[]>(
[]
);
const handleChange =
(option: customizationOptions) =>
(e: React.ChangeEvent<HTMLInputElement>) =>
setCustomizations((prev) => {
const set = new Set(prev || []);
if (e.target.checked) set.add(option);
else set.delete(option);
return Array.from(set);
});
const generatedRules = `match /${collection}/{${
customizations.includes("subcollections") ? "document=**" : "docId"
}} {
allow read, write: if hasAnyRole(${JSON.stringify(roles)});${
customizations.includes("allRead")
? "\n allow read: if true;"
: customizations.includes("authRead")
? "\n allow read: if request.auth != null;"
: ""
}${
customizations.includes("user")
? `\n
allow create: if request.auth != null;
allow get, update, delete: if isDocOwner(userId);`
: ""
}
}`;
return (
<>
<InputLabel sx={{ mb: 0.5, ml: 0.25 }}>{label}</InputLabel>
<pre style={{ margin: 0, userSelect: "all", whiteSpace: "pre-wrap" }}>
{generatedRules}
</pre>
<Collapse in={customized}>
<Grid container>
<Grid item xs={12} sm={6}>
<FormControlLabel
control={
<Checkbox
checked={customizations.includes("allRead")}
onChange={handleChange("allRead")}
/>
}
label="Anyone can read"
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormControlLabel
control={
<Checkbox
checked={customizations.includes("authRead")}
onChange={handleChange("authRead")}
/>
}
label="All signed-in users can read"
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormControlLabel
control={
<Checkbox
checked={customizations.includes("user")}
onChange={handleChange("user")}
/>
}
label="Users can create and edit docs"
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormControlLabel
control={
<Checkbox
checked={customizations.includes("subcollections")}
onChange={handleChange("subcollections")}
/>
}
label="Same rules for all subcollections"
/>
</Grid>
</Grid>
</Collapse>
<Grid container spacing={1} style={{ marginTop: 0 }}>
{!customized && (
<Grid item>
<Button onClick={() => setCustomized(true)}>Customize</Button>
</Grid>
)}
<Grid item>
<Button onClick={() => navigator.clipboard.writeText(generatedRules)}>
Copy to clipboard
</Button>
</Grid>
<Grid item>
<Button
href={`https://console.firebase.google.com/u/0/project/${projectId}/firestore/rules`}
target="_blank"
rel="noopener noreferrer"
>
Set rules in Firebase Console
<InlineOpenInNewIcon />
</Button>
</Grid>
</Grid>
</>
);
}