mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-20 01:11:25 +00:00
Postgre quickstart UI (#1319)
This commit is contained in:
103
src/Explorer/Quickstart/QuickstartCarousel.tsx
Normal file
103
src/Explorer/Quickstart/QuickstartCarousel.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
import { DefaultButton, IconButton, Image, Modal, PrimaryButton, Stack, Text } from "@fluentui/react";
|
||||
import { useCarousel } from "hooks/useCarousel";
|
||||
import React, { useState } from "react";
|
||||
import Youtube from "react-youtube";
|
||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||
import { traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
|
||||
import { userContext } from "UserContext";
|
||||
import Image1 from "../../../images/CarouselImage1.svg";
|
||||
import Image2 from "../../../images/CarouselImage2.svg";
|
||||
|
||||
interface QuickstartCarouselProps {
|
||||
isOpen: boolean;
|
||||
}
|
||||
|
||||
export const QuickstartCarousel: React.FC<QuickstartCarouselProps> = ({
|
||||
isOpen,
|
||||
}: QuickstartCarouselProps): JSX.Element => {
|
||||
const [page, setPage] = useState<number>(1);
|
||||
return (
|
||||
<Modal
|
||||
styles={{ main: { width: 640 } }}
|
||||
isOpen={isOpen && page < 4}
|
||||
onDismissed={() => userContext.apiType === "SQL" && useCarousel.getState().setShowCoachMark(true)}
|
||||
>
|
||||
<Stack>
|
||||
<Stack horizontal horizontalAlign="space-between" style={{ padding: 16 }}>
|
||||
<Text variant="xLarge">{getHeaderText(page)}</Text>
|
||||
<IconButton iconProps={{ iconName: "Cancel" }} onClick={() => setPage(4)} />
|
||||
</Stack>
|
||||
{getContent(page)}
|
||||
<Text variant="medium" style={{ padding: "0 16px" }}>
|
||||
{getDescriptionText(page)}
|
||||
</Text>
|
||||
<Stack horizontal horizontalAlign="end">
|
||||
{page !== 1 && (
|
||||
<DefaultButton text="Previous" style={{ margin: "16px 8px 16px 0" }} onClick={() => setPage(page - 1)} />
|
||||
)}
|
||||
<PrimaryButton
|
||||
style={{ margin: "16px 16px 16px 0" }}
|
||||
text={page === 3 ? "Finish" : "Next"}
|
||||
onClick={() => {
|
||||
if (
|
||||
userContext.apiType === "Cassandra" ||
|
||||
userContext.apiType === "Tables" ||
|
||||
userContext.apiType === "Gremlin"
|
||||
) {
|
||||
setPage(page + 2);
|
||||
} else {
|
||||
if (page === 3 && userContext.apiType === "SQL") {
|
||||
useCarousel.getState().setShowCoachMark(true);
|
||||
}
|
||||
setPage(page + 1);
|
||||
}
|
||||
|
||||
if (page === 3) {
|
||||
traceSuccess(Action.CompleteCarousel);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
const getHeaderText = (page: number): string => {
|
||||
switch (page) {
|
||||
case 1:
|
||||
return "Welcome! What is Cosmos DB?";
|
||||
case 2:
|
||||
return "Get Started with Sample Data";
|
||||
case 3:
|
||||
return "Connect to your database";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
const getContent = (page: number): JSX.Element => {
|
||||
switch (page) {
|
||||
case 1:
|
||||
return <Youtube videoId="Jvgh64rvdXU" onPlay={() => traceSuccess(Action.PlayCarouselVideo)} />;
|
||||
case 2:
|
||||
return <Image style={{ width: 640 }} src={Image1} />;
|
||||
case 3:
|
||||
return <Image style={{ width: 640 }} src={Image2} />;
|
||||
default:
|
||||
return <></>;
|
||||
}
|
||||
};
|
||||
|
||||
const getDescriptionText = (page: number): string => {
|
||||
switch (page) {
|
||||
case 1:
|
||||
return "Azure Cosmos DB is a fully managed NoSQL database service for modern app development. ";
|
||||
case 2:
|
||||
return "Launch the quickstart for a tutotrial to learn how to create a database, add sample data, connect to a sample app and more.";
|
||||
case 3:
|
||||
return "Already have an existing app? Connect your database to an app, or tooling of your choice from Data Explorer.";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
290
src/Explorer/Quickstart/QuickstartGuide.tsx
Normal file
290
src/Explorer/Quickstart/QuickstartGuide.tsx
Normal file
@@ -0,0 +1,290 @@
|
||||
import {
|
||||
DefaultButton,
|
||||
Icon,
|
||||
IconButton,
|
||||
Image,
|
||||
IPivotItemProps,
|
||||
Pivot,
|
||||
PivotItem,
|
||||
PrimaryButton,
|
||||
Stack,
|
||||
Text,
|
||||
TextField,
|
||||
} from "@fluentui/react";
|
||||
import React, { useState } from "react";
|
||||
import Youtube from "react-youtube";
|
||||
import Pivot1SelectedIcon from "../../../images/Pivot1_selected.svg";
|
||||
import Pivot2Icon from "../../../images/Pivot2.svg";
|
||||
import Pivot2SelectedIcon from "../../../images/Pivot2_selected.svg";
|
||||
import Pivot3Icon from "../../../images/Pivot3.svg";
|
||||
import Pivot3SelectedIcon from "../../../images/Pivot3_selected.svg";
|
||||
import Pivot4Icon from "../../../images/Pivot4.svg";
|
||||
import Pivot4SelectedIcon from "../../../images/Pivot4_selected.svg";
|
||||
import Pivot5Icon from "../../../images/Pivot5.svg";
|
||||
import Pivot5SelectedIcon from "../../../images/Pivot5_selected.svg";
|
||||
import CompleteIcon from "../../../images/QuickstartComplete.svg";
|
||||
import { ReactTabKind, useTabs } from "../../hooks/useTabs";
|
||||
|
||||
enum GuideSteps {
|
||||
Login,
|
||||
NewTable,
|
||||
DistributeTable,
|
||||
LoadData,
|
||||
Query,
|
||||
}
|
||||
|
||||
export const QuickstartGuide: React.FC = (): JSX.Element => {
|
||||
const [currentStep, setCurrentStep] = useState<number>(0);
|
||||
const newTableCommand = `CREATE TABLE github_users
|
||||
(
|
||||
user_id bigint,
|
||||
url text,
|
||||
login text,
|
||||
.....`;
|
||||
const distributeTableCommand = `SELECT create_distributed_table('github_users', 'user_id');
|
||||
SELECT create_distributed_table('github_events', 'user_id');`;
|
||||
const loadDataCommand = `-- download users and store in table
|
||||
|
||||
COPY github_users FROM PROGRAM 'curl https://examples.citusdata.com/
|
||||
users.csv' WITH (FORMAT CSV)`;
|
||||
const queryCommand = `-- Find all events for a single user.
|
||||
-- (A common transactional/operational query)
|
||||
|
||||
SELECT created_at, event_type, repo->>'name' AS repo_name
|
||||
FROM github_events
|
||||
WHERE user_id = 3861633;`;
|
||||
|
||||
const onCopyBtnClicked = (selector: string): void => {
|
||||
const textfield: HTMLInputElement = document.querySelector(selector);
|
||||
textfield.select();
|
||||
document.execCommand("copy");
|
||||
};
|
||||
|
||||
const getPivotHeaderIcon = (step: number): string => {
|
||||
switch (step) {
|
||||
case 0:
|
||||
return Pivot1SelectedIcon;
|
||||
case 1:
|
||||
return step === currentStep ? Pivot2SelectedIcon : Pivot2Icon;
|
||||
case 2:
|
||||
return step === currentStep ? Pivot3SelectedIcon : Pivot3Icon;
|
||||
case 3:
|
||||
return step === currentStep ? Pivot4SelectedIcon : Pivot4Icon;
|
||||
case 4:
|
||||
return step === currentStep ? Pivot5SelectedIcon : Pivot5Icon;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
const customPivotHeaderRenderer = (
|
||||
link: IPivotItemProps,
|
||||
defaultRenderer: (link?: IPivotItemProps) => JSX.Element | null,
|
||||
step: number
|
||||
): JSX.Element | null => {
|
||||
if (!link || !defaultRenderer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack horizontal verticalAlign="center">
|
||||
{currentStep > step ? (
|
||||
<Icon iconName="CompletedSolid" style={{ color: "#57A300", marginRight: 8 }} />
|
||||
) : (
|
||||
<Image style={{ marginRight: 8 }} src={getPivotHeaderIcon(step)} />
|
||||
)}
|
||||
{defaultRenderer({ ...link, itemIcon: undefined })}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack style={{ paddingTop: 8, height: "100%", width: "100%" }}>
|
||||
<Stack style={{ flexGrow: 1, padding: "0 20px", overflow: "auto" }}>
|
||||
<Text variant="xxLarge">Quick start guide</Text>
|
||||
<Text variant="medium">Gettings started in Cosmos DB</Text>
|
||||
{currentStep < 5 && (
|
||||
<Pivot style={{ marginTop: 10, width: "100%" }} selectedKey={GuideSteps[currentStep]}>
|
||||
<PivotItem
|
||||
headerText="Login"
|
||||
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 0)}
|
||||
itemKey={GuideSteps[0]}
|
||||
onClick={() => setCurrentStep(0)}
|
||||
>
|
||||
<Stack style={{ marginTop: 20 }}>
|
||||
<Text>
|
||||
This tutorial walks you through the most essential Cosmos DB PostgreSQL statements that will be used
|
||||
in the PostgreSQL shell (on the right). You can also choose to go through this quick start by
|
||||
connecting to PGAdmin or other tooling of your choice. <br />
|
||||
<br /> Before you can interact with your data using PGShell, you will need to login - please follow
|
||||
instructions on the right to enter your password
|
||||
</Text>
|
||||
<Youtube videoId="Jvgh64rvdXU" style={{ margin: "20px 0" }} opts={{ width: "60%" }} />
|
||||
</Stack>
|
||||
</PivotItem>
|
||||
<PivotItem
|
||||
headerText="New table"
|
||||
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 1)}
|
||||
itemKey={GuideSteps[1]}
|
||||
onClick={() => setCurrentStep(1)}
|
||||
>
|
||||
<Stack style={{ marginTop: 20 }}>
|
||||
<Text>
|
||||
After logging in, let’s create some new tables for storing data. We will start with two sample tables
|
||||
- one for storing github users and one for storing github events
|
||||
</Text>
|
||||
<DefaultButton style={{ marginTop: 16, width: 110 }}>New table</DefaultButton>
|
||||
<Stack horizontal style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
id="newTableCommand"
|
||||
multiline
|
||||
rows={6}
|
||||
readOnly
|
||||
defaultValue={newTableCommand}
|
||||
styles={{ root: { width: "90%" } }}
|
||||
/>
|
||||
<IconButton
|
||||
iconProps={{
|
||||
iconName: "Copy",
|
||||
}}
|
||||
onClick={() => onCopyBtnClicked("#newTableCommand")}
|
||||
/>
|
||||
</Stack>
|
||||
<Youtube videoId="Jvgh64rvdXU" style={{ margin: "20px 0" }} opts={{ width: "60%" }} />
|
||||
</Stack>
|
||||
</PivotItem>
|
||||
<PivotItem
|
||||
headerText="Distribute table"
|
||||
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 2)}
|
||||
itemKey={GuideSteps[2]}
|
||||
onClick={() => setCurrentStep(2)}
|
||||
>
|
||||
<Stack style={{ marginTop: 20 }}>
|
||||
<Text>
|
||||
Congratulations, you have now created your first 2 tables.
|
||||
<br />
|
||||
<br />
|
||||
Your table needs to be sharded on the worker nodes. You need to distribute table before you load any
|
||||
data or run any queries
|
||||
</Text>
|
||||
<DefaultButton style={{ marginTop: 16, width: 150 }}>Distribute table</DefaultButton>
|
||||
<Stack horizontal style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
id="distributeTableCommand"
|
||||
multiline
|
||||
rows={2}
|
||||
readOnly
|
||||
defaultValue={distributeTableCommand}
|
||||
styles={{ root: { width: "90%" } }}
|
||||
/>
|
||||
<IconButton
|
||||
iconProps={{
|
||||
iconName: "Copy",
|
||||
}}
|
||||
onClick={() => onCopyBtnClicked("#distributeTableCommand")}
|
||||
/>
|
||||
</Stack>
|
||||
<Youtube videoId="Jvgh64rvdXU" style={{ margin: "20px 0" }} opts={{ width: "60%" }} />
|
||||
</Stack>
|
||||
</PivotItem>
|
||||
<PivotItem
|
||||
headerText="Load data"
|
||||
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 3)}
|
||||
itemKey={GuideSteps[3]}
|
||||
onClick={() => setCurrentStep(3)}
|
||||
>
|
||||
<Stack style={{ marginTop: 20 }}>
|
||||
<Text>
|
||||
We're ready to fill the tables with sample data.
|
||||
<br />
|
||||
<br />
|
||||
For this quick start, we'll use a dataset previously captured from the GitHub API. Run the
|
||||
command below to load the data
|
||||
</Text>
|
||||
<DefaultButton style={{ marginTop: 16, width: 110 }}>Load data</DefaultButton>
|
||||
<Stack horizontal style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
id="loadDataCommand"
|
||||
multiline
|
||||
rows={4}
|
||||
readOnly
|
||||
defaultValue={loadDataCommand}
|
||||
styles={{ root: { width: "90%" } }}
|
||||
/>
|
||||
<IconButton
|
||||
iconProps={{
|
||||
iconName: "Copy",
|
||||
}}
|
||||
onClick={() => onCopyBtnClicked("#loadDataCommand")}
|
||||
/>
|
||||
</Stack>
|
||||
<Youtube videoId="Jvgh64rvdXU" style={{ margin: "20px 0" }} opts={{ width: "60%" }} />
|
||||
</Stack>
|
||||
</PivotItem>
|
||||
<PivotItem
|
||||
headerText="Query"
|
||||
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 4)}
|
||||
itemKey={GuideSteps[4]}
|
||||
onClick={() => setCurrentStep(4)}
|
||||
>
|
||||
<Stack style={{ marginTop: 20 }}>
|
||||
<Text>
|
||||
github_users is a distributed table, meaning its data is divided between multiple shards. Hyperscale
|
||||
(Citus) automatically runs the count on all shards in parallel, and combines the results. Let’s try a
|
||||
query.
|
||||
</Text>
|
||||
<DefaultButton style={{ marginTop: 16, width: 110 }}>Try query</DefaultButton>
|
||||
<Stack horizontal style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
id="queryCommand"
|
||||
multiline
|
||||
rows={6}
|
||||
readOnly
|
||||
defaultValue={queryCommand}
|
||||
styles={{ root: { width: "90%" } }}
|
||||
/>
|
||||
<IconButton
|
||||
iconProps={{
|
||||
iconName: "Copy",
|
||||
}}
|
||||
onClick={() => onCopyBtnClicked("#queryCommand")}
|
||||
/>
|
||||
</Stack>
|
||||
<Youtube videoId="Jvgh64rvdXU" style={{ margin: "20px 0" }} opts={{ width: "60%" }} />
|
||||
</Stack>
|
||||
</PivotItem>
|
||||
</Pivot>
|
||||
)}
|
||||
{currentStep === 5 && (
|
||||
<Stack style={{ margin: "auto" }} horizontalAlign="center">
|
||||
<Image src={CompleteIcon} />
|
||||
<Text variant="mediumPlus" style={{ fontWeight: 600, marginTop: 7 }}>
|
||||
You are all set!
|
||||
</Text>
|
||||
<Text variant="mediumPlus" style={{ marginTop: 8 }}>
|
||||
You have completed the quick start guide.{" "}
|
||||
</Text>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
<Stack horizontal style={{ padding: "16px 20px", boxShadow: "inset 0px 1px 0px rgba(204, 204, 204, 0.8)" }}>
|
||||
<DefaultButton disabled={currentStep === 0} onClick={() => setCurrentStep(currentStep - 1)}>
|
||||
Previous
|
||||
</DefaultButton>
|
||||
{currentStep < 5 && (
|
||||
<PrimaryButton onClick={() => setCurrentStep(currentStep + 1)} style={{ marginLeft: 8 }}>
|
||||
Next
|
||||
</PrimaryButton>
|
||||
)}
|
||||
{currentStep === 5 && (
|
||||
<PrimaryButton
|
||||
onClick={() => useTabs.getState().closeReactTab(ReactTabKind.Quickstart)}
|
||||
style={{ marginLeft: 8 }}
|
||||
>
|
||||
Close
|
||||
</PrimaryButton>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
202
src/Explorer/Quickstart/Tutorials/MongoQuickstartTutorial.tsx
Normal file
202
src/Explorer/Quickstart/Tutorials/MongoQuickstartTutorial.tsx
Normal 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 <></>;
|
||||
}
|
||||
};
|
||||
180
src/Explorer/Quickstart/Tutorials/SQLQuickstartTutorial.tsx
Normal file
180
src/Explorer/Quickstart/Tutorials/SQLQuickstartTutorial.tsx
Normal file
@@ -0,0 +1,180 @@
|
||||
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 SQLQuickstartTutorial: React.FC = (): JSX.Element => {
|
||||
const { step, isSampleDBExpanded, isDocumentsTabOpened, sampleCollection, setStep } = useTeachingBubble();
|
||||
|
||||
const onDimissTeachingBubble = (): void => {
|
||||
setStep(0);
|
||||
traceCancel(Action.CancelUITour, { step });
|
||||
};
|
||||
|
||||
if (userContext.apiType !== "SQL") {
|
||||
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 7"
|
||||
>
|
||||
Start viewing and working with your data by opening Items under Data
|
||||
</TeachingBubble>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
case 2:
|
||||
return isDocumentsTabOpened ? (
|
||||
<TeachingBubble
|
||||
headline="View item"
|
||||
target={".queryButton"}
|
||||
hasCloseButton
|
||||
primaryButtonProps={{
|
||||
text: "Next",
|
||||
onClick: () => setStep(3),
|
||||
}}
|
||||
secondaryButtonProps={{
|
||||
text: "Previous",
|
||||
onClick: () => setStep(1),
|
||||
}}
|
||||
onDismiss={() => onDimissTeachingBubble()}
|
||||
footerContent="Step 2 of 7"
|
||||
>
|
||||
View item here using the items window. Additionally you can also filter items to be reviewed with the filter
|
||||
function
|
||||
</TeachingBubble>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
case 3:
|
||||
return (
|
||||
<TeachingBubble
|
||||
headline="Add new item"
|
||||
target={"#uploadItemBtn"}
|
||||
hasCloseButton
|
||||
primaryButtonProps={{
|
||||
text: "Next",
|
||||
onClick: () => setStep(4),
|
||||
}}
|
||||
secondaryButtonProps={{
|
||||
text: "Previous",
|
||||
onClick: () => setStep(2),
|
||||
}}
|
||||
onDismiss={() => onDimissTeachingBubble()}
|
||||
footerContent="Step 3 of 7"
|
||||
>
|
||||
Add new item by copy / pasting JSON; or uploading a JSON
|
||||
</TeachingBubble>
|
||||
);
|
||||
case 4:
|
||||
return (
|
||||
<TeachingBubble
|
||||
headline="Run a query"
|
||||
target={"#newQueryBtn"}
|
||||
hasCloseButton
|
||||
primaryButtonProps={{
|
||||
text: "Next",
|
||||
onClick: () => setStep(5),
|
||||
}}
|
||||
secondaryButtonProps={{
|
||||
text: "Previous",
|
||||
onClick: () => setStep(3),
|
||||
}}
|
||||
onDismiss={() => onDimissTeachingBubble()}
|
||||
footerContent="Step 4 of 7"
|
||||
>
|
||||
Query your data using either the filter function or new query.
|
||||
</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 7"
|
||||
>
|
||||
Change throughput provisioned to your container according to your needs
|
||||
</TeachingBubble>
|
||||
);
|
||||
case 6:
|
||||
return (
|
||||
<TeachingBubble
|
||||
headline="Create notebook"
|
||||
target={"#newNotebookBtn"}
|
||||
hasCloseButton
|
||||
primaryButtonProps={{
|
||||
text: "Next",
|
||||
onClick: () => setStep(7),
|
||||
}}
|
||||
secondaryButtonProps={{
|
||||
text: "Previous",
|
||||
onClick: () => setStep(5),
|
||||
}}
|
||||
onDismiss={() => onDimissTeachingBubble()}
|
||||
footerContent="Step 6 of 7"
|
||||
>
|
||||
Visualize your data, store queries in an interactive document
|
||||
</TeachingBubble>
|
||||
);
|
||||
case 7:
|
||||
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(6),
|
||||
}}
|
||||
onDismiss={() => onDimissTeachingBubble()}
|
||||
footerContent="Step 7 of 7"
|
||||
>
|
||||
<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 <></>;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user