Compare commits

..

3 Commits

Author SHA1 Message Date
sunilyadav840
bd1009c849 fixed eslint of ConflictsTab 2021-10-20 14:13:47 +05:30
victor-meng
55837db65b Revert "Fix keyboard focus does not retain on 'New Database' button a… (#1139)
* Revert "Fix keyboard focus does not retain on 'New Database' button after closing the 'New Database' blade via ESC key (#1109)"

This reverts commit f7e7240010.

* Revert "Fix ally database panel open issue (#1120)"

This reverts commit ed1ffb692f.
2021-10-15 17:36:48 -07:00
victor-meng
9f27cb95b9 Only use the SET keyword once in the update query (#1138) 2021-10-15 12:33:59 -07:00
9 changed files with 77 additions and 89 deletions

View File

@@ -85,10 +85,13 @@ src/Explorer/Tables/DataTable/DataTableViewModel.ts
src/Explorer/Tables/DataTable/TableEntityListViewModel.ts
src/Explorer/Tables/QueryBuilder/CustomTimestampHelper.ts
src/Explorer/Tables/TableDataClient.ts
src/Explorer/Tables/TableEntityProcessor.ts
src/Explorer/Tables/Utilities.ts
src/Explorer/Tabs/ConflictsTab.ts
src/Explorer/Tabs/DatabaseSettingsTab.ts
src/Explorer/Tabs/DocumentsTab.test.ts
src/Explorer/Tabs/DocumentsTab.ts
src/Explorer/Tabs/GraphTab.ts
src/Explorer/Tabs/MongoDocumentsTab.ts
src/Explorer/Tabs/NotebookV2Tab.ts
src/Explorer/Tabs/ScriptTabBase.ts
src/Explorer/Tabs/TabComponents.ts

View File

@@ -307,18 +307,11 @@ function createOpenSynapseLinkDialogButton(container: Explorer): CommandButtonCo
function createNewDatabase(container: Explorer): CommandButtonComponentProps {
const label = "New " + getDatabaseName();
const newDatabaseButton = document.activeElement as HTMLElement;
return {
iconSrc: AddDatabaseIcon,
iconAlt: label,
onCommandClick: () =>
useSidePanel
.getState()
.openSidePanel(
"New " + getDatabaseName(),
<AddDatabasePanel explorer={container} buttonElement={newDatabaseButton} />
),
useSidePanel.getState().openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={container} />),
commandButtonLabel: label,
ariaLabel: label,
hasPopup: true,

View File

@@ -23,12 +23,10 @@ import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneFor
export interface AddDatabasePaneProps {
explorer: Explorer;
buttonElement?: HTMLElement;
}
export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
explorer: container,
buttonElement,
}: AddDatabasePaneProps) => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
let throughput: number;
@@ -79,7 +77,6 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
dataExplorerArea: Constants.Areas.ContextualPane,
};
TelemetryProcessor.trace(Action.CreateDatabase, ActionModifiers.Open, addDatabasePaneOpenMessage);
buttonElement.focus();
}, []);
const onSubmit = () => {

View File

@@ -307,23 +307,16 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
iconSrc: AddDatabaseIcon,
title: "New " + getDatabaseName(),
description: undefined,
onClick: () => this.openAddDatabasePanel(),
onClick: () =>
useSidePanel
.getState()
.openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={this.container} />),
});
}
return items;
}
private openAddDatabasePanel() {
const newDatabaseButton = document.activeElement as HTMLElement;
useSidePanel
.getState()
.openSidePanel(
"New " + getDatabaseName(),
<AddDatabasePanel explorer={this.container} buttonElement={newDatabaseButton} />
);
}
private decorateOpenCollectionActivity({ databaseId, collectionId }: MostRecentActivity.OpenCollectionItem) {
return {
iconSrc: NotebookIcon,

View File

@@ -202,14 +202,21 @@ export class CassandraAPIDataClient extends TableDataClient {
let updateQuery = `UPDATE ${collection.databaseId}.${collection.id()}`;
let isPropertyUpdated = false;
let isFirstPropertyToUpdate = true;
for (let property in newEntity) {
if (
!originalDocument[property] ||
newEntity[property]._.toString() !== originalDocument[property]._.toString()
) {
updateQuery += this.isStringType(newEntity[property].$)
? ` SET ${property} = '${newEntity[property]._}',`
: ` SET ${property} = ${newEntity[property]._},`;
let propertyQuerySegment = this.isStringType(newEntity[property].$)
? `${property} = '${newEntity[property]._}',`
: `${property} = ${newEntity[property]._},`;
// Only add the "SET" keyword once
if (isFirstPropertyToUpdate) {
propertyQuerySegment = " SET " + propertyQuerySegment;
isFirstPropertyToUpdate = false;
}
updateQuery += propertyQuerySegment;
isPropertyUpdated = true;
}
}

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as ViewModels from "../../Contracts/ViewModels";
import * as Constants from "./Constants";
import * as Entities from "./Entities";
@@ -17,12 +16,12 @@ enum DataTypes {
Int64 = 18,
}
const tablesIndexers = {
var tablesIndexers = {
Value: "$v",
Type: "$t",
};
export const keyProperties = {
export var keyProperties = {
PartitionKey: "$pk",
Id: "id",
Id2: "$id", // This should always be the same value as Id
@@ -34,17 +33,14 @@ export const keyProperties = {
};
export function convertDocumentsToEntities(documents: any[]): Entities.ITableEntityForTablesAPI[] {
const results: Entities.ITableEntityForTablesAPI[] = [];
let results: Entities.ITableEntityForTablesAPI[] = [];
documents &&
documents.forEach((document) => {
if (
!Object.prototype.hasOwnProperty.call(document, keyProperties.PartitionKey) ||
Object.prototype.hasOwnProperty.call(document, keyProperties.Id)
) {
if (!document.hasOwnProperty(keyProperties.PartitionKey) || !document.hasOwnProperty(keyProperties.Id)) {
//Document does not match the current required format for Tables, so we ignore it
return; // The rest of the key properties should be guaranteed as DocumentDB properties
}
const entity: Entities.ITableEntityForTablesAPI = <Entities.ITableEntityForTablesAPI>{
let entity: Entities.ITableEntityForTablesAPI = <Entities.ITableEntityForTablesAPI>{
PartitionKey: {
_: document[keyProperties.PartitionKey],
$: Constants.TableType.String,
@@ -75,8 +71,8 @@ export function convertDocumentsToEntities(documents: any[]): Entities.ITableEnt
$: Constants.TableType.String,
},
};
for (const property in document) {
if (Object.prototype.hasOwnProperty.call(document, property)) {
for (var property in document) {
if (document.hasOwnProperty(property)) {
if (
property !== keyProperties.PartitionKey &&
property !== keyProperties.Id &&
@@ -87,10 +83,7 @@ export function convertDocumentsToEntities(documents: any[]): Entities.ITableEnt
property !== keyProperties.attachments &&
property !== keyProperties.Id2
) {
if (
!Object.prototype.hasOwnProperty.call(document[property], "$v") ||
!Object.prototype.hasOwnProperty.call(document[property], "$t")
) {
if (!document[property].hasOwnProperty("$v") || !document[property].hasOwnProperty("$t")) {
return; //Document property does not match the current required format for Tables, so we ignore it
}
if (DataTypes[document[property][tablesIndexers.Type]] === DataTypes[DataTypes.DateTime]) {
@@ -118,10 +111,10 @@ export function convertEntitiesToDocuments(
entities: Entities.ITableEntityForTablesAPI[],
collection: ViewModels.Collection
): any[] {
const results: any[] = [];
let results: any[] = [];
entities &&
entities.forEach((entity) => {
const document: any = {
let document: any = {
$id: entity.RowKey._,
id: entity.RowKey._,
ts: DateTimeUtilities.convertJSDateToUnix(entity.Timestamp._), // Convert back to unix time
@@ -136,7 +129,7 @@ export function convertEntitiesToDocuments(
document[collection.partitionKeyProperty] = entity.PartitionKey._;
document["partitionKeyValue"] = entity.PartitionKey._;
}
for (const property in entity) {
for (var property in entity) {
if (
property !== Constants.EntityKeyNames.PartitionKey &&
property !== Constants.EntityKeyNames.RowKey &&
@@ -167,7 +160,7 @@ export function convertEntitiesToDocuments(
}
export function convertEntityToNewDocument(entity: Entities.ITableEntityForTablesAPI): any {
const document: any = {
let document: any = {
$pk: entity.PartitionKey._,
$id: entity.RowKey._,
id: entity.RowKey._,

View File

@@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/switch-exhaustiveness-check */
import { ConflictDefinition, FeedOptions, QueryIterator, Resource } from "@azure/cosmos";
import * as ko from "knockout";
import Q from "q";
@@ -69,13 +71,13 @@ export default class ConflictsTab extends TabsBase {
ViewModels.DocumentExplorerState.noDocumentSelected
);
this.selectedConflictId = ko.observable<ConflictId>();
this.selectedConflictContent = editable.observable<any>("");
this.selectedConflictCurrent = editable.observable<any>("");
this.selectedConflictContent = editable.observable<string>("");
this.selectedConflictCurrent = editable.observable<string>("");
this.partitionKey = options.partitionKey || (this.collection && this.collection.partitionKey);
this.conflictIds = options.conflictIds;
this.partitionKeyPropertyHeader =
(this.collection && this.collection.partitionKeyPropertyHeader) || this._getPartitionKeyPropertyHeader();
this.partitionKeyProperty = !!this.partitionKeyPropertyHeader
this.partitionKeyProperty = this.partitionKeyPropertyHeader
? this.partitionKeyPropertyHeader.replace(/[/]+/g, ".").substr(1).replace(/[']+/g, "")
: null;
@@ -187,7 +189,7 @@ export default class ConflictsTab extends TabsBase {
this.buildCommandBarOptions();
this.shouldShowDiffEditor = ko.pureComputed<boolean>(() => {
const documentHasContent: boolean =
this.selectedConflictContent() != null && this.selectedConflictContent().length > 0;
this.selectedConflictContent() !== null && this.selectedConflictContent().length > 0;
const operationIsReplace: boolean = this.conflictOperation() === Constants.ConflictOperationType.Replace;
const isLoadingData: boolean = this.loadingConflictData();
return documentHasContent && operationIsReplace && !isLoadingData;
@@ -195,7 +197,7 @@ export default class ConflictsTab extends TabsBase {
this.shouldShowEditor = ko.pureComputed<boolean>(() => {
const documentHasContent: boolean =
this.selectedConflictContent() != null && this.selectedConflictContent().length > 0;
this.selectedConflictContent() !== null && this.selectedConflictContent().length > 0;
const operationIsInsert: boolean = this.conflictOperation() === Constants.ConflictOperationType.Create;
const operationIsDelete: boolean = this.conflictOperation() === Constants.ConflictOperationType.Delete;
const isLoadingData: boolean = this.loadingConflictData();
@@ -242,7 +244,7 @@ export default class ConflictsTab extends TabsBase {
return true;
};
public onConflictIdClick(clickedDocumentId: ConflictId): Q.Promise<any> {
public onConflictIdClick(): Q.Promise<unknown> {
if (this.editorState() !== ViewModels.DocumentExplorerState.noDocumentSelected) {
return Q();
}
@@ -405,19 +407,19 @@ export default class ConflictsTab extends TabsBase {
}
};
public onDiscardClick = (): Q.Promise<any> => {
public onDiscardClick = (): Q.Promise<unknown> => {
this.selectedConflictContent(this.selectedConflictContent.getEditableOriginalValue());
this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentNoEdits);
return Q();
};
public onValidDocumentEdit(): Q.Promise<any> {
public onValidDocumentEdit(): Q.Promise<unknown> {
this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentDirtyValid);
return Q();
}
public onInvalidDocumentEdit(): Q.Promise<any> {
public onInvalidDocumentEdit(): Q.Promise<unknown> {
if (
this.editorState() === ViewModels.DocumentExplorerState.exisitingDocumentNoEdits ||
this.editorState() === ViewModels.DocumentExplorerState.exisitingDocumentDirtyValid
@@ -442,7 +444,7 @@ export default class ConflictsTab extends TabsBase {
this._documentsIterator = await this.createIterator();
await this.loadNextPage();
} catch (error) {
if (this.onLoadStartKey != null && this.onLoadStartKey != undefined) {
if (this.onLoadStartKey !== null && this.onLoadStartKey !== undefined) {
TelemetryProcessor.traceFailure(
Action.Tab,
{
@@ -471,7 +473,7 @@ export default class ConflictsTab extends TabsBase {
return queryConflicts(this.collection.databaseId, this.collection.id(), query, options as FeedOptions);
}
public loadNextPage(): Q.Promise<any> {
public loadNextPage(): Q.Promise<unknown> {
this.isExecuting(true);
this.isExecutionError(false);
return this._loadNextPageInternal()
@@ -491,7 +493,7 @@ export default class ConflictsTab extends TabsBase {
const merged = currentConflicts.concat(nextConflictIds);
this.conflictIds(merged);
if (this.onLoadStartKey != null && this.onLoadStartKey != undefined) {
if (this.onLoadStartKey !== null && this.onLoadStartKey !== undefined) {
TelemetryProcessor.traceSuccess(
Action.Tab,
{
@@ -508,7 +510,7 @@ export default class ConflictsTab extends TabsBase {
},
(error) => {
this.isExecutionError(true);
if (this.onLoadStartKey != null && this.onLoadStartKey != undefined) {
if (this.onLoadStartKey !== null && this.onLoadStartKey !== undefined) {
TelemetryProcessor.traceFailure(
Action.Tab,
{
@@ -541,18 +543,18 @@ export default class ConflictsTab extends TabsBase {
return Q(this._documentsIterator.fetchNext().then((response) => response.resources));
}
protected _onEditorContentChange(newContent: string) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected _onEditorContentChange(_newContent: string) {
try {
const parsed: any = JSON.parse(newContent);
this.onValidDocumentEdit();
} catch (e) {
this.onInvalidDocumentEdit();
}
}
public initDocumentEditorForCreate(documentId: ConflictId, documentToInsert: any): Q.Promise<any> {
public initDocumentEditorForCreate(documentId: ConflictId, documentToInsert: any): Q.Promise<unknown> {
if (documentId) {
let parsedConflictContent: any = JSON.parse(documentToInsert);
const parsedConflictContent: any = JSON.parse(documentToInsert);
const renderedConflictContent: string = this.renderObjectForEditor(parsedConflictContent, null, 4);
this.selectedConflictContent.setBaseline(renderedConflictContent);
this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentNoEdits);
@@ -565,7 +567,7 @@ export default class ConflictsTab extends TabsBase {
documentId: ConflictId,
conflictContent: any,
currentContent: any
): Q.Promise<any> {
): Q.Promise<unknown> {
if (documentId) {
currentContent = ConflictsTab.removeSystemProperties(currentContent);
const renderedCurrentContent: string = this.renderObjectForEditor(currentContent, null, 4);
@@ -582,7 +584,7 @@ export default class ConflictsTab extends TabsBase {
return Q();
}
public initDocumentEditorForDelete(documentId: ConflictId, documentToDelete: any): Q.Promise<any> {
public initDocumentEditorForDelete(documentId: ConflictId, documentToDelete: any): Q.Promise<unknown> {
if (documentId) {
let parsedDocumentToDelete: any = JSON.parse(documentToDelete);
parsedDocumentToDelete = ConflictsTab.removeSystemProperties(parsedDocumentToDelete);
@@ -594,7 +596,8 @@ export default class ConflictsTab extends TabsBase {
return Q();
}
public initDocumentEditorForNoOp(documentId: ConflictId): Q.Promise<any> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public initDocumentEditorForNoOp(_documentId: ConflictId): Q.Promise<unknown> {
this.selectedConflictContent(null);
this.selectedConflictCurrent(null);
this.editorState(ViewModels.DocumentExplorerState.noDocumentSelected);

View File

@@ -92,7 +92,7 @@ export default class DocumentsTab extends TabsBase {
this.partitionKeyPropertyHeader =
(this.collection && this.collection.partitionKeyPropertyHeader) || this._getPartitionKeyPropertyHeader();
this.partitionKeyProperty = this.partitionKeyPropertyHeader
this.partitionKeyProperty = !!this.partitionKeyPropertyHeader
? this.partitionKeyPropertyHeader.replace(/[/]+/g, ".").substr(1).replace(/[']+/g, "")
: null;
@@ -446,8 +446,8 @@ export default class DocumentsTab extends TabsBase {
this.partitionKey as PartitionKeyDefinition
);
const partitionKeyValue = partitionKeyValueArray && partitionKeyValueArray[0];
const id = new DocumentId(this, savedDocument, partitionKeyValue);
const ids = this.documentIds();
let id = new DocumentId(this, savedDocument, partitionKeyValue);
let ids = this.documentIds();
ids.push(id);
this.selectedDocumentId(id);
@@ -682,10 +682,10 @@ export default class DocumentsTab extends TabsBase {
}
public createIterator(): QueryIterator<ItemDefinition & Resource> {
const filters = this.lastFilterContents();
let filters = this.lastFilterContents();
const filter: string = this.filterContent().trim();
const query: string = this.buildQuery(filter);
const options: any = {};
let options: any = {};
options.enableCrossPartitionQuery = HeadersUtility.shouldEnableCrossPartitionKey();
if (this._resourceTokenPartitionKey) {
@@ -778,7 +778,7 @@ export default class DocumentsTab extends TabsBase {
protected _onEditorContentChange(newContent: string) {
try {
const parsed: any = JSON.parse(newContent);
let parsed: any = JSON.parse(newContent);
this.onValidDocumentEdit();
} catch (e) {
this.onInvalidDocumentEdit();

View File

@@ -1,5 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-vars */
import { extractPartitionKey, PartitionKeyDefinition } from "@azure/cosmos";
import * as ko from "knockout";
import Q from "q";
@@ -46,7 +44,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
super.buildCommandBarOptions();
}
public onSaveNewDocumentClick = (): Promise<void> => {
public onSaveNewDocumentClick = (): Promise<any> => {
const documentContent = JSON.parse(this.selectedDocumentContent());
this.displayedError("");
const startKey: number = TelemetryProcessor.traceStart(Action.CreateDocument, {
@@ -61,8 +59,9 @@ export default class MongoDocumentsTab extends DocumentsTab {
) {
const message = `The document is lacking the shard property: ${this.partitionKeyProperty}`;
this.displayedError(message);
let that = this;
setTimeout(() => {
this.displayedError("");
that.displayedError("");
}, Constants.ClientDefaults.errorNotificationTimeoutMs);
this.isExecutionError(true);
TelemetryProcessor.traceFailure(
@@ -83,19 +82,19 @@ export default class MongoDocumentsTab extends DocumentsTab {
return createDocument(this.collection.databaseId, this.collection, this.partitionKeyProperty, documentContent)
.then(
(savedDocument: any) => {
const partitionKeyArray = extractPartitionKey(
let partitionKeyArray = extractPartitionKey(
savedDocument,
this._getPartitionKeyDefinition() as PartitionKeyDefinition
);
const partitionKeyValue = partitionKeyArray && partitionKeyArray[0];
let partitionKeyValue = partitionKeyArray && partitionKeyArray[0];
const id = new ObjectId(this, savedDocument, partitionKeyValue);
const ids = this.documentIds();
let id = new ObjectId(this, savedDocument, partitionKeyValue);
let ids = this.documentIds();
ids.push(id);
delete savedDocument._self;
const value: string = this.renderObjectForEditor(savedDocument || {}, null, 4);
let value: string = this.renderObjectForEditor(savedDocument || {}, null, 4);
this.selectedDocumentContent.setBaseline(value);
this.selectedDocumentId(id);
@@ -129,7 +128,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
.finally(() => this.isExecuting(false));
};
public onSaveExisitingDocumentClick = (): Promise<void> => {
public onSaveExisitingDocumentClick = (): Promise<any> => {
const selectedDocumentId = this.selectedDocumentId();
const documentContent = this.selectedDocumentContent();
this.isExecutionError(false);
@@ -142,7 +141,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
return updateDocument(this.collection.databaseId, this.collection, selectedDocumentId, documentContent)
.then(
(updatedDocument: any) => {
const value: string = this.renderObjectForEditor(updatedDocument || {}, null, 4);
let value: string = this.renderObjectForEditor(updatedDocument || {}, null, 4);
this.selectedDocumentContent.setBaseline(value);
this.documentIds().forEach((documentId: DocumentId) => {
@@ -152,7 +151,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
this._getPartitionKeyDefinition() as PartitionKeyDefinition
);
const partitionKeyValue = partitionKeyArray && partitionKeyArray[0];
let partitionKeyValue = partitionKeyArray && partitionKeyArray[0];
const id = new ObjectId(this, updatedDocument, partitionKeyValue);
documentId.id(id.id());
@@ -197,7 +196,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
this.initDocumentEditor(documentId, content);
}
public loadNextPage(): Q.Promise<void> {
public loadNextPage(): Q.Promise<any> {
this.isExecuting(true);
this.isExecutionError(false);
const filter: string = this.filterContent().trim();
@@ -229,7 +228,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
this.selectedDocumentId(null);
this.editorState(ViewModels.DocumentExplorerState.noDocumentSelected);
}
if (this.onLoadStartKey !== null && this.onLoadStartKey !== undefined) {
if (this.onLoadStartKey != null && this.onLoadStartKey != undefined) {
TelemetryProcessor.traceSuccess(
Action.Tab,
{
@@ -244,8 +243,8 @@ export default class MongoDocumentsTab extends DocumentsTab {
this.onLoadStartKey = null;
}
},
(error: Error) => {
if (this.onLoadStartKey !== null && this.onLoadStartKey !== undefined) {
(error: any) => {
if (this.onLoadStartKey != null && this.onLoadStartKey != undefined) {
TelemetryProcessor.traceFailure(
Action.Tab,
{
@@ -266,13 +265,13 @@ export default class MongoDocumentsTab extends DocumentsTab {
.finally(() => this.isExecuting(false));
}
protected _onEditorContentChange(newContent: string): void {
protected _onEditorContentChange(newContent: string) {
try {
if (
this.editorState() === ViewModels.DocumentExplorerState.newDocumentValid ||
this.editorState() === ViewModels.DocumentExplorerState.newDocumentInvalid
) {
const parsed: any = JSON.parse(newContent);
let parsed: any = JSON.parse(newContent);
}
// Mongo uses BSON format for _id, trying to parse it as JSON blocks normal flow in an edit