Remove SplashScreenComponentAdapter (#440)

Merge SplashScreenComponentAdapter and SplashScreenComponent into one SplashScreen React component.
This commit is contained in:
Jordi Bunster 2021-02-23 11:15:57 -08:00 committed by GitHub
parent f0c82a430b
commit e8e5eb55cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 153 additions and 207 deletions

View File

@ -162,7 +162,7 @@ src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts
src/Explorer/Panes/UploadFilePane.ts
src/Explorer/Panes/UploadItemsPane.ts
src/Explorer/SplashScreen/SplashScreenComponentAdapter.test.ts
src/Explorer/SplashScreen/SplashScreen.test.ts
src/Explorer/Tables/Constants.ts
src/Explorer/Tables/DataTable/CacheBase.ts
src/Explorer/Tables/DataTable/DataTableBindingManager.ts
@ -377,8 +377,7 @@ src/Explorer/Notebook/temp/inputs/editor.tsx
src/Explorer/Notebook/temp/markdown-cell.tsx
src/Explorer/Notebook/temp/source.tsx
src/Explorer/Notebook/temp/syntax-highlighter/index.tsx
src/Explorer/SplashScreen/SplashScreenComponent.tsx
src/Explorer/SplashScreen/SplashScreenComponentApdapter.tsx
src/Explorer/SplashScreen/SplashScreen.tsx
src/Explorer/Tabs/GalleryTab.tsx
src/Explorer/Tabs/NotebookViewerTab.tsx
src/Explorer/Tabs/TerminalTab.tsx

View File

@ -1138,12 +1138,6 @@ exports[`SettingsComponent renders 1`] = `
"shouldShowShareDialogContents": [Function],
"signInAad": [Function],
"sparkClusterConnectionInfo": [Function],
"splashScreenAdapter": SplashScreenComponentAdapter {
"clearMostRecent": [Function],
"container": [Circular],
"forceRender": [Function],
"parameters": [Function],
},
"splitter": Splitter {
"bounds": Object {
"max": 400,
@ -2383,12 +2377,6 @@ exports[`SettingsComponent renders 1`] = `
"shouldShowShareDialogContents": [Function],
"signInAad": [Function],
"sparkClusterConnectionInfo": [Function],
"splashScreenAdapter": SplashScreenComponentAdapter {
"clearMostRecent": [Function],
"container": [Circular],
"forceRender": [Function],
"parameters": [Function],
},
"splitter": Splitter {
"bounds": Object {
"max": 400,
@ -3641,12 +3629,6 @@ exports[`SettingsComponent renders 1`] = `
"shouldShowShareDialogContents": [Function],
"signInAad": [Function],
"sparkClusterConnectionInfo": [Function],
"splashScreenAdapter": SplashScreenComponentAdapter {
"clearMostRecent": [Function],
"container": [Circular],
"forceRender": [Function],
"parameters": [Function],
},
"splitter": Splitter {
"bounds": Object {
"max": 400,
@ -4886,12 +4868,6 @@ exports[`SettingsComponent renders 1`] = `
"shouldShowShareDialogContents": [Function],
"signInAad": [Function],
"sparkClusterConnectionInfo": [Function],
"splashScreenAdapter": SplashScreenComponentAdapter {
"clearMostRecent": [Function],
"container": [Circular],
"forceRender": [Function],
"parameters": [Function],
},
"splitter": Splitter {
"bounds": Object {
"max": 400,

View File

@ -63,7 +63,7 @@ import { RouteHandler } from "../RouteHandlers/RouteHandler";
import { SaveQueryPane } from "./Panes/SaveQueryPane";
import { SettingsPane } from "./Panes/SettingsPane";
import { SetupNotebooksPane } from "./Panes/SetupNotebooksPane";
import { SplashScreenComponentAdapter } from "./SplashScreen/SplashScreenComponentApdapter";
import { SplashScreen } from "./SplashScreen/SplashScreen";
import { Splitter, SplitterBounds, SplitterDirection } from "../Common/Splitter";
import { StringInputPane } from "./Panes/StringInputPane";
import { TableColumnOptionsPane } from "./Panes/Tables/TableColumnOptionsPane";
@ -263,7 +263,6 @@ export default class Explorer {
// React adapters
private commandBarComponentAdapter: CommandBarComponentAdapter;
private splashScreenAdapter: SplashScreenComponentAdapter;
private dialogComponentAdapter: DialogComponentAdapter;
private _dialogProps: ko.Observable<DialogProps>;
private addSynapseLinkDialog: DialogComponentAdapter;
@ -986,7 +985,6 @@ export default class Explorer {
});
this.dialogComponentAdapter = new DialogComponentAdapter();
this.dialogComponentAdapter.parameters = this._dialogProps;
this.splashScreenAdapter = new SplashScreenComponentAdapter(this);
this.mostRecentActivity = new MostRecentActivity.MostRecentActivity(this);
this._addSynapseLinkDialogProps = ko.observable<DialogProps>({

View File

@ -1,6 +1,6 @@
import * as ko from "knockout";
import { DataSamplesUtil } from "../DataSamples/DataSamplesUtil";
import { SplashScreenComponentAdapter } from "./SplashScreenComponentApdapter";
import { SplashScreen } from "./SplashScreen";
import { TabsManager } from "../Tabs/TabsManager";
import Explorer from "../Explorer";
jest.mock("../Explorer");
@ -14,7 +14,7 @@ const createExplorer = () => {
return mock as jest.Mocked<Explorer>;
};
describe("SplashScreenComponentAdapter", () => {
describe("SplashScreen", () => {
it("allows sample collection creation for supported api's", () => {
const explorer = createExplorer();
const dataSampleUtil = new DataSamplesUtil(explorer);
@ -25,9 +25,9 @@ describe("SplashScreenComponentAdapter", () => {
// Sample is supported
jest.spyOn(dataSampleUtil, "isSampleContainerCreationSupported").mockImplementation(() => true);
const splashScreenAdapter = new SplashScreenComponentAdapter(explorer);
jest.spyOn(splashScreenAdapter, "createDataSampleUtil").mockImplementation(() => dataSampleUtil);
const mainButtons = splashScreenAdapter.createMainItems();
const splashScreen = new SplashScreen({ explorer });
jest.spyOn(splashScreen, "createDataSampleUtil").mockImplementation(() => dataSampleUtil);
const mainButtons = splashScreen.createMainItems();
// Press all buttons and make sure create gets called
mainButtons.forEach((button) => {
@ -50,9 +50,9 @@ describe("SplashScreenComponentAdapter", () => {
// Sample is not supported
jest.spyOn(dataSampleUtil, "isSampleContainerCreationSupported").mockImplementation(() => false);
const splashScreenAdapter = new SplashScreenComponentAdapter(explorerStub);
jest.spyOn(splashScreenAdapter, "createDataSampleUtil").mockImplementation(() => dataSampleUtil);
const mainButtons = splashScreenAdapter.createMainItems();
const splashScreen = new SplashScreen({ explorer: explorerStub });
jest.spyOn(splashScreen, "createDataSampleUtil").mockImplementation(() => dataSampleUtil);
const mainButtons = splashScreen.createMainItems();
// Press all buttons and make sure create doesn't get called
mainButtons.forEach((button) => {

View File

@ -1,63 +1,161 @@
/**
* Accordion top class
*/
import * as ko from "knockout";
import * as React from "react";
import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
import * as ViewModels from "../../Contracts/ViewModels";
import * as Constants from "../../Common/Constants";
import { Link } from "office-ui-fabric-react/lib/Link";
import NewContainerIcon from "../../../images/Hero-new-container.svg";
import NewNotebookIcon from "../../../images/Hero-new-notebook.svg";
import NewQueryIcon from "../../../images/AddSqlQuery_16x16.svg";
import OpenQueryIcon from "../../../images/BrowseQuery.svg";
import NewStoredProcedureIcon from "../../../images/AddStoredProcedure.svg";
import ScaleAndSettingsIcon from "../../../images/Scale_15x15.svg";
import { SplashScreenComponent, SplashScreenItem } from "./SplashScreenComponent";
import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity";
import AddDatabaseIcon from "../../../images/AddDatabase.svg";
import SampleIcon from "../../../images/Hero-sample.svg";
import { DataSamplesUtil } from "../DataSamples/DataSamplesUtil";
import Explorer from "../Explorer";
import { userContext } from "../../UserContext";
import { FeaturePanelLauncher } from "../Controls/FeaturePanel/FeaturePanelLauncher";
/**
* TODO Remove this when fully ported to ReactJS
*/
export class SplashScreenComponentAdapter implements ReactAdapter {
export interface SplashScreenItem {
iconSrc: string;
title: string;
info?: string;
description: string;
onClick: () => void;
}
export interface SplashScreenProps {
explorer: Explorer;
}
export class SplashScreen extends React.Component<SplashScreenProps> {
private static readonly seeMoreItemTitle: string = "See more Cosmos DB documentation";
private static readonly seeMoreItemUrl: string = "https://aka.ms/cosmosdbdocument";
private static readonly dataModelingUrl = "https://docs.microsoft.com/azure/cosmos-db/modeling-data";
private static readonly throughputEstimatorUrl = "https://cosmos.azure.com/capacitycalculator";
private static readonly failoverUrl = "https://docs.microsoft.com/azure/cosmos-db/high-availability";
public parameters: ko.Observable<number>;
private readonly container: Explorer;
constructor(private container: Explorer) {
this.parameters = ko.observable<number>(Date.now());
this.container.tabsManager.openedTabs.subscribe((tabs) => {
if (tabs.length === 0) {
this.forceRender();
}
});
this.container.selectedNode.subscribe(this.forceRender);
this.container.isNotebookEnabled.subscribe(this.forceRender);
constructor(props: SplashScreenProps) {
super(props);
this.container = props.explorer;
this.container.tabsManager.openedTabs.subscribe(() => this.setState({}));
this.container.selectedNode.subscribe(() => this.setState({}));
this.container.isNotebookEnabled.subscribe(() => this.setState({}));
}
public forceRender = (): void => {
window.requestAnimationFrame(() => this.parameters(Date.now()));
};
public shouldComponentUpdate() {
return this.container.tabsManager.openedTabs.length === 0;
}
private clearMostRecent = (): void => {
this.container.mostRecentActivity.clear(userContext.databaseAccount?.id);
this.forceRender();
this.setState({});
};
public renderComponent(): JSX.Element {
public render(): JSX.Element {
const mainItems = this.createMainItems();
const commonTaskItems = this.createCommonTaskItems();
const recentItems = this.createRecentItems();
const tipsItems = this.createTipsItems();
const onClearRecent = this.clearMostRecent;
return (
<SplashScreenComponent
mainItems={this.createMainItems()}
commonTaskItems={this.createCommonTaskItems()}
recentItems={this.createRecentItems()}
tipsItems={this.createTipsItems()}
onClearRecent={this.clearMostRecent}
/>
<div className="splashScreenContainer">
<div className="splashScreen">
<div className="title">
Welcome to Cosmos DB
<FeaturePanelLauncher />
</div>
<div className="subtitle">Globally distributed, multi-model database service for any scale</div>
<div className="mainButtonsContainer">
{mainItems.map((item) => (
<div
className="mainButton focusable"
key={`${item.title}`}
onClick={item.onClick}
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
tabIndex={0}
role="button"
>
<img src={item.iconSrc} alt="" />
<div className="legendContainer">
<div className="legend">{item.title}</div>
<div className="description">{item.description}</div>
</div>
</div>
))}
</div>
<div className="moreStuffContainer">
<div className="moreStuffColumn commonTasks">
<div className="title">Common Tasks</div>
<ul>
{commonTaskItems.map((item) => (
<li
className="focusable"
key={`${item.title}${item.description}`}
onClick={item.onClick}
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
tabIndex={0}
role="button"
>
<img src={item.iconSrc} alt="" />
<span className="oneLineContent" title={item.info}>
{item.title}
</span>
</li>
))}
</ul>
</div>
<div className="moreStuffColumn">
<div className="title">Recents</div>
<ul>
{recentItems.map((item, index) => (
<li key={`${item.title}${item.description}${index}`}>
<img src={item.iconSrc} alt="" />
<span className="twoLineContent">
<Link onClick={item.onClick} title={item.info}>
{item.title}
</Link>
<div className="description">{item.description}</div>
</span>
</li>
))}
</ul>
{recentItems.length > 0 && <Link onClick={() => onClearRecent()}>Clear Recents</Link>}
</div>
<div className="moreStuffColumn tipsContainer">
<div className="title">Tips</div>
<ul>
{tipsItems.map((item) => (
<li
className="tipContainer focusable"
key={`${item.title}${item.description}`}
onClick={item.onClick}
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
tabIndex={0}
role="link"
>
<div className="title" title={item.info}>
{item.title}
</div>
<div className="description">{item.description}</div>
</li>
))}
<li>
<a role="link" href={SplashScreen.seeMoreItemUrl} target="_blank" tabIndex={0}>
{SplashScreen.seeMoreItemTitle}
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
);
}
@ -198,7 +296,7 @@ export class SplashScreenComponentAdapter implements ReactAdapter {
iconSrc: MostRecentActivity.MostRecentActivity.getItemIcon(item),
title: item.title,
description: item.description,
info: SplashScreenComponentAdapter.getInfo(item),
info: SplashScreen.getInfo(item),
onClick: () => this.container.mostRecentActivity.onItemClicked(item),
}));
}
@ -209,20 +307,27 @@ export class SplashScreenComponentAdapter implements ReactAdapter {
iconSrc: null,
title: "Data Modeling",
description: "Learn more about modeling",
onClick: () => window.open(SplashScreenComponentAdapter.dataModelingUrl),
onClick: () => window.open(SplashScreen.dataModelingUrl),
},
{
iconSrc: null,
title: "Cost & Throughput Calculation",
description: "Learn more about cost calculation",
onClick: () => window.open(SplashScreenComponentAdapter.throughputEstimatorUrl),
onClick: () => window.open(SplashScreen.throughputEstimatorUrl),
},
{
iconSrc: null,
title: "Configure automatic failover",
description: "Learn more about Cosmos DB high-availability",
onClick: () => window.open(SplashScreenComponentAdapter.failoverUrl),
onClick: () => window.open(SplashScreen.failoverUrl),
},
];
}
private onSplashScreenItemKeyPress(event: React.KeyboardEvent, callback: () => void) {
if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) {
callback();
event.stopPropagation();
}
}
}

View File

@ -1,133 +0,0 @@
/**
* Accordion top class
*/
import * as React from "react";
import * as Constants from "../../Common/Constants";
import { Link } from "office-ui-fabric-react/lib/Link";
import { FeaturePanelLauncher } from "../Controls/FeaturePanel/FeaturePanelLauncher";
export interface SplashScreenItem {
iconSrc: string;
title: string;
info?: string;
description: string;
onClick: () => void;
}
export interface SplashScreenComponentProps {
mainItems: SplashScreenItem[];
commonTaskItems: SplashScreenItem[];
recentItems: SplashScreenItem[];
tipsItems: SplashScreenItem[];
onClearRecent: () => void;
}
export class SplashScreenComponent extends React.Component<SplashScreenComponentProps> {
private static readonly seeMoreItemTitle: string = "See more Cosmos DB documentation";
private static readonly seeMoreItemUrl: string = "https://aka.ms/cosmosdbdocument";
public render(): JSX.Element {
return (
<div className="splashScreenContainer">
<div className="splashScreen">
<div className="title">
Welcome to Cosmos DB
<FeaturePanelLauncher />
</div>
<div className="subtitle">Globally distributed, multi-model database service for any scale</div>
<div className="mainButtonsContainer">
{this.props.mainItems.map((item: SplashScreenItem) => (
<div
className="mainButton focusable"
key={`${item.title}`}
onClick={item.onClick}
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
tabIndex={0}
role="button"
>
<img src={item.iconSrc} alt="" />
<div className="legendContainer">
<div className="legend">{item.title}</div>
<div className="description">{item.description}</div>
</div>
</div>
))}
</div>
<div className="moreStuffContainer">
<div className="moreStuffColumn commonTasks">
<div className="title">Common Tasks</div>
<ul>
{this.props.commonTaskItems.map((item: SplashScreenItem) => (
<li
className="focusable"
key={`${item.title}${item.description}`}
onClick={item.onClick}
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
tabIndex={0}
role="button"
>
<img src={item.iconSrc} alt="" />
<span className="oneLineContent" title={item.info}>
{item.title}
</span>
</li>
))}
</ul>
</div>
<div className="moreStuffColumn">
<div className="title">Recents</div>
<ul>
{this.props.recentItems.map((item: SplashScreenItem, index: number) => (
<li key={`${item.title}${item.description}${index}`}>
<img src={item.iconSrc} alt="" />
<span className="twoLineContent">
<Link onClick={item.onClick} title={item.info}>
{item.title}
</Link>
<div className="description">{item.description}</div>
</span>
</li>
))}
</ul>
{this.props.recentItems.length > 0 && (
<Link onClick={() => this.props.onClearRecent()}>Clear Recents</Link>
)}
</div>
<div className="moreStuffColumn tipsContainer">
<div className="title">Tips</div>
<ul>
{this.props.tipsItems.map((item: SplashScreenItem) => (
<li
className="tipContainer focusable"
key={`${item.title}${item.description}`}
onClick={item.onClick}
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
tabIndex={0}
role="link"
>
<div className="title" title={item.info}>
{item.title}
</div>
<div className="description">{item.description}</div>
</li>
))}
<li>
<a role="link" href={SplashScreenComponent.seeMoreItemUrl} target="_blank" tabIndex={0}>
{SplashScreenComponent.seeMoreItemTitle}
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
);
}
private onSplashScreenItemKeyPress(event: React.KeyboardEvent, callback: () => void) {
if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) {
callback();
event.stopPropagation();
}
}
}

View File

@ -30,7 +30,7 @@ import "./Explorer/Panes/GraphNewVertexPane.less";
import "./Explorer/Tabs/QueryTab.less";
import "./Explorer/Controls/TreeComponent/treeComponent.less";
import "./Explorer/Controls/Accordion/AccordionComponent.less";
import "./Explorer/SplashScreen/SplashScreenComponent.less";
import "./Explorer/SplashScreen/SplashScreen.less";
import "./Explorer/Controls/Notebook/NotebookTerminalComponent.less";
// Image Dependencies
@ -68,6 +68,7 @@ import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer";
import { useSidePanel } from "./hooks/useSidePanel";
import { NotificationConsoleComponent } from "./Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
import { PanelContainerComponent } from "./Explorer/Panes/PanelContainerComponent";
import { SplashScreen } from "./Explorer/SplashScreen/SplashScreen";
initializeIcons();
@ -87,7 +88,7 @@ const App: React.FunctionComponent = () => {
closeSidePanel,
};
const config = useConfig();
useKnockoutExplorer(config?.platform, explorerParams);
const explorer = useKnockoutExplorer(config?.platform, explorerParams);
return (
<div className="flexContainer">
@ -275,7 +276,7 @@ const App: React.FunctionComponent = () => {
data-bind="visible: !isRefreshingExplorer() && tabsManager.openedTabs().length === 0"
>
<form className="connectExplorerFormContainer">
<div className="connectExplorer" data-bind="react: splashScreenAdapter" />
<SplashScreen explorer={explorer} />
</form>
</div>
<div