Add teaching bubbles for mongo quickstart (#1313)

This commit is contained in:
victor-meng 2022-08-03 13:54:01 -07:00 committed by GitHub
parent c2673ec707
commit d0c2f72ed3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 235 additions and 13 deletions

View File

@ -28,6 +28,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
isSharded,
isFreeTier,
showFreeTierExceedThroughputTooltip,
isQuickstart,
setThroughputValue,
setIsAutoscale,
setIsThroughputCapExceeded,
@ -35,7 +36,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
}: ThroughputInputProps) => {
const [isAutoscaleSelected, setIsAutoScaleSelected] = useState<boolean>(true);
const [throughput, setThroughput] = useState<number>(
isFreeTier ? AutoPilotUtils.autoPilotThroughput1K : AutoPilotUtils.autoPilotThroughput4K
isFreeTier || isQuickstart ? AutoPilotUtils.autoPilotThroughput1K : AutoPilotUtils.autoPilotThroughput4K
);
const [isCostAcknowledged, setIsCostAcknowledged] = useState<boolean>(false);
const [throughputError, setThroughputError] = useState<string>("");

View File

@ -1,5 +1,6 @@
import { createCollection } from "../../Common/dataAccess/createCollection";
import { createDocument } from "../../Common/dataAccess/createDocument";
import { createDocument as createMongoDocument } from "../../Common/MongoProxyClient";
import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import { userContext } from "../../UserContext";
@ -28,7 +29,7 @@ export class ContainerSampleGenerator {
dataFileContent = await import(
/* webpackChunkName: "gremlinSampleJsonData" */ "../../../sampleData/gremlinSampleData.json"
);
} else if (userContext.apiType === "SQL") {
} else if (userContext.apiType === "SQL" || userContext.apiType === "Mongo") {
dataFileContent = await import(
/* webpackChunkName: "sqlSampleJsonData" */ "../../../sampleData/sqlSampleData.json"
);
@ -68,7 +69,7 @@ export class ContainerSampleGenerator {
return database.findCollectionWithId(this.sampleDataFile.collectionId);
}
public async populateContainerAsync(collection: ViewModels.Collection): Promise<void> {
public async populateContainerAsync(collection: ViewModels.Collection, shardKey?: string): Promise<void> {
if (!collection) {
throw new Error("No container to populate");
}
@ -99,7 +100,9 @@ export class ContainerSampleGenerator {
await Promise.all(
this.sampleDataFile.data.map(async (doc) => {
try {
await createDocument(collection, doc);
userContext.apiType === "Mongo"
? await createMongoDocument(collection.databaseId, collection, shardKey, doc)
: await createDocument(collection, doc);
} catch (error) {
NotificationConsoleUtils.logConsoleError(error);
}

View File

@ -346,6 +346,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
isDatabase={true}
isSharded={this.state.isSharded}
isFreeTier={this.isFreeTierAccount()}
isQuickstart={this.props.isQuickstart}
setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)}
setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)}
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
@ -581,6 +582,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
isDatabase={false}
isSharded={this.state.isSharded}
isFreeTier={this.isFreeTierAccount()}
isQuickstart={this.props.isQuickstart}
setThroughputValue={(throughput: number) => (this.collectionThroughput = throughput)}
setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)}
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
@ -1249,7 +1251,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
collection.isSampleCollection = true;
useTeachingBubble.getState().setSampleCollection(collection);
const sampleGenerator = await ContainerSampleGenerator.createSampleGeneratorAsync(this.props.explorer);
await sampleGenerator.populateContainerAsync(collection);
await sampleGenerator.populateContainerAsync(collection, partitionKeyString);
// auto-expand sample database + container and show teaching bubble
await database.expandDatabase();
collection.expandCollection();

View File

@ -190,11 +190,8 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
iconSrc: QuickStartIcon,
title: "Launch quick start",
description: "Launch a quick start tutorial to get started with sample data",
showLinkIcon: userContext.apiType === "Mongo",
onClick: () => {
userContext.apiType === "Mongo"
? window.open("http://aka.ms/mongodbquickstart", "_blank")
: this.container.onNewCollectionClicked({ isQuickstart: true });
this.container.onNewCollectionClicked({ isQuickstart: true });
traceOpen(Action.LaunchQuickstart, { apiType: userContext.apiType });
},
};

View File

@ -811,6 +811,7 @@ export default class DocumentsTab extends TabsBase {
ariaLabel: label,
hasPopup: false,
disabled: !this.newDocumentButton.enabled(),
id: "mongoNewDocumentBtn",
});
}

View File

@ -120,7 +120,10 @@ const CloseButton = ({
role="button"
aria-label="Close Tab"
className="cancelButton"
onClick={() => (tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeReactTab(tabKind))}
onClick={(event: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
event.stopPropagation();
tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeReactTab(tabKind);
}}
tabIndex={active ? 0 : undefined}
onKeyPress={({ nativeEvent: e }) => tab.onKeyPressClose(undefined, e)}
>

View File

@ -531,8 +531,13 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
}
if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) {
let id = "";
if (collection.isSampleCollection) {
id = database.isDatabaseShared() ? "sampleSettings" : "sampleScaleSettings";
}
children.push({
id: collection.isSampleCollection && !database.isDatabaseShared() ? "sampleScaleSettings" : "",
id,
label: database.isDatabaseShared() || isServerlessAccount() ? "Settings" : "Scale & Settings",
onClick: collection.onSettingsClick.bind(collection),
isSelected: () =>

View File

@ -0,0 +1,202 @@
import { Link, Stack, TeachingBubble, Text } from "@fluentui/react";
import { ReactTabKind, useTabs } from "hooks/useTabs";
import { useTeachingBubble } from "hooks/useTeachingBubble";
import React from "react";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceCancel, traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
import { userContext } from "UserContext";
export const MongoQuickstartTutorial: React.FC = (): JSX.Element => {
const { step, isSampleDBExpanded, isDocumentsTabOpened, sampleCollection, setStep } = useTeachingBubble();
const onDimissTeachingBubble = (): void => {
setStep(0);
traceCancel(Action.CancelUITour, { step });
};
if (userContext.apiType !== "Mongo") {
return <></>;
}
switch (step) {
case 1:
return isSampleDBExpanded ? (
<TeachingBubble
headline="View sample data"
target={"#sampleItems"}
hasCloseButton
primaryButtonProps={{
text: "Open Items",
onClick: () => {
sampleCollection.openTab();
setStep(2);
},
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 1 of 8"
>
Start viewing and working with your data by opening Documents under Data
</TeachingBubble>
) : (
<></>
);
case 2:
return isDocumentsTabOpened ? (
<TeachingBubble
headline="View Documents"
target={".documentsGridHeaderContainer"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(3),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(1),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 2 of 8"
>
View documents here using the documents window. You can also use your favorite MongoDB tools and drivers to do
so.
</TeachingBubble>
) : (
<></>
);
case 3:
return (
<TeachingBubble
headline="Add new document"
target={"#mongoNewDocumentBtn"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(4),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(2),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 3 of 8"
>
Add new document by copy / pasting JSON or uploading a JSON. You can also use your favorite MongoDB tools and
drivers to do so.
</TeachingBubble>
);
case 4:
return (
<TeachingBubble
headline="Run a query"
target={".querydropdown"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(5),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(3),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 4 of 8"
>
Query your data using the filter function. Azure Cosmos DB API for MongoDB provides comprehensive support for
MongoDB query language constructs. You can also use your favorite MongoDB tools and drivers to do so.
</TeachingBubble>
);
case 5:
return (
<TeachingBubble
headline="Scale throughput"
target={"#sampleScaleSettings"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(6),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(4),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 5 of 8"
>
Change throughput provisioned to your collection according to your needs
</TeachingBubble>
);
case 6:
return (
<TeachingBubble
headline="Indexing Policy"
target={"#sampleSettings"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(7),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(5),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 6 of 8"
>
Use the indexing policy editor to create and edit your indexes.
</TeachingBubble>
);
case 7:
return (
<TeachingBubble
headline="Create notebook"
target={"#newNotebookBtn"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(8),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(6),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 7 of 8"
>
Visualize your data, store queries in an interactive document
</TeachingBubble>
);
case 8:
return (
<TeachingBubble
headline="Congratulations!"
target={"#newNotebookBtn"}
hasCloseButton
primaryButtonProps={{
text: "Launch connect",
onClick: () => {
traceSuccess(Action.CompleteUITour);
useTabs.getState().openAndActivateReactTab(ReactTabKind.Connect);
},
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(7),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 8 of 8"
>
<Stack>
<Text style={{ color: "white" }}>
You have finished the tour in data explorer. For next steps, you may want to launch connect and start
connecting with your current app.
</Text>
<Link style={{ color: "white", fontWeight: 600 }} target="_blank" href="https://aka.ms/cosmosdbsurvey">
Share your feedback
</Link>
</Stack>
</TeachingBubble>
);
default:
return <></>;
}
};

View File

@ -4,6 +4,7 @@ import { useTeachingBubble } from "hooks/useTeachingBubble";
import React from "react";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceCancel, traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
import { userContext } from "UserContext";
export const QuickstartTutorial: React.FC = (): JSX.Element => {
const { step, isSampleDBExpanded, isDocumentsTabOpened, sampleCollection, setStep } = useTeachingBubble();
@ -13,6 +14,10 @@ export const QuickstartTutorial: React.FC = (): JSX.Element => {
traceCancel(Action.CancelUITour, { step });
};
if (userContext.apiType !== "SQL") {
return <></>;
}
switch (step) {
case 1:
return isSampleDBExpanded ? (

View File

@ -1,6 +1,7 @@
// CSS Dependencies
import { initializeIcons } from "@fluentui/react";
import "bootstrap/dist/css/bootstrap.css";
import { MongoQuickstartTutorial } from "Explorer/Tutorials/MongoQuickstartTutorial";
import { QuickstartCarousel } from "Explorer/Tutorials/QuickstartCarousel";
import { QuickstartTutorial } from "Explorer/Tutorials/QuickstartTutorial";
import { useCarousel } from "hooks/useCarousel";
@ -116,6 +117,7 @@ const App: React.FunctionComponent = () => {
<Dialog />
{<QuickstartCarousel isOpen={isCarouselOpen} />}
{<QuickstartTutorial />}
{<MongoQuickstartTutorial />}
</div>
);
};

View File

@ -132,12 +132,13 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
},
closeReactTab: (tabKind: ReactTabKind) => {
const { activeReactTab, openedTabs, openedReactTabs } = get();
const updatedOpenedReactTabs = openedReactTabs.filter((tab: ReactTabKind) => tabKind !== tab);
if (activeReactTab === tabKind) {
openedTabs?.length > 0
? set({ activeTab: openedTabs[0], activeReactTab: undefined })
: set({ activeTab: undefined, activeReactTab: openedReactTabs[0] });
: set({ activeTab: undefined, activeReactTab: updatedOpenedReactTabs[0] });
}
set({ openedReactTabs: openedReactTabs.filter((tab: ReactTabKind) => tabKind !== tab) });
set({ openedReactTabs: updatedOpenedReactTabs });
},
}));