Move notification console to react (#400)

This commit is contained in:
victor-meng 2021-01-26 15:32:37 -08:00 committed by GitHub
parent 59ec18cd9b
commit bd4d8da065
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 370 additions and 218 deletions

View File

@ -958,7 +958,6 @@ exports[`SettingsComponent renders 1`] = `
"isMongoIndexingEnabled": [Function], "isMongoIndexingEnabled": [Function],
"isNotebookEnabled": [Function], "isNotebookEnabled": [Function],
"isNotebooksEnabledForAccount": [Function], "isNotebooksEnabledForAccount": [Function],
"isNotificationConsoleExpanded": [Function],
"isPreferredApiCassandra": [Function], "isPreferredApiCassandra": [Function],
"isPreferredApiDocumentDB": [Function], "isPreferredApiDocumentDB": [Function],
"isPreferredApiGraph": [Function], "isPreferredApiGraph": [Function],
@ -1018,12 +1017,6 @@ exports[`SettingsComponent renders 1`] = `
"nonSystemDatabases": [Function], "nonSystemDatabases": [Function],
"notebookBasePath": [Function], "notebookBasePath": [Function],
"notebookServerInfo": [Function], "notebookServerInfo": [Function],
"notificationConsoleComponentAdapter": NotificationConsoleComponentAdapter {
"consoleData": [Function],
"container": [Circular],
"parameters": [Function],
},
"notificationConsoleData": [Function],
"onRefreshDatabasesKeyPress": [Function], "onRefreshDatabasesKeyPress": [Function],
"onRefreshResourcesClick": [Function], "onRefreshResourcesClick": [Function],
"onSwitchToConnectionString": [Function], "onSwitchToConnectionString": [Function],
@ -1129,6 +1122,9 @@ exports[`SettingsComponent renders 1`] = `
}, },
"selfServeType": [Function], "selfServeType": [Function],
"serverId": [Function], "serverId": [Function],
"setInProgressConsoleDataIdToBeDeleted": undefined,
"setIsNotificationConsoleExpanded": undefined,
"setNotificationConsoleData": undefined,
"settingsPane": SettingsPane { "settingsPane": SettingsPane {
"container": [Circular], "container": [Circular],
"crossPartitionQueryEnabled": [Function], "crossPartitionQueryEnabled": [Function],
@ -2241,7 +2237,6 @@ exports[`SettingsComponent renders 1`] = `
"isMongoIndexingEnabled": [Function], "isMongoIndexingEnabled": [Function],
"isNotebookEnabled": [Function], "isNotebookEnabled": [Function],
"isNotebooksEnabledForAccount": [Function], "isNotebooksEnabledForAccount": [Function],
"isNotificationConsoleExpanded": [Function],
"isPreferredApiCassandra": [Function], "isPreferredApiCassandra": [Function],
"isPreferredApiDocumentDB": [Function], "isPreferredApiDocumentDB": [Function],
"isPreferredApiGraph": [Function], "isPreferredApiGraph": [Function],
@ -2301,12 +2296,6 @@ exports[`SettingsComponent renders 1`] = `
"nonSystemDatabases": [Function], "nonSystemDatabases": [Function],
"notebookBasePath": [Function], "notebookBasePath": [Function],
"notebookServerInfo": [Function], "notebookServerInfo": [Function],
"notificationConsoleComponentAdapter": NotificationConsoleComponentAdapter {
"consoleData": [Function],
"container": [Circular],
"parameters": [Function],
},
"notificationConsoleData": [Function],
"onRefreshDatabasesKeyPress": [Function], "onRefreshDatabasesKeyPress": [Function],
"onRefreshResourcesClick": [Function], "onRefreshResourcesClick": [Function],
"onSwitchToConnectionString": [Function], "onSwitchToConnectionString": [Function],
@ -2412,6 +2401,9 @@ exports[`SettingsComponent renders 1`] = `
}, },
"selfServeType": [Function], "selfServeType": [Function],
"serverId": [Function], "serverId": [Function],
"setInProgressConsoleDataIdToBeDeleted": undefined,
"setIsNotificationConsoleExpanded": undefined,
"setNotificationConsoleData": undefined,
"settingsPane": SettingsPane { "settingsPane": SettingsPane {
"container": [Circular], "container": [Circular],
"crossPartitionQueryEnabled": [Function], "crossPartitionQueryEnabled": [Function],
@ -3537,7 +3529,6 @@ exports[`SettingsComponent renders 1`] = `
"isMongoIndexingEnabled": [Function], "isMongoIndexingEnabled": [Function],
"isNotebookEnabled": [Function], "isNotebookEnabled": [Function],
"isNotebooksEnabledForAccount": [Function], "isNotebooksEnabledForAccount": [Function],
"isNotificationConsoleExpanded": [Function],
"isPreferredApiCassandra": [Function], "isPreferredApiCassandra": [Function],
"isPreferredApiDocumentDB": [Function], "isPreferredApiDocumentDB": [Function],
"isPreferredApiGraph": [Function], "isPreferredApiGraph": [Function],
@ -3597,12 +3588,6 @@ exports[`SettingsComponent renders 1`] = `
"nonSystemDatabases": [Function], "nonSystemDatabases": [Function],
"notebookBasePath": [Function], "notebookBasePath": [Function],
"notebookServerInfo": [Function], "notebookServerInfo": [Function],
"notificationConsoleComponentAdapter": NotificationConsoleComponentAdapter {
"consoleData": [Function],
"container": [Circular],
"parameters": [Function],
},
"notificationConsoleData": [Function],
"onRefreshDatabasesKeyPress": [Function], "onRefreshDatabasesKeyPress": [Function],
"onRefreshResourcesClick": [Function], "onRefreshResourcesClick": [Function],
"onSwitchToConnectionString": [Function], "onSwitchToConnectionString": [Function],
@ -3708,6 +3693,9 @@ exports[`SettingsComponent renders 1`] = `
}, },
"selfServeType": [Function], "selfServeType": [Function],
"serverId": [Function], "serverId": [Function],
"setInProgressConsoleDataIdToBeDeleted": undefined,
"setIsNotificationConsoleExpanded": undefined,
"setNotificationConsoleData": undefined,
"settingsPane": SettingsPane { "settingsPane": SettingsPane {
"container": [Circular], "container": [Circular],
"crossPartitionQueryEnabled": [Function], "crossPartitionQueryEnabled": [Function],
@ -4820,7 +4808,6 @@ exports[`SettingsComponent renders 1`] = `
"isMongoIndexingEnabled": [Function], "isMongoIndexingEnabled": [Function],
"isNotebookEnabled": [Function], "isNotebookEnabled": [Function],
"isNotebooksEnabledForAccount": [Function], "isNotebooksEnabledForAccount": [Function],
"isNotificationConsoleExpanded": [Function],
"isPreferredApiCassandra": [Function], "isPreferredApiCassandra": [Function],
"isPreferredApiDocumentDB": [Function], "isPreferredApiDocumentDB": [Function],
"isPreferredApiGraph": [Function], "isPreferredApiGraph": [Function],
@ -4880,12 +4867,6 @@ exports[`SettingsComponent renders 1`] = `
"nonSystemDatabases": [Function], "nonSystemDatabases": [Function],
"notebookBasePath": [Function], "notebookBasePath": [Function],
"notebookServerInfo": [Function], "notebookServerInfo": [Function],
"notificationConsoleComponentAdapter": NotificationConsoleComponentAdapter {
"consoleData": [Function],
"container": [Circular],
"parameters": [Function],
},
"notificationConsoleData": [Function],
"onRefreshDatabasesKeyPress": [Function], "onRefreshDatabasesKeyPress": [Function],
"onRefreshResourcesClick": [Function], "onRefreshResourcesClick": [Function],
"onSwitchToConnectionString": [Function], "onSwitchToConnectionString": [Function],
@ -4991,6 +4972,9 @@ exports[`SettingsComponent renders 1`] = `
}, },
"selfServeType": [Function], "selfServeType": [Function],
"serverId": [Function], "serverId": [Function],
"setInProgressConsoleDataIdToBeDeleted": undefined,
"setIsNotificationConsoleExpanded": undefined,
"setNotificationConsoleData": undefined,
"settingsPane": SettingsPane { "settingsPane": SettingsPane {
"container": [Circular], "container": [Circular],
"crossPartitionQueryEnabled": [Function], "crossPartitionQueryEnabled": [Function],

View File

@ -55,7 +55,6 @@ import { sendMessage, sendCachedDataMessage, handleCachedDataMessage } from "../
import { NotebookContentItem, NotebookContentItemType } from "./Notebook/NotebookContentItem"; import { NotebookContentItem, NotebookContentItemType } from "./Notebook/NotebookContentItem";
import { NotebookUtil } from "./Notebook/NotebookUtil"; import { NotebookUtil } from "./Notebook/NotebookUtil";
import { NotebookWorkspaceManager } from "../NotebookWorkspaceManager/NotebookWorkspaceManager"; import { NotebookWorkspaceManager } from "../NotebookWorkspaceManager/NotebookWorkspaceManager";
import { NotificationConsoleComponentAdapter } from "./Menus/NotificationConsole/NotificationConsoleComponentAdapter";
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils"; import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
import { QueriesClient } from "../Common/QueriesClient"; import { QueriesClient } from "../Common/QueriesClient";
import { QuerySelectPane } from "./Panes/Tables/QuerySelectPane"; import { QuerySelectPane } from "./Panes/Tables/QuerySelectPane";
@ -107,6 +106,12 @@ interface AdHocAccessData {
readUrl: string; readUrl: string;
} }
export interface ExplorerParams {
setIsNotificationConsoleExpanded: (isExpanded: boolean) => void;
setNotificationConsoleData: (consoleData: ConsoleData) => void;
setInProgressConsoleDataIdToBeDeleted: (id: string) => void;
}
export default class Explorer { export default class Explorer {
public flight: ko.Observable<string> = ko.observable<string>( public flight: ko.Observable<string> = ko.observable<string>(
SharedConstants.CollectionCreation.DefaultAddCollectionDefaultFlight SharedConstants.CollectionCreation.DefaultAddCollectionDefaultFlight
@ -146,8 +151,9 @@ export default class Explorer {
public mostRecentActivity: MostRecentActivity.MostRecentActivity; public mostRecentActivity: MostRecentActivity.MostRecentActivity;
// Notification Console // Notification Console
public notificationConsoleData: ko.ObservableArray<ConsoleData>; private setIsNotificationConsoleExpanded: (isExpanded: boolean) => void;
public isNotificationConsoleExpanded: ko.Observable<boolean>; private setNotificationConsoleData: (consoleData: ConsoleData) => void;
private setInProgressConsoleDataIdToBeDeleted: (id: string) => void;
// Panes // Panes
public contextPanes: ContextualPaneBase[]; public contextPanes: ContextualPaneBase[];
@ -260,7 +266,6 @@ export default class Explorer {
// React adapters // React adapters
private commandBarComponentAdapter: CommandBarComponentAdapter; private commandBarComponentAdapter: CommandBarComponentAdapter;
private splashScreenAdapter: SplashScreenComponentAdapter; private splashScreenAdapter: SplashScreenComponentAdapter;
private notificationConsoleComponentAdapter: NotificationConsoleComponentAdapter;
private dialogComponentAdapter: DialogComponentAdapter; private dialogComponentAdapter: DialogComponentAdapter;
private _dialogProps: ko.Observable<DialogProps>; private _dialogProps: ko.Observable<DialogProps>;
private addSynapseLinkDialog: DialogComponentAdapter; private addSynapseLinkDialog: DialogComponentAdapter;
@ -269,7 +274,11 @@ export default class Explorer {
private static readonly MaxNbDatabasesToAutoExpand = 5; private static readonly MaxNbDatabasesToAutoExpand = 5;
constructor() { constructor(params?: ExplorerParams) {
this.setIsNotificationConsoleExpanded = params?.setIsNotificationConsoleExpanded;
this.setNotificationConsoleData = params?.setNotificationConsoleData;
this.setInProgressConsoleDataIdToBeDeleted = params?.setInProgressConsoleDataIdToBeDeleted;
const startKey: number = TelemetryProcessor.traceStart(Action.InitializeDataExplorer, { const startKey: number = TelemetryProcessor.traceStart(Action.InitializeDataExplorer, {
dataExplorerArea: Constants.Areas.ResourceTree, dataExplorerArea: Constants.Areas.ResourceTree,
}); });
@ -430,7 +439,6 @@ export default class Explorer {
); );
this.isSchemaEnabled = ko.computed<boolean>(() => this.isFeatureEnabled(Constants.Features.enableSchema)); this.isSchemaEnabled = ko.computed<boolean>(() => this.isFeatureEnabled(Constants.Features.enableSchema));
this.isNotificationConsoleExpanded = ko.observable<boolean>(false);
this.isAutoscaleDefaultEnabled = ko.observable<boolean>(false); this.isAutoscaleDefaultEnabled = ko.observable<boolean>(false);
@ -478,7 +486,6 @@ export default class Explorer {
bounds: splitterBounds, bounds: splitterBounds,
direction: SplitterDirection.Vertical, direction: SplitterDirection.Vertical,
}); });
this.notificationConsoleData = ko.observableArray<ConsoleData>([]);
this.defaultExperience = ko.observable<string>(); this.defaultExperience = ko.observable<string>();
this.databaseAccount.subscribe((databaseAccount) => { this.databaseAccount.subscribe((databaseAccount) => {
const defaultExperience: string = DefaultExperienceUtility.getDefaultExperienceFromDatabaseAccount( const defaultExperience: string = DefaultExperienceUtility.getDefaultExperienceFromDatabaseAccount(
@ -892,7 +899,6 @@ export default class Explorer {
this.commandBarComponentAdapter = new CommandBarComponentAdapter(this); this.commandBarComponentAdapter = new CommandBarComponentAdapter(this);
this.selfServeLoadingComponentAdapter = new SelfServeLoadingComponentAdapter(); this.selfServeLoadingComponentAdapter = new SelfServeLoadingComponentAdapter();
this.notificationConsoleComponentAdapter = new NotificationConsoleComponentAdapter(this);
this._initSettings(); this._initSettings();
@ -1349,23 +1355,19 @@ export default class Explorer {
} }
public logConsoleData(consoleData: ConsoleData): void { public logConsoleData(consoleData: ConsoleData): void {
this.notificationConsoleData.splice(0, 0, consoleData); this.setNotificationConsoleData(consoleData);
} }
public deleteInProgressConsoleDataWithId(id: string): void { public deleteInProgressConsoleDataWithId(id: string): void {
const updatedConsoleData = _.reject( this.setInProgressConsoleDataIdToBeDeleted(id);
this.notificationConsoleData(),
(data: ConsoleData) => data.type === ConsoleDataType.InProgress && data.id === id
);
this.notificationConsoleData(updatedConsoleData);
} }
public expandConsole(): void { public expandConsole(): void {
this.isNotificationConsoleExpanded(true); this.setIsNotificationConsoleExpanded(true);
} }
public collapseConsole(): void { public collapseConsole(): void {
this.isNotificationConsoleExpanded(false); this.setIsNotificationConsoleExpanded(false);
} }
public toggleLeftPaneExpanded() { public toggleLeftPaneExpanded() {

View File

@ -2,7 +2,6 @@ import React from "react";
import { shallow } from "enzyme"; import { shallow } from "enzyme";
import { import {
NotificationConsoleComponentProps, NotificationConsoleComponentProps,
ConsoleData,
NotificationConsoleComponent, NotificationConsoleComponent,
ConsoleDataType, ConsoleDataType,
} from "./NotificationConsoleComponent"; } from "./NotificationConsoleComponent";
@ -10,38 +9,40 @@ import {
describe("NotificationConsoleComponent", () => { describe("NotificationConsoleComponent", () => {
const createBlankProps = (): NotificationConsoleComponentProps => { const createBlankProps = (): NotificationConsoleComponentProps => {
return { return {
consoleData: [], consoleData: undefined,
isConsoleExpanded: true, isConsoleExpanded: false,
onConsoleDataChange: (consoleData: ConsoleData[]) => {}, inProgressConsoleDataIdToBeDeleted: "",
onConsoleExpandedChange: (isExpanded: boolean) => {}, setIsConsoleExpanded: (isExpanded: boolean): void => {},
}; };
}; };
it("renders the console (expanded)", () => { it("renders the console", () => {
const props = createBlankProps(); const props = createBlankProps();
props.consoleData.push({ const wrapper = shallow(<NotificationConsoleComponent {...props} />);
expect(wrapper).toMatchSnapshot();
props.consoleData = {
type: ConsoleDataType.Info, type: ConsoleDataType.Info,
date: "date", date: "date",
message: "message", message: "message",
}); };
wrapper.setProps(props);
const wrapper = shallow(<NotificationConsoleComponent {...props} />);
expect(wrapper).toMatchSnapshot(); expect(wrapper).toMatchSnapshot();
}); });
it("shows proper progress count", () => { it("shows proper progress count", () => {
const count = 100; const count = 100;
const props = createBlankProps(); const props = createBlankProps();
const wrapper = shallow(<NotificationConsoleComponent {...props} />);
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
props.consoleData.push({ props.consoleData = {
type: ConsoleDataType.InProgress, type: ConsoleDataType.InProgress,
date: "date", date: "date" + i,
message: "message", message: "message",
}); };
wrapper.setProps(props);
} }
const wrapper = shallow(<NotificationConsoleComponent {...props} />);
expect(wrapper.find(".notificationConsoleHeader .numInProgress").text()).toEqual(count.toString()); expect(wrapper.find(".notificationConsoleHeader .numInProgress").text()).toEqual(count.toString());
expect(wrapper.find(".notificationConsoleHeader .numErroredItems").text()).toEqual("0"); expect(wrapper.find(".notificationConsoleHeader .numErroredItems").text()).toEqual("0");
expect(wrapper.find(".notificationConsoleHeader .numInfoItems").text()).toEqual("0"); expect(wrapper.find(".notificationConsoleHeader .numInfoItems").text()).toEqual("0");
@ -50,16 +51,17 @@ describe("NotificationConsoleComponent", () => {
it("shows proper error count", () => { it("shows proper error count", () => {
const count = 100; const count = 100;
const props = createBlankProps(); const props = createBlankProps();
const wrapper = shallow(<NotificationConsoleComponent {...props} />);
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
props.consoleData.push({ props.consoleData = {
type: ConsoleDataType.Error, type: ConsoleDataType.Error,
date: "date", date: "date" + i,
message: "message", message: "message",
}); };
wrapper.setProps(props);
} }
const wrapper = shallow(<NotificationConsoleComponent {...props} />);
expect(wrapper.find(".notificationConsoleHeader .numInProgress").text()).toEqual("0"); expect(wrapper.find(".notificationConsoleHeader .numInProgress").text()).toEqual("0");
expect(wrapper.find(".notificationConsoleHeader .numErroredItems").text()).toEqual(count.toString()); expect(wrapper.find(".notificationConsoleHeader .numErroredItems").text()).toEqual(count.toString());
expect(wrapper.find(".notificationConsoleHeader .numInfoItems").text()).toEqual("0"); expect(wrapper.find(".notificationConsoleHeader .numInfoItems").text()).toEqual("0");
@ -68,31 +70,34 @@ describe("NotificationConsoleComponent", () => {
it("shows proper info count", () => { it("shows proper info count", () => {
const count = 100; const count = 100;
const props = createBlankProps(); const props = createBlankProps();
const wrapper = shallow(<NotificationConsoleComponent {...props} />);
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
props.consoleData.push({ props.consoleData = {
type: ConsoleDataType.Info, type: ConsoleDataType.Info,
date: "date", date: "date" + i,
message: "message", message: "message",
}); };
wrapper.setProps(props);
} }
const wrapper = shallow(<NotificationConsoleComponent {...props} />);
expect(wrapper.find(".notificationConsoleHeader .numInProgress").text()).toEqual("0"); expect(wrapper.find(".notificationConsoleHeader .numInProgress").text()).toEqual("0");
expect(wrapper.find(".notificationConsoleHeader .numErroredItems").text()).toEqual("0"); expect(wrapper.find(".notificationConsoleHeader .numErroredItems").text()).toEqual("0");
expect(wrapper.find(".notificationConsoleHeader .numInfoItems").text()).toEqual(count.toString()); expect(wrapper.find(".notificationConsoleHeader .numInfoItems").text()).toEqual(count.toString());
}); });
const testRenderNotification = (date: string, msg: string, type: ConsoleDataType, iconClassName: string) => { const testRenderNotification = (date: string, message: string, type: ConsoleDataType, iconClassName: string) => {
const props = createBlankProps(); const props = createBlankProps();
props.consoleData.push({
date: date,
message: msg,
type: type,
});
const wrapper = shallow(<NotificationConsoleComponent {...props} />); const wrapper = shallow(<NotificationConsoleComponent {...props} />);
props.consoleData = {
type,
date,
message,
};
wrapper.setProps(props);
expect(wrapper.find(".notificationConsoleData .date").text()).toEqual(date); expect(wrapper.find(".notificationConsoleData .date").text()).toEqual(date);
expect(wrapper.find(".notificationConsoleData .message").text()).toEqual(msg); expect(wrapper.find(".notificationConsoleData .message").text()).toEqual(message);
expect(wrapper.exists(`.notificationConsoleData .${iconClassName}`)); expect(wrapper.exists(`.notificationConsoleData .${iconClassName}`));
}; };
@ -110,55 +115,78 @@ describe("NotificationConsoleComponent", () => {
it("clears notifications", () => { it("clears notifications", () => {
const props = createBlankProps(); const props = createBlankProps();
props.consoleData.push({ const wrapper = shallow(<NotificationConsoleComponent {...props} />);
props.consoleData = {
type: ConsoleDataType.InProgress, type: ConsoleDataType.InProgress,
date: "date", date: "date",
message: "message1", message: "message1",
}); };
props.consoleData.push({ wrapper.setProps(props);
props.consoleData = {
type: ConsoleDataType.Error, type: ConsoleDataType.Error,
date: "date", date: "date",
message: "message2", message: "message2",
}); };
props.consoleData.push({ wrapper.setProps(props);
props.consoleData = {
type: ConsoleDataType.Info, type: ConsoleDataType.Info,
date: "date", date: "date",
message: "message3", message: "message3",
}); };
wrapper.setProps(props);
const wrapper = shallow(<NotificationConsoleComponent {...props} />);
wrapper.find(".clearNotificationsButton").simulate("click"); wrapper.find(".clearNotificationsButton").simulate("click");
expect(!wrapper.exists(".notificationConsoleData")); expect(!wrapper.exists(".notificationConsoleData"));
}); });
it("collapses and hide content", () => { it("collapses and hide content", () => {
const props = createBlankProps(); const props = createBlankProps();
props.consoleData.push({ const wrapper = shallow(<NotificationConsoleComponent {...props} />);
props.consoleData = {
type: ConsoleDataType.Info,
date: "date", date: "date",
message: "message", message: "message",
type: ConsoleDataType.Info, };
});
props.isConsoleExpanded = true; props.isConsoleExpanded = true;
wrapper.setProps(props);
const wrapper = shallow(<NotificationConsoleComponent {...props} />);
wrapper.find(".notificationConsoleHeader").simulate("click"); wrapper.find(".notificationConsoleHeader").simulate("click");
expect(!wrapper.exists(".notificationConsoleContent")); expect(!wrapper.exists(".notificationConsoleContent"));
}); });
it("display latest data in header", () => { it("display latest data in header", () => {
const latestData = "latest data"; const latestData = "latest data";
const props1 = createBlankProps(); const props = createBlankProps();
const props2 = createBlankProps(); const wrapper = shallow(<NotificationConsoleComponent {...props} />);
props2.consoleData.push({
props.consoleData = {
type: ConsoleDataType.Info,
date: "date", date: "date",
message: latestData, message: latestData,
type: ConsoleDataType.Info, };
}); props.isConsoleExpanded = true;
props2.isConsoleExpanded = true; wrapper.setProps(props);
const wrapper = shallow(<NotificationConsoleComponent {...props1} />);
wrapper.setProps(props2);
expect(wrapper.find(".headerStatusEllipsis").text()).toEqual(latestData); expect(wrapper.find(".headerStatusEllipsis").text()).toEqual(latestData);
}); });
it("delete in progress message", () => {
const props = createBlankProps();
props.consoleData = {
type: ConsoleDataType.InProgress,
date: "date",
message: "message",
id: "1",
};
const wrapper = shallow(<NotificationConsoleComponent {...props} />);
expect(wrapper.find(".notificationConsoleHeader .numInProgress").text()).toEqual("1");
props.inProgressConsoleDataIdToBeDeleted = "1";
wrapper.setProps(props);
expect(wrapper.find(".notificationConsoleHeader .numInProgress").text()).toEqual("0");
});
}); });

View File

@ -37,15 +37,15 @@ export interface ConsoleData {
export interface NotificationConsoleComponentProps { export interface NotificationConsoleComponentProps {
isConsoleExpanded: boolean; isConsoleExpanded: boolean;
onConsoleExpandedChange: (isExpanded: boolean) => void; consoleData: ConsoleData;
consoleData: ConsoleData[]; inProgressConsoleDataIdToBeDeleted: string;
onConsoleDataChange: (consoleData: ConsoleData[]) => void; setIsConsoleExpanded: (isExpanded: boolean) => void;
} }
interface NotificationConsoleComponentState { interface NotificationConsoleComponentState {
headerStatus: string; headerStatus: string;
selectedFilter: string; selectedFilter: string;
isExpanded: boolean; allConsoleData: ConsoleData[];
} }
export class NotificationConsoleComponent extends React.Component< export class NotificationConsoleComponent extends React.Component<
@ -60,28 +60,28 @@ export class NotificationConsoleComponent extends React.Component<
{ key: "Error", text: "Error" }, { key: "Error", text: "Error" },
]; ];
private headerTimeoutId?: number; private headerTimeoutId?: number;
private prevHeaderStatus: string | null; private prevHeaderStatus: string;
private consoleHeaderElement?: HTMLElement; private consoleHeaderElement?: HTMLElement;
constructor(props: NotificationConsoleComponentProps) { constructor(props: NotificationConsoleComponentProps) {
super(props); super(props);
this.state = { this.state = {
headerStatus: "", headerStatus: undefined,
selectedFilter: NotificationConsoleComponent.FilterOptions[0].key || "", selectedFilter: NotificationConsoleComponent.FilterOptions[0].key,
isExpanded: props.isConsoleExpanded, allConsoleData: props.consoleData ? [props.consoleData] : [],
}; };
this.prevHeaderStatus = null; this.prevHeaderStatus = undefined;
} }
public componentDidUpdate( public componentDidUpdate(
prevProps: NotificationConsoleComponentProps, prevProps: NotificationConsoleComponentProps,
prevState: NotificationConsoleComponentState prevState: NotificationConsoleComponentState
) { ) {
const currentHeaderStatus = NotificationConsoleComponent.extractHeaderStatus(this.props); const currentHeaderStatus = NotificationConsoleComponent.extractHeaderStatus(this.props.consoleData);
if ( if (
this.prevHeaderStatus !== currentHeaderStatus && this.prevHeaderStatus !== currentHeaderStatus &&
currentHeaderStatus !== null && currentHeaderStatus !== undefined &&
prevState.headerStatus !== currentHeaderStatus prevState.headerStatus !== currentHeaderStatus
) { ) {
this.setHeaderStatus(currentHeaderStatus); this.setHeaderStatus(currentHeaderStatus);
@ -92,10 +92,8 @@ export class NotificationConsoleComponent extends React.Component<
// updates: currentHeaderStatus -> "" -> currentHeaderStatus -> "" etc. // updates: currentHeaderStatus -> "" -> currentHeaderStatus -> "" etc.
this.prevHeaderStatus = currentHeaderStatus; this.prevHeaderStatus = currentHeaderStatus;
if (prevProps.isConsoleExpanded !== this.props.isConsoleExpanded) { if (this.props.consoleData || this.props.inProgressConsoleDataIdToBeDeleted) {
// Sync state and props this.updateConsoleData(prevProps);
// TODO react anti-pattern: remove isExpanded from state which duplicates prop's isConsoleExpanded
this.setState({ isExpanded: this.props.isConsoleExpanded });
} }
} }
@ -104,12 +102,14 @@ export class NotificationConsoleComponent extends React.Component<
}; };
public render(): JSX.Element { public render(): JSX.Element {
const numInProgress = this.props.consoleData.filter((data: ConsoleData) => data.type === ConsoleDataType.InProgress) const numInProgress = this.state.allConsoleData.filter(
(data: ConsoleData) => data.type === ConsoleDataType.InProgress
).length;
const numErroredItems = this.state.allConsoleData.filter((data: ConsoleData) => data.type === ConsoleDataType.Error)
.length; .length;
const numErroredItems = this.props.consoleData.filter((data: ConsoleData) => data.type === ConsoleDataType.Error) const numInfoItems = this.state.allConsoleData.filter((data: ConsoleData) => data.type === ConsoleDataType.Info)
.length;
const numInfoItems = this.props.consoleData.filter((data: ConsoleData) => data.type === ConsoleDataType.Info)
.length; .length;
return ( return (
<div className="notificationConsoleContainer"> <div className="notificationConsoleContainer">
<div <div
@ -143,18 +143,18 @@ export class NotificationConsoleComponent extends React.Component<
className="expandCollapseButton" className="expandCollapseButton"
role="button" role="button"
tabIndex={0} tabIndex={0}
aria-label={"console button" + (this.state.isExpanded ? " collapsed" : " expanded")} aria-label={"console button" + (this.props.isConsoleExpanded ? " collapsed" : " expanded")}
aria-expanded={!this.state.isExpanded} aria-expanded={!this.props.isConsoleExpanded}
> >
<img <img
src={this.state.isExpanded ? ChevronDownIcon : ChevronUpIcon} src={this.props.isConsoleExpanded ? ChevronDownIcon : ChevronUpIcon}
alt={this.state.isExpanded ? "ChevronDownIcon" : "ChevronUpIcon"} alt={this.props.isConsoleExpanded ? "ChevronDownIcon" : "ChevronUpIcon"}
/> />
</div> </div>
</div> </div>
<AnimateHeight <AnimateHeight
duration={NotificationConsoleComponent.transitionDurationMs} duration={NotificationConsoleComponent.transitionDurationMs}
height={this.state.isExpanded ? "auto" : 0} height={this.props.isConsoleExpanded ? "auto" : 0}
onAnimationEnd={this.onConsoleWasExpanded} onAnimationEnd={this.onConsoleWasExpanded}
> >
<div className="notificationConsoleContents"> <div className="notificationConsoleContents">
@ -189,7 +189,7 @@ export class NotificationConsoleComponent extends React.Component<
); );
} }
private expandCollapseConsole() { private expandCollapseConsole() {
this.setState({ isExpanded: !this.state.isExpanded }); this.props.setIsConsoleExpanded(!this.props.isConsoleExpanded);
} }
private onExpandCollapseKeyPress = (event: React.KeyboardEvent<HTMLDivElement>): void => { private onExpandCollapseKeyPress = (event: React.KeyboardEvent<HTMLDivElement>): void => {
@ -209,7 +209,7 @@ export class NotificationConsoleComponent extends React.Component<
}; };
private clearNotifications(): void { private clearNotifications(): void {
this.props.onConsoleDataChange([]); this.setState({ allConsoleData: [] });
} }
private renderAllFilteredConsoleData(rowData: ConsoleData[]): JSX.Element[] { private renderAllFilteredConsoleData(rowData: ConsoleData[]): JSX.Element[] {
@ -229,12 +229,9 @@ export class NotificationConsoleComponent extends React.Component<
}; };
private getFilteredConsoleData(): ConsoleData[] { private getFilteredConsoleData(): ConsoleData[] {
let filterType: ConsoleDataType | null = null; let filterType: ConsoleDataType;
switch (this.state.selectedFilter) { switch (this.state.selectedFilter) {
case "All":
filterType = null;
break;
case "In Progress": case "In Progress":
filterType = ConsoleDataType.InProgress; filterType = ConsoleDataType.InProgress;
break; break;
@ -245,12 +242,12 @@ export class NotificationConsoleComponent extends React.Component<
filterType = ConsoleDataType.Error; filterType = ConsoleDataType.Error;
break; break;
default: default:
filterType = null; filterType = undefined;
} }
return filterType == null return filterType
? this.props.consoleData ? this.state.allConsoleData.filter((data: ConsoleData) => data.type === filterType)
: this.props.consoleData.filter((data: ConsoleData) => data.type === filterType); : this.state.allConsoleData;
} }
private setHeaderStatus(statusMessage: string): void { private setHeaderStatus(statusMessage: string): void {
@ -266,18 +263,43 @@ export class NotificationConsoleComponent extends React.Component<
); );
} }
private static extractHeaderStatus(props: NotificationConsoleComponentProps) { private static extractHeaderStatus(consoleData: ConsoleData) {
if (props.consoleData && props.consoleData.length > 0) { return consoleData?.message.split(":\n")[0];
return props.consoleData[0].message.split(":\n")[0];
} else {
return null;
}
} }
private onConsoleWasExpanded = (): void => { private onConsoleWasExpanded = (): void => {
this.props.onConsoleExpandedChange(this.state.isExpanded); if (this.props.isConsoleExpanded && this.consoleHeaderElement) {
if (this.state.isExpanded && this.consoleHeaderElement) {
this.consoleHeaderElement.focus(); this.consoleHeaderElement.focus();
} }
}; };
private updateConsoleData = (prevProps: NotificationConsoleComponentProps): void => {
if (!this.areConsoleDataEqual(this.props.consoleData, prevProps.consoleData)) {
this.setState({ allConsoleData: [this.props.consoleData, ...this.state.allConsoleData] });
}
if (
this.props.inProgressConsoleDataIdToBeDeleted &&
prevProps.inProgressConsoleDataIdToBeDeleted !== this.props.inProgressConsoleDataIdToBeDeleted
) {
const allConsoleData = this.state.allConsoleData.filter(
(data: ConsoleData) =>
!(data.type === ConsoleDataType.InProgress && data.id === this.props.inProgressConsoleDataIdToBeDeleted)
);
this.setState({ allConsoleData });
}
};
private areConsoleDataEqual = (currentData: ConsoleData, prevData: ConsoleData): boolean => {
if (!currentData || !prevData) {
return !currentData && !prevData;
}
return (
currentData.date === prevData.date &&
currentData.message === prevData.message &&
currentData.type === prevData.type &&
currentData.id === prevData.id
);
};
} }

View File

@ -1,47 +0,0 @@
import * as ko from "knockout";
import * as React from "react";
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
import * as ViewModels from "../../../Contracts/ViewModels";
import { NotificationConsoleComponent } from "./NotificationConsoleComponent";
import { ConsoleData } from "./NotificationConsoleComponent";
import Explorer from "../../Explorer";
export class NotificationConsoleComponentAdapter implements ReactAdapter {
public parameters: ko.Observable<number>;
public container: Explorer;
private consoleData: ko.ObservableArray<ConsoleData>;
constructor(container: Explorer) {
this.container = container;
this.consoleData = container.notificationConsoleData;
this.consoleData.subscribe((newValue: ConsoleData[]) => this.triggerRender());
container.isNotificationConsoleExpanded.subscribe(() => this.triggerRender());
this.parameters = ko.observable(Date.now());
}
private onConsoleExpandedChange(isExpanded: boolean): void {
isExpanded ? this.container.expandConsole() : this.container.collapseConsole();
this.triggerRender();
}
private onConsoleDataChange(consoleData: ConsoleData[]): void {
this.consoleData(consoleData);
this.triggerRender();
}
public renderComponent(): JSX.Element {
return (
<NotificationConsoleComponent
isConsoleExpanded={this.container.isNotificationConsoleExpanded()}
onConsoleExpandedChange={this.onConsoleExpandedChange.bind(this)}
consoleData={this.consoleData()}
onConsoleDataChange={this.onConsoleDataChange.bind(this)}
/>
);
}
private triggerRender() {
window.requestAnimationFrame(() => this.parameters(Date.now()));
}
}

View File

@ -1,6 +1,169 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`NotificationConsoleComponent renders the console (expanded) 1`] = ` exports[`NotificationConsoleComponent renders the console 1`] = `
<div
className="notificationConsoleContainer"
>
<div
className="notificationConsoleHeader"
onClick={[Function]}
onKeyDown={[Function]}
tabIndex={0}
>
<div
className="statusBar"
>
<span
className="dataTypeIcons"
>
<span
className="notificationConsoleHeaderIconWithData"
>
<img
alt="in progress items"
src=""
/>
<span
className="numInProgress"
>
0
</span>
</span>
<span
className="notificationConsoleHeaderIconWithData"
>
<img
alt="error items"
src=""
/>
<span
className="numErroredItems"
>
0
</span>
</span>
<span
className="notificationConsoleHeaderIconWithData"
>
<img
alt="info items"
src=""
/>
<span
className="numInfoItems"
>
0
</span>
</span>
</span>
<span
className="consoleSplitter"
/>
<span
className="headerStatus"
>
<span
className="headerStatusEllipsis"
/>
</span>
</div>
<div
aria-expanded={true}
aria-label="console button expanded"
className="expandCollapseButton"
role="button"
tabIndex={0}
>
<img
alt="ChevronUpIcon"
src=""
/>
</div>
</div>
<AnimateHeight
animateOpacity={false}
animationStateClasses={
Object {
"animating": "rah-animating",
"animatingDown": "rah-animating--down",
"animatingToHeightAuto": "rah-animating--to-height-auto",
"animatingToHeightSpecific": "rah-animating--to-height-specific",
"animatingToHeightZero": "rah-animating--to-height-zero",
"animatingUp": "rah-animating--up",
"static": "rah-static",
"staticHeightAuto": "rah-static--height-auto",
"staticHeightSpecific": "rah-static--height-specific",
"staticHeightZero": "rah-static--height-zero",
}
}
applyInlineTransitions={true}
delay={0}
duration={200}
easing="ease"
height={0}
onAnimationEnd={[Function]}
style={Object {}}
>
<div
className="notificationConsoleContents"
>
<div
className="notificationConsoleControls"
>
<StyledWithResponsiveMode
aria-label="All"
aria-labelledby="consoleFilterLabel"
label="Filter:"
onChange={[Function]}
options={
Array [
Object {
"key": "All",
"text": "All",
},
Object {
"key": "In Progress",
"text": "In progress",
},
Object {
"key": "Info",
"text": "Info",
},
Object {
"key": "Error",
"text": "Error",
},
]
}
role="combobox"
selectedKey="All"
/>
<span
className="consoleSplitter"
/>
<span
className="clearNotificationsButton"
onClick={[Function]}
onKeyDown={[Function]}
role="button"
tabIndex={0}
>
<img
alt="clear notifications image"
src=""
/>
Clear Notifications
</span>
</div>
<div
className="notificationConsoleData"
/>
</div>
</AnimateHeight>
</div>
`;
exports[`NotificationConsoleComponent renders the console 2`] = `
<div <div
className="notificationConsoleContainer" className="notificationConsoleContainer"
> >
@ -64,18 +227,20 @@ exports[`NotificationConsoleComponent renders the console (expanded) 1`] = `
> >
<span <span
className="headerStatusEllipsis" className="headerStatusEllipsis"
/> >
message
</span>
</span> </span>
</div> </div>
<div <div
aria-expanded={false} aria-expanded={true}
aria-label="console button collapsed" aria-label="console button expanded"
className="expandCollapseButton" className="expandCollapseButton"
role="button" role="button"
tabIndex={0} tabIndex={0}
> >
<img <img
alt="ChevronDownIcon" alt="ChevronUpIcon"
src="" src=""
/> />
</div> </div>
@ -100,7 +265,7 @@ exports[`NotificationConsoleComponent renders the console (expanded) 1`] = `
delay={0} delay={0}
duration={200} duration={200}
easing="ease" easing="ease"
height="auto" height={0}
onAnimationEnd={[Function]} onAnimationEnd={[Function]}
style={Object {}} style={Object {}}
> >

View File

@ -29,10 +29,6 @@ export abstract class ContextualPaneBase extends WaitsForTemplateViewModel {
this.title = ko.observable<string>(); this.title = ko.observable<string>();
this.formErrorsDetails = ko.observable<string>(); this.formErrorsDetails = ko.observable<string>();
this.isExecuting = ko.observable<boolean>(false); this.isExecuting = ko.observable<boolean>(false);
this.container.isNotificationConsoleExpanded.subscribe((isExpanded: boolean) => {
this.resizePane();
});
this.container.isNotificationConsoleExpanded.extend({ rateLimit: 10 });
} }
public cancel() { public cancel() {

View File

@ -57,7 +57,6 @@ describe("Delete Collection Confirmation Pane", () => {
describe("shouldRecordFeedback()", () => { describe("shouldRecordFeedback()", () => {
it("should return true if last collection and database does not have shared throughput else false", () => { it("should return true if last collection and database does not have shared throughput else false", () => {
let fakeExplorer = new Explorer(); let fakeExplorer = new Explorer();
fakeExplorer.isNotificationConsoleExpanded = ko.observable<boolean>(false);
fakeExplorer.refreshAllDatabases = () => Q.resolve(); fakeExplorer.refreshAllDatabases = () => Q.resolve();
let pane = new DeleteCollectionConfirmationPane({ let pane = new DeleteCollectionConfirmationPane({
@ -101,7 +100,6 @@ describe("Delete Collection Confirmation Pane", () => {
rid: "test", rid: "test",
} as ViewModels.Collection; } as ViewModels.Collection;
}; };
fakeExplorer.isNotificationConsoleExpanded = ko.observable<boolean>(false);
fakeExplorer.selectedCollectionId = ko.computed<string>(() => selectedCollectionId); fakeExplorer.selectedCollectionId = ko.computed<string>(() => selectedCollectionId);
fakeExplorer.isSelectedDatabaseShared = () => false; fakeExplorer.isSelectedDatabaseShared = () => false;
const SubscriptionId = "testId"; const SubscriptionId = "testId";

View File

@ -55,7 +55,6 @@ describe("Delete Database Confirmation Pane", () => {
describe("shouldRecordFeedback()", () => { describe("shouldRecordFeedback()", () => {
it("should return true if last non empty database or is last database that has shared throughput, else false", () => { it("should return true if last non empty database or is last database that has shared throughput, else false", () => {
let fakeExplorer = {} as Explorer; let fakeExplorer = {} as Explorer;
fakeExplorer.isNotificationConsoleExpanded = ko.observable<boolean>(false);
let pane = new DeleteDatabaseConfirmationPane({ let pane = new DeleteDatabaseConfirmationPane({
id: "deletedatabaseconfirmationpane", id: "deletedatabaseconfirmationpane",
@ -92,7 +91,6 @@ describe("Delete Database Confirmation Pane", () => {
} as ViewModels.Database; } as ViewModels.Database;
}; };
fakeExplorer.refreshAllDatabases = () => Q.resolve(); fakeExplorer.refreshAllDatabases = () => Q.resolve();
fakeExplorer.isNotificationConsoleExpanded = ko.observable<boolean>(false);
fakeExplorer.selectedDatabaseId = ko.computed<string>(() => selectedDatabaseId); fakeExplorer.selectedDatabaseId = ko.computed<string>(() => selectedDatabaseId);
fakeExplorer.isSelectedDatabaseShared = () => false; fakeExplorer.isSelectedDatabaseShared = () => false;
const SubscriptionId = "testId"; const SubscriptionId = "testId";

View File

@ -34,13 +34,6 @@ export class GenericRightPaneComponent extends React.Component<GenericRightPaneP
}; };
} }
public componentDidMount(): void {
this.notificationConsoleSubscription = this.props.container.isNotificationConsoleExpanded.subscribe(() => {
this.setState({ panelHeight: this.getPanelHeight() });
});
this.props.container.isNotificationConsoleExpanded.extend({ rateLimit: 10 });
}
public componentWillUnmount(): void { public componentWillUnmount(): void {
this.notificationConsoleSubscription && this.notificationConsoleSubscription.dispose(); this.notificationConsoleSubscription && this.notificationConsoleSubscription.dispose();
} }

View File

@ -240,10 +240,7 @@ function updateTableScrollableRegionHeight(): void {
var dataTablesScrollBodyPosY = $(tabElement).find(Constants.htmlSelectors.dataTableScrollBodySelector).offset().top; var dataTablesScrollBodyPosY = $(tabElement).find(Constants.htmlSelectors.dataTableScrollBodySelector).offset().top;
var dataTablesInfoElem = $(tabElement).find(".dataTables_info"); var dataTablesInfoElem = $(tabElement).find(".dataTables_info");
var dataTablesPaginateElem = $(tabElement).find(".dataTables_paginate"); var dataTablesPaginateElem = $(tabElement).find(".dataTables_paginate");
const explorer = window.dataExplorer; const notificationConsoleHeight = 32; /** Header height **/
const notificationConsoleHeight = explorer.isNotificationConsoleExpanded()
? 252 /** 32px(header) + 220px(content height) **/
: 32; /** Header height **/
var scrollHeight = var scrollHeight =
bodyHeight - bodyHeight -

View File

@ -54,7 +54,8 @@ import "./Libs/is-integer-polyfill";
import "url-polyfill/url-polyfill.min"; import "url-polyfill/url-polyfill.min";
import { initializeIcons } from "office-ui-fabric-react/lib/Icons"; import { initializeIcons } from "office-ui-fabric-react/lib/Icons";
import React from "react"; import { ExplorerParams } from "./Explorer/Explorer";
import React, { useState } from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import copyImage from "../images/Copy.svg"; import copyImage from "../images/Copy.svg";
import hdeConnectImage from "../images/HdeConnectCosmosDB.svg"; import hdeConnectImage from "../images/HdeConnectCosmosDB.svg";
@ -63,12 +64,22 @@ import arrowLeftImg from "../images/imgarrowlefticon.svg";
import { KOCommentEnd, KOCommentIfStart } from "./koComment"; import { KOCommentEnd, KOCommentIfStart } from "./koComment";
import { useConfig } from "./hooks/useConfig"; import { useConfig } from "./hooks/useConfig";
import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer"; import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer";
import { NotificationConsoleComponent } from "./Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
initializeIcons(); initializeIcons();
const App: React.FunctionComponent = () => { const App: React.FunctionComponent = () => {
const [isNotificationConsoleExpanded, setIsNotificationConsoleExpanded] = useState(false);
const [notificationConsoleData, setNotificationConsoleData] = useState(undefined);
//TODO: Refactor so we don't need to pass the id to remove a console data
const [inProgressConsoleDataIdToBeDeleted, setInProgressConsoleDataIdToBeDeleted] = useState("");
const explorerParams: ExplorerParams = {
setIsNotificationConsoleExpanded,
setNotificationConsoleData,
setInProgressConsoleDataIdToBeDeleted,
};
const config = useConfig(); const config = useConfig();
useKnockoutExplorer(config); useKnockoutExplorer(config, explorerParams);
return ( return (
<div className="flexContainer"> <div className="flexContainer">
@ -270,9 +281,15 @@ const App: React.FunctionComponent = () => {
role="contentinfo" role="contentinfo"
aria-label="Notification console" aria-label="Notification console"
id="explorerNotificationConsole" id="explorerNotificationConsole"
data-bind="react: notificationConsoleComponentAdapter" >
<NotificationConsoleComponent
isConsoleExpanded={isNotificationConsoleExpanded}
consoleData={notificationConsoleData}
inProgressConsoleDataIdToBeDeleted={inProgressConsoleDataIdToBeDeleted}
setIsConsoleExpanded={setIsNotificationConsoleExpanded}
/> />
</div> </div>
</div>
{/* Global loader - Start */} {/* Global loader - Start */}
<div className="splashLoaderContainer" data-bind="visible: isRefreshingExplorer"> <div className="splashLoaderContainer" data-bind="visible: isRefreshingExplorer">

View File

@ -19,14 +19,13 @@ export function logConsoleMessage(type: ConsoleDataType, message: string, id?: s
if (!id) { if (!id) {
id = _.uniqueId(); id = _.uniqueId();
} }
dataExplorer.logConsoleData({ type: type, date: formattedDate, message: message, id: id }); dataExplorer.logConsoleData({ type, date: formattedDate, message, id });
} }
return id || ""; return id || "";
} }
export function clearInProgressMessageWithId(id: string): void { export function clearInProgressMessageWithId(id: string): void {
const dataExplorer = _global.dataExplorer; _global.dataExplorer?.deleteInProgressConsoleDataWithId(id);
dataExplorer && dataExplorer.deleteInProgressConsoleDataWithId(id);
} }
export function logConsoleProgress(message: string): () => void { export function logConsoleProgress(message: string): () => void {

View File

@ -7,7 +7,7 @@ import { configContext, ConfigContext, Platform } from "../ConfigContext";
import { ActionType, DataExplorerAction } from "../Contracts/ActionContracts"; import { ActionType, DataExplorerAction } from "../Contracts/ActionContracts";
import { MessageTypes } from "../Contracts/ExplorerContracts"; import { MessageTypes } from "../Contracts/ExplorerContracts";
import { DataExplorerInputsFrame } from "../Contracts/ViewModels"; import { DataExplorerInputsFrame } from "../Contracts/ViewModels";
import Explorer from "../Explorer/Explorer"; import Explorer, { ExplorerParams } from "../Explorer/Explorer";
import { import {
AAD, AAD,
ConnectionString, ConnectionString,
@ -34,8 +34,8 @@ import { isInvalidParentFrameOrigin } from "../Utils/MessageValidation";
// Pleas tread carefully :) // Pleas tread carefully :)
let explorer: Explorer; let explorer: Explorer;
export function useKnockoutExplorer(config: ConfigContext): Explorer { export function useKnockoutExplorer(config: ConfigContext, explorerParams: ExplorerParams): Explorer {
explorer = explorer || new Explorer(); explorer = explorer || new Explorer(explorerParams);
useEffect(() => { useEffect(() => {
const effect = async () => { const effect = async () => {
if (config) { if (config) {