refactor documentTab code

This commit is contained in:
sunilyadav840 2021-07-12 01:03:03 +05:30
parent 8f1f3c1c65
commit d9614cb751
5 changed files with 89 additions and 192 deletions

View File

@ -87,6 +87,7 @@ export interface SubscriptionPolicies {
} }
export interface Resource { export interface Resource {
_partitionKeyValue?: string;
_rid: string; _rid: string;
_self: string; _self: string;
_etag: string; _etag: string;

View File

@ -15,9 +15,7 @@ exports[`Upload Items Pane should render Default properly 1`] = `
multiple={true} multiple={true}
onUpload={[Function]} onUpload={[Function]}
tabIndex={0} tabIndex={0}
tooltip="Select one or more JSON files to upload. Each file can contain a single JSON document or an array of JSON tooltip="Select one or more JSON files to upload. Each file can contain a single JSON document or an array of JSON documents. The combined size of all files in an individual upload operation must be less than 2 MB. You can perform multiple upload operations for larger data sets."
documents. The combined size of all files in an individual upload operation must be less than 2 MB. You
can perform multiple upload operations for larger data sets."
/> />
</div> </div>
</RightPaneForm> </RightPaneForm>

View File

@ -86,13 +86,14 @@ export function formatDocumentContent(row: DocumentId): string {
} }
export function formatSqlDocumentContent(row: Resource): string { export function formatSqlDocumentContent(row: Resource): string {
const { id, _rid, _self, _ts, _etag } = row; const { id, _rid, _self, _ts, _etag, _partitionKeyValue } = row;
const documentContent = JSON.stringify({ const documentContent = JSON.stringify({
id: id || "", id: id || "",
_rid: _rid || "", _rid: _rid || "",
_self: _self || "", _self: _self || "",
_ts: _ts || "", _ts: _ts || "",
_etag: _etag || "", _etag: _etag || "",
_partitionKeyValue: _partitionKeyValue || "",
}); });
const formattedDocumentContent = documentContent.replace(/,/g, ",\n").replace("{", "{\n").replace("}", "\n}"); const formattedDocumentContent = documentContent.replace(/,/g, ",\n").replace("{", "{\n").replace("}", "\n}");
return formattedDocumentContent; return formattedDocumentContent;
@ -142,5 +143,11 @@ export const getfilterText = (isPreferredApiMongoDB: boolean, filter: string): s
} }
return "No filter applied"; return "No filter applied";
} }
return "Select * from C"; return `Select * from C ${filter}`;
};
export const getConfirmationMessage = (apiType: string): string => {
return apiType !== "Mongo"
? "Are you sure you want to delete the selected item ?"
: "Are you sure you want to delete the selected document ?";
}; };

View File

@ -10,7 +10,7 @@ import {
SelectionMode, SelectionMode,
Stack, Stack,
Text, Text,
TextField TextField,
} from "@fluentui/react"; } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import SplitterLayout from "react-splitter-layout"; import SplitterLayout from "react-splitter-layout";
@ -45,6 +45,7 @@ import DocumentsTab from "./DocumentsTab";
import { import {
formatDocumentContent, formatDocumentContent,
formatSqlDocumentContent, formatSqlDocumentContent,
getConfirmationMessage,
getDocumentItems, getDocumentItems,
getFilterPlaceholder, getFilterPlaceholder,
getFilterSuggestions, getFilterSuggestions,
@ -54,7 +55,7 @@ import {
IButton, IButton,
IDocumentsTabContentState, IDocumentsTabContentState,
imageProps, imageProps,
tabButtonVisibility tabButtonVisibility,
} from "./DocumentTabUtils"; } from "./DocumentTabUtils";
const filterIcon: IIconProps = { iconName: "Filter" }; const filterIcon: IIconProps = { iconName: "Filter" };
@ -108,15 +109,16 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
onRender: (item: DocumentId) => { onRender: (item: DocumentId) => {
return ( return (
<div onClick={() => this.handleRow(item)} className="documentIdItem"> <div onClick={() => this.handleRow(item)} className="documentIdItem">
{item.partitionKeyValue} {isPreferredApiMongoDB ? item.partitionKeyValue : item._partitionKeyValue}
</div> </div>
); );
}, },
}, },
]; ];
this.intitalDocumentContent = `{ \n ${isPreferredApiMongoDB ? '"_id"' : '"id"' this.intitalDocumentContent = `{ \n ${
}: "replace_with_new_document_id" \n }`; isPreferredApiMongoDB ? '"_id"' : '"id"'
}: "replace_with_new_document_id" \n }`;
this.state = { this.state = {
columns: columns, columns: columns,
@ -150,7 +152,7 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
return QueryUtils.buildDocumentsQuery(filter, this.props.partitionKeyProperty, this.props.partitionKey); return QueryUtils.buildDocumentsQuery(filter, this.props.partitionKeyProperty, this.props.partitionKey);
} }
querySqlDocumentsData = async (): Promise<void> => { private querySqlDocumentsData = async (): Promise<void> => {
this.props.isExecuting(true); this.props.isExecuting(true);
this.props.isExecutionError(false); this.props.isExecutionError(false);
const { filter } = this.state; const { filter } = this.state;
@ -175,7 +177,7 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
} }
}; };
queryDocumentsData = async (): Promise<void> => { private queryDocumentsData = async (): Promise<void> => {
this.props.isExecuting(true); this.props.isExecuting(true);
this.props.isExecutionError(false); this.props.isExecutionError(false);
try { try {
@ -202,7 +204,6 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
{ {
databaseName: this.props.collection.databaseId, databaseName: this.props.collection.databaseId,
collectionName: this.props.collection.id(), collectionName: this.props.collection.id(),
dataExplorerArea: Areas.Tab, dataExplorerArea: Areas.Tab,
tabTitle: this.props.tabTitle(), tabTitle: this.props.tabTitle(),
}, },
@ -217,7 +218,6 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
{ {
databaseName: this.props.collection.databaseId, databaseName: this.props.collection.databaseId,
collectionName: this.props.collection.id(), collectionName: this.props.collection.id(),
dataExplorerArea: Areas.Tab, dataExplorerArea: Areas.Tab,
tabTitle: this.props.tabTitle(), tabTitle: this.props.tabTitle(),
error: getErrorMessage(error), error: getErrorMessage(error),
@ -230,7 +230,7 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
} }
}; };
handleRow = (row: DocumentId | Resource): void => { private handleRow = (row: DocumentId | Resource): void => {
if (this.state.isEditorContentEdited) { if (this.state.isEditorContentEdited) {
const isChangesConfirmed = window.confirm("Your unsaved changes will be lost."); const isChangesConfirmed = window.confirm("Your unsaved changes will be lost.");
if (isChangesConfirmed) { if (isChangesConfirmed) {
@ -243,7 +243,7 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
} }
}; };
handleRowContent = (row: DocumentId | Resource): void => { private handleRowContent = (row: DocumentId | Resource): void => {
const formattedDocumentContent = const formattedDocumentContent =
userContext.apiType === "Mongo" userContext.apiType === "Mongo"
? formatDocumentContent(row as DocumentId) ? formatDocumentContent(row as DocumentId)
@ -255,7 +255,7 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
: this.updateSqlContent(row as Resource, formattedDocumentContent); : this.updateSqlContent(row as Resource, formattedDocumentContent);
}; };
updateContent = (row: DocumentId, formattedDocumentContent: string): void => { private updateContent = (row: DocumentId, formattedDocumentContent: string): void => {
this.setState( this.setState(
{ {
documentContent: formattedDocumentContent, documentContent: formattedDocumentContent,
@ -269,7 +269,7 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
); );
}; };
updateSqlContent = (row: Resource, formattedDocumentContent: string): void => { private updateSqlContent = (row: Resource, formattedDocumentContent: string): void => {
this.setState( this.setState(
{ {
documentContent: formattedDocumentContent, documentContent: formattedDocumentContent,
@ -283,7 +283,7 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
); );
}; };
handleFilter = (): void => { private handleFilter = (): void => {
userContext.apiType === "Mongo" ? this.queryDocumentsData() : this.querySqlDocumentsData(); userContext.apiType === "Mongo" ? this.queryDocumentsData() : this.querySqlDocumentsData();
this.setState({ this.setState({
isSuggestionVisible: false, isSuggestionVisible: false,
@ -291,7 +291,7 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
}; };
async updateSqlDocument(): Promise<void> { async updateSqlDocument(): Promise<void> {
const { partitionKey, partitionKeyProperty, isExecutionError, isExecuting, tabTitle, collection } = this.props; const { partitionKey, partitionKeyProperty, isExecutionError, isExecuting, collection } = this.props;
const { documentContent } = this.state; const { documentContent } = this.state;
const partitionKeyArray = extractPartitionKey( const partitionKeyArray = extractPartitionKey(
this.state.selectedSqlDocumentId, this.state.selectedSqlDocumentId,
@ -305,11 +305,7 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
partitionKeyValue partitionKeyValue
); );
isExecutionError(false); isExecutionError(false);
const startKey: number = TelemetryProcessor.traceStart(Action.UpdateDocument, { const startKey: number = this.getStartKey(Action.UpdateDocument);
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
});
try { try {
isExecuting(true); isExecuting(true);
const updateSqlDocumentRes = await updateSqlDocuments( const updateSqlDocumentRes = await updateSqlDocuments(
@ -318,45 +314,21 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
JSON.parse(documentContent) JSON.parse(documentContent)
); );
if (updateSqlDocumentRes) { if (updateSqlDocumentRes) {
TelemetryProcessor.traceSuccess( this.setTraceSuccess(Action.UpdateDocument, startKey);
Action.UpdateDocument,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
},
startKey
);
this.querySqlDocumentsData(); this.querySqlDocumentsData();
isExecuting(false);
} }
} catch (error) { } catch (error) {
isExecutionError(true); window.alert(getErrorMessage(error));
isExecuting(false); this.setTraceFail(Action.UpdateDocument, startKey, error);
const errorMessage = getErrorMessage(error);
window.alert(errorMessage);
TelemetryProcessor.traceFailure(
Action.UpdateDocument,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
error: errorMessage,
errorStack: getErrorStack(error),
},
startKey
);
} }
} }
private async updateMongoDocument(): Promise<void> { private async updateMongoDocument(): Promise<void> {
const { selectedDocumentId, documentContent, documentIds } = this.state; const { selectedDocumentId, documentContent, documentIds } = this.state;
const { isExecutionError, isExecuting, tabTitle, collection, partitionKey, partitionKeyProperty } = this.props; const { isExecutionError, isExecuting, collection, partitionKey, partitionKeyProperty } = this.props;
isExecutionError(false); isExecutionError(false);
isExecuting(true); isExecuting(true);
const startKey: number = TelemetryProcessor.traceStart(Action.UpdateDocument, { const startKey: number = this.getStartKey(Action.UpdateDocument);
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
});
try { try {
const updatedDocument = await updateDocument( const updatedDocument = await updateDocument(
collection.databaseId, collection.databaseId,
@ -376,31 +348,11 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
documentId.id(id.id()); documentId.id(id.id());
} }
}); });
TelemetryProcessor.traceSuccess( this.setTraceSuccess(Action.UpdateDocument, startKey);
Action.UpdateDocument,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
},
startKey
);
this.setState({ isEditorContentEdited: false }); this.setState({ isEditorContentEdited: false });
isExecuting(false);
} catch (error) { } catch (error) {
isExecutionError(true); window.alert(getErrorMessage(error));
const errorMessage = getErrorMessage(error); this.setTraceFail(Action.UpdateDocument, startKey, error);
window.alert(errorMessage);
TelemetryProcessor.traceFailure(
Action.UpdateDocument,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
error: errorMessage,
errorStack: getErrorStack(error),
},
startKey
);
isExecuting(false);
} }
} }
@ -515,19 +467,10 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
} }
private async onDeleteExisitingDocumentClick(): Promise<void> { private async onDeleteExisitingDocumentClick(): Promise<void> {
const msg = const confirmationMessage = getConfirmationMessage(userContext.apiType);
userContext.apiType !== "Mongo" const { isExecuting, collection, partitionKey, partitionKeyProperty } = this.props;
? "Are you sure you want to delete the selected item ?" const startKey: number = this.getStartKey(Action.DeleteDocument);
: "Are you sure you want to delete the selected document ?"; if (window.confirm(confirmationMessage)) {
const { isExecutionError, isExecuting, collection, tabTitle, partitionKey, partitionKeyProperty } = this.props;
const startKey: number = TelemetryProcessor.traceStart(Action.DeleteDocument, {
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
});
if (window.confirm(msg)) {
try { try {
isExecuting(true); isExecuting(true);
if (userContext.apiType === "Mongo") { if (userContext.apiType === "Mongo") {
@ -551,29 +494,10 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
await deleteSqlDocument(collection as ViewModels.Collection, selectedDocumentId); await deleteSqlDocument(collection as ViewModels.Collection, selectedDocumentId);
this.querySqlDocumentsData(); this.querySqlDocumentsData();
} }
TelemetryProcessor.traceSuccess( this.setTraceSuccess(Action.DeleteDocument, startKey);
Action.DeleteDocument,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
},
startKey
);
this.setState({ isEditorVisible: false }); this.setState({ isEditorVisible: false });
isExecuting(false);
} catch (error) { } catch (error) {
isExecutionError(true); this.setTraceFail(Action.DeleteDocument, startKey, error);
isExecuting(false);
TelemetryProcessor.traceFailure(
Action.DeleteDocument,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
error: getErrorMessage(error),
errorStack: getErrorStack(error),
},
startKey
);
} }
} }
} }
@ -610,47 +534,22 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
}; };
public onSaveSqlNewMongoDocumentClick = async (): Promise<void> => { public onSaveSqlNewMongoDocumentClick = async (): Promise<void> => {
const { isExecutionError, tabTitle, isExecuting, collection } = this.props; const { isExecutionError, isExecuting, collection } = this.props;
isExecutionError(false); isExecutionError(false);
const startKey: number = TelemetryProcessor.traceStart(Action.CreateDocument, { const startKey: number = this.getStartKey(Action.CreateDocument);
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
});
const document = JSON.parse(this.state.documentContent); const document = JSON.parse(this.state.documentContent);
isExecuting(true); isExecuting(true);
try { try {
const savedDocument = await createSqlDocuments(collection, document); const savedDocument = await createSqlDocuments(collection, document);
if (savedDocument) { if (savedDocument) {
this.handleRowContent(savedDocument as Resource); this.handleRowContent(savedDocument as Resource);
this.updateTabButtonVisibility(); this.updateTabButtonVisibility();
TelemetryProcessor.traceSuccess( this.setTraceSuccess(Action.CreateDocument, startKey);
Action.CreateDocument,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
},
startKey
);
} }
isExecuting(false);
this.querySqlDocumentsData(); this.querySqlDocumentsData();
} catch (error) { } catch (error) {
isExecutionError(true); window.alert(getErrorMessage(error));
const errorMessage = getErrorMessage(error); this.setTraceFail(Action.CreateDocument, startKey, error);
window.alert(errorMessage);
TelemetryProcessor.traceFailure(
Action.CreateDocument,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
error: errorMessage,
errorStack: getErrorStack(error),
},
startKey
);
isExecuting(false);
} }
}; };
@ -670,18 +569,12 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
partitionKey, partitionKey,
partitionKeyProperty, partitionKeyProperty,
displayedError, displayedError,
tabTitle,
isExecutionError, isExecutionError,
isExecuting, isExecuting,
collection, collection,
} = this.props; } = this.props;
displayedError(""); displayedError("");
const startKey: number = this.getStartKey(Action.CreateDocument);
const startKey: number = TelemetryProcessor.traceStart(Action.CreateDocument, {
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
});
if ( if (
partitionKeyProperty && partitionKeyProperty &&
partitionKeyProperty !== "_id" && partitionKeyProperty !== "_id" &&
@ -689,19 +582,10 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
) { ) {
const message = `The document is lacking the shard property: ${partitionKeyProperty}`; const message = `The document is lacking the shard property: ${partitionKeyProperty}`;
displayedError(message); displayedError(message);
TelemetryProcessor.traceFailure( this.setTraceFail(Action.CreateDocument, startKey, message);
Action.CreateDocument,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
error: message,
},
startKey
);
logError("Failed to save new document: Document shard key not defined", "MongoDocumentsTab"); logError("Failed to save new document: Document shard key not defined", "MongoDocumentsTab");
throw new Error("Document without shard key"); throw new Error("Document without shard key");
} }
isExecutionError(false); isExecutionError(false);
isExecuting(true); isExecuting(true);
try { try {
@ -714,36 +598,53 @@ export default class DocumentsTabContent extends React.Component<DocumentsTab, I
if (savedDocument) { if (savedDocument) {
this.handleLoadMoreDocument(); this.handleLoadMoreDocument();
this.updateTabButtonVisibility(); this.updateTabButtonVisibility();
TelemetryProcessor.traceSuccess( this.setTraceSuccess(Action.CreateDocument, startKey);
Action.CreateDocument,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
},
startKey
);
} }
this.setState({ isEditorContentEdited: false }); this.setState({ isEditorContentEdited: false });
this.queryDocumentsData(); this.queryDocumentsData();
isExecuting(false);
} catch (error) { } catch (error) {
isExecutionError(true); window.alert(getErrorMessage(error));
const errorMessage = getErrorMessage(error); this.setTraceFail(Action.CreateDocument, startKey, error);
window.alert(errorMessage);
TelemetryProcessor.traceFailure(
Action.CreateDocument,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
error: errorMessage,
errorStack: getErrorStack(error),
},
startKey
);
isExecuting(false);
} }
}; };
private getStartKey = (action: number): number => {
const startKey: number = TelemetryProcessor.traceStart(action, {
dataExplorerArea: Areas.Tab,
tabTitle: this.props.tabTitle(),
});
return startKey;
};
private setTraceSuccess = (action: number, startKey: number): void => {
const { isExecuting, tabTitle } = this.props;
TelemetryProcessor.traceSuccess(
action,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
},
startKey
);
isExecuting(false);
};
private setTraceFail = (action: number, startKey: number, error: Error | string): void => {
const { isExecuting, tabTitle, isExecutionError } = this.props;
TelemetryProcessor.traceFailure(
action,
{
dataExplorerArea: Areas.Tab,
tabTitle: tabTitle(),
error: getErrorMessage(error),
errorStack: getErrorStack(error),
},
startKey
);
isExecuting(false);
isExecutionError(true);
};
private onRevertNewDocumentClick = () => { private onRevertNewDocumentClick = () => {
this.newDocumentButton = tabButtonVisibility(true, true); this.newDocumentButton = tabButtonVisibility(true, true);
this.saveNewDocumentButton = tabButtonVisibility(true, false); this.saveNewDocumentButton = tabButtonVisibility(true, false);

View File

@ -13,6 +13,7 @@ export default class DocumentId {
public partitionKeyValue: any; public partitionKeyValue: any;
public stringPartitionKeyValue: string; public stringPartitionKeyValue: string;
public isDirty: ko.Observable<boolean>; public isDirty: ko.Observable<boolean>;
public _partitionKeyValue: string;
constructor(container: DocumentsTab, data: any, partitionKeyValue: any) { constructor(container: DocumentsTab, data: any, partitionKeyValue: any) {
this.container = container; this.container = container;
@ -27,13 +28,6 @@ export default class DocumentId {
this.isDirty = ko.observable(false); this.isDirty = ko.observable(false);
} }
// public click() {
// if (!this.container.isEditorDirty() || window.confirm("Your unsaved changes will be lost.")) {
// this.loadDocument();
// }
// return;
// }
public partitionKeyHeader(): Object { public partitionKeyHeader(): Object {
if (!this.partitionKeyProperty) { if (!this.partitionKeyProperty) {
return undefined; return undefined;
@ -64,8 +58,4 @@ export default class DocumentId {
return JSON.stringify(partitionKeyValue); return JSON.stringify(partitionKeyValue);
} }
// public async loadDocument(): Promise<void> {
// await this.container.selectDocument(this);
// }
} }