import { ActionButton, Checkbox, DefaultButton, DirectionalHint, Dropdown, Icon, IconButton, IDropdownOption, Link, ProgressIndicator, Separator, Stack, TeachingBubble, Text, TooltipHost, } from "@fluentui/react"; import * as Constants from "Common/Constants"; import { createCollection } from "Common/dataAccess/createCollection"; import { getNewDatabaseSharedThroughputDefault } from "Common/DatabaseUtility"; import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils"; import { configContext, Platform } from "ConfigContext"; import * as DataModels from "Contracts/DataModels"; import { FullTextPoliciesComponent, getFullTextLanguageOptions, } from "Explorer/Controls/FullTextSeach/FullTextPoliciesComponent"; import { VectorEmbeddingPoliciesComponent } from "Explorer/Controls/VectorSearch/VectorEmbeddingPoliciesComponent"; import { useSidePanel } from "hooks/useSidePanel"; import { useTeachingBubble } from "hooks/useTeachingBubble"; import { isFabricNative } from "Platform/Fabric/FabricUtil"; import React from "react"; import { CollectionCreation } from "Shared/Constants"; import { Action } from "Shared/Telemetry/TelemetryConstants"; import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor"; import { userContext } from "UserContext"; import { getCollectionName } from "Utils/APITypeUtils"; import { isCapabilityEnabled, isFullTextSearchEnabled, isServerlessAccount, isVectorSearchEnabled, } from "Utils/CapabilityUtils"; import { getUpsellMessage } from "Utils/PricingUtils"; import { CollapsibleSectionComponent } from "../Controls/CollapsiblePanel/CollapsibleSectionComponent"; import { ThroughputInput } from "../Controls/ThroughputInput/ThroughputInput"; import "../Controls/ThroughputInput/ThroughputInput.less"; import { ContainerSampleGenerator } from "../DataSamples/ContainerSampleGenerator"; import Explorer from "../Explorer"; import { useDatabases } from "../useDatabases"; import { PanelFooterComponent } from "./PanelFooterComponent"; import { PanelInfoErrorComponent } from "./PanelInfoErrorComponent"; import { PanelLoadingScreen } from "./PanelLoadingScreen"; export interface AddCollectionPanelProps { explorer: Explorer; databaseId?: string; isQuickstart?: boolean; } const SharedDatabaseDefault: DataModels.IndexingPolicy = { indexingMode: "consistent", automatic: true, includedPaths: [], excludedPaths: [ { path: "/*", }, ], }; export const AllPropertiesIndexed: DataModels.IndexingPolicy = { indexingMode: "consistent", automatic: true, includedPaths: [ { path: "/*", indexes: [ { kind: "Range", dataType: "Number", precision: -1, }, { kind: "Range", dataType: "String", precision: -1, }, ], }, ], excludedPaths: [], }; export const DefaultVectorEmbeddingPolicy: DataModels.VectorEmbeddingPolicy = { vectorEmbeddings: [], }; export interface AddCollectionPanelState { createNewDatabase: boolean; newDatabaseId: string; isSharedThroughputChecked: boolean; selectedDatabaseId: string; collectionId: string; enableIndexing: boolean; isSharded: boolean; partitionKey: string; subPartitionKeys: string[]; enableDedicatedThroughput: boolean; createMongoWildCardIndex: boolean; useHashV1: boolean; enableAnalyticalStore: boolean; uniqueKeys: string[]; errorMessage: string; showErrorDetails: boolean; isExecuting: boolean; isThroughputCapExceeded: boolean; teachingBubbleStep: number; vectorIndexingPolicy: DataModels.VectorIndex[]; vectorEmbeddingPolicy: DataModels.VectorEmbedding[]; vectorPolicyValidated: boolean; fullTextPolicy: DataModels.FullTextPolicy; fullTextIndexes: DataModels.FullTextIndex[]; fullTextPolicyValidated: boolean; } export class AddCollectionPanel extends React.Component { private newDatabaseThroughput: number; private isNewDatabaseAutoscale: boolean; private collectionThroughput: number; private isCollectionAutoscale: boolean; private isCostAcknowledged: boolean; constructor(props: AddCollectionPanelProps) { super(props); this.state = { createNewDatabase: userContext.apiType !== "Tables" && configContext.platform !== Platform.Fabric && !this.props.databaseId, newDatabaseId: props.isQuickstart ? this.getSampleDBName() : "", isSharedThroughputChecked: getNewDatabaseSharedThroughputDefault(), selectedDatabaseId: userContext.apiType === "Tables" ? CollectionCreation.TablesAPIDefaultDatabase : this.props.databaseId, collectionId: props.isQuickstart ? `Sample${getCollectionName()}` : "", enableIndexing: true, isSharded: userContext.apiType !== "Tables", partitionKey: this.getPartitionKey(), subPartitionKeys: [], enableDedicatedThroughput: false, createMongoWildCardIndex: isCapabilityEnabled("EnableMongo") && !isCapabilityEnabled("EnableMongo16MBDocumentSupport"), useHashV1: false, enableAnalyticalStore: false, uniqueKeys: [], errorMessage: "", showErrorDetails: false, isExecuting: false, isThroughputCapExceeded: false, teachingBubbleStep: 0, vectorEmbeddingPolicy: [], vectorIndexingPolicy: [], vectorPolicyValidated: true, fullTextPolicy: { defaultLanguage: getFullTextLanguageOptions()[0].key as never, fullTextPaths: [] }, fullTextIndexes: [], fullTextPolicyValidated: true, }; } componentDidMount(): void { if (this.state.teachingBubbleStep === 0 && this.props.isQuickstart) { this.setState({ teachingBubbleStep: 1 }); } } componentDidUpdate(_prevProps: AddCollectionPanelProps, prevState: AddCollectionPanelState): void { if (this.state.errorMessage && this.state.errorMessage !== prevState.errorMessage) { this.scrollToSection("panelContainer"); } } render(): JSX.Element { const isFirstResourceCreated = useDatabases.getState().isFirstResourceCreated(); return (
{this.state.errorMessage && ( )} {!this.state.errorMessage && this.isFreeTierAccount() && ( )} {this.state.teachingBubbleStep === 1 && ( this.setState({ teachingBubbleStep: 2 }) }} secondaryButtonProps={{ text: "Cancel", onClick: () => this.setState({ teachingBubbleStep: 0 }) }} onDismiss={() => this.setState({ teachingBubbleStep: 0 })} footerContent="Step 1 of 4" > Database is the parent of a container. You can create a new database or use an existing one. In this tutorial we are creating a new database named SampleDB. Learn more about resources. )} {this.state.teachingBubbleStep === 2 && ( this.setState({ teachingBubbleStep: 3 }) }} secondaryButtonProps={{ text: "Previous", onClick: () => this.setState({ teachingBubbleStep: 1 }) }} onDismiss={() => this.setState({ teachingBubbleStep: 0 })} footerContent="Step 2 of 4" > Cosmos DB recommends sharing throughput across database. Autoscale will give you a flexible amount of throughput based on the max RU/s set (Request Units). Learn more about RU/s. )} {this.state.teachingBubbleStep === 3 && ( this.setState({ teachingBubbleStep: 4 }) }} secondaryButtonProps={{ text: "Previous", onClick: () => this.setState({ teachingBubbleStep: 2 }) }} onDismiss={() => this.setState({ teachingBubbleStep: 0 })} footerContent="Step 3 of 4" > Name your container )} {this.state.teachingBubbleStep === 4 && ( { this.setState({ teachingBubbleStep: 5 }); this.submit(); }, }} secondaryButtonProps={{ text: "Previous", onClick: () => this.setState({ teachingBubbleStep: 2 }) }} onDismiss={() => this.setState({ teachingBubbleStep: 0 })} footerContent="Step 4 of 4" > Last step - you will need to define a partition key for your collection. /address was chosen for this particular example. A good partition key should have a wide range of possible value )}
{!(isFabricNative() && this.props.databaseId !== undefined) && ( )} {`${getCollectionName()} id`} ) => this.setState({ collectionId: event.target.value }) } /> {this.shouldShowIndexingOptionsForFreeTierAccount() && ( Indexing Automatic Off {this.getFreeTierIndexingText()}{" "} Learn more )} {userContext.apiType === "Mongo" && (!this.state.isSharedThroughputChecked || this.props.explorer.isFixedCollectionWithSharedThroughputSupported()) && ( Sharding Unsharded (20GB limit) Sharded )} {this.state.isSharded && ( {this.getPartitionKeyName()} {this.getPartitionKeySubtext()} ) => { if ( userContext.apiType !== "Mongo" && !this.state.partitionKey && !event.target.value.startsWith("/") ) { this.setState({ partitionKey: "/" + event.target.value }); } else { this.setState({ partitionKey: event.target.value }); } }} /> {userContext.apiType === "SQL" && this.state.subPartitionKeys.map((subPartitionKey: string, index: number) => { return (
0 ? 1 : 0} className="panelTextField" autoComplete="off" placeholder={this.getPartitionKeyPlaceHolder(index)} aria-label={this.getPartitionKeyName()} pattern={".*"} title={""} value={subPartitionKey} onChange={(event: React.ChangeEvent) => { const subPartitionKeys = [...this.state.subPartitionKeys]; if (!this.state.subPartitionKeys[index] && !event.target.value.startsWith("/")) { subPartitionKeys[index] = "/" + event.target.value.trim(); this.setState({ subPartitionKeys }); } else { subPartitionKeys[index] = event.target.value.trim(); this.setState({ subPartitionKeys }); } }} /> { const subPartitionKeys = this.state.subPartitionKeys.filter((uniqueKey, j) => index !== j); this.setState({ subPartitionKeys }); }} />
); })} {!isFabricNative() && userContext.apiType === "SQL" && ( {this.state.subPartitionKeys.length > 0 && ( This feature allows you to partition your data with up to three levels of keys for better data distribution. Requires .NET V3, Java V4 SDK, or preview JavaScript V3 SDK.{" "} Learn more )} )}
)} {!isServerlessAccount() && !this.state.createNewDatabase && this.isSelectedDatabaseSharedThroughput() && ( , isChecked: boolean) => this.setState({ enableDedicatedThroughput: isChecked }) } /> )} {this.shouldShowCollectionThroughputInput() && ( (this.collectionThroughput = throughput)} setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)} setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) => this.setState({ isThroughputCapExceeded }) } onCostAcknowledgeChange={(isAcknowledged: boolean) => { this.isCostAcknowledged = isAcknowledged; }} /> )} {!isFabricNative() && userContext.apiType === "SQL" && ( Unique keys {this.state.uniqueKeys.map((uniqueKey: string, i: number): JSX.Element => { return ( ) => { const uniqueKeys = this.state.uniqueKeys.map((uniqueKey: string, j: number) => { if (i === j) { return event.target.value; } return uniqueKey; }); this.setState({ uniqueKeys }); }} /> { const uniqueKeys = this.state.uniqueKeys.filter((uniqueKey, j) => i !== j); this.setState({ uniqueKeys }); }} /> ); })} this.setState({ uniqueKeys: [...this.state.uniqueKeys, ""] })} > Add unique key )} {this.shouldShowAnalyticalStoreOptions() && ( {this.getAnalyticalStorageContent()}
On Off
{!this.isSynapseLinkEnabled() && ( Azure Synapse Link is required for creating an analytical store{" "} {getCollectionName().toLocaleLowerCase()}. Enable Synapse Link for this Cosmos DB account.{" "} Learn more this.props.explorer.openEnableSynapseLinkDialog()} style={{ height: 27, width: 80 }} styles={{ label: { fontSize: 12 } }} /> )}
)} {this.shouldShowVectorSearchParameters() && ( { this.scrollToSection("collapsibleVectorPolicySectionContent"); }} tooltipContent={this.getContainerVectorPolicyTooltipContent()} > { this.setState({ vectorEmbeddingPolicy, vectorIndexingPolicy, vectorPolicyValidated }); }} /> )} {this.shouldShowFullTextSearchParameters() && ( { this.scrollToSection("collapsibleFullTextPolicySectionContent"); }} //TODO: uncomment when learn more text becomes available // tooltipContent={this.getContainerFullTextPolicyTooltipContent()} > { this.setState({ fullTextPolicy, fullTextIndexes, fullTextPolicyValidated }); }} /> )} {!isFabricNative() && userContext.apiType !== "Tables" && ( { TelemetryProcessor.traceOpen(Action.ExpandAddCollectionPaneAdvancedSection); this.scrollToSection("collapsibleAdvancedSectionContent"); }} > {isCapabilityEnabled("EnableMongo") && !isCapabilityEnabled("EnableMongo16MBDocumentSupport") && ( Indexing , isChecked: boolean) => this.setState({ createMongoWildCardIndex: isChecked }) } /> )} {userContext.apiType === "SQL" && ( , isChecked: boolean) => this.setState({ useHashV1: isChecked, subPartitionKeys: [] }) } /> To ensure compatibility with older SDKs, the created container will use a legacy partitioning scheme that supports partition key values of size only up to 101 bytes. If this is enabled, you will not be able to use hierarchical partition keys.{" "} Learn more )} )}
{this.state.isExecuting && (
{this.state.teachingBubbleStep === 5 && ( this.setState({ teachingBubbleStep: 0 })} styles={{ footer: { width: "100%" } }} > A sample container is now being created and we are adding sample data for you. It should take about 1 minute.

Once the sample container is created, review your sample dataset and follow next steps

)}
)} ); } private getDatabaseOptions(): IDropdownOption[] { return useDatabases.getState().databases?.map((database) => ({ key: database.id(), text: database.id(), })); } private getPartitionKeyName(isLowerCase?: boolean): string { const partitionKeyName = userContext.apiType === "Mongo" ? "Shard key" : "Partition key"; return isLowerCase ? partitionKeyName.toLocaleLowerCase() : partitionKeyName; } private getPartitionKeyPlaceHolder(index?: number): string { switch (userContext.apiType) { case "Mongo": return "e.g., categoryId"; case "Gremlin": return "e.g., /address"; case "SQL": return `${ index === undefined ? "Required - first partition key e.g., /TenantId" : index === 0 ? "second partition key e.g., /UserId" : "third partition key e.g., /SessionId" }`; default: return "e.g., /address/zipCode"; } } private onCreateNewDatabaseRadioBtnChange(event: React.ChangeEvent): void { if (event.target.checked && !this.state.createNewDatabase) { this.setState({ createNewDatabase: true, }); } } private onUseExistingDatabaseRadioBtnChange(event: React.ChangeEvent): void { if (event.target.checked && this.state.createNewDatabase) { this.setState({ createNewDatabase: false, }); } } private onUnshardedRadioBtnChange(event: React.ChangeEvent): void { if (event.target.checked && this.state.isSharded) { this.setState({ isSharded: false, }); } } private onShardedRadioBtnChange(event: React.ChangeEvent): void { if (event.target.checked && !this.state.isSharded) { this.setState({ isSharded: true, }); } } private onEnableAnalyticalStoreRadioBtnChange(event: React.ChangeEvent): void { if (event.target.checked && !this.state.enableAnalyticalStore) { this.setState({ enableAnalyticalStore: true, }); } } private onDisableAnalyticalStoreRadioBtnChange(event: React.ChangeEvent): void { if (event.target.checked && this.state.enableAnalyticalStore) { this.setState({ enableAnalyticalStore: false, }); } } private onTurnOnIndexing(event: React.ChangeEvent): void { if (event.target.checked && !this.state.enableIndexing) { this.setState({ enableIndexing: true, }); } } private onTurnOffIndexing(event: React.ChangeEvent): void { if (event.target.checked && this.state.enableIndexing) { this.setState({ enableIndexing: false, }); } } private setVectorEmbeddingPolicy(vectorEmbeddingPolicy: DataModels.VectorEmbedding[]): void { this.setState({ vectorEmbeddingPolicy, }); } private setVectorIndexingPolicy(vectorIndexingPolicy: DataModels.VectorIndex[]): void { this.setState({ vectorIndexingPolicy, }); } private isSelectedDatabaseSharedThroughput(): boolean { if (!this.state.selectedDatabaseId) { return false; } const selectedDatabase = useDatabases .getState() .databases?.find((database) => database.id() === this.state.selectedDatabaseId); return !!selectedDatabase?.offer(); } private isFreeTierAccount(): boolean { return userContext.databaseAccount?.properties?.enableFreeTier; } private getFreeTierIndexingText(): string { return this.state.enableIndexing ? "All properties in your documents will be indexed by default for flexible and efficient queries." : "Indexing will be turned off. Recommended if you don't need to run queries or only have key value operations."; } private getPartitionKeyTooltipText(): string { if (userContext.apiType === "Mongo") { return "The shard key (field) is used to split your data across many replica sets (shards) to achieve unlimited scalability. It’s critical to choose a field that will evenly distribute your data."; } let tooltipText = `The ${this.getPartitionKeyName( true, )} is used to automatically distribute data across partitions for scalability. Choose a property in your JSON document that has a wide range of values and evenly distributes request volume.`; if (userContext.apiType === "SQL") { tooltipText += " For small read-heavy workloads or write-heavy workloads of any size, id is often a good choice."; } return tooltipText; } private getPartitionKey(): string { if (userContext.apiType !== "SQL" && userContext.apiType !== "Mongo") { return ""; } if (userContext.features.partitionKeyDefault) { return userContext.apiType === "SQL" ? "/id" : "_id"; } if (userContext.features.partitionKeyDefault2) { return userContext.apiType === "SQL" ? "/pk" : "pk"; } if (this.props.isQuickstart) { return userContext.apiType === "SQL" ? "/categoryId" : "categoryId"; } return ""; } private getPartitionKeySubtext(): string { if ( userContext.features.partitionKeyDefault && (userContext.apiType === "SQL" || userContext.apiType === "Mongo") ) { const subtext = "For small workloads, the item ID is a suitable choice for the partition key."; return subtext; } return ""; } private getAnalyticalStorageContent(): JSX.Element { return ( Enable analytical store capability to perform near real-time analytics on your operational data, without impacting the performance of transactional workloads.{" "} Learn more ); } private getContainerVectorPolicyTooltipContent(): JSX.Element { return ( Describe any properties in your data that contain vectors, so that they can be made available for similarity queries.{" "} Learn more ); } //TODO: uncomment when learn more text becomes available // private getContainerFullTextPolicyTooltipContent(): JSX.Element { // return ( // // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore // magna aliqua.{" "} // // Learn more // // // ); // } private shouldShowCollectionThroughputInput(): boolean { if (isFabricNative() || isServerlessAccount()) { return false; } if (this.state.createNewDatabase) { return !this.state.isSharedThroughputChecked; } if (this.state.enableDedicatedThroughput) { return true; } return this.state.selectedDatabaseId && !this.isSelectedDatabaseSharedThroughput(); } private shouldShowIndexingOptionsForFreeTierAccount(): boolean { if (!this.isFreeTierAccount()) { return false; } return this.state.createNewDatabase ? this.state.isSharedThroughputChecked : this.isSelectedDatabaseSharedThroughput(); } private shouldShowAnalyticalStoreOptions(): boolean { if (isFabricNative() || configContext.platform === Platform.Emulator) { return false; } switch (userContext.apiType) { case "SQL": case "Mongo": return true; default: return false; } } private isSynapseLinkEnabled(): boolean { if (!userContext.databaseAccount) { return false; } const { properties } = userContext.databaseAccount; if (!properties) { return false; } if (properties.enableAnalyticalStorage) { return true; } return properties.capabilities?.some( (capability) => capability.name === Constants.CapabilityNames.EnableStorageAnalytics, ); } private shouldShowVectorSearchParameters() { return isVectorSearchEnabled() && (isServerlessAccount() || this.shouldShowCollectionThroughputInput()); } private shouldShowFullTextSearchParameters() { return isFullTextSearchEnabled() && (isServerlessAccount() || this.shouldShowCollectionThroughputInput()); } private parseUniqueKeys(): DataModels.UniqueKeyPolicy { if (this.state.uniqueKeys?.length === 0) { return undefined; } const uniqueKeyPolicy: DataModels.UniqueKeyPolicy = { uniqueKeys: [] }; this.state.uniqueKeys.forEach((uniqueKey) => { if (uniqueKey) { const validPaths: string[] = uniqueKey.split(",")?.filter((path) => path?.length > 0); const trimmedPaths: string[] = validPaths?.map((path) => path.trim()); if (trimmedPaths?.length > 0) { if (userContext.apiType === "Mongo") { trimmedPaths.map((path) => { const transformedPath = path.split(".").join("/"); if (transformedPath[0] !== "/") { return "/" + transformedPath; } return transformedPath; }); } uniqueKeyPolicy.uniqueKeys.push({ paths: trimmedPaths }); } } }); return uniqueKeyPolicy; } private validateInputs(): boolean { if (!this.state.createNewDatabase && !this.state.selectedDatabaseId) { this.setState({ errorMessage: "Please select an existing database" }); return false; } const throughput = this.state.createNewDatabase ? this.newDatabaseThroughput : this.collectionThroughput; if (throughput > CollectionCreation.DefaultCollectionRUs100K && !this.isCostAcknowledged) { const errorMessage = this.isNewDatabaseAutoscale ? "Please acknowledge the estimated monthly spend." : "Please acknowledge the estimated daily spend."; this.setState({ errorMessage }); return false; } if (throughput > CollectionCreation.MaxRUPerPartition && !this.state.isSharded) { this.setState({ errorMessage: "Unsharded collections support up to 10,000 RUs" }); return false; } if ( userContext.apiType === "Gremlin" && (this.state.partitionKey === "/id" || this.state.partitionKey === "/label") ) { this.setState({ errorMessage: "/id and /label as partition keys are not allowed for graph." }); return false; } if (this.shouldShowVectorSearchParameters()) { if (!this.state.vectorPolicyValidated) { this.setState({ errorMessage: "Please fix errors in container vector policy" }); return false; } if (!this.state.fullTextPolicyValidated) { this.setState({ errorMessage: "Please fix errors in container full text search polilcy" }); return false; } } return true; } private getAnalyticalStorageTtl(): number { if (!this.isSynapseLinkEnabled()) { return undefined; } if (!this.shouldShowAnalyticalStoreOptions()) { return undefined; } if (this.state.enableAnalyticalStore) { // TODO: always default to 90 days once the backend hotfix is deployed return userContext.features.ttl90Days ? Constants.AnalyticalStorageTtl.Days90 : Constants.AnalyticalStorageTtl.Infinite; } return Constants.AnalyticalStorageTtl.Disabled; } private scrollToSection(id: string): void { document.getElementById(id)?.scrollIntoView(); } private getSampleDBName(): string { const existingSampleDBs = useDatabases .getState() .databases?.filter((database) => database.id().startsWith("SampleDB")); const existingSampleDBNames = existingSampleDBs?.map((database) => database.id()); if (!existingSampleDBNames || existingSampleDBNames.length === 0) { return "SampleDB"; } let i = 1; while (existingSampleDBNames.indexOf(`SampleDB${i}`) !== -1) { i++; } return `SampleDB${i}`; } private async submit(event?: React.FormEvent): Promise { event?.preventDefault(); if (!this.validateInputs()) { return; } const collectionId: string = this.state.collectionId.trim(); let databaseId = this.state.createNewDatabase ? this.state.newDatabaseId.trim() : this.state.selectedDatabaseId; let partitionKeyString = this.state.isSharded ? this.state.partitionKey.trim() : undefined; if (userContext.apiType === "Tables") { // Table require fixed Database: TablesDB, and fixed Partition Key: /'$pk' databaseId = CollectionCreation.TablesAPIDefaultDatabase; partitionKeyString = "/'$pk'"; } const uniqueKeyPolicy: DataModels.UniqueKeyPolicy = this.parseUniqueKeys(); const partitionKeyVersion = this.state.useHashV1 ? undefined : 2; const partitionKey: DataModels.PartitionKey = partitionKeyString ? { paths: [ partitionKeyString, ...(userContext.apiType === "SQL" && this.state.subPartitionKeys.length > 0 ? this.state.subPartitionKeys : []), ], kind: userContext.apiType === "SQL" && this.state.subPartitionKeys.length > 0 ? "MultiHash" : "Hash", version: partitionKeyVersion, } : undefined; const indexingPolicy: DataModels.IndexingPolicy = this.state.enableIndexing ? AllPropertiesIndexed : SharedDatabaseDefault; let vectorEmbeddingPolicy: DataModels.VectorEmbeddingPolicy; if (this.shouldShowVectorSearchParameters()) { indexingPolicy.vectorIndexes = this.state.vectorIndexingPolicy; vectorEmbeddingPolicy = { vectorEmbeddings: this.state.vectorEmbeddingPolicy, }; } if (this.shouldShowFullTextSearchParameters()) { indexingPolicy.fullTextIndexes = this.state.fullTextIndexes; } const telemetryData = { database: { id: databaseId, new: this.state.createNewDatabase, shared: this.state.createNewDatabase ? this.state.isSharedThroughputChecked : this.isSelectedDatabaseSharedThroughput(), }, collection: { id: this.state.collectionId, throughput: this.collectionThroughput, isAutoscale: this.isCollectionAutoscale, partitionKey, uniqueKeyPolicy, collectionWithDedicatedThroughput: this.state.enableDedicatedThroughput, }, subscriptionQuotaId: userContext.quotaId, dataExplorerArea: Constants.Areas.ContextualPane, useIndexingForSharedThroughput: this.state.enableIndexing, isQuickstart: !!this.props.isQuickstart, }; const startKey: number = TelemetryProcessor.traceStart(Action.CreateCollection, telemetryData); const databaseLevelThroughput: boolean = this.state.createNewDatabase ? this.state.isSharedThroughputChecked : this.isSelectedDatabaseSharedThroughput() && !this.state.enableDedicatedThroughput; let offerThroughput: number; let autoPilotMaxThroughput: number; if (databaseLevelThroughput) { if (this.state.createNewDatabase) { if (this.isNewDatabaseAutoscale) { autoPilotMaxThroughput = this.newDatabaseThroughput; } else { offerThroughput = this.newDatabaseThroughput; } } } else { if (this.isCollectionAutoscale) { autoPilotMaxThroughput = this.collectionThroughput; } else { offerThroughput = this.collectionThroughput; } } const createCollectionParams: DataModels.CreateCollectionParams = { createNewDatabase: this.state.createNewDatabase, collectionId, databaseId, databaseLevelThroughput, offerThroughput, autoPilotMaxThroughput, analyticalStorageTtl: this.getAnalyticalStorageTtl(), indexingPolicy, partitionKey, uniqueKeyPolicy, createMongoWildcardIndex: this.state.createMongoWildCardIndex, vectorEmbeddingPolicy, fullTextPolicy: this.state.fullTextPolicy, }; this.setState({ isExecuting: true }); try { await createCollection(createCollectionParams); await this.props.explorer.refreshAllDatabases(); if (this.props.isQuickstart) { const database = useDatabases.getState().findDatabaseWithId(databaseId); if (database) { database.isSampleDB = true; // populate sample container with sample data await database.loadCollections(); const collection = database.findCollectionWithId(collectionId); collection.isSampleCollection = true; useTeachingBubble.getState().setSampleCollection(collection); const sampleGenerator = await ContainerSampleGenerator.createSampleGeneratorAsync(this.props.explorer); await sampleGenerator.populateContainerAsync(collection, partitionKeyString); // auto-expand sample database + container and show teaching bubble await database.expandDatabase(); collection.expandCollection(); useDatabases.getState().updateDatabase(database); useTeachingBubble.getState().setIsSampleDBExpanded(true); TelemetryProcessor.traceOpen(Action.LaunchUITour); } } this.setState({ isExecuting: false }); TelemetryProcessor.traceSuccess(Action.CreateCollection, telemetryData, startKey); useSidePanel.getState().closeSidePanel(); } catch (error) { const errorMessage: string = getErrorMessage(error); this.setState({ isExecuting: false, errorMessage, showErrorDetails: true }); const failureTelemetryData = { ...telemetryData, error: errorMessage, errorStack: getErrorStack(error) }; TelemetryProcessor.traceFailure(Action.CreateCollection, failureTelemetryData, startKey); } } }