implemented user rights

master
Tudor Stanciu 2023-04-04 18:28:01 +03:00
parent 6bad079252
commit b9726950cc
14 changed files with 137 additions and 21 deletions

14
package-lock.json generated
View File

@ -1316,21 +1316,21 @@
"integrity": "sha512-6NBXdZgRrHbLXw4EMgyqCIzOVAlUgr1+8QGHjlA+n5Iw2Lp/+dP3FTgAfPW/cHR/PBI3cj7gUDVUf/zD/qTPOQ==" "integrity": "sha512-6NBXdZgRrHbLXw4EMgyqCIzOVAlUgr1+8QGHjlA+n5Iw2Lp/+dP3FTgAfPW/cHR/PBI3cj7gUDVUf/zD/qTPOQ=="
}, },
"@flare/tuitio-client": { "@flare/tuitio-client": {
"version": "1.2.3", "version": "1.2.4",
"resolved": "https://lab.code-rove.com/public-node-registry/@flare/tuitio-client/-/tuitio-client-1.2.3.tgz", "resolved": "https://lab.code-rove.com/public-node-registry/@flare/tuitio-client/-/tuitio-client-1.2.4.tgz",
"integrity": "sha512-m1cJZNTLNXwviD2hkeAvs6I/jlC17GHkUraExfaEaYOUrmDpovE64sg6Xheb01mXnDADCdA2MYxdJgxODNJAqw==", "integrity": "sha512-qLVneFf/uACqnr6fIDceVXvIHDmE1y7z6S/sVUPAPHipXmVq8bCiqvCeyGb+If0Mjj16WexedF+FNBltg5UYCA==",
"requires": { "requires": {
"@flare/js-utils": "^1.1.0", "@flare/js-utils": "^1.1.0",
"axios": "^1.3.2" "axios": "^1.3.2"
} }
}, },
"@flare/tuitio-client-react": { "@flare/tuitio-client-react": {
"version": "1.2.3", "version": "1.2.4",
"resolved": "https://lab.code-rove.com/public-node-registry/@flare/tuitio-client-react/-/tuitio-client-react-1.2.3.tgz", "resolved": "https://lab.code-rove.com/public-node-registry/@flare/tuitio-client-react/-/tuitio-client-react-1.2.4.tgz",
"integrity": "sha512-ry8eiNJh+TrAVu+PN/vuZ6MJXVMDDEBixz+X37rPOKzY283FhiLSJt76l0rBjfSKuFHyqE8Bx5g4mJ0XgutjMg==", "integrity": "sha512-AM/TXHI8J9YxBMS8P6YHJANYRwVGGNsssR7HU3Mo+EgkTxwImOgT1nkKNZEEQmx1O/KlOxYz58VD3YyDzA0RCQ==",
"requires": { "requires": {
"@flare/js-utils": "^1.1.0", "@flare/js-utils": "^1.1.0",
"@flare/tuitio-client": "^1.2.3" "@flare/tuitio-client": "^1.2.4"
} }
}, },
"@gar/promisify": { "@gar/promisify": {

View File

@ -14,7 +14,7 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@flare/js-utils": "^1.1.0", "@flare/js-utils": "^1.1.0",
"@flare/tuitio-client-react": "^1.2.3", "@flare/tuitio-client-react": "^1.2.4",
"@material-ui/core": "^4.11.2", "@material-ui/core": "^4.11.2",
"@material-ui/icons": "^4.11.2", "@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.61", "@material-ui/lab": "^4.0.0-alpha.61",

View File

@ -36,6 +36,18 @@
"Label": "Login", "Label": "Login",
"IncorrectCredentials": "Incorrect credentials." "IncorrectCredentials": "Incorrect credentials."
}, },
"Dashboard": {
"Announcements": {
"Guest": {
"Title": "Hello there! I'm glad you're here!",
"Message": "You are currently browsing my application as a guest. Keep in mind that you cannot perform actions, and most of the data you see is fake. The purpose of the application in this state is for presentation."
},
"User": {
"Title": "Welcome back, {{userName}}",
"Message": "The application is in continuous development, so if you identify a problem, please report it. Thank you!"
}
}
},
"User": { "User": {
"Profile": { "Profile": {
"Label": "Profile", "Label": "Profile",

View File

@ -27,6 +27,18 @@
"Label": "Autentificare", "Label": "Autentificare",
"IncorrectCredentials": "Credențiale incorecte." "IncorrectCredentials": "Credențiale incorecte."
}, },
"Dashboard": {
"Announcements": {
"Guest": {
"Title": "Salutare! Sunt bucuros ca ești aici!",
"Message": "În acest moment, răsfoiești aplicația mea că invitat. Reține că nu poți efectua acțiuni, iar majoritatea datelor pe care le vezi sunt false. Scopul aplicației în această stare este de prezentare."
},
"User": {
"Title": "Bine ai revenit, {{userName}}",
"Message": "Aplicația este în continuă dezvoltare, așa că dacă identifici o problemă, te rog să o raportezi. Mulțumesc!"
}
}
},
"User": { "User": {
"Profile": { "Profile": {
"Label": "Profil", "Label": "Profil",

View File

@ -4,7 +4,7 @@ import PageNotFound from "./PageNotFound";
import NetworkContainer from "../../features/network/components/NetworkContainer"; import NetworkContainer from "../../features/network/components/NetworkContainer";
import SystemContainer from "../../features/system/SystemContainer"; import SystemContainer from "../../features/system/SystemContainer";
import SettingsContainer from "../../features/settings/SettingsContainer"; import SettingsContainer from "../../features/settings/SettingsContainer";
import DashboardContainer from "../../features/dashboard/components/DashboardContainer"; import DashboardContainer from "../../features/dashboard/DashboardContainer";
import UserProfileContainer from "../../features/user/profile/card/UserProfileContainer"; import UserProfileContainer from "../../features/user/profile/card/UserProfileContainer";
import AboutContainer from "../../features/about/AboutContainer"; import AboutContainer from "../../features/about/AboutContainer";

View File

@ -0,0 +1,10 @@
import React from "react";
import AnnouncementsSection from "./announcements/AnnouncementsSection";
const DashboardContainer = () => (
<>
<AnnouncementsSection />
</>
);
export default DashboardContainer;

View File

@ -0,0 +1,19 @@
import React from "react";
import GuestAnnouncement from "./GuestAnnouncement";
import UserAnnouncement from "./UserAnnouncement";
import { useTuitioUserInfo } from "@flare/tuitio-client-react";
const AnnouncementsSection = () => {
const { userInfo, isGuest } = useTuitioUserInfo();
const loading = !userInfo;
if (loading) return "";
return (
<>
{isGuest && <GuestAnnouncement />}
{!isGuest && <UserAnnouncement userData={userInfo} />}
</>
);
};
export default AnnouncementsSection;

View File

@ -0,0 +1,21 @@
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import { Alert, AlertTitle } from "@material-ui/lab";
import styles from "../styles";
import { useTranslation } from "react-i18next";
const useStyles = makeStyles(styles);
export default function GuestAnnouncement() {
const classes = useStyles();
const { t } = useTranslation();
return (
<div className={classes.alert}>
<Alert variant="outlined" severity="warning">
<AlertTitle>{t("Dashboard.Announcements.Guest.Title")}</AlertTitle>
{t("Dashboard.Announcements.Guest.Message")}
</Alert>
</div>
);
}

View File

@ -0,0 +1,30 @@
import React from "react";
import PropTypes from "prop-types";
import { makeStyles } from "@material-ui/core/styles";
import { Alert, AlertTitle } from "@material-ui/lab";
import styles from "../styles";
import { useTranslation } from "react-i18next";
const useStyles = makeStyles(styles);
export default function UserAnnouncement({ userData }) {
const classes = useStyles();
const { t } = useTranslation();
return (
<div className={classes.alert}>
<Alert variant="outlined" severity="info">
<AlertTitle>
{t("Dashboard.Announcements.User.Title", {
userName: userData.firstName
})}
</AlertTitle>
{t("Dashboard.Announcements.User.Message")}
</Alert>
</div>
);
}
UserAnnouncement.propTypes = {
userData: PropTypes.object.isRequired
};

View File

@ -1,5 +0,0 @@
import React from "react";
const DashboardContainer = () => <h2>In development...</h2>;
export default DashboardContainer;

View File

@ -0,0 +1,10 @@
const styles = theme => ({
alert: {
width: "100%",
"& > * + *": {
marginTop: theme.spacing(1)
}
}
});
export default styles;

View File

@ -3,7 +3,7 @@ import PropTypes from "prop-types";
import { IconButton, Tooltip } from "@material-ui/core"; import { IconButton, Tooltip } from "@material-ui/core";
const ActionButton = React.forwardRef((props, _ref) => { const ActionButton = React.forwardRef((props, _ref) => {
const { action, machine, callback } = props; const { action, machine, callback, disabled } = props;
const id = `machine-item-${machine.machineId}-${action.code}`; const id = `machine-item-${machine.machineId}-${action.code}`;
const handleActionClick = event => { const handleActionClick = event => {
action.effect(machine, event); action.effect(machine, event);
@ -22,6 +22,7 @@ const ActionButton = React.forwardRef((props, _ref) => {
size={"small"} size={"small"}
onFocus={event => event.stopPropagation()} onFocus={event => event.stopPropagation()}
onClick={handleActionClick} onClick={handleActionClick}
disabled={disabled}
> >
<action.icon /> <action.icon />
</IconButton> </IconButton>
@ -39,7 +40,8 @@ ActionButton.propTypes = {
tooltip: PropTypes.string.isRequired, tooltip: PropTypes.string.isRequired,
effect: PropTypes.func.isRequired effect: PropTypes.func.isRequired
}).isRequired, }).isRequired,
callback: PropTypes.func callback: PropTypes.func,
disabled: PropTypes.bool
}; };
export default ActionButton; export default ActionButton;

View File

@ -5,11 +5,13 @@ import ActionButton from "./ActionButton";
import { Menu } from "@material-ui/core"; import { Menu } from "@material-ui/core";
import { MoreHoriz } from "@material-ui/icons"; import { MoreHoriz } from "@material-ui/icons";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useTuitioUserInfo } from "@flare/tuitio-client-react";
const ActionsGroup = ({ machine, actions, addLog }) => { const ActionsGroup = ({ machine, actions, addLog }) => {
const [menuAnchor, setMenuAnchor] = useState(null); const [menuAnchor, setMenuAnchor] = useState(null);
const { t } = useTranslation(); const { t } = useTranslation();
const { isSysAdmin } = useTuitioUserInfo();
const mainActions = useMemo( const mainActions = useMemo(
() => actions.filter(a => a.main === true), () => actions.filter(a => a.main === true),
@ -31,12 +33,13 @@ const ActionsGroup = ({ machine, actions, addLog }) => {
return ( return (
<> <>
<WakeComponent machine={machine} addLog={addLog} /> <WakeComponent machine={machine} addLog={addLog} disabled={!isSysAdmin} />
{mainActions.map(action => ( {mainActions.map(action => (
<ActionButton <ActionButton
key={`machine-item-${machine.machineId}-${action.code}`} key={`machine-item-${machine.machineId}-${action.code}`}
action={action} action={action}
machine={machine} machine={machine}
disabled={!isSysAdmin}
/> />
))} ))}
<ActionButton <ActionButton
@ -62,6 +65,7 @@ const ActionsGroup = ({ machine, actions, addLog }) => {
action={action} action={action}
machine={machine} machine={machine}
callback={handleMenuClose} callback={handleMenuClose}
disabled={!isSysAdmin}
/> />
))} ))}
</Menu> </Menu>

View File

@ -11,7 +11,7 @@ const initialState = { on: false };
const defaultPingInterval = 1200000; //20 minutes const defaultPingInterval = 1200000; //20 minutes
const defaultStartingTime = 300000; //5 minutes const defaultStartingTime = 300000; //5 minutes
const WakeComponent = ({ machine, addLog }) => { const WakeComponent = ({ machine, addLog, disabled }) => {
const [state, setState] = useState(initialState); const [state, setState] = useState(initialState);
const [trigger, setTrigger] = useState(false); const [trigger, setTrigger] = useState(false);
@ -91,9 +91,9 @@ const WakeComponent = ({ machine, addLog }) => {
<IconButton <IconButton
id={`machine-${machine.machineId}-wake`} id={`machine-${machine.machineId}-wake`}
size={"small"} size={"small"}
disabled={state.on} disabled={disabled || state.on}
onClick={handleWakeClick} onClick={handleWakeClick}
style={state.on ? { color: "#33cc33" } : {}} style={state.on ? { color: "#33cc33" } : undefined}
onFocus={event => event.stopPropagation()} onFocus={event => event.stopPropagation()}
> >
<PowerSettingsNew /> <PowerSettingsNew />
@ -105,7 +105,8 @@ const WakeComponent = ({ machine, addLog }) => {
WakeComponent.propTypes = { WakeComponent.propTypes = {
machine: PropTypes.object.isRequired, machine: PropTypes.object.isRequired,
addLog: PropTypes.func.isRequired addLog: PropTypes.func.isRequired,
disabled: PropTypes.bool
}; };
export default WakeComponent; export default WakeComponent;