WIP Access control UI
This commit is contained in:
parent
e650f813c5
commit
7487b0da58
2 changed files with 142 additions and 6 deletions
|
@ -183,7 +183,7 @@
|
||||||
"account_usage_plan_code_business_plus": "Business Plus",
|
"account_usage_plan_code_business_plus": "Business Plus",
|
||||||
"account_usage_messages_title": "Published messages",
|
"account_usage_messages_title": "Published messages",
|
||||||
"account_usage_emails_title": "Emails sent",
|
"account_usage_emails_title": "Emails sent",
|
||||||
"account_usage_topics_title": "Topics reserved",
|
"account_usage_topics_title": "Reserved topics",
|
||||||
"account_usage_attachment_storage_title": "Attachment storage",
|
"account_usage_attachment_storage_title": "Attachment storage",
|
||||||
"account_usage_attachment_storage_subtitle": "{{filesize}} per file",
|
"account_usage_attachment_storage_subtitle": "{{filesize}} per file",
|
||||||
"account_usage_basis_ip_description": "Usage stats and limits for this account are based on your IP address, so they may be shared with other users.",
|
"account_usage_basis_ip_description": "Usage stats and limits for this account are based on your IP address, so they may be shared with other users.",
|
||||||
|
@ -239,6 +239,17 @@
|
||||||
"prefs_users_dialog_button_save": "Save",
|
"prefs_users_dialog_button_save": "Save",
|
||||||
"prefs_appearance_title": "Appearance",
|
"prefs_appearance_title": "Appearance",
|
||||||
"prefs_appearance_language_title": "Language",
|
"prefs_appearance_language_title": "Language",
|
||||||
|
"prefs_access_title": "Reserved topics",
|
||||||
|
"prefs_access_description": "You may reserve topic names for personal use here, and define access to a topic for other users.",
|
||||||
|
"prefs_access_add_button": "Add reserved topic",
|
||||||
|
"prefs_access_edit_button": "Edit topic access",
|
||||||
|
"prefs_access_delete_button": "Reset topic access",
|
||||||
|
"prefs_access_table": "Reserved topics table",
|
||||||
|
"prefs_access_table_topic_header": "Topic",
|
||||||
|
"prefs_access_table_access_header": "Access",
|
||||||
|
"prefs_access_table_perms_private": "Only I can publish and subscribe",
|
||||||
|
"prefs_access_table_perms_public_read": "I can publish, everyone can subscribe",
|
||||||
|
"prefs_access_table_perms_public": "Everyone can publish and subscribe",
|
||||||
"priority_min": "min",
|
"priority_min": "min",
|
||||||
"priority_low": "low",
|
"priority_low": "low",
|
||||||
"priority_default": "default",
|
"priority_default": "default",
|
||||||
|
|
|
@ -10,7 +10,8 @@ import {
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableRow, Tooltip,
|
TableRow,
|
||||||
|
Tooltip,
|
||||||
useMediaQuery
|
useMediaQuery
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
|
@ -32,22 +33,23 @@ import DialogTitle from "@mui/material/DialogTitle";
|
||||||
import DialogContent from "@mui/material/DialogContent";
|
import DialogContent from "@mui/material/DialogContent";
|
||||||
import DialogActions from "@mui/material/DialogActions";
|
import DialogActions from "@mui/material/DialogActions";
|
||||||
import userManager from "../app/UserManager";
|
import userManager from "../app/UserManager";
|
||||||
import {playSound, shuffle, sounds, validTopic, validUrl} from "../app/utils";
|
import {playSound, shuffle, sounds, validUrl} from "../app/utils";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import session from "../app/Session";
|
import session from "../app/Session";
|
||||||
import routes from "./routes";
|
import routes from "./routes";
|
||||||
import accountApi, {UnauthorizedError} from "../app/AccountApi";
|
import accountApi, {UnauthorizedError} from "../app/AccountApi";
|
||||||
import {Pref, PrefGroup} from "./Pref";
|
import {Pref, PrefGroup} from "./Pref";
|
||||||
import InfoIcon from '@mui/icons-material/Info';
|
import {useOutletContext} from "react-router-dom";
|
||||||
import {useNavigate} from "react-router-dom";
|
import LockIcon from "@mui/icons-material/Lock";
|
||||||
|
|
||||||
const Preferences = () => {
|
const Preferences = () => {
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="md" sx={{marginTop: 3, marginBottom: 3}}>
|
<Container maxWidth="md" sx={{marginTop: 3, marginBottom: 3}}>
|
||||||
<Stack spacing={3}>
|
<Stack spacing={3}>
|
||||||
<Notifications/>
|
<Notifications/>
|
||||||
<Appearance/>
|
<Access/>
|
||||||
<Users/>
|
<Users/>
|
||||||
|
<Appearance/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
@ -471,6 +473,129 @@ const Language = () => {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Access = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { account } = useOutletContext();
|
||||||
|
const [dialogKey, setDialogKey] = useState(0);
|
||||||
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
|
|
||||||
|
const handleAddClick = () => {
|
||||||
|
setDialogKey(prev => prev+1);
|
||||||
|
setDialogOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDialogCancel = () => {
|
||||||
|
setDialogOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDialogSubmit = async (entry) => {
|
||||||
|
setDialogOpen(false);
|
||||||
|
try {
|
||||||
|
await accountApi.addAccessEntry();
|
||||||
|
console.debug(`[Preferences] Added entry ${entry.topic}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`[Preferences] Error adding access entry.`, e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!session.exists() || !account) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card sx={{ padding: 1 }} aria-label={t("prefs_access_title")}>
|
||||||
|
<CardContent sx={{ paddingBottom: 1 }}>
|
||||||
|
<Typography variant="h5" sx={{marginBottom: 2}}>
|
||||||
|
{t("prefs_access_title")}
|
||||||
|
</Typography>
|
||||||
|
<Paragraph>
|
||||||
|
{t("prefs_access_description")}
|
||||||
|
</Paragraph>
|
||||||
|
{account.access.length > 0 && <AccessTable entries={account.access}/>}
|
||||||
|
</CardContent>
|
||||||
|
<CardActions>
|
||||||
|
<Button onClick={handleAddClick}>{t("prefs_access_add_button")}</Button>
|
||||||
|
{/*<UserDialog
|
||||||
|
key={`userEditDialog${dialogKey}`}
|
||||||
|
open={dialogOpen}
|
||||||
|
user={dialogUser}
|
||||||
|
users={props.users}
|
||||||
|
onCancel={handleDialogCancel}
|
||||||
|
onSubmit={handleDialogSubmit}
|
||||||
|
/>*/}
|
||||||
|
</CardActions>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AccessTable = (props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [dialogKey, setDialogKey] = useState(0);
|
||||||
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
|
const [dialogUser, setDialogUser] = useState(null);
|
||||||
|
|
||||||
|
const handleEditClick = (user) => {
|
||||||
|
setDialogKey(prev => prev+1);
|
||||||
|
setDialogUser(user);
|
||||||
|
setDialogOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDialogCancel = () => {
|
||||||
|
setDialogOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDialogSubmit = async (user) => {
|
||||||
|
setDialogOpen(false);
|
||||||
|
// FIXME
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteClick = async (user) => {
|
||||||
|
// FIXME
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table size="small" aria-label={t("prefs_access_table")}>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell sx={{paddingLeft: 0}}>{t("prefs_access_table_topic_header")}</TableCell>
|
||||||
|
<TableCell>{t("prefs_access_table_access_header")}</TableCell>
|
||||||
|
<TableCell/>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{props.entries.map(entry => (
|
||||||
|
<TableRow
|
||||||
|
key={entry.topic}
|
||||||
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
|
>
|
||||||
|
<TableCell component="th" scope="row" sx={{paddingLeft: 0}} aria-label={t("prefs_access_table_topic_header")}>{entry.topic}</TableCell>
|
||||||
|
<TableCell aria-label={t("prefs_access_table_access_header")}>
|
||||||
|
<LockIcon fontSize="small" sx={{verticalAlign: "bottom", mr: 0.5}}/>
|
||||||
|
{t("prefs_access_table_perms_private")}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="right">
|
||||||
|
<IconButton onClick={() => handleEditClick(entry)} aria-label={t("prefs_access_edit_button")}>
|
||||||
|
<EditIcon/>
|
||||||
|
</IconButton>
|
||||||
|
<IconButton onClick={() => handleDeleteClick(entry)} aria-label={t("prefs_access_delete_button")}>
|
||||||
|
<CloseIcon/>
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
{/*<UserDialog
|
||||||
|
key={`userEditDialog${dialogKey}`}
|
||||||
|
open={dialogOpen}
|
||||||
|
user={dialogUser}
|
||||||
|
users={props.users}
|
||||||
|
onCancel={handleDialogCancel}
|
||||||
|
onSubmit={handleDialogSubmit}
|
||||||
|
/>*/}
|
||||||
|
</Table>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const maybeUpdateAccountSettings = async (payload) => {
|
const maybeUpdateAccountSettings = async (payload) => {
|
||||||
if (!session.exists()) {
|
if (!session.exists()) {
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue