Skip to content

Commit

Permalink
Merge pull request #287 from Tauffer-Consulting/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
vinicvaz authored Apr 29, 2024
2 parents 1db8614 + 6a5a967 commit 6e761fe
Show file tree
Hide file tree
Showing 16 changed files with 310 additions and 118 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ pyvenv.cfg
pip-selfcheck.json

### VisualStudioCode ###
.vscode/*
**/.vscode/*

### VisualStudioCode Patch ###
# Ignore all local history of files
Expand Down
54 changes: 54 additions & 0 deletions frontend/src/components/AuthorizationComponent/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useWorkspaces } from "@context/workspaces";
import ReportProblemIcon from "@mui/icons-material/ReportProblem";
import { Box, Button, type SxProps, type Theme, Tooltip } from "@mui/material";
import { type Roles } from "@utils/roles";
import React, { type ReactNode } from "react";

interface IProps {
children?: ReactNode;
allowedRoles: Roles[];
sx?: SxProps<Theme>;
}

export const AuthorizationComponent: React.FC<IProps> = ({
allowedRoles,
children,
sx,
}) => {
const { workspace } = useWorkspaces();

const authorized = allowedRoles.some(
(item) => workspace?.user_permission === item,
);

return authorized ? (
<>{children}</>
) : React.isValidElement(children) && children.type === Button ? (
<Tooltip
title="You don't have enough permissions to access this feature"
sx={sx}
>
<span>
<Button disabled variant="contained">
<ReportProblemIcon />
Unauthorized
</Button>
</span>
</Tooltip>
) : (
<Box
sx={{
height: "100%",
width: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
...sx,
}}
>
<Tooltip title="You don't have enough permissions to access this feature">
<ReportProblemIcon fontSize="large" color="warning" />
</Tooltip>
</Box>
);
};
11 changes: 9 additions & 2 deletions frontend/src/components/PrivateLayout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Box, Container } from "@mui/material";
import { type FC, type ReactNode } from "react";

import { DrawerHeader } from "./header/drawerMenu.style";
import { Header } from "./header/header";

interface Props {
Expand All @@ -9,10 +10,16 @@ interface Props {

export const PrivateLayout: FC<Props> = ({ children }) => {
return (
<Box sx={{ display: "flex", width: "100%", marginTop: "64px" }}>
<Box sx={{ display: "flex" }}>
<Header />

<Container component="main" maxWidth={false} sx={{ padding: 3 }}>
<Container
component="main"
maxWidth={false}
sx={{ padding: 3, overflow: "auto" }}
>
<DrawerHeader />

<Box sx={{ paddingLeft: 0 }}>{children}</Box>
</Container>
</Box>
Expand Down
21 changes: 0 additions & 21 deletions frontend/src/components/RoleComponent/index.tsx

This file was deleted.

8 changes: 4 additions & 4 deletions frontend/src/components/Routes/AuthorizationRoute/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type Props = {
* | requireWorkspace | allowedRoles.length | workspace | Result |
* |------------------|---------------------|-----------|---------------------------|
* | false | 0 | null | Render children |
* | false | 0 | not null | Redirect to unauthorized |
* | false | 0 | not null | Redirect to forbidden |
* | false | > 0 | null | Redirect to workspaces |
* | false | > 0 | not null | Check permission |
* | true | 0 | null | Redirect to workspaces |
Expand Down Expand Up @@ -68,10 +68,10 @@ export const AuthorizationRoute = ({
return hasPermission ? (
<>{children}</>
) : (
<Navigate to="/unauthorized" replace />
<Navigate to="/forbidden" replace />
);
}

// Redirect to unauthorized if no other conditions met
return <Navigate to="/unauthorized" replace />;
// Redirect to forbidden if no other conditions met
return <Navigate to="/forbidden" replace />;
};
74 changes: 74 additions & 0 deletions frontend/src/components/Routes/ForbiddenPage/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import PrivateLayout from "@components/PrivateLayout";
import { useAuthentication } from "@context/authentication";
import {
Button,
Card,
CardContent,
CardHeader,
Divider,
Typography,
} from "@mui/material";
import React from "react";
import { type NavigateFunction, useNavigate } from "react-router-dom";

export const ForbiddenPage: React.FC = () => {
const { isLogged } = useAuthentication();
const navigate = useNavigate();

return (
<>
{isLogged ? (
<PrivateLayout>
<ForbiddenCard navigate={navigate} />
</PrivateLayout>
) : (
<ForbiddenCard navigate={navigate} />
)}
</>
);
};

const ForbiddenCard: React.FC<{ navigate: NavigateFunction }> = ({
navigate,
}) => (
<Card
sx={{
maxWidth: 400,
margin: "auto",
marginTop: 4,
boxShadow: "0 4px 8px rgba(0, 0, 0, 0.1)",
}}
>
<CardHeader
title="Forbidden"
sx={{
backgroundColor: (theme) => theme.palette.error.main,
color: "white",
textAlign: "center",
}}
/>
<Divider />
<CardContent
sx={{
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
minHeight: "50vh",
}}
>
<Typography variant="body1" align="center">
You are not authorized to access this page.
</Typography>
<Button
onClick={() => {
navigate(-1);
}}
variant="outlined"
sx={{ marginTop: 2 }}
>
<Typography component="span">{`< Go back `}</Typography>
</Button>
</CardContent>
</Card>
);
2 changes: 2 additions & 0 deletions frontend/src/features/auth/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ForbiddenPage } from "@components/Routes/ForbiddenPage";
import { NotFoundRoute } from "@components/Routes/NotFoundRoute";
import { PublicRoute } from "@components/Routes/PublicRoute";
import React from "react";
Expand All @@ -14,6 +15,7 @@ export const AuthRoutes: React.FC = () => {
<Route path="sign-up" element={<SignUpPage />} />
<Route path="recover-password" element={<h1>Recover password</h1>} />
<Route path="404" element={<NotFoundRoute />} />,
<Route path="forbidden" element={<ForbiddenPage />} />
<Route
path="*"
element={
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AuthorizationComponent } from "@components/AuthorizationComponent";
import RefreshIcon from "@mui/icons-material/Refresh";
import { Button, Grid } from "@mui/material";
import {
Expand Down Expand Up @@ -38,9 +39,13 @@ export const WorkflowRunTableFooter = React.forwardRef<HTMLDivElement, Props>(
sx={{ height: "100%" }}
>
<Grid item sx={{ paddingLeft: "1rem" }}>
<Button variant="contained" onClick={triggerRun}>
Run
</Button>
<AuthorizationComponent
allowedRoles={["owner", "admin", "write"]}
>
<Button variant="contained" onClick={triggerRun}>
Run
</Button>
</AuthorizationComponent>
</Grid>
<Grid item sx={{ paddingLeft: "1rem" }}>
<Button
Expand Down
113 changes: 62 additions & 51 deletions frontend/src/features/workflowEditor/components/ButtonsMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AuthorizationComponent } from "@components/AuthorizationComponent";
import ClearIcon from "@mui/icons-material/Clear";
import DownloadIcon from "@mui/icons-material/Download";
import IosShareIcon from "@mui/icons-material/IosShare";
Expand Down Expand Up @@ -121,55 +122,63 @@ export const ButtonsMenu: React.FC<Props> = ({
style={{ marginBottom: 10 }}
>
<Grid item>
<Button
color="primary"
variant="contained"
startIcon={<SettingsSuggestIcon />}
onClick={handleSettings}
>
Settings
</Button>
<AuthorizationComponent allowedRoles={["admin", "owner", "write"]}>
<Button
color="primary"
variant="contained"
startIcon={<SettingsSuggestIcon />}
onClick={handleSettings}
>
Settings
</Button>
</AuthorizationComponent>
</Grid>
<Grid item>
<Button
color="primary"
variant="contained"
startIcon={<SaveIcon />}
onClick={handleSave}
>
Create
</Button>
<AuthorizationComponent allowedRoles={["admin", "owner", "write"]}>
<Button
color="primary"
variant="contained"
startIcon={<SaveIcon />}
onClick={handleSave}
>
Create
</Button>
</AuthorizationComponent>
</Grid>
<Grid item>
<Button
color="primary"
variant="contained"
startIcon={<IosShareIcon />}
onClick={handleExport}
>
Export
</Button>
<AuthorizationComponent allowedRoles={["admin", "owner", "write"]}>
<Button
color="primary"
variant="contained"
startIcon={<IosShareIcon />}
onClick={handleExport}
>
Export
</Button>
</AuthorizationComponent>
</Grid>
<Grid item>
<Button
variant="contained"
startIcon={<DownloadIcon />}
id="import-button"
aria-controls={importMenuOpen ? "import-menu" : undefined}
aria-haspopup="true"
aria-expanded={importMenuOpen ? "true" : undefined}
onClick={handleClickImportMenu}
>
<VisuallyHiddenInput
type="file"
onChange={async (e) => {
const json = await importJsonWorkflow(e);
handleImportedJson(json);
}}
ref={fileInputRef}
/>
Import
</Button>
<AuthorizationComponent allowedRoles={["admin", "owner", "write"]}>
<Button
variant="contained"
startIcon={<DownloadIcon />}
id="import-button"
aria-controls={importMenuOpen ? "import-menu" : undefined}
aria-haspopup="true"
aria-expanded={importMenuOpen ? "true" : undefined}
onClick={handleClickImportMenu}
>
<VisuallyHiddenInput
type="file"
onChange={async (e) => {
const json = await importJsonWorkflow(e);
handleImportedJson(json);
}}
ref={fileInputRef}
/>
Import
</Button>
</AuthorizationComponent>
<Menu
id="import-menu"
anchorEl={menuElement}
Expand Down Expand Up @@ -207,14 +216,16 @@ export const ButtonsMenu: React.FC<Props> = ({
/>
</Grid>
<Grid item>
<Button
color="primary"
variant="contained"
startIcon={<ClearIcon />}
onClick={handleClear}
>
Clear
</Button>
<AuthorizationComponent allowedRoles={["admin", "owner", "write"]}>
<Button
color="primary"
variant="contained"
startIcon={<ClearIcon />}
onClick={handleClear}
>
Clear
</Button>
</AuthorizationComponent>
</Grid>
</Grid>
);
Expand Down
Loading

0 comments on commit 6e761fe

Please sign in to comment.