/** * React component for control bar */ import * as React from "react"; import { ClientDefaults, KeyCodes } from "../../../Common/Constants"; import AnimateHeight from "react-animate-height"; import LoadingIcon from "../../../../images/loading.svg"; import ErrorBlackIcon from "../../../../images/error_black.svg"; import infoBubbleIcon from "../../../../images/info-bubble-9x9.svg"; import InfoIcon from "../../../../images/info_color.svg"; import ErrorRedIcon from "../../../../images/error_red.svg"; import LoaderIcon from "../../../../images/circular_loader_black_16x16.gif"; import ClearIcon from "../../../../images/Clear.svg"; import ChevronUpIcon from "../../../../images/QueryBuilder/CollapseChevronUp_16x.png"; import ChevronDownIcon from "../../../../images/QueryBuilder/CollapseChevronDown_16x.png"; /** * Log levels */ export enum ConsoleDataType { Info = 0, Error = 1, InProgress = 2 } /** * Interface for the data/content that will be recorded */ export interface ConsoleData { type: ConsoleDataType; date: string; message: string; id?: string; } export interface NotificationConsoleComponentProps { isConsoleExpanded: boolean; onConsoleExpandedChange: (isExpanded: boolean) => void; consoleData: ConsoleData[]; onConsoleDataChange: (consoleData: ConsoleData[]) => void; } interface NotificationConsoleComponentState { headerStatus: string; selectedFilter: string; isExpanded: boolean; } export class NotificationConsoleComponent extends React.Component< NotificationConsoleComponentProps, NotificationConsoleComponentState > { private static readonly transitionDurationMs = 200; private static readonly FilterOptions = ["All", "In Progress", "Info", "Error"]; private headerTimeoutId: number; private prevHeaderStatus: string; private consoleHeaderElement: HTMLElement; constructor(props: NotificationConsoleComponentProps) { super(props); this.state = { headerStatus: "", selectedFilter: NotificationConsoleComponent.FilterOptions[0], isExpanded: props.isConsoleExpanded }; this.prevHeaderStatus = null; } public componentDidUpdate( prevProps: NotificationConsoleComponentProps, prevState: NotificationConsoleComponentState ) { const currentHeaderStatus = NotificationConsoleComponent.extractHeaderStatus(this.props); if ( this.prevHeaderStatus !== currentHeaderStatus && currentHeaderStatus !== null && prevState.headerStatus !== currentHeaderStatus ) { this.setHeaderStatus(currentHeaderStatus); } // Call setHeaderStatus() only to clear HeaderStatus or update status to a different value. // Cache previous headerStatus externally. Otherwise, simply comparing with previous state/props will cause circular // updates: currentHeaderStatus -> "" -> currentHeaderStatus -> "" etc. this.prevHeaderStatus = currentHeaderStatus; if (prevProps.isConsoleExpanded !== this.props.isConsoleExpanded) { // Sync state and props // TODO react anti-pattern: remove isExpanded from state which duplicates prop's isConsoleExpanded this.setState({ isExpanded: this.props.isConsoleExpanded }); } } public render(): JSX.Element { const numInProgress = this.props.consoleData.filter((data: ConsoleData) => data.type === ConsoleDataType.InProgress) .length; const numErroredItems = this.props.consoleData.filter((data: ConsoleData) => data.type === ConsoleDataType.Error) .length; const numInfoItems = this.props.consoleData.filter((data: ConsoleData) => data.type === ConsoleDataType.Info) .length; return (