Skip to content

Commit fcf7402

Browse files
committed
Show app-level notifications on dashboard
1 parent 4bf6fef commit fcf7402

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

components/dashboard/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import SelectIDEModal from "./settings/SelectIDEModal";
4949
import { StartPage, StartPhase } from "./start/StartPage";
5050
import { isGitpodIo } from "./utils";
5151
import { BlockedRepositories } from "./admin/BlockedRepositories";
52+
import { AppNotifications } from "./AppNotifications";
5253

5354
const Setup = React.lazy(() => import(/* webpackPrefetch: true */ "./Setup"));
5455
const Workspaces = React.lazy(() => import(/* webpackPrefetch: true */ "./workspaces/Workspaces"));
@@ -346,6 +347,7 @@ function App() {
346347
<Route>
347348
<div className="container">
348349
<Menu />
350+
<AppNotifications />
349351
<Switch>
350352
<Route path={projectsPathNew} exact component={NewProject} />
351353
<Route path="/open" exact component={Open} />
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License-AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { useEffect, useState } from "react";
8+
import Alert from "./components/Alert";
9+
import { getGitpodService } from "./service/service";
10+
11+
const KEY_APP_NOTIFICATIONS = "KEY_APP_NOTIFICATIONS";
12+
13+
export function AppNotifications() {
14+
const [notifications, setNotifications] = useState<string[]>([]);
15+
16+
useEffect(() => {
17+
let localState = getLocalStorageObject(KEY_APP_NOTIFICATIONS);
18+
if (Array.isArray(localState)) {
19+
setNotifications(localState);
20+
return;
21+
}
22+
(async () => {
23+
const serverState = await getGitpodService().server.getNotifications();
24+
setNotifications(serverState);
25+
setLocalStorageObject(KEY_APP_NOTIFICATIONS, serverState);
26+
})();
27+
}, []);
28+
29+
const topNotification = notifications[0];
30+
if (topNotification === undefined) {
31+
return null;
32+
}
33+
34+
const dismissNotification = () => {
35+
removeLocalStorageObject(KEY_APP_NOTIFICATIONS);
36+
setNotifications([]);
37+
};
38+
39+
return (
40+
<div className="app-container pt-2">
41+
<Alert
42+
type={"warning"}
43+
closable={true}
44+
onClose={() => dismissNotification()}
45+
showIcon={true}
46+
className="flex rounded mb-2 w-full"
47+
>
48+
<span>{topNotification}</span>
49+
</Alert>
50+
</div>
51+
);
52+
}
53+
54+
function getLocalStorageObject(key: string): any {
55+
try {
56+
const string = window.localStorage.getItem(key);
57+
if (!string) {
58+
return;
59+
}
60+
return JSON.parse(string);
61+
} catch (error) {
62+
return;
63+
}
64+
}
65+
66+
function removeLocalStorageObject(key: string): void {
67+
window.localStorage.removeItem(key);
68+
}
69+
70+
function setLocalStorageObject(key: string, object: Object): void {
71+
try {
72+
window.localStorage.setItem(key, JSON.stringify(object));
73+
} catch (error) {
74+
console.error("Setting localstorage item failed", key, object, error);
75+
}
76+
}

components/dashboard/src/components/Alert.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export interface AlertProps {
2626
// Without background color, default false
2727
light?: boolean;
2828
closable?: boolean;
29+
onClose?: () => void;
2930
showIcon?: boolean;
3031
icon?: React.ReactNode;
3132
children?: React.ReactNode;
@@ -80,7 +81,15 @@ export default function Alert(props: AlertProps) {
8081
<span className="flex-1 text-left">{props.children}</span>
8182
{props.closable && (
8283
<span className={`mt-1 ml-4 h-4 w-4`}>
83-
<XSvg onClick={() => setVisible(false)} className="w-3 h-4 cursor-pointer"></XSvg>
84+
<XSvg
85+
onClick={() => {
86+
setVisible(false);
87+
if (props.onClose) {
88+
props.onClose();
89+
}
90+
}}
91+
className="w-3 h-4 cursor-pointer"
92+
></XSvg>
8493
</span>
8594
)}
8695
</div>

0 commit comments

Comments
 (0)