Added a notification icon, parser, backend and basic APIs
This commit is contained in:
@@ -5896,6 +5896,7 @@ func initHandlers() {
|
|||||||
r.HandleFunc("/api/v1/files/{fileId}", shuffle.HandleDeleteFile).Methods("DELETE", "OPTIONS")
|
r.HandleFunc("/api/v1/files/{fileId}", shuffle.HandleDeleteFile).Methods("DELETE", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/files", shuffle.HandleGetFiles).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/files", shuffle.HandleGetFiles).Methods("GET", "OPTIONS")
|
||||||
|
|
||||||
|
// Introduced in 0.9.21 to handle notifications for e.g. failed Workflow
|
||||||
r.HandleFunc("/api/v1/notifications", shuffle.HandleGetNotifications).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/notifications", shuffle.HandleGetNotifications).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/notifications/{notificationId}/markasread", shuffle.HandleMarkAsRead).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/notifications/{notificationId}/markasread", shuffle.HandleMarkAsRead).Methods("GET", "OPTIONS")
|
||||||
//r.HandleFunc("/api/v1/notifications/{notificationId}/markasread", shuffle.HandleMarkAsRead).Methods("GET", "OPTIONS")
|
//r.HandleFunc("/api/v1/notifications/{notificationId}/markasread", shuffle.HandleMarkAsRead).Methods("GET", "OPTIONS")
|
||||||
|
|||||||
+51
-1
@@ -49,6 +49,36 @@ if ( window.location.port === "3000") {
|
|||||||
|
|
||||||
const App = (message, props) => {
|
const App = (message, props) => {
|
||||||
const [userdata, setUserData] = useState({});
|
const [userdata, setUserData] = useState({});
|
||||||
|
const [notifications, setNotifications] = useState([
|
||||||
|
{
|
||||||
|
"image": "https://dytvr9ot2sszz.cloudfront.net/whats-new-announcements/billboard_metricsdashbd_sept2021.png",
|
||||||
|
"created_at": 1519211809934,
|
||||||
|
"updated_at": 1519211809934,
|
||||||
|
"title": "some title",
|
||||||
|
"description": "This is a description",
|
||||||
|
"dismissable": true,
|
||||||
|
"personal": false,
|
||||||
|
"org_id": "",
|
||||||
|
"tags": ["tag1", "tag2"],
|
||||||
|
"amount": 3,
|
||||||
|
"id": "123",
|
||||||
|
"read": false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image": "https://dytvr9ot2sszz.cloudfront.net/whats-new-announcements/billboard_metricsdashbd_sept2021.png",
|
||||||
|
"created_at": 1519211809934,
|
||||||
|
"updated_at": 1519211809934,
|
||||||
|
"title": "some title",
|
||||||
|
"description": "This is a description",
|
||||||
|
"dismissable": true,
|
||||||
|
"personal": false,
|
||||||
|
"org_id": "",
|
||||||
|
"tags": ["tag1", "tag2"],
|
||||||
|
"amount": 3,
|
||||||
|
"id": "456",
|
||||||
|
"read": true,
|
||||||
|
}
|
||||||
|
]);
|
||||||
const [cookies, setCookie, removeCookie] = useCookies([]);
|
const [cookies, setCookie, removeCookie] = useCookies([]);
|
||||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||||
const [dataset, setDataset] = useState(false);
|
const [dataset, setDataset] = useState(false);
|
||||||
@@ -57,6 +87,7 @@ const App = (message, props) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dataset === false) {
|
if (dataset === false) {
|
||||||
|
getUserNotifications()
|
||||||
checkLogin()
|
checkLogin()
|
||||||
setDataset(true)
|
setDataset(true)
|
||||||
}
|
}
|
||||||
@@ -66,6 +97,25 @@ const App = (message, props) => {
|
|||||||
window.location = "/login"
|
window.location = "/login"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getUserNotifications = () => {
|
||||||
|
fetch(`${globalUrl}/api/v1/notifications`, {
|
||||||
|
credentials: "include",
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(responseJson => {
|
||||||
|
if (responseJson.success === true && responseJson.notifications !== null && responseJson.notifications !== undefined) {
|
||||||
|
console.log("RESP: ", responseJson)
|
||||||
|
setNotifications(responseJson.notifications)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log("Failed getting notifications for user: ", error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const checkLogin = () => {
|
const checkLogin = () => {
|
||||||
var baseurl = globalUrl
|
var baseurl = globalUrl
|
||||||
fetch(baseurl + "/api/v1/users/getinfo", {
|
fetch(baseurl + "/api/v1/users/getinfo", {
|
||||||
@@ -107,7 +157,7 @@ const App = (message, props) => {
|
|||||||
</div> :
|
</div> :
|
||||||
<div style={{ backgroundColor: "#1F2023", color: "rgba(255, 255, 255, 0.65)", minHeight: "100vh" }}>
|
<div style={{ backgroundColor: "#1F2023", color: "rgba(255, 255, 255, 0.65)", minHeight: "100vh" }}>
|
||||||
<ScrollToTop setCurpath={setCurpath} />
|
<ScrollToTop setCurpath={setCurpath} />
|
||||||
<Header checkLogin={checkLogin} cookies={cookies} removeCookie={removeCookie} isLoaded={isLoaded} globalUrl={globalUrl} setIsLoggedIn={setIsLoggedIn} isLoggedIn={isLoggedIn} userdata={userdata} {...props} />
|
<Header notifications={notifications} checkLogin={checkLogin} cookies={cookies} removeCookie={removeCookie} isLoaded={isLoaded} globalUrl={globalUrl} setIsLoggedIn={setIsLoggedIn} isLoggedIn={isLoggedIn} userdata={userdata} {...props} />
|
||||||
<div style={{marginTop: 60}}/>
|
<div style={{marginTop: 60}}/>
|
||||||
<Route exact path="/login" render={props => <LoginPage isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} checkLogin={checkLogin} {...props} />} />
|
<Route exact path="/login" render={props => <LoginPage isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} checkLogin={checkLogin} {...props} />} />
|
||||||
<Route exact path="/admin" render={props => <Admin userdata={userdata} isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
|
<Route exact path="/admin" render={props => <Admin userdata={userdata} isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {Link} from 'react-router-dom';
|
|||||||
|
|
||||||
import { useTheme } from '@material-ui/core/styles';
|
import { useTheme } from '@material-ui/core/styles';
|
||||||
|
|
||||||
import { Badge, Typography, Paper, Tooltip, List, Avatar, Menu, ListItem, MenuItem, Select, Button, IconButton, Grid } from '@material-ui/core';
|
import { Chip, Badge, Typography, Paper, Tooltip, List, Avatar, Menu, ListItem, MenuItem, Select, Button, IconButton, Grid } from '@material-ui/core';
|
||||||
import { Notifications as NotificationsIcon, Home as HomeIcon, Polymer as PolymerIcon, Apps as AppsIcon, Description as DescriptionIcon} from '@material-ui/icons';
|
import { Notifications as NotificationsIcon, Home as HomeIcon, Polymer as PolymerIcon, Apps as AppsIcon, Description as DescriptionIcon} from '@material-ui/icons';
|
||||||
import { useAlert } from "react-alert";
|
import { useAlert } from "react-alert";
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ const hoverColor = "#f85a3e"
|
|||||||
const hoverOutColor = "#e8eaf6"
|
const hoverOutColor = "#e8eaf6"
|
||||||
|
|
||||||
const Header = props => {
|
const Header = props => {
|
||||||
const { globalUrl, isLoggedIn, removeCookie, homePage, isLoaded, userdata, cookies } = props;
|
const { globalUrl, notifications, isLoggedIn, removeCookie, homePage, isLoaded, userdata, cookies } = props;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const [HomeHoverColor, setHomeHoverColor] = useState(hoverOutColor);
|
const [HomeHoverColor, setHomeHoverColor] = useState(hoverOutColor);
|
||||||
@@ -22,6 +22,7 @@ const Header = props => {
|
|||||||
const [DocsHoverColor, setDocsHoverColor] = useState(hoverOutColor);
|
const [DocsHoverColor, setDocsHoverColor] = useState(hoverOutColor);
|
||||||
const [HelpHoverColor, setHelpHoverColor] = useState(hoverOutColor);
|
const [HelpHoverColor, setHelpHoverColor] = useState(hoverOutColor);
|
||||||
const [anchorEl, setAnchorEl] = React.useState(null);
|
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||||
|
const [anchorElAvatar, setAnchorElAvatar] = React.useState(null);
|
||||||
const alert = useAlert()
|
const alert = useAlert()
|
||||||
|
|
||||||
const hrefStyle = {
|
const hrefStyle = {
|
||||||
@@ -29,6 +30,36 @@ const Header = props => {
|
|||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dismissNotification = (alert_id) => {
|
||||||
|
// Don't really care about the logout
|
||||||
|
fetch(`${globalUrl}/api/v1/notifications/${alert_id}/markasread`, {
|
||||||
|
credentials: "include",
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(function(response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.log("Error in response")
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
}).then(function(responseJson) {
|
||||||
|
if (responseJson.success !== undefined && responseJson.success) {
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload()
|
||||||
|
}, 2000)
|
||||||
|
} else {
|
||||||
|
alert.error("Failed changing org: ", responseJson.reason)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log("error changing: ", error)
|
||||||
|
//removeCookie("session_token", {path: "/"})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// DEBUG HERE
|
// DEBUG HERE
|
||||||
const handleClickLogout = () => {
|
const handleClickLogout = () => {
|
||||||
console.log("COOKIES: ", cookies, "Remover: ", removeCookie)
|
console.log("COOKIES: ", cookies, "Remover: ", removeCookie)
|
||||||
@@ -146,17 +177,56 @@ const Header = props => {
|
|||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
|
setAnchorElAvatar(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const notifications = [{
|
const chipStyle = {
|
||||||
"image": "https://dytvr9ot2sszz.cloudfront.net/whats-new-announcements/billboard_metricsdashbd_sept2021.png",
|
backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",
|
||||||
"date": "1519211809934",
|
}
|
||||||
"title": "some title",
|
const NotificationItem = (props) => {
|
||||||
"description": "This is a escription",
|
const {data} = props
|
||||||
"dismissable": true,
|
|
||||||
"personal": false,
|
return (
|
||||||
"org_id": "",
|
<Paper style={{width: 300, padding: 25, borderBottom: "1px solid rgba(255,255,255,0.4)"}}>
|
||||||
}]
|
<Typography variant="h6">
|
||||||
|
{new Date(data.updated_at).toISOString()}
|
||||||
|
</Typography >
|
||||||
|
<Typography variant="h6">
|
||||||
|
{data.title}
|
||||||
|
</Typography >
|
||||||
|
{data.image !== undefined && data.image !== null && data.image.length > 0 ?
|
||||||
|
<img alt={data.title} src={data.image} style={{height: 100, width: 100, }} />
|
||||||
|
:
|
||||||
|
null
|
||||||
|
}
|
||||||
|
<Typography variant="body1">
|
||||||
|
{data.description}
|
||||||
|
</Typography >
|
||||||
|
{/*data.tags !== undefined && data.tags !== null && data.tags.length > 0 ?
|
||||||
|
data.tags.map((tag, index) => {
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
key={index}
|
||||||
|
style={chipStyle}
|
||||||
|
label={tag}
|
||||||
|
onClick={() => {
|
||||||
|
}}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
: null */}
|
||||||
|
{data.read === false ?
|
||||||
|
<Button color="primary" variant="contained" style={{marginTop: 15}} onClick={() => {
|
||||||
|
dismissNotification(data.id)
|
||||||
|
}}>
|
||||||
|
Dismiss
|
||||||
|
</Button>
|
||||||
|
: null}
|
||||||
|
</Paper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const notificationMenu =
|
const notificationMenu =
|
||||||
<span style={{zIndex: 10001}}>
|
<span style={{zIndex: 10001}}>
|
||||||
@@ -172,27 +242,14 @@ const Header = props => {
|
|||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
keepMounted
|
keepMounted
|
||||||
open={Boolean(anchorEl)}
|
open={Boolean(anchorEl)}
|
||||||
style={{zIndex: 10002}}
|
style={{zIndex: 10002, maxHeight: "100vh", overflowX: "hidden", overflowY: "auto",}}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
handleClose()
|
handleClose()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{notifications.map((data, index) => {
|
{notifications.map((data, index) => {
|
||||||
return (
|
return (
|
||||||
<MenuItem onClick={(event) => {}}>
|
<NotificationItem data={data} key={index} />
|
||||||
<Paper style={{width: 300, height: 150, }}>
|
|
||||||
<Grid container direction="row" alignItems="center">
|
|
||||||
<Grid item>
|
|
||||||
<Typography variant="h6">
|
|
||||||
{new Date(data.date).toISOString()}
|
|
||||||
</Typography >
|
|
||||||
<Typography variant="h6">
|
|
||||||
{data.title}
|
|
||||||
</Typography >
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Paper>
|
|
||||||
</MenuItem>
|
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</Menu>
|
</Menu>
|
||||||
@@ -202,15 +259,15 @@ const Header = props => {
|
|||||||
const avatarMenu =
|
const avatarMenu =
|
||||||
<span style={{zIndex: 10001}}>
|
<span style={{zIndex: 10001}}>
|
||||||
<IconButton color="primary" style={{zIndex: 10001, marginRight: 15, }} aria-controls="simple-menu" aria-haspopup="true" onClick={(event) => {
|
<IconButton color="primary" style={{zIndex: 10001, marginRight: 15, }} aria-controls="simple-menu" aria-haspopup="true" onClick={(event) => {
|
||||||
setAnchorEl(event.currentTarget);
|
setAnchorElAvatar(event.currentTarget);
|
||||||
}}>
|
}}>
|
||||||
<Avatar style={{height: 35, width: 35,}} alt="Your username here" src="" />
|
<Avatar style={{height: 35, width: 35,}} alt="Your username here" src="" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Menu
|
<Menu
|
||||||
id="simple-menu"
|
id="simple-menu"
|
||||||
anchorEl={anchorEl}
|
anchorEl={anchorElAvatar}
|
||||||
keepMounted
|
keepMounted
|
||||||
open={Boolean(anchorEl)}
|
open={Boolean(anchorElAvatar)}
|
||||||
style={{zIndex: 10002}}
|
style={{zIndex: 10002}}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
handleClose()
|
handleClose()
|
||||||
@@ -315,7 +372,7 @@ const Header = props => {
|
|||||||
</div>
|
</div>
|
||||||
<div style={{flex: "10", display: "flex", flexDirection: "row-reverse"}}>
|
<div style={{flex: "10", display: "flex", flexDirection: "row-reverse"}}>
|
||||||
{avatarMenu}
|
{avatarMenu}
|
||||||
{notificationMenu}
|
{/*notificationMenu*/}
|
||||||
{userdata === undefined || userdata.admin === undefined || userdata.admin === null || !userdata.admin ? null :
|
{userdata === undefined || userdata.admin === undefined || userdata.admin === null || !userdata.admin ? null :
|
||||||
<Link to="/admin" style={hrefStyle}>
|
<Link to="/admin" style={hrefStyle}>
|
||||||
<Button color="primary" variant="contained" style={{marginRight: 15, marginTop: 12}}>
|
<Button color="primary" variant="contained" style={{marginRight: 15, marginTop: 12}}>
|
||||||
|
|||||||
Reference in New Issue
Block a user