From 467a6b16fbfbd195a6e8c0d375e73e3eb3c0d6a2 Mon Sep 17 00:00:00 2001 From: Chaiwat Ekkaewnumchai Date: Fri, 23 Oct 2020 04:33:04 -0700 Subject: [PATCH] Add Notification View Summary: This stack tries to migrate notification system to Sandy. This diff contains on the view; other functionalities aren't working. Also, some of the views will be implemented as functionalities are added. Reviewed By: mweststrate Differential Revision: D24390370 fbshipit-source-id: 8e11a01d9462934ff1fadf411e7e8f57ca7ef078 --- desktop/app/src/sandy-chrome/LeftRail.tsx | 23 ++- desktop/app/src/sandy-chrome/SandyApp.tsx | 20 +- .../notification/Notification.tsx | 188 ++++++++++++++++++ 3 files changed, 224 insertions(+), 7 deletions(-) create mode 100644 desktop/app/src/sandy-chrome/notification/Notification.tsx diff --git a/desktop/app/src/sandy-chrome/LeftRail.tsx b/desktop/app/src/sandy-chrome/LeftRail.tsx index 9d2291c97..5107d477c 100644 --- a/desktop/app/src/sandy-chrome/LeftRail.tsx +++ b/desktop/app/src/sandy-chrome/LeftRail.tsx @@ -118,7 +118,10 @@ export function LeftRail({ }} /> } title="Plugin Manager" /> - } title="Notifications" /> + state.notifications.activeNotifications.length, + ); + return ( + } + title="Notifications" + selected={toplevelSelection === 'notification'} + count={notificationCount} + onClick={() => setToplevelSelection('notification')} + /> + ); +} + function DebugLogsButton({ toplevelSelection, setToplevelSelection, diff --git a/desktop/app/src/sandy-chrome/SandyApp.tsx b/desktop/app/src/sandy-chrome/SandyApp.tsx index accc8731b..a879223e9 100644 --- a/desktop/app/src/sandy-chrome/SandyApp.tsx +++ b/desktop/app/src/sandy-chrome/SandyApp.tsx @@ -24,8 +24,13 @@ import {toggleLeftSidebarVisible} from '../reducers/application'; import {AppInspect} from './appinspect/AppInspect'; import PluginContainer from '../PluginContainer'; import {ContentContainer} from './ContentContainer'; +import {Notification} from './notification/Notification'; -export type ToplevelNavItem = 'appinspect' | 'flipperlogs' | undefined; +export type ToplevelNavItem = + | 'appinspect' + | 'flipperlogs' + | 'notification' + | undefined; export type ToplevelProps = { toplevelSelection: ToplevelNavItem; setToplevelSelection: (_newSelection: ToplevelNavItem) => void; @@ -51,7 +56,8 @@ export function SandyApp({logger}: {logger: Logger}) { const setToplevelSelection = useCallback( (newSelection: ToplevelNavItem) => { // toggle sidebar visibility if needed - const hasLeftSidebar = newSelection === 'appinspect'; + const hasLeftSidebar = + newSelection === 'appinspect' || newSelection === 'notification'; if (hasLeftSidebar) { if (newSelection === toplevelSelection) { dispatch(toggleLeftSidebarVisible()); @@ -76,10 +82,12 @@ export function SandyApp({logger}: {logger: Logger}) { // eslint-disable-next-line }, []); - const leftMenuContent = - leftSidebarVisible && toplevelSelection === 'appinspect' ? ( - - ) : null; + const leftMenuContent = !leftSidebarVisible ? null : toplevelSelection === + 'appinspect' ? ( + + ) : toplevelSelection === 'notification' ? ( + + ) : null; return ( diff --git a/desktop/app/src/sandy-chrome/notification/Notification.tsx b/desktop/app/src/sandy-chrome/notification/Notification.tsx new file mode 100644 index 000000000..5daad7784 --- /dev/null +++ b/desktop/app/src/sandy-chrome/notification/Notification.tsx @@ -0,0 +1,188 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import React from 'react'; +import {Layout, styled} from '../../ui'; +import {Input, Typography, Button, Collapse} from 'antd'; +import { + DownOutlined, + UpOutlined, + SearchOutlined, + ExclamationCircleOutlined, + SettingOutlined, + DeleteOutlined, +} from '@ant-design/icons'; +import {LeftSidebar, SidebarTitle} from '../LeftSidebar'; +import {PluginNotification} from '../../reducers/notifications'; +import {theme} from '../theme'; + +const {Title, Text, Paragraph} = Typography; + +// NOTE: remove after the component link to state +const notificationExample: Array = [ + { + notification: { + id: 'testid_0', + title: ` + CRASH: FATAL EXCEPTION: + mainReason: java.lang.RuntimeException: Artificially triggered crash from Flipper sample app + `, + message: + 'very very very very very very very very very very very very very very very very very very very very very long', + severity: 'error', + }, + pluginId: 'testPluginId', + client: 'iPortaldroid', + }, + { + notification: { + id: 'testid_1', + title: `CRASH: FATAL EXCEPTION: + mainReason: java.lang.RuntimeException: Artificially triggered crash from Flipper sample app + `, + message: `FATAL EXCEPTION: main`, + severity: 'error', + }, + pluginId: 'testPluginId', + client: 'iPortaldroid', + }, + { + notification: { + id: 'testid_2', + action: '1', + title: `CRASH: FATAL EXCEPTION: mainReason: java.lang.RuntimeException: Artificially triggered`, + message: `Callstack: FATAL EXCEPTION: main Process: com.facebook.flipper.sample, PID: 1646 java.lang.RuntimeException: Artificially triggered crash from Flipper sample app at com.facebook.flipper.sample.RootComponentSpec`, + severity: 'error', + category: + 'java.lang.RuntimeException: Artificially triggered crash from Flipper sample app', + }, + pluginId: 'CrashReporter', + client: 'emulator-5554', + }, +]; + +const CollapseContainer = styled.div({ + '.ant-collapse-ghost .ant-collapse-item': { + '& > .ant-collapse-header': { + paddingLeft: '16px', + }, + '& > .ant-collapse-content > .ant-collapse-content-box': { + padding: 0, + }, + }, +}); + +function DetailCollapse({detail}: {detail: string | React.ReactNode}) { + const detailView = + typeof detail === 'string' ? ( + + {detail} + + ) : ( + detail + ); + return ( + + + isActive ? ( + + ) : ( + + ) + }> + + View detail + + }> + {detailView} + + + + ); +} + +function NotificationEntry({notification}: {notification: PluginNotification}) { + const {notification: content, pluginId, client} = notification; + // TODO: figure out how to transform app name to icon + const icon = React.createElement(ExclamationCircleOutlined, { + style: {color: theme.primaryColor}, + }); + return ( + + + {icon} + {pluginId} + + + {content.title} + + + {client} + + + + + ); +} + +function NotificationList({ + notifications, +}: { + notifications: Array; +}) { + return ( + + + {notifications.map((notification) => ( + + ))} + + + ); +} + +export function Notification() { + const actions = ( +
+ + + + +
+ ); + return ( + + + + notifications + + } /> + + + + + + ); +}