Migrate Query Tab to React (#852)

Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
This commit is contained in:
vaidankarswapnil
2021-06-15 00:45:13 +05:30
committed by GitHub
parent baa3252ba8
commit 999fad3bad
13 changed files with 1496 additions and 62 deletions

View File

@@ -12,7 +12,7 @@ import {
QueriesGridComponentProps,
} from "../../Controls/QueriesGridReactComponent/QueriesGridComponent";
import Explorer from "../../Explorer";
import QueryTab from "../../Tabs/QueryTab";
import { NewQueryTab } from "../../Tabs/QueryTab/QueryTab";
interface BrowseQueriesPaneProps {
explorer: Explorer;
@@ -31,13 +31,13 @@ export const BrowseQueriesPane: FunctionComponent<BrowseQueriesPaneProps> = ({
} else if (userContext.apiType === "Mongo") {
selectedCollection.onNewMongoQueryClick(selectedCollection, undefined);
} else {
selectedCollection.onNewQueryClick(selectedCollection, undefined);
selectedCollection.onNewQueryClick(selectedCollection, undefined, savedQuery.query);
}
const queryTab = explorer.tabsManager.activeTab() as QueryTab;
const queryTab = explorer && (explorer.tabsManager.activeTab() as NewQueryTab);
queryTab.tabTitle(savedQuery.queryName);
queryTab.tabPath(`${selectedCollection.databaseId}>${selectedCollection.id()}>${savedQuery.queryName}`);
queryTab.initialEditorContent(savedQuery.query);
queryTab.sqlQueryEditorContent(savedQuery.query);
trace(Action.LoadSavedQuery, ActionModifiers.Mark, {
dataExplorerArea: Areas.ContextualPane,
queryName: savedQuery.queryName,

View File

@@ -8,7 +8,6 @@ import { useSidePanel } from "../../../hooks/useSidePanel";
import { userContext } from "../../../UserContext";
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
import Explorer from "../../Explorer";
import QueryTab from "../../Tabs/QueryTab";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
interface LoadQueryPaneProps {
@@ -60,20 +59,19 @@ export const LoadQueryPane: FunctionComponent<LoadQueryPaneProps> = ({ explorer
const loadQueryFromFile = async (file: File): Promise<void> => {
const selectedCollection: Collection = explorer?.findSelectedCollection();
if (!selectedCollection) {
logError("No collection was selected", "LoadQueryPane.loadQueryFromFile");
} else if (userContext.apiType === "Mongo") {
selectedCollection.onNewMongoQueryClick(selectedCollection, undefined);
} else {
selectedCollection.onNewQueryClick(selectedCollection, undefined);
}
const reader = new FileReader();
let fileData: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
reader.onload = (evt: any): void => {
const fileData: string = evt.target.result;
const queryTab = explorer.tabsManager.activeTab() as QueryTab;
queryTab.initialEditorContent(fileData);
queryTab.sqlQueryEditorContent(fileData);
fileData = evt.target.result;
if (!selectedCollection) {
logError("No collection was selected", "LoadQueryPane.loadQueryFromFile");
} else if (userContext.apiType === "Mongo") {
selectedCollection.onNewMongoQueryClick(selectedCollection, undefined);
} else {
selectedCollection.onNewQueryClick(selectedCollection, undefined, fileData);
}
};
reader.onerror = (): void => {

View File

@@ -9,7 +9,7 @@ import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
import { traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor";
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
import Explorer from "../../Explorer";
import QueryTab from "../../Tabs/QueryTab";
import { NewQueryTab } from "../../Tabs/QueryTab/QueryTab";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
interface SaveQueryPaneProps {
@@ -33,8 +33,9 @@ export const SaveQueryPane: FunctionComponent<SaveQueryPaneProps> = ({ explorer
logConsoleError("Failed to save query: account not setup to save queries");
}
const queryTab = explorer && (explorer.tabsManager.activeTab() as QueryTab);
const query: string = queryTab && queryTab.sqlQueryEditorContent();
const queryTab = explorer && (explorer.tabsManager.activeTab() as NewQueryTab);
const query: string = queryTab && queryTab.iTabAccessor.onSaveClickEvent();
if (!queryName || queryName.length === 0) {
setFormError("No query name specified");
logConsoleError("Could not save query -- No query name specified. Please specify a query name.");

View File

@@ -281,7 +281,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
}
/** Renders a Javascript object to be displayed inside Monaco Editor */
protected renderObjectForEditor(value: any, replacer: any, space: string | number): string {
public renderObjectForEditor(value: any, replacer: any, space: string | number): string {
return MongoUtility.tojson(value, null, false);
}

View File

@@ -1,10 +1,10 @@
import * as ViewModels from "../../Contracts/ViewModels";
import Q from "q";
import MongoUtility from "../../Common/MongoUtility";
import QueryTab from "./QueryTab";
import * as HeadersUtility from "../../Common/HeadersUtility";
import { queryIterator } from "../../Common/MongoProxyClient";
import { MinimalQueryIterator } from "../../Common/IteratorUtilities";
import { queryIterator } from "../../Common/MongoProxyClient";
import MongoUtility from "../../Common/MongoUtility";
import * as ViewModels from "../../Contracts/ViewModels";
import QueryTab from "./QueryTab";
export default class MongoQueryTab extends QueryTab {
public collection: ViewModels.Collection;
@@ -16,7 +16,7 @@ export default class MongoQueryTab extends QueryTab {
this.monacoSettings = new ViewModels.MonacoEditorSettings("plaintext", false);
}
/** Renders a Javascript object to be displayed inside Monaco Editor */
protected renderObjectForEditor(value: any, replacer: any, space: string | number): string {
public renderObjectForEditor(value: any, replacer: any, space: string | number): string {
return MongoUtility.tojson(value, null, false);
}

View File

@@ -0,0 +1,54 @@
import React from "react";
import * as DataModels from "../../../Contracts/DataModels";
import type { QueryTabOptions } from "../../../Contracts/ViewModels";
import Explorer from "../../Explorer";
import { IQueryTabComponentProps, ITabAccessor } from "../../Tabs/QueryTab/QueryTabComponent";
import TabsBase from "../TabsBase";
import QueryTabComponent from "./QueryTabComponent";
export interface IQueryTabProps {
container: Explorer;
}
export class NewQueryTab extends TabsBase {
public queryText: string;
public currentQuery: string;
public partitionKey: DataModels.PartitionKey;
public iQueryTabComponentProps: IQueryTabComponentProps;
public iTabAccessor: ITabAccessor;
constructor(options: QueryTabOptions, private props: IQueryTabProps) {
super(options);
this.partitionKey = options.partitionKey;
this.iQueryTabComponentProps = {
collection: this.collection,
isExecutionError: this.isExecutionError(),
tabId: this.tabId,
tabsBaseInstance: this,
queryText: options.queryText,
partitionKey: this.partitionKey,
container: this.props.container,
onTabAccessor: (instance: ITabAccessor): void => {
this.iTabAccessor = instance;
},
};
}
public render(): JSX.Element {
return <QueryTabComponent {...this.iQueryTabComponentProps} />;
}
public onTabClick(): void {
this.manager?.activateTab(this);
this.iTabAccessor.onTabClickEvent();
}
public onCloseTabButtonClick(): void {
this.manager?.closeTab(this);
this.iTabAccessor.onCloseClickEvent(true);
}
public getContainer(): Explorer {
return this.props.container;
}
}

View File

@@ -0,0 +1,285 @@
@import "../../../../less/Common/Constants.less";
@import "../../../../less/Common/TabCommon.less";
@MongoQueryEditorHeight: 50px;
@ResultsTextFontWeight: 600;
@ToggleHeight: 30px;
@ToggleWidth: 250px;
@QueryEngineExeInfo: 305px;
.tab-pane {
.tabContentContainer();
.tabPaneContentContainer {
position: relative;
.tabContentContainer();
.mongoQueryHelper {
margin: @DefaultSpace 0px 0px 44px;
}
.splitter-layout {
.layout-pane-primary {
overflow: hidden !important;
.queryEditor {
.flex-display();
height: 100%;
width: 100%;
margin-top: @SmallSpace;
.jsonEditor {
border: none;
margin-top: @SmallSpace;
}
}
}
.queryEditor.mongoQueryEditor {
margin-top: 32px;
overflow: hidden;
}
.queryEditorHorizontalSplitter {
margin: auto;
display: block;
}
}
.queryErrorsHeaderContainer {
padding: 24px @LargeSpace 0px @MediumSpace;
.queryErrors {
font-size: @mediumFontSize;
list-style-type: none;
color: @BaseDark;
font-weight: bold;
margin-left: 24px;
}
}
.queryResultErrorContentContainer {
.flex-display();
.flex-direction();
font-size: @DefaultFontSize;
padding: @DefaultSpace;
height: 100%;
width: 100%;
overflow: hidden;
.queryEditorWatermark {
text-align: center;
margin: auto;
height: 25vh; // this is to align the water mark in center of the layout.
p {
margin-bottom: @LargeSpace;
color: @BaseHigh;
}
.queryEditorWatermarkText {
color: @BaseHigh;
font-size: @DefaultFontSize;
font-family: @DataExplorerFont;
}
}
.queryResultsErrorsContent {
height: 100%;
margin-left: @MediumSpace;
.flex-display();
.flex-direction();
div[role="tabpanel"] {
height: 100%;
div:nth-child(1) {
height: 100%;
}
}
.result-metadata {
padding: @LargeSpace @SmallSpace @MediumSpace @MediumSpace;
height: auto !important;
.queryResultDivider {
margin-left: @SmallSpace;
margin-right: @SmallSpace;
}
.queryResultNextEnable {
color: @AccentMediumHigh;
font-size: @mediumFontSize;
cursor: pointer;
img {
height: @ImgHeight;
width: @ImgWidth;
margin-left: @SmallSpace;
}
}
.queryResultNextDisable {
color: @BaseMediumHigh;
opacity: 0.5;
font-size: @mediumFontSize;
img {
height: @ImgHeight;
width: @ImgWidth;
margin-left: @SmallSpace;
}
}
}
.tab-pane.active {
height: 100%;
width: 100%;
}
.errorContent {
.flex-display();
width: 60%;
white-space: nowrap;
font-size: @mediumFontSize;
padding: 0px @MediumSpace 0px @MediumSpace;
.errorMessage {
padding: @SmallSpace;
overflow: hidden;
text-overflow: ellipsis;
}
}
.errorDetailsLink {
cursor: pointer;
padding: @SmallSpace;
}
.queryMetricsSummaryContainer {
.flex-display();
.flex-direction();
overflow: hidden;
position: relative;
height: 100%;
.queryMetricsSummary {
margin: @LargeSpace @LargeSpace 0px @DefaultSpace;
table-layout: fixed;
display: block;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
caption {
width: 100px;
}
.queryMetricsSummaryHead {
.flex-display();
}
.queryMetricsSummaryHeader.queryMetricsSummaryTuple {
font-size: 10px;
}
.queryMetricsSummaryBody {
.flex-display();
.flex-direction();
}
.queryMetricsSummaryTuple {
border-bottom: 1px solid @BaseMedium;
height: 32px;
font-size: 12px;
width: 100%;
.flex-display();
th,
td {
padding: @DefaultSpace;
&:nth-child(1) {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
flex: 0 0 50%;
}
&:nth-child(3) {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
flex: 0 0 50%;
}
.queryMetricInfoTooltip {
.infoTooltip();
&:hover .queryMetricTooltipText {
.tooltipVisible();
}
&:focus .queryMetricTooltipText {
.tooltipVisible();
}
.queryMetricTooltipText {
top: -50px;
width: auto;
white-space: nowrap;
left: 6px;
visibility: hidden;
background-color: @BaseHigh;
color: @BaseLight;
position: absolute;
z-index: 1;
padding: @MediumSpace;
&::after {
border-width: (2 * @MediumSpace) (2 * @MediumSpace) 0px 0px;
bottom: -14px;
.tooltipTextAfter();
}
}
.queryEngineExeTimeInfo {
width: @QueryEngineExeInfo;
top: -85px;
white-space: pre-wrap;
}
}
}
}
}
.downloadMetricsLinkContainer {
margin: 24px 0px 50px @MediumSpace;
position: sticky;
#downloadMetricsLink {
color: @BaseHigh;
padding: @DefaultSpace;
font-size: @mediumFontSize;
border: @ButtonBorderWidth solid @BaseLight;
cursor: pointer;
&:hover {
.hover();
}
&:active {
border: @ButtonBorderWidth dashed @AccentMedium;
.active();
}
}
}
}
json-editor {
.flex-display();
.flex-direction();
overflow: hidden;
height: 100%;
width: 100%;
padding: @SmallSpace 0px @SmallSpace @MediumSpace;
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,6 @@ import Explorer from "../Explorer";
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
import { TabsManager } from "./TabsManager";
// TODO: Use specific actions for logging telemetry data
export default class TabsBase extends WaitsForTemplateViewModel {
private static id = 0;
@@ -149,7 +148,7 @@ export default class TabsBase extends WaitsForTemplateViewModel {
}
/** Renders a Javascript object to be displayed inside Monaco Editor */
protected renderObjectForEditor(value: any, replacer: any, space: string | number): string {
public renderObjectForEditor(value: any, replacer: any, space: string | number): string {
return JSON.stringify(value, replacer, space);
}
@@ -164,7 +163,7 @@ export default class TabsBase extends WaitsForTemplateViewModel {
return [];
}
protected updateNavbarWithTabsButtons = (): void => {
public updateNavbarWithTabsButtons = (): void => {
if (this.isActive()) {
useCommandBar.getState().setContextButtons(this.getTabsButtons());
}

View File

@@ -30,7 +30,7 @@ import GraphTab from "../Tabs/GraphTab";
import MongoDocumentsTab from "../Tabs/MongoDocumentsTab";
import MongoQueryTab from "../Tabs/MongoQueryTab";
import MongoShellTab from "../Tabs/MongoShellTab";
import QueryTab from "../Tabs/QueryTab";
import { NewQueryTab } from "../Tabs/QueryTab/QueryTab";
import QueryTablesTab from "../Tabs/QueryTablesTab";
import { CollectionSettingsTabV2 } from "../Tabs/SettingsTabV2";
import ConflictId from "./ConflictId";
@@ -617,19 +617,22 @@ export default class Collection implements ViewModels.Collection {
tabTitle: title,
});
const queryTab: QueryTab = new QueryTab({
tabKind: ViewModels.CollectionTabKind.Query,
title: title,
tabPath: "",
collection: this,
node: this,
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/query`,
queryText: queryText,
partitionKey: collection.partitionKey,
onLoadStartKey: startKey,
});
this.container.tabsManager.activateNewTab(queryTab);
this.container.tabsManager.activateNewTab(
new NewQueryTab(
{
tabKind: ViewModels.CollectionTabKind.Query,
title: title,
tabPath: "",
collection: this,
node: this,
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/query`,
queryText: queryText,
partitionKey: collection.partitionKey,
onLoadStartKey: startKey,
},
{ container: this.container }
)
);
}
public onNewMongoQueryClick(source: any, event: MouseEvent, queryText?: string) {