diff --git a/.eslintignore b/.eslintignore
index 430f7bcc3..050bbc0dc 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -119,14 +119,10 @@ src/Explorer/Panes/ContextualPaneBase.ts
src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts
src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts
src/Explorer/Panes/GraphStylingPane.ts
-# src/Explorer/Panes/NewVertexPane.ts
src/Explorer/Panes/PaneComponents.ts
src/Explorer/Panes/RenewAdHocAccessPane.ts
src/Explorer/Panes/SetupNotebooksPane.ts
src/Explorer/Panes/SwitchDirectoryPane.ts
-src/Explorer/Panes/Tables/EditTableEntityPane.ts
-src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
-src/Explorer/Panes/Tables/TableEntityPane.ts
src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts
diff --git a/src/Explorer/ComponentRegisterer.ts b/src/Explorer/ComponentRegisterer.ts
index af9ef47a7..0ec97eb49 100644
--- a/src/Explorer/ComponentRegisterer.ts
+++ b/src/Explorer/ComponentRegisterer.ts
@@ -22,6 +22,4 @@ ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponent
ko.components.register("add-database-pane", new PaneComponents.AddDatabasePaneComponent());
ko.components.register("add-collection-pane", new PaneComponents.AddCollectionPaneComponent());
ko.components.register("graph-styling-pane", new PaneComponents.GraphStylingPaneComponent());
-ko.components.register("table-add-entity-pane", new PaneComponents.TableAddEntityPaneComponent());
-ko.components.register("table-edit-entity-pane", new PaneComponents.TableEditEntityPaneComponent());
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
diff --git a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap
index 63d6712b8..671725d4f 100644
--- a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap
+++ b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap
@@ -103,6 +103,7 @@ exports[`SettingsComponent renders 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
@@ -253,6 +254,7 @@ exports[`SettingsComponent renders 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
@@ -1379,6 +1381,7 @@ exports[`SettingsComponent renders 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
@@ -1529,6 +1532,7 @@ exports[`SettingsComponent renders 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
@@ -2668,6 +2672,7 @@ exports[`SettingsComponent renders 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
@@ -2818,6 +2823,7 @@ exports[`SettingsComponent renders 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
@@ -3944,6 +3950,7 @@ exports[`SettingsComponent renders 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
@@ -4094,6 +4101,7 @@ exports[`SettingsComponent renders 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
diff --git a/src/Explorer/Explorer.tsx b/src/Explorer/Explorer.tsx
index 47af1ae40..223ab657c 100644
--- a/src/Explorer/Explorer.tsx
+++ b/src/Explorer/Explorer.tsx
@@ -1,6 +1,5 @@
-import * as ko from "knockout";
import { IChoiceGroupProps } from "@fluentui/react";
-import * as path from "path";
+import * as ko from "knockout";
import Q from "q";
import React from "react";
import _ from "underscore";
@@ -1843,39 +1842,6 @@ export default class Explorer {
}
}
- public async openNotebookViewer(notebookUrl: string) {
- const title = path.basename(notebookUrl);
- const hashLocation = notebookUrl;
- const NotebookViewerTab = await (
- await import(/* webpackChunkName: "NotebookViewerTab" */ "./Tabs/NotebookViewerTab")
- ).default;
-
- const notebookViewerTab = this.tabsManager.getTabs(ViewModels.CollectionTabKind.NotebookV2).find((tab) => {
- return tab.hashLocation() == hashLocation && tab instanceof NotebookViewerTab && tab.notebookUrl === notebookUrl;
- });
-
- if (notebookViewerTab) {
- this.tabsManager.activateNewTab(notebookViewerTab);
- } else {
- const notebookViewerTab = new NotebookViewerTab({
- account: userContext.databaseAccount,
- tabKind: ViewModels.CollectionTabKind.NotebookViewer,
- node: null,
- title: title,
- tabPath: title,
- collection: null,
- hashLocation: hashLocation,
- isTabsContentExpanded: ko.observable(true),
- onLoadStartKey: null,
- onUpdateTabsButtons: this.onUpdateTabsButtons,
- container: this,
- notebookUrl,
- });
-
- this.tabsManager.activateNewTab(notebookViewerTab);
- }
- }
-
public onNewCollectionClicked(databaseId?: string): void {
if (userContext.apiType === "Cassandra") {
this.cassandraAddCollectionPane.open();
diff --git a/src/Explorer/Panes/AddCollectionPane.html b/src/Explorer/Panes/AddCollectionPane.html
index 4bba48d36..2d0cfe8ba 100644
--- a/src/Explorer/Panes/AddCollectionPane.html
+++ b/src/Explorer/Panes/AddCollectionPane.html
@@ -438,7 +438,7 @@
-
+
Indexing
diff --git a/src/Explorer/Panes/AddCollectionPane.ts b/src/Explorer/Panes/AddCollectionPane.ts
index c626f151a..17aef98fa 100644
--- a/src/Explorer/Panes/AddCollectionPane.ts
+++ b/src/Explorer/Panes/AddCollectionPane.ts
@@ -14,6 +14,7 @@ import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstan
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../UserContext";
import * as AutoPilotUtils from "../../Utils/AutoPilotUtils";
+import { isCapabilityEnabled } from "../../Utils/CapabilityUtils";
import * as PricingUtils from "../../Utils/PricingUtils";
import { DynamicListItem } from "../Controls/DynamicList/DynamicListComponent";
import { ContextualPaneBase } from "./ContextualPaneBase";
@@ -95,6 +96,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
public shouldCreateMongoWildcardIndex: ko.Observable
;
private _isSynapseLinkEnabled: ko.Computed;
+ private isEnableMongoCapabilityEnabled: ko.Observable;
constructor(options: AddCollectionPaneOptions) {
super(options);
@@ -634,6 +636,8 @@ export default class AddCollectionPane extends ContextualPaneBase {
});
});
+ this.isEnableMongoCapabilityEnabled = ko.observable(isCapabilityEnabled("EnableMongo"));
+
this.shouldCreateMongoWildcardIndex = ko.observable(this.container.isMongoIndexingEnabled());
}
diff --git a/src/Explorer/Panes/AddCollectionPanel.tsx b/src/Explorer/Panes/AddCollectionPanel.tsx
index ffbea654a..89cf46d6c 100644
--- a/src/Explorer/Panes/AddCollectionPanel.tsx
+++ b/src/Explorer/Panes/AddCollectionPanel.tsx
@@ -25,6 +25,7 @@ import { Action } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../UserContext";
import { getCollectionName } from "../../Utils/APITypeUtils";
+import { isCapabilityEnabled } from "../../Utils/CapabilityUtils";
import { getUpsellMessage } from "../../Utils/PricingUtils";
import { CollapsibleSectionComponent } from "../Controls/CollapsiblePanel/CollapsibleSectionComponent";
import { ThroughputInput } from "../Controls/ThroughputInput/ThroughputInput";
@@ -80,7 +81,7 @@ export class AddCollectionPanel extends React.Component
- {userContext.databaseAccount.properties.capabilities.find((c) => c.name === "EnableMongo") && (
+ {isCapabilityEnabled("EnableMongo") && (
*
@@ -851,7 +852,7 @@ export class AddCollectionPanel extends React.Component capability.name === Constants.CapabilityNames.EnableStorageAnalytics
);
}
diff --git a/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap b/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap
index 233653711..21eb5eaac 100644
--- a/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap
+++ b/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap
@@ -92,6 +92,7 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
@@ -242,6 +243,7 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
diff --git a/src/Explorer/Panes/PaneComponents.ts b/src/Explorer/Panes/PaneComponents.ts
index d0a9704b6..9d730887d 100644
--- a/src/Explorer/Panes/PaneComponents.ts
+++ b/src/Explorer/Panes/PaneComponents.ts
@@ -2,8 +2,6 @@ import AddCollectionPaneTemplate from "./AddCollectionPane.html";
import AddDatabasePaneTemplate from "./AddDatabasePane.html";
import CassandraAddCollectionPaneTemplate from "./CassandraAddCollectionPane.html";
import GraphStylingPaneTemplate from "./GraphStylingPane.html";
-import TableAddEntityPaneTemplate from "./Tables/TableAddEntityPane.html";
-import TableEditEntityPaneTemplate from "./Tables/TableEditEntityPane.html";
export class PaneComponent {
constructor(data: any) {
@@ -38,23 +36,6 @@ export class GraphStylingPaneComponent {
}
}
-export class TableAddEntityPaneComponent {
- constructor() {
- return {
- viewModel: PaneComponent,
- template: TableAddEntityPaneTemplate,
- };
- }
-}
-
-export class TableEditEntityPaneComponent {
- constructor() {
- return {
- viewModel: PaneComponent,
- template: TableEditEntityPaneTemplate,
- };
- }
-}
export class CassandraAddCollectionPaneComponent {
constructor() {
return {
diff --git a/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap b/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap
index 7cbfacdd1..54de722ba 100644
--- a/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap
+++ b/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap
@@ -82,6 +82,7 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
@@ -232,6 +233,7 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
diff --git a/src/Explorer/Panes/Tables/EditTableEntityPane.ts b/src/Explorer/Panes/Tables/EditTableEntityPane.ts
deleted file mode 100644
index 5b69fcd35..000000000
--- a/src/Explorer/Panes/Tables/EditTableEntityPane.ts
+++ /dev/null
@@ -1,225 +0,0 @@
-import * as ko from "knockout";
-import _ from "underscore";
-import * as ViewModels from "../../../Contracts/ViewModels";
-import { userContext } from "../../../UserContext";
-import Explorer from "../../Explorer";
-import * as TableConstants from "../../Tables/Constants";
-import * as Entities from "../../Tables/Entities";
-import { CassandraAPIDataClient, CassandraTableKey } from "../../Tables/TableDataClient";
-import * as TableEntityProcessor from "../../Tables/TableEntityProcessor";
-import * as Utilities from "../../Tables/Utilities";
-import EntityPropertyViewModel from "./EntityPropertyViewModel";
-import TableEntityPane from "./TableEntityPane";
-
-export default class EditTableEntityPane extends TableEntityPane {
- container: Explorer;
- visible: ko.Observable;
-
- public originEntity: Entities.ITableEntity;
- public originalNumberOfProperties: number;
- private originalDocument: any;
-
- constructor(options: ViewModels.PaneOptions) {
- super(options);
- this.submitButtonText("Update Entity");
- if (userContext.apiType === "Cassandra") {
- this.submitButtonText("Update Row");
- }
- this.scrollId = ko.observable("editEntityScroll");
- }
-
- public submit() {
- if (!this.canApply()) {
- return;
- }
- let entity: Entities.ITableEntity = this.updateEntity(this.displayedAttributes());
- this.container.tableDataClient
- .updateDocument(this.tableViewModel.queryTablesTab.collection, this.originalDocument, entity)
- .then((newEntity: Entities.ITableEntity) => {
- var numberOfProperties = 0;
- for (var property in newEntity) {
- if (
- property !== TableEntityProcessor.keyProperties.attachments &&
- property !== TableEntityProcessor.keyProperties.etag &&
- property !== TableEntityProcessor.keyProperties.resourceId &&
- property !== TableEntityProcessor.keyProperties.self &&
- (userContext.apiType !== "Cassandra" || property !== TableConstants.EntityKeyNames.RowKey)
- ) {
- numberOfProperties++;
- }
- }
-
- var propertiesDelta = numberOfProperties - this.originalNumberOfProperties;
-
- return this.tableViewModel
- .updateCachedEntity(newEntity)
- .then(() => {
- if (!this.tryInsertNewHeaders(this.tableViewModel, newEntity)) {
- this.tableViewModel.redrawTableThrottled();
- }
- })
- .then(() => {
- // Selecting updated entity
- this.tableViewModel.selected.removeAll();
- this.tableViewModel.selected.push(newEntity);
- });
- });
- this.close();
- }
-
- public open() {
- this.displayedAttributes(this.constructDisplayedAttributes(this.originEntity));
- if (userContext.apiType === "Tables") {
- this.originalDocument = TableEntityProcessor.convertEntitiesToDocuments(
- [this.originEntity],
- this.tableViewModel.queryTablesTab.collection
- )[0]; // TODO change for Cassandra
- this.originalDocument.id = ko.observable(this.originalDocument.id);
- } else {
- this.originalDocument = this.originEntity;
- }
- this.updateIsActionEnabled();
- super.open();
- }
-
- private constructDisplayedAttributes(entity: Entities.ITableEntity): EntityPropertyViewModel[] {
- var displayedAttributes: EntityPropertyViewModel[] = [];
- const keys = Object.keys(entity);
- keys &&
- keys.forEach((key: string) => {
- if (
- key !== TableEntityProcessor.keyProperties.attachments &&
- key !== TableEntityProcessor.keyProperties.etag &&
- key !== TableEntityProcessor.keyProperties.resourceId &&
- key !== TableEntityProcessor.keyProperties.self &&
- (userContext.apiType !== "Cassandra" || key !== TableConstants.EntityKeyNames.RowKey)
- ) {
- if (userContext.apiType === "Cassandra") {
- const cassandraKeys = this.tableViewModel.queryTablesTab.collection.cassandraKeys.partitionKeys
- .concat(this.tableViewModel.queryTablesTab.collection.cassandraKeys.clusteringKeys)
- .map((key) => key.property);
- var entityAttribute: Entities.ITableEntityAttribute = entity[key];
- var entityAttributeType: string = entityAttribute.$;
- var displayValue: any = this.getPropertyDisplayValue(entity, key, entityAttributeType);
- var removable: boolean = false;
- // TODO figure out validation story for blob and Inet so we can allow adding/editing them
- const nonEditableType: boolean =
- entityAttributeType === TableConstants.CassandraType.Blob ||
- entityAttributeType === TableConstants.CassandraType.Inet;
-
- displayedAttributes.push(
- new EntityPropertyViewModel(
- this,
- key,
- entityAttributeType,
- displayValue,
- /* namePlaceholder */ undefined,
- /* valuePlaceholder */ undefined,
- false,
- /* default valid name */ true,
- /* default valid value */ true,
- /* isRequired */ false,
- removable,
- /*value editable*/ !_.contains(cassandraKeys, key) && !nonEditableType
- )
- );
- } else {
- var entityAttribute: Entities.ITableEntityAttribute = entity[key];
- var entityAttributeType: string = entityAttribute.$;
- var displayValue: any = this.getPropertyDisplayValue(entity, key, entityAttributeType);
- var editable: boolean = this.isAttributeEditable(key, entityAttributeType);
- // As per VSO:189935, Binary properties are read-only, we still want to be able to remove them.
- var removable: boolean = editable || entityAttributeType === TableConstants.TableType.Binary;
-
- displayedAttributes.push(
- new EntityPropertyViewModel(
- this,
- key,
- entityAttributeType,
- displayValue,
- /* namePlaceholder */ undefined,
- /* valuePlaceholder */ undefined,
- editable,
- /* default valid name */ true,
- /* default valid value */ true,
- /* isRequired */ false,
- removable
- )
- );
- }
- }
- });
- if (userContext.apiType === "Cassandra") {
- (this.container.tableDataClient)
- .getTableSchema(this.tableViewModel.queryTablesTab.collection)
- .then((properties: CassandraTableKey[]) => {
- properties &&
- properties.forEach((property) => {
- if (!_.contains(keys, property.property)) {
- this.insertAttribute(property.property, property.type);
- }
- });
- });
- }
- return displayedAttributes;
- }
-
- private updateEntity(displayedAttributes: EntityPropertyViewModel[]): Entities.ITableEntity {
- var updatedEntity: any = {};
- displayedAttributes &&
- displayedAttributes.forEach((attribute: EntityPropertyViewModel) => {
- if (attribute.name() && (userContext.apiType !== "Cassandra" || attribute.value() !== "")) {
- var value = attribute.getPropertyValue();
- var type = attribute.type();
- if (type === TableConstants.TableType.Int64) {
- value = Utilities.padLongWithZeros(value);
- }
- updatedEntity[attribute.name()] = {
- _: value,
- $: type,
- };
- }
- });
- return updatedEntity;
- }
-
- private isAttributeEditable(attributeName: string, entityAttributeType: string) {
- return !(
- attributeName === TableConstants.EntityKeyNames.PartitionKey ||
- attributeName === TableConstants.EntityKeyNames.RowKey ||
- attributeName === TableConstants.EntityKeyNames.Timestamp ||
- // As per VSO:189935, Making Binary properties read-only in Edit Entity dialog until we have a full story for it.
- entityAttributeType === TableConstants.TableType.Binary
- );
- }
-
- private getPropertyDisplayValue(entity: Entities.ITableEntity, name: string, type: string): any {
- var attribute: Entities.ITableEntityAttribute = entity[name];
- var displayValue: any = attribute._;
- var isBinary: boolean = type === TableConstants.TableType.Binary;
-
- // Showing the value in base64 for binary properties since that is what the Azure Storage Client Library expects.
- // This means that, even if the Azure Storage API returns a byte[] of binary content, it needs that same array
- // *base64 - encoded * as the value for the updated property or the whole update operation will fail.
- if (isBinary && displayValue && $.isArray(displayValue.data)) {
- var bytes: number[] = displayValue.data;
- displayValue = this.getBase64DisplayValue(bytes);
- }
-
- return displayValue;
- }
-
- private getBase64DisplayValue(bytes: number[]): string {
- var displayValue: string = null;
-
- try {
- var chars: string[] = bytes.map((byte: number) => String.fromCharCode(byte));
- var toEncode: string = chars.join("");
- displayValue = window.btoa(toEncode);
- } catch (error) {
- // Error
- }
-
- return displayValue;
- }
-}
diff --git a/src/Explorer/Panes/Tables/EntityPropertyViewModel.ts b/src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
deleted file mode 100644
index 9fd007683..000000000
--- a/src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
+++ /dev/null
@@ -1,164 +0,0 @@
-import * as ko from "knockout";
-
-import * as DateTimeUtilities from "../../Tables/QueryBuilder/DateTimeUtilities";
-import * as EntityPropertyNameValidator from "./Validators/EntityPropertyNameValidator";
-import EntityPropertyValueValidator from "./Validators/EntityPropertyValueValidator";
-import * as Constants from "../../Tables/Constants";
-import * as Utilities from "../../Tables/Utilities";
-import TableEntityPane from "./TableEntityPane";
-
-export interface IValidationResult {
- isInvalid: boolean;
- help: string;
-}
-
-export interface IActionEnabledDialog {
- updateIsActionEnabled: () => void;
-}
-
-/**
- * View model for an entity proprety
- */
-export default class EntityPropertyViewModel {
- /* Constants */
- public static noTooltip = "";
- // Maximum number of custom properties, see Azure Service Data Model
- // At https://msdn.microsoft.com/library/azure/dd179338.aspx
- public static maximumNumberOfProperties = 252;
-
- // Labels
- public closeButtonLabel: string = "Close"; // localize
-
- /* Observables */
- public name: ko.Observable;
- public type: ko.Observable;
- public value: ko.Observable;
- public inputType: ko.Computed;
-
- public nameTooltip: ko.Observable;
- public isInvalidName: ko.Observable;
-
- public valueTooltip: ko.Observable;
- public isInvalidValue: ko.Observable;
-
- public namePlaceholder: ko.Observable;
- public valuePlaceholder: ko.Observable;
-
- public hasFocus: ko.Observable;
- public valueHasFocus: ko.Observable;
- public isDateType: ko.Computed;
-
- public editable: boolean; // If a property's name or type is editable, these two are always the same regarding editability.
- public valueEditable: boolean; // If a property's value is editable, could be different from name or type.
- public removable: boolean; // If a property is removable, usually, PartitionKey, RowKey and TimeStamp (if applicable) are not removable.
- public isRequired: boolean; // If a property's value is required, used to differentiate the place holder label.
- public ignoreEmptyValue: boolean;
-
- /* Members */
- private tableEntityPane: TableEntityPane;
- private _validator: EntityPropertyValueValidator;
-
- constructor(
- tableEntityPane: TableEntityPane,
- name: string,
- type: string,
- value: any,
- namePlaceholder: string = "",
- valuePlaceholder: string = "",
- editable: boolean = false,
- defaultValidName: boolean = true,
- defaultValidValue: boolean = false,
- isRequired: boolean = false,
- removable: boolean = editable,
- valueEditable: boolean = editable,
- ignoreEmptyValue: boolean = false
- ) {
- this.name = ko.observable(name);
- this.type = ko.observable(type);
- this.isDateType = ko.pureComputed(() => this.type() === Constants.TableType.DateTime);
- if (this.isDateType()) {
- value = value ? DateTimeUtilities.getLocalDateTime(value) : value;
- }
- this.value = ko.observable(value);
- this.inputType = ko.pureComputed(() => {
- if (!this.valueHasFocus() && !this.value() && this.isDateType()) {
- return Constants.InputType.Text;
- }
- return Utilities.getInputTypeFromDisplayedName(this.type());
- });
-
- this.namePlaceholder = ko.observable(namePlaceholder);
- this.valuePlaceholder = ko.observable(valuePlaceholder);
-
- this.editable = editable;
- this.isRequired = isRequired;
- this.removable = removable;
- this.valueEditable = valueEditable;
-
- this._validator = new EntityPropertyValueValidator(isRequired);
-
- this.tableEntityPane = tableEntityPane;
-
- this.nameTooltip = ko.observable(EntityPropertyViewModel.noTooltip);
- this.isInvalidName = ko.observable(!defaultValidName);
- this.name.subscribe((name: string) => this.validateName(name));
- if (!defaultValidName) {
- this.validateName(name);
- }
-
- this.valueTooltip = ko.observable(EntityPropertyViewModel.noTooltip);
- this.isInvalidValue = ko.observable(!defaultValidValue);
- this.value.subscribe((value: string) => this.validateValue(value, this.type()));
- if (!defaultValidValue) {
- this.validateValue(value, type);
- }
-
- this.type.subscribe((type: string) => this.validateValue(this.value(), type));
-
- this.hasFocus = ko.observable(false);
- this.valueHasFocus = ko.observable(false);
- }
-
- /**
- * Gets the Javascript value of the entity property based on its EDM type.
- */
- public getPropertyValue(): any {
- var value: string = this.value();
- if (this.type() === Constants.TableType.DateTime) {
- value = DateTimeUtilities.getUTCDateTime(value);
- }
- return this._validator.parseValue(value, this.type());
- }
-
- private validateName(name: string): void {
- var result: IValidationResult = this.isInvalidNameInput(name);
-
- this.isInvalidName(result.isInvalid);
- this.nameTooltip(result.help);
- this.namePlaceholder(result.help);
- this.tableEntityPane.updateIsActionEnabled();
- }
-
- private validateValue(value: string, type: string): void {
- var result: IValidationResult = this.isInvalidValueInput(value, type);
- if (!result) {
- return;
- }
-
- this.isInvalidValue(result.isInvalid);
- this.valueTooltip(result.help);
- this.valuePlaceholder(result.help);
- this.tableEntityPane.updateIsActionEnabled();
- }
-
- private isInvalidNameInput(name: string): IValidationResult {
- return EntityPropertyNameValidator.validate(name);
- }
-
- private isInvalidValueInput(value: string, type: string): IValidationResult {
- if (this.ignoreEmptyValue && this.value() === "") {
- return { isInvalid: false, help: "" };
- }
- return this._validator.validate(value, type);
- }
-}
diff --git a/src/Explorer/Panes/Tables/TableAddEntityPane.html b/src/Explorer/Panes/Tables/TableAddEntityPane.html
deleted file mode 100644
index cf8a6cf98..000000000
--- a/src/Explorer/Panes/Tables/TableAddEntityPane.html
+++ /dev/null
@@ -1,190 +0,0 @@
-
diff --git a/src/Explorer/Panes/Tables/TableEditEntityPane.html b/src/Explorer/Panes/Tables/TableEditEntityPane.html
deleted file mode 100644
index 44cbc6c9a..000000000
--- a/src/Explorer/Panes/Tables/TableEditEntityPane.html
+++ /dev/null
@@ -1,187 +0,0 @@
-
diff --git a/src/Explorer/Panes/Tables/TableEntityPane.ts b/src/Explorer/Panes/Tables/TableEntityPane.ts
deleted file mode 100644
index 23eafff11..000000000
--- a/src/Explorer/Panes/Tables/TableEntityPane.ts
+++ /dev/null
@@ -1,279 +0,0 @@
-import * as ko from "knockout";
-import _ from "underscore";
-import { KeyCodes } from "../../../Common/Constants";
-import * as ViewModels from "../../../Contracts/ViewModels";
-import { userContext } from "../../../UserContext";
-import * as TableConstants from "../../Tables/Constants";
-import * as DataTableUtilities from "../../Tables/DataTable/DataTableUtilities";
-import TableEntityListViewModel from "../../Tables/DataTable/TableEntityListViewModel";
-import * as Entities from "../../Tables/Entities";
-import * as TableEntityProcessor from "../../Tables/TableEntityProcessor";
-import * as Utilities from "../../Tables/Utilities";
-import { ContextualPaneBase } from "../ContextualPaneBase";
-import EntityPropertyViewModel from "./EntityPropertyViewModel";
-
-// Class with variables and functions that are common to both adding and editing entities
-export default abstract class TableEntityPane extends ContextualPaneBase {
- protected static requiredFieldsForTablesAPI: string[] = [
- TableConstants.EntityKeyNames.PartitionKey,
- TableConstants.EntityKeyNames.RowKey,
- ];
-
- /* Labels */
- public attributeNameLabel = "Property Name"; // localize
- public dataTypeLabel = "Type"; // localize
- public attributeValueLabel = "Value"; // localize
-
- /* Controls */
- public removeButtonLabel = "Remove"; // localize
- public editButtonLabel = "Edit"; // localize
- public addButtonLabel = "Add Property"; // localize
-
- public edmTypes: ko.ObservableArray = ko.observableArray([
- TableConstants.TableType.String,
- TableConstants.TableType.Boolean,
- TableConstants.TableType.Binary,
- TableConstants.TableType.DateTime,
- TableConstants.TableType.Double,
- TableConstants.TableType.Guid,
- TableConstants.TableType.Int32,
- TableConstants.TableType.Int64,
- ]);
-
- public canAdd: ko.Computed;
- public canApply: ko.Observable;
- public displayedAttributes = ko.observableArray();
- public editingProperty = ko.observable();
- public isEditing = ko.observable(false);
- public submitButtonText = ko.observable();
-
- public tableViewModel: TableEntityListViewModel;
-
- protected scrollId: ko.Observable;
-
- constructor(options: ViewModels.PaneOptions) {
- super(options);
- if (userContext.apiType === "Cassandra") {
- this.edmTypes([
- TableConstants.CassandraType.Text,
- TableConstants.CassandraType.Ascii,
- TableConstants.CassandraType.Bigint,
- TableConstants.CassandraType.Blob,
- TableConstants.CassandraType.Boolean,
- TableConstants.CassandraType.Decimal,
- TableConstants.CassandraType.Double,
- TableConstants.CassandraType.Float,
- TableConstants.CassandraType.Int,
- TableConstants.CassandraType.Uuid,
- TableConstants.CassandraType.Varchar,
- TableConstants.CassandraType.Varint,
- TableConstants.CassandraType.Inet,
- TableConstants.CassandraType.Smallint,
- TableConstants.CassandraType.Tinyint,
- ]);
- }
-
- this.canAdd = ko.computed(() => {
- // Cassandra can't add since the schema can't be changed once created
- if (userContext.apiType === "Cassandra") {
- return false;
- }
- // Adding '2' to the maximum to take into account PartitionKey and RowKey
- return this.displayedAttributes().length < EntityPropertyViewModel.maximumNumberOfProperties + 2;
- });
- this.canApply = ko.observable(true);
- this.editingProperty(this.displayedAttributes()[0]);
- }
-
- public removeAttribute = (index: number, data: any): void => {
- this.displayedAttributes.splice(index, 1);
- this.updateIsActionEnabled();
- document.getElementById("addProperty").focus();
- };
-
- public editAttribute = (index: number, data: EntityPropertyViewModel): void => {
- this.editingProperty(data);
- this.isEditing(true);
- document.getElementById("textAreaEditProperty").focus();
- };
-
- public finishEditingAttribute = (): void => {
- this.isEditing(false);
- this.editingProperty(null);
- };
-
- public onKeyUp = (data: any, event: KeyboardEvent): boolean => {
- var handled: boolean = Utilities.onEsc(event, ($sourceElement: JQuery) => {
- this.finishEditingAttribute();
- });
-
- return !handled;
- };
-
- public onAddPropertyKeyDown = (source: any, event: KeyboardEvent): boolean => {
- if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
- this.insertAttribute();
- event.stopPropagation();
- return false;
- }
-
- return true;
- };
-
- public onEditPropertyKeyDown = (
- index: number,
- data: EntityPropertyViewModel,
- event: KeyboardEvent,
- source: any
- ): boolean => {
- if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
- this.editAttribute(index, data);
- event.stopPropagation();
- return false;
- }
-
- return true;
- };
-
- public onDeletePropertyKeyDown = (
- index: number,
- data: EntityPropertyViewModel,
- event: KeyboardEvent,
- source: any
- ): boolean => {
- if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
- this.removeAttribute(index, data);
- event.stopPropagation();
- return false;
- }
-
- return true;
- };
-
- public onBackButtonKeyDown = (source: any, event: KeyboardEvent): boolean => {
- if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
- this.finishEditingAttribute();
- event.stopPropagation();
- return false;
- }
-
- return true;
- };
-
- public insertAttribute = (name?: string, type?: string): void => {
- let entityProperty: EntityPropertyViewModel;
- if (!!name && !!type && userContext.apiType === "Cassandra") {
- // TODO figure out validation story for blob and Inet so we can allow adding/editing them
- const nonEditableType: boolean =
- type === TableConstants.CassandraType.Blob || type === TableConstants.CassandraType.Inet;
- entityProperty = new EntityPropertyViewModel(
- this,
- name,
- type,
- "", // default to empty string
- /* namePlaceholder */ undefined,
- /* valuePlaceholder */ undefined,
- /* editable */ false,
- /* default valid name */ false,
- /* default valid value */ true,
- /* isRequired */ false,
- /* removable */ false,
- /*value editable*/ !nonEditableType
- );
- } else {
- entityProperty = new EntityPropertyViewModel(
- this,
- "",
- this.edmTypes()[0], // default to the first Edm type: 'string'
- "", // default to empty string
- /* namePlaceholder */ undefined,
- /* valuePlaceholder */ undefined,
- /* editable */ true,
- /* default valid name */ false,
- /* default valid value */ true
- );
- }
-
- this.displayedAttributes.push(entityProperty);
- this.updateIsActionEnabled();
- this.scrollToBottom();
-
- entityProperty.hasFocus(true);
- };
-
- public updateIsActionEnabled(needRequiredFields: boolean = true): void {
- var properties: EntityPropertyViewModel[] = this.displayedAttributes() || [];
- var disable: boolean = _.some(properties, (property: EntityPropertyViewModel) => {
- return property.isInvalidName() || property.isInvalidValue();
- });
-
- this.canApply(!disable);
- }
-
- protected entityFromAttributes(displayedAttributes: EntityPropertyViewModel[]): Entities.ITableEntity {
- var entity: any = {};
-
- displayedAttributes &&
- displayedAttributes.forEach((attribute: EntityPropertyViewModel) => {
- if (attribute.name() && (attribute.value() !== "" || attribute.isRequired)) {
- var value = attribute.getPropertyValue();
- var type = attribute.type();
- if (type === TableConstants.TableType.Int64) {
- value = Utilities.padLongWithZeros(value);
- }
- entity[attribute.name()] = {
- _: value,
- $: type,
- };
- }
- });
-
- return entity;
- }
-
- // Removing Binary from Add Entity dialog until we have a full story for it.
- protected setOptionDisable(option: Node, value: string): void {
- ko.applyBindingsToNode(option, { disable: value === TableConstants.TableType.Binary }, value);
- }
-
- /**
- * Parse the updated entity to see if there are any new attributes that old headers don't have.
- * In this case, add these attributes names as new headers.
- * Remarks: adding new headers will automatically trigger table redraw.
- */
- protected tryInsertNewHeaders(viewModel: TableEntityListViewModel, newEntity: Entities.ITableEntity): boolean {
- var newHeaders: string[] = [];
- const keys = Object.keys(newEntity);
- keys &&
- keys.forEach((key: string) => {
- if (
- !_.contains(viewModel.headers, key) &&
- key !== TableEntityProcessor.keyProperties.attachments &&
- key !== TableEntityProcessor.keyProperties.etag &&
- key !== TableEntityProcessor.keyProperties.resourceId &&
- key !== TableEntityProcessor.keyProperties.self &&
- (userContext.apiType !== "Cassandra" || key !== TableConstants.EntityKeyNames.RowKey)
- ) {
- newHeaders.push(key);
- }
- });
-
- var newHeadersInserted: boolean = false;
- if (newHeaders.length) {
- if (!DataTableUtilities.checkForDefaultHeader(viewModel.headers)) {
- newHeaders = viewModel.headers.concat(newHeaders);
- }
- viewModel.updateHeaders(newHeaders, /* notifyColumnChanges */ true, /* enablePrompt */ false);
- newHeadersInserted = true;
- }
- return newHeadersInserted;
- }
-
- protected scrollToBottom(): void {
- var scrollBox = document.getElementById(this.scrollId());
- var isScrolledToBottom = scrollBox.scrollHeight - scrollBox.clientHeight <= scrollBox.scrollHeight + 1;
- if (isScrolledToBottom) {
- scrollBox.scrollTop = scrollBox.scrollHeight - scrollBox.clientHeight;
- }
- }
-}
diff --git a/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap b/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap
index 1a7042440..2a6672833 100644
--- a/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap
+++ b/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap
@@ -80,6 +80,7 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
@@ -230,6 +231,7 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
+ "isEnableMongoCapabilityEnabled": [Function],
"isExecuting": [Function],
"isFixedStorageSelected": [Function],
"isFreeTierAccount": [Function],
diff --git a/src/Explorer/Tables/TableEntityProcessor.ts b/src/Explorer/Tables/TableEntityProcessor.ts
index f26d2c38d..c18f7bab9 100644
--- a/src/Explorer/Tables/TableEntityProcessor.ts
+++ b/src/Explorer/Tables/TableEntityProcessor.ts
@@ -183,12 +183,14 @@ export function convertEntityToNewDocument(entity: Entities.ITableEntityForTable
parsedValue = DateTimeUtilities.convertJSDateToTicksWithPadding(propertyValue);
break;
case Constants.TableType.Boolean:
- parsedValue = propertyValue.toLowerCase() === "true";
+ parsedValue = propertyValue.toString().toLowerCase() === "true";
break;
case Constants.TableType.Int32:
- case Constants.TableType.Int64:
parsedValue = parseInt(propertyValue, 10);
break;
+ case Constants.TableType.Int64:
+ parsedValue = propertyValue.toString();
+ break;
case Constants.TableType.Double:
parsedValue = parseFloat(propertyValue);
break;
diff --git a/src/Explorer/Tabs/NotebookViewerTab.tsx b/src/Explorer/Tabs/NotebookViewerTab.tsx
deleted file mode 100644
index 677ca21a8..000000000
--- a/src/Explorer/Tabs/NotebookViewerTab.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import * as ko from "knockout";
-import * as React from "react";
-import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
-import { DatabaseAccount } from "../../Contracts/DataModels";
-import * as ViewModels from "../../Contracts/ViewModels";
-import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
-import {
- NotebookViewerComponent,
- NotebookViewerComponentProps,
-} from "../Controls/NotebookViewer/NotebookViewerComponent";
-import Explorer from "../Explorer";
-import TabsBase from "./TabsBase";
-
-interface NotebookViewerTabOptions extends ViewModels.TabOptions {
- account: DatabaseAccount;
- container: Explorer;
- notebookUrl: string;
-}
-
-/**
- * Notebook Viewer tab
- */
-class NotebookViewerComponentAdapter implements ReactAdapter {
- // parameters: true: show, false: hide
- public parameters: ko.Computed;
- constructor(private notebookUrl: string) {}
-
- public renderComponent(): JSX.Element {
- const props: NotebookViewerComponentProps = {
- notebookUrl: this.notebookUrl,
- backNavigationText: undefined,
- onBackClick: undefined,
- onTagClick: undefined,
- };
-
- return this.parameters() ? : <>>;
- }
-}
-
-export default class NotebookViewerTab extends TabsBase {
- public readonly html = '';
- private container: Explorer;
- public notebookUrl: string;
-
- public notebookViewerComponentAdapter: NotebookViewerComponentAdapter;
-
- constructor(options: NotebookViewerTabOptions) {
- super(options);
- this.container = options.container;
- this.notebookUrl = options.notebookUrl;
-
- this.notebookViewerComponentAdapter = new NotebookViewerComponentAdapter(options.notebookUrl);
-
- this.notebookViewerComponentAdapter.parameters = ko.computed(() => {
- if (this.isTemplateReady() && this.container.isNotebookEnabled()) {
- return true;
- }
- return false;
- });
- }
-
- public getContainer(): Explorer {
- return this.container;
- }
-
- protected getTabsButtons(): CommandButtonComponentProps[] {
- return [];
- }
-
- protected buildCommandBarOptions(): void {
- this.updateNavbarWithTabsButtons();
- }
-}
diff --git a/src/Utils/CapabilityUtils.ts b/src/Utils/CapabilityUtils.ts
new file mode 100644
index 000000000..8e04e044c
--- /dev/null
+++ b/src/Utils/CapabilityUtils.ts
@@ -0,0 +1,4 @@
+import { userContext } from "../UserContext";
+
+export const isCapabilityEnabled = (capabilityName: string): boolean =>
+ userContext.databaseAccount?.properties?.capabilities?.some((capability) => capability.name === capabilityName);
diff --git a/tsconfig.strict.json b/tsconfig.strict.json
index 736631ee4..15c304aec 100644
--- a/tsconfig.strict.json
+++ b/tsconfig.strict.json
@@ -43,6 +43,7 @@
"./src/Explorer/Graph/GraphExplorerComponent/ArraysByKeyCache.ts",
"./src/Explorer/Graph/GraphExplorerComponent/EdgeInfoCache.ts",
"./src/Explorer/Graph/GraphExplorerComponent/GraphData.ts",
+ "./src/Explorer/LazyMonaco.ts",
"./src/Explorer/Notebook/FileSystemUtil.ts",
"./src/Explorer/Notebook/NTeractUtil.ts",
"./src/Explorer/Notebook/NotebookComponent/actions.ts",
@@ -54,6 +55,8 @@
"./src/Explorer/Notebook/NotebookRenderer/AzureTheme.tsx",
"./src/Explorer/Notebook/NotebookRenderer/decorators/CellCreator.tsx",
"./src/Explorer/Notebook/NotebookUtil.ts",
+ "./src/Explorer/OpenFullScreen.test.tsx",
+ "./src/Explorer/OpenFullScreen.tsx",
"./src/Explorer/Panes/PaneComponents.ts",
"./src/Explorer/Panes/PanelFooterComponent.tsx",
"./src/Explorer/Panes/PanelLoadingScreen.tsx",
@@ -70,6 +73,7 @@
"./src/HostedExplorerChildFrame.ts",
"./src/Index.ts",
"./src/NotebookWorkspaceManager/NotebookWorkspaceResourceProviderMockClients.ts",
+ "./src/Platform/Hosted/Authorization.ts",
"./src/Platform/Hosted/Components/SignInButton.tsx",
"./src/Platform/Hosted/extractFeatures.test.ts",
"./src/Platform/Hosted/extractFeatures.ts",
@@ -87,6 +91,7 @@
"./src/Shared/StringUtility.ts",
"./src/Shared/appInsights.ts",
"./src/UserContext.ts",
+ "./src/Utils/APITypeUtils.ts",
"./src/Utils/AutoPilotUtils.ts",
"./src/Utils/Base64Utils.test.ts",
"./src/Utils/Base64Utils.ts",
@@ -97,15 +102,19 @@
"./src/Utils/MessageValidation.ts",
"./src/Utils/PricingUtils.ts",
"./src/Utils/StringUtils.ts",
+ "./src/Utils/StyleUtils.ts",
"./src/Utils/WindowUtils.test.ts",
"./src/Utils/WindowUtils.ts",
"./src/hooks/useDirectories.tsx",
+ "./src/hooks/useFullScreenURLs.tsx",
+ "./src/hooks/useObservable.ts",
"./src/i18n.ts",
"./src/quickstart.ts",
"./src/setupTests.ts",
"./src/userContext.test.ts"
],
"include": [
+ "src/CellOutputViewer/transforms/**/*",
"src/Controls/**/*",
"src/Definitions/**/*",
"src/Explorer/Controls/ErrorDisplayComponent/**/*",