import * as React from "react"; import * as ViewModels from "../../../../Contracts/ViewModels"; import { GeospatialConfigType, TtlType, ChangeFeedPolicyState, isDirty, IsComponentDirtyResult, TtlOn, TtlOff, TtlOnNoDefault, getSanitizedInputValue, } from "../SettingsUtils"; import Explorer from "../../../Explorer"; import { Int32 } from "../../../Panes/Tables/Validators/EntityPropertyValidationCommon"; import { Label, Text, TextField, Stack, IChoiceGroupOption, ChoiceGroup, MessageBar } from "office-ui-fabric-react"; import { getTextFieldStyles, changeFeedPolicyToolTip, subComponentStackProps, titleAndInputStackProps, getChoiceGroupStyles, ttlWarning, messageBarStyles, } from "../SettingsRenderUtils"; import { ToolTipLabelComponent } from "./ToolTipLabelComponent"; export interface SubSettingsComponentProps { collection: ViewModels.Collection; container: Explorer; timeToLive: TtlType; timeToLiveBaseline: TtlType; onTtlChange: (newTtl: TtlType) => void; timeToLiveSeconds: number; timeToLiveSecondsBaseline: number; onTimeToLiveSecondsChange: (newTimeToLiveSeconds: number) => void; geospatialConfigType: GeospatialConfigType; geospatialConfigTypeBaseline: GeospatialConfigType; onGeoSpatialConfigTypeChange: (newGeoSpatialConfigType: GeospatialConfigType) => void; isAnalyticalStorageEnabled: boolean; analyticalStorageTtlSelection: TtlType; analyticalStorageTtlSelectionBaseline: TtlType; onAnalyticalStorageTtlSelectionChange: (newAnalyticalStorageTtlSelection: TtlType) => void; analyticalStorageTtlSeconds: number; analyticalStorageTtlSecondsBaseline: number; onAnalyticalStorageTtlSecondsChange: (newAnalyticalStorageTtlSeconds: number) => void; changeFeedPolicyVisible: boolean; changeFeedPolicy: ChangeFeedPolicyState; changeFeedPolicyBaseline: ChangeFeedPolicyState; onChangeFeedPolicyChange: (newChangeFeedPolicyState: ChangeFeedPolicyState) => void; onSubSettingsSaveableChange: (isSubSettingsSaveable: boolean) => void; onSubSettingsDiscardableChange: (isSubSettingsDiscardable: boolean) => void; } export class SubSettingsComponent extends React.Component { private shouldCheckComponentIsDirty = true; private ttlVisible: boolean; private geospatialVisible: boolean; private partitionKeyValue: string; private partitionKeyName: string; constructor(props: SubSettingsComponentProps) { super(props); this.ttlVisible = (this.props.container && !this.props.container.isPreferredApiCassandra()) || false; this.geospatialVisible = this.props.container.isPreferredApiDocumentDB(); this.partitionKeyValue = "/" + this.props.collection.partitionKeyProperty; this.partitionKeyName = this.props.container.isPreferredApiMongoDB() ? "Shard key" : "Partition key"; } componentDidMount(): void { this.onComponentUpdate(); } componentDidUpdate(): void { this.onComponentUpdate(); } private onComponentUpdate = (): void => { if (!this.shouldCheckComponentIsDirty) { this.shouldCheckComponentIsDirty = true; return; } const isComponentDirtyResult = this.IsComponentDirty(); this.props.onSubSettingsSaveableChange(isComponentDirtyResult.isSaveable); this.props.onSubSettingsDiscardableChange(isComponentDirtyResult.isDiscardable); this.shouldCheckComponentIsDirty = false; }; public IsComponentDirty = (): IsComponentDirtyResult => { if ( (this.props.timeToLive === TtlType.On && !this.props.timeToLiveSeconds) || (this.props.analyticalStorageTtlSelection === TtlType.On && !this.props.analyticalStorageTtlSeconds) ) { return { isSaveable: false, isDiscardable: true }; } else if ( isDirty(this.props.timeToLive, this.props.timeToLiveBaseline) || (this.props.timeToLive === TtlType.On && isDirty(this.props.timeToLiveSeconds, this.props.timeToLiveSecondsBaseline)) || isDirty(this.props.analyticalStorageTtlSelection, this.props.analyticalStorageTtlSelectionBaseline) || (this.props.analyticalStorageTtlSelection === TtlType.On && isDirty(this.props.analyticalStorageTtlSeconds, this.props.analyticalStorageTtlSecondsBaseline)) || isDirty(this.props.geospatialConfigType, this.props.geospatialConfigTypeBaseline) || isDirty(this.props.changeFeedPolicy, this.props.changeFeedPolicyBaseline) ) { return { isSaveable: true, isDiscardable: true }; } return { isSaveable: false, isDiscardable: false }; }; private ttlChoiceGroupOptions: IChoiceGroupOption[] = [ { key: TtlType.Off, text: "Off" }, { key: TtlType.OnNoDefault, text: "On (no default)" }, { key: TtlType.On, text: "On" }, ]; public getTtlValue = (value: string): TtlType => { switch (value) { case TtlOn: return TtlType.On; case TtlOff: return TtlType.Off; case TtlOnNoDefault: return TtlType.OnNoDefault; } return undefined; }; private onTtlChange = (ev?: React.FormEvent, option?: IChoiceGroupOption): void => this.props.onTtlChange(this.getTtlValue(option.key)); private onTimeToLiveSecondsChange = ( event: React.FormEvent, newValue?: string ): void => { const newTimeToLiveSeconds = getSanitizedInputValue(newValue, Int32.Max); this.props.onTimeToLiveSecondsChange(newTimeToLiveSeconds); }; private onGeoSpatialConfigTypeChange = ( ev?: React.FormEvent, option?: IChoiceGroupOption ): void => this.props.onGeoSpatialConfigTypeChange(GeospatialConfigType[option.key as keyof typeof GeospatialConfigType]); private onAnalyticalStorageTtlSelectionChange = ( ev?: React.FormEvent, option?: IChoiceGroupOption ): void => this.props.onAnalyticalStorageTtlSelectionChange(this.getTtlValue(option.key)); private onAnalyticalStorageTtlSecondsChange = ( event: React.FormEvent, newValue?: string ): void => { const newAnalyticalStorageTtlSeconds = getSanitizedInputValue(newValue, Int32.Max); this.props.onAnalyticalStorageTtlSecondsChange(newAnalyticalStorageTtlSeconds); }; private onChangeFeedPolicyChange = ( ev?: React.FormEvent, option?: IChoiceGroupOption ): void => this.props.onChangeFeedPolicyChange(ChangeFeedPolicyState[option.key as keyof typeof ChangeFeedPolicyState]); private getTtlComponent = (): JSX.Element => ( {isDirty(this.props.timeToLive, this.props.timeToLiveBaseline) && this.props.timeToLive === TtlType.On && ( {ttlWarning} )} {this.props.timeToLive === TtlType.On && ( )} ); private analyticalTtlChoiceGroupOptions: IChoiceGroupOption[] = [ { key: TtlType.Off, text: "Off", disabled: true }, { key: TtlType.OnNoDefault, text: "On (no default)" }, { key: TtlType.On, text: "On" }, ]; private getAnalyticalStorageTtlComponent = (): JSX.Element => ( {this.props.analyticalStorageTtlSelection === TtlType.On && ( )} ); private geoSpatialConfigTypeChoiceGroupOptions: IChoiceGroupOption[] = [ { key: GeospatialConfigType.Geography, text: "Geography" }, { key: GeospatialConfigType.Geometry, text: "Geometry" }, ]; private getGeoSpatialComponent = (): JSX.Element => ( ); private changeFeedChoiceGroupOptions: IChoiceGroupOption[] = [ { key: ChangeFeedPolicyState.Off, text: "Off" }, { key: ChangeFeedPolicyState.On, text: "On" }, ]; private getChangeFeedComponent = (): JSX.Element => { const labelId = "settingsV2ChangeFeedLabelId"; return ( ); }; private getPartitionKeyComponent = (): JSX.Element => ( {this.getPartitionKeyVisible() && ( )} {this.isLargePartitionKeyEnabled() && Large {this.partitionKeyName.toLowerCase()} has been enabled} ); public getPartitionKeyVisible = (): boolean => { if ( this.props.container.isPreferredApiCassandra() || this.props.container.isPreferredApiTable() || !this.props.collection.partitionKeyProperty || (this.props.container.isPreferredApiMongoDB() && this.props.collection.partitionKey.systemKey) ) { return false; } return true; }; public isLargePartitionKeyEnabled = (): boolean => this.props.collection.partitionKey?.version >= 2; public render(): JSX.Element { return ( {this.ttlVisible && this.getTtlComponent()} {this.geospatialVisible && this.getGeoSpatialComponent()} {this.props.isAnalyticalStorageEnabled && this.getAnalyticalStorageTtlComponent()} {this.props.changeFeedPolicyVisible && this.getChangeFeedComponent()} {this.getPartitionKeyComponent()} ); } }