Skip to content
This repository has been archived by the owner on Jul 24, 2024. It is now read-only.

Commit

Permalink
Merge pull request #264 from riccardo-forina/new-version-notification
Browse files Browse the repository at this point in the history
  • Loading branch information
pure-bot[bot] authored May 10, 2019
2 parents 8691031 + 85645ef commit 86b3c98
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 11 deletions.
1 change: 1 addition & 0 deletions app/ui-react/packages/ui/src/Layout/ButtonLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const ButtonLink: React.FunctionComponent<IButtonLinkProps> = ({
onClick={onClick}
className={className}
disabled={disabled || (!onClick && !href)}
{...props}
>
{children}
</button>
Expand Down
1 change: 1 addition & 0 deletions app/ui-react/packages/ui/src/Shared/DndFileChooser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ export class DndFileChooser extends React.Component<
const notifications = rejectedFiles.map(file => ({
key: file.name,
message: this.props.onUploadRejected(file.name),
persistent: false,
type: 'error' as INotificationType,
}));

Expand Down
19 changes: 12 additions & 7 deletions app/ui-react/packages/ui/src/Shared/Notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export type INotificationType = 'success' | 'info' | 'warning' | 'error';

export interface INotification {
key: string;
message: string;
message: React.ReactNode;
persistent: boolean;
type: INotificationType;
}

Expand All @@ -27,18 +28,22 @@ export class Notifications extends React.Component<INotificationsProps> {
<TimedToastNotification
key={notification.key}
type={notification.type}
persistent={false}
persistent={notification.persistent}
onDismiss={this.props.removeNotificationAction.bind(
this,
notification
)}
timerdelay={this.props.notificationTimerDelay}
>
<Container
dangerouslySetInnerHTML={{
__html: notification.message,
}}
/>
{typeof notification.message === 'string' ? (
<Container
dangerouslySetInnerHTML={{
__html: notification.message,
}}
/>
) : (
<Container>{notification.message}</Container>
)}
</TimedToastNotification>
))}
</ToastNotificationList>
Expand Down
3 changes: 2 additions & 1 deletion app/ui-react/syndesis/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"react-i18next": "^10.2.0",
"react-loadable": "^5.5.0",
"react-router": "^5.0.0",
"react-router-dom": "^5.0.0"
"react-router-dom": "^5.0.0",
"workbox-window": "^4.3.1"
},
"scripts": {
"lint": "tslint -c ../tslint.json --project .",
Expand Down
4 changes: 2 additions & 2 deletions app/ui-react/syndesis/public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"short_name": "Syndesis",
"name": "Syndesis",
"icons": [
{
"src": "favicon.ico",
Expand Down
50 changes: 49 additions & 1 deletion app/ui-react/syndesis/src/app/UI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { WithApiVersion } from '@syndesis/api';
import {
AppLayout,
AppTopMenu,
ButtonLink,
INotification,
INotificationType,
Notifications,
Expand All @@ -14,6 +15,7 @@ import { useState } from 'react';
import * as React from 'react';
import { Translation } from 'react-i18next';
import { Link, Route, Switch } from 'react-router-dom';
import { Workbox } from 'workbox-window';
import resolvers from '../modules/resolvers';
import { PageNotFound, WithErrorBoundary } from '../shared';
import { IAppRoute, IAppRoutes, IAppRouteWithChildrens } from './App';
Expand All @@ -39,12 +41,17 @@ export const UI: React.FunctionComponent<IAppUIProps> = ({ routes }) => {
};

const [notifications, setNotifications] = useState<INotification[]>([]);
const pushNotification = (msg: string, type: INotificationType) => {
const pushNotification = (
msg: React.ReactNode,
type: INotificationType,
persistent: boolean = false
) => {
setNotifications([
...notifications,
{
key: Date.now().toString(),
message: msg,
persistent,
type,
},
]);
Expand All @@ -55,6 +62,47 @@ export const UI: React.FunctionComponent<IAppUIProps> = ({ routes }) => {
);
};

React.useEffect(() => {
let refreshNotificationDisplayed = false;
// tslint:disable
if ('serviceWorker' in navigator) {
const wb = new Workbox('/service-worker.js');

const refreshApp = () => {
wb.addEventListener('controlling', event => {
window.location.reload();
});
// Send a message telling the service worker to skip waiting.
// This will trigger the `controlling` event handler above.
wb.messageSW({ type: 'SKIP_WAITING' });
};

wb.addEventListener('waiting', event => {
if (!refreshNotificationDisplayed) {
refreshNotificationDisplayed = true;
pushNotification(
<>
<div className="pull-right toast-pf-action">
<ButtonLink
onClick={refreshApp}
as={'link'}
style={{ padding: 0, border: 0 }}
>
Reload
</ButtonLink>
</div>
A new version is available.
</>,
'warning',
true
);
}
});

wb.register();
}
}, []); // eslint-disable-line

return (
<UIContext.Provider
value={{
Expand Down
46 changes: 46 additions & 0 deletions app/ui-react/typings/workbox-window/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
declare module 'workbox-window' {
class Workbox {
constructor(scriptURL: string, registerOptions?: object);

register(immediate?: boolean): Promise<any>;
active(): Promise<ServiceWorker>;
controlling(): Promise<ServiceWorker>;
getSW(): Promise<ServiceWorker>;
messageSW(data: object): Promise<object>;

addEventListener(event: 'message', callback: (data: IWorkboxEventMessage) => void): void;
addEventListener(event: 'installed', callback: (data: IWorkboxEvent) => void): void;
addEventListener(event: 'waiting', callback: (data: IWorkboxEventWaiting) => void): void;
addEventListener(event: 'controlling', callback: (data: IWorkboxEvent) => void): void;
addEventListener(event: 'activated', callback: (data: IWorkboxEvent) => void): void;
addEventListener(event: 'redundant', callback: (data: IWorkboxEvent) => void): void;
addEventListener(event: 'externalinstalled', callback: (data: IWorkboxEventExternal) => void): void;
addEventListener(event: 'externalwaiting', callback: (data: IWorkboxEventExternal) => void): void;
addEventListener(event: 'externalactivated', callback: (data: IWorkboxEventExternal) => void): void;
}

type WorkboxEvent = 'message' | 'installed' | 'waiting' | 'controlling' | 'activated' | 'redundant' | 'externalinstalled' | 'externalwaiting' | 'externalactivated';

interface IWorkboxEventBase {
originalEvent: Event;
type: WorkboxEvent;
target: Workbox;
}

interface IWorkboxEventMessage extends IWorkboxEventBase {
data: any;
}

interface IWorkboxEvent extends IWorkboxEventBase {
sw: ServiceWorker;
isUpdate: boolean|undefined;
}

interface IWorkboxEventWaiting extends IWorkboxEvent {
wasWaitingBeforeRegister: boolean|undefined;
}

interface IWorkboxEventExternal extends IWorkboxEventBase {
sw: ServiceWorker;
}
}
5 changes: 5 additions & 0 deletions app/ui-react/typings/workbox-window/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "@types/workbox-window",
"version": "1.0.0",
"license": "MIT"
}

0 comments on commit 86b3c98

Please sign in to comment.