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/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/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 @@ -
-
-
- -
-
- -
- -
- Close -
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
- -
- -
- -
- - -
- -
- -
- - Edit - - - Cancel - -
-
-
-
-
-
- - Insert attribute - - -
-
-
-
-
-
-
- -
-
-
-
- - - - -
-
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 @@ -
-
-
- -
-
- -
- -
- Close -
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
- -
- -
- -
- - -
- -
- -
- - Edit attribute - - - Remove attribute - -
-
-
-
-
-
- - Add attribute - - -
-
-
-
-
-
-
- -
-
-
-
- - - - -
-
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; - } - } -}