mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-04-22 01:24:21 +01:00
Add teaching bubbles after creating sample DB (#1270)
* Add teaching bubbles after creating sample DB * Add teaching bubble while creating sample container * Remove test code * Update tests and always show teaching bubbles in add collection panel when launched from quick start * Fix snapshot
This commit is contained in:
parent
37122acc33
commit
60525f654b
@ -173,6 +173,7 @@ export class TreeNodeComponent extends React.Component<TreeNodeComponentProps, T
|
|||||||
onClick={(event: React.MouseEvent<HTMLDivElement>) => this.onNodeClick(event, node)}
|
onClick={(event: React.MouseEvent<HTMLDivElement>) => this.onNodeClick(event, node)}
|
||||||
onKeyPress={(event: React.KeyboardEvent<HTMLDivElement>) => this.onNodeKeyPress(event, node)}
|
onKeyPress={(event: React.KeyboardEvent<HTMLDivElement>) => this.onNodeKeyPress(event, node)}
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
|
id={node.id}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`treeNodeHeader ${this.state.isMenuShowing ? "showingMenu" : ""}`}
|
className={`treeNodeHeader ${this.state.isMenuShowing ? "showingMenu" : ""}`}
|
||||||
|
@ -137,6 +137,7 @@ exports[`TreeNodeComponent does not render children by default 1`] = `
|
|||||||
exports[`TreeNodeComponent renders a simple node (sorted children, expanded) 1`] = `
|
exports[`TreeNodeComponent renders a simple node (sorted children, expanded) 1`] = `
|
||||||
<div
|
<div
|
||||||
className="nodeClassname main12 nodeItem "
|
className="nodeClassname main12 nodeItem "
|
||||||
|
id="id"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
onKeyPress={[Function]}
|
onKeyPress={[Function]}
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
@ -359,6 +360,7 @@ exports[`TreeNodeComponent renders loading icon 1`] = `
|
|||||||
exports[`TreeNodeComponent renders sorted children, expanded, leaves and parents separated 1`] = `
|
exports[`TreeNodeComponent renders sorted children, expanded, leaves and parents separated 1`] = `
|
||||||
<div
|
<div
|
||||||
className="nodeClassname main12 nodeItem "
|
className="nodeClassname main12 nodeItem "
|
||||||
|
id="id"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
onKeyPress={[Function]}
|
onKeyPress={[Function]}
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
|
@ -298,7 +298,7 @@ export default class Explorer {
|
|||||||
db1.id().localeCompare(db2.id())
|
db1.id().localeCompare(db2.id())
|
||||||
);
|
);
|
||||||
useDatabases.setState({ databases: updatedDatabases });
|
useDatabases.setState({ databases: updatedDatabases });
|
||||||
await this.refreshAndExpandNewDatabases(deltaDatabases.toAdd, currentDatabases);
|
await this.refreshAndExpandNewDatabases(deltaDatabases.toAdd, updatedDatabases);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = getErrorMessage(error);
|
const errorMessage = getErrorMessage(error);
|
||||||
TelemetryProcessor.traceFailure(
|
TelemetryProcessor.traceFailure(
|
||||||
@ -1135,7 +1135,6 @@ export default class Explorer {
|
|||||||
options: {
|
options: {
|
||||||
databaseId?: string;
|
databaseId?: string;
|
||||||
isQuickstart?: boolean;
|
isQuickstart?: boolean;
|
||||||
showTeachingBubble?: boolean;
|
|
||||||
} = {}
|
} = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (userContext.apiType === "Cassandra") {
|
if (userContext.apiType === "Cassandra") {
|
||||||
|
@ -309,6 +309,7 @@ function createNewSQLQueryButton(selectedNodeState: SelectedNodeState): CommandB
|
|||||||
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
|
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
|
||||||
const label = "New SQL Query";
|
const label = "New SQL Query";
|
||||||
return {
|
return {
|
||||||
|
id: "newQueryBtn",
|
||||||
iconSrc: AddSqlQueryIcon,
|
iconSrc: AddSqlQueryIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
@ -323,6 +324,7 @@ function createNewSQLQueryButton(selectedNodeState: SelectedNodeState): CommandB
|
|||||||
} else if (userContext.apiType === "Mongo") {
|
} else if (userContext.apiType === "Mongo") {
|
||||||
const label = "New Query";
|
const label = "New Query";
|
||||||
return {
|
return {
|
||||||
|
id: "newQueryBtn",
|
||||||
iconSrc: AddSqlQueryIcon,
|
iconSrc: AddSqlQueryIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
@ -409,6 +411,7 @@ function applyNotebooksTemporarilyDownStyle(buttonProps: CommandButtonComponentP
|
|||||||
function createNewNotebookButton(container: Explorer): CommandButtonComponentProps {
|
function createNewNotebookButton(container: Explorer): CommandButtonComponentProps {
|
||||||
const label = "New Notebook";
|
const label = "New Notebook";
|
||||||
return {
|
return {
|
||||||
|
id: "newNotebookBtn",
|
||||||
iconSrc: NewNotebookIcon,
|
iconSrc: NewNotebookIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => container.onNewNotebookClicked(),
|
onCommandClick: () => container.onNewNotebookClicked(),
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
IDropdownOption,
|
IDropdownOption,
|
||||||
Link,
|
Link,
|
||||||
|
ProgressIndicator,
|
||||||
Separator,
|
Separator,
|
||||||
Stack,
|
Stack,
|
||||||
TeachingBubble,
|
TeachingBubble,
|
||||||
@ -21,6 +22,7 @@ import { configContext, Platform } from "ConfigContext";
|
|||||||
import * as DataModels from "Contracts/DataModels";
|
import * as DataModels from "Contracts/DataModels";
|
||||||
import { SubscriptionType } from "Contracts/SubscriptionType";
|
import { SubscriptionType } from "Contracts/SubscriptionType";
|
||||||
import { useSidePanel } from "hooks/useSidePanel";
|
import { useSidePanel } from "hooks/useSidePanel";
|
||||||
|
import { useTeachingBubble } from "hooks/useTeachingBubble";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { CollectionCreation } from "Shared/Constants";
|
import { CollectionCreation } from "Shared/Constants";
|
||||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||||
@ -42,7 +44,6 @@ export interface AddCollectionPanelProps {
|
|||||||
explorer: Explorer;
|
explorer: Explorer;
|
||||||
databaseId?: string;
|
databaseId?: string;
|
||||||
isQuickstart?: boolean;
|
isQuickstart?: boolean;
|
||||||
showTeachingBubble?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SharedDatabaseDefault: DataModels.IndexingPolicy = {
|
const SharedDatabaseDefault: DataModels.IndexingPolicy = {
|
||||||
@ -134,7 +135,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
if (this.state.teachingBubbleStep === 0 && this.props.showTeachingBubble) {
|
if (this.state.teachingBubbleStep === 0 && this.props.isQuickstart) {
|
||||||
this.setState({ teachingBubbleStep: 1 });
|
this.setState({ teachingBubbleStep: 1 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +214,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
primaryButtonProps={{
|
primaryButtonProps={{
|
||||||
text: "Create container",
|
text: "Create container",
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
this.setState({ teachingBubbleStep: 0 });
|
this.setState({ teachingBubbleStep: 5 });
|
||||||
this.submit();
|
this.submit();
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@ -764,7 +765,30 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
|
|
||||||
<PanelFooterComponent buttonLabel="OK" isButtonDisabled={this.state.isThroughputCapExceeded} />
|
<PanelFooterComponent buttonLabel="OK" isButtonDisabled={this.state.isThroughputCapExceeded} />
|
||||||
|
|
||||||
{this.state.isExecuting && <PanelLoadingScreen />}
|
{this.state.isExecuting && (
|
||||||
|
<div>
|
||||||
|
<PanelLoadingScreen />
|
||||||
|
{this.state.teachingBubbleStep === 5 && (
|
||||||
|
<TeachingBubble
|
||||||
|
headline="Creating sample container"
|
||||||
|
target={"#loadingScreen"}
|
||||||
|
onDismiss={() => this.setState({ teachingBubbleStep: 0 })}
|
||||||
|
footerContent={
|
||||||
|
<ProgressIndicator
|
||||||
|
styles={{ itemName: { color: "rgb(255, 255, 255)" } }}
|
||||||
|
label="Adding sample data set"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
A sample container is now being created and we are adding sample data for you. It should take about 1
|
||||||
|
minute.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Once the sample container is created, review your sample dataset and follow next steps
|
||||||
|
</TeachingBubble>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1176,10 +1200,16 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
if (this.props.isQuickstart) {
|
if (this.props.isQuickstart) {
|
||||||
const database = useDatabases.getState().findDatabaseWithId("SampleDB");
|
const database = useDatabases.getState().findDatabaseWithId("SampleDB");
|
||||||
if (database) {
|
if (database) {
|
||||||
|
// populate sample container with sample data
|
||||||
await database.loadCollections();
|
await database.loadCollections();
|
||||||
const collection = database.findCollectionWithId("SampleContainer");
|
const collection = database.findCollectionWithId("SampleContainer");
|
||||||
const sampleGenerator = await ContainerSampleGenerator.createSampleGeneratorAsync(this.props.explorer);
|
const sampleGenerator = await ContainerSampleGenerator.createSampleGeneratorAsync(this.props.explorer);
|
||||||
sampleGenerator.populateContainerAsync(collection);
|
await sampleGenerator.populateContainerAsync(collection);
|
||||||
|
// auto-expand sample database + container and show teaching bubble
|
||||||
|
await database.expandDatabase();
|
||||||
|
collection.expandCollection();
|
||||||
|
useDatabases.getState().updateDatabase(database);
|
||||||
|
useTeachingBubble.getState().setIsSampleDBExpanded(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.setState({ isExecuting: false });
|
this.setState({ isExecuting: false });
|
||||||
|
@ -2,7 +2,7 @@ import React from "react";
|
|||||||
import LoadingIndicator_3Squares from "../../../images/LoadingIndicator_3Squares.gif";
|
import LoadingIndicator_3Squares from "../../../images/LoadingIndicator_3Squares.gif";
|
||||||
|
|
||||||
export const PanelLoadingScreen: React.FunctionComponent = () => (
|
export const PanelLoadingScreen: React.FunctionComponent = () => (
|
||||||
<div className="dataExplorerLoaderContainer dataExplorerPaneLoaderContainer">
|
<div id="loadingScreen" className="dataExplorerLoaderContainer dataExplorerPaneLoaderContainer">
|
||||||
<img className="dataExplorerLoader" src={LoadingIndicator_3Squares} />
|
<img className="dataExplorerLoader" src={LoadingIndicator_3Squares} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -149,7 +149,7 @@ export class SplashScreen extends React.Component<SplashScreenProps, SplashScree
|
|||||||
text: "Get started",
|
text: "Get started",
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
this.setState({ showCoachmark: false });
|
this.setState({ showCoachmark: false });
|
||||||
this.container.onNewCollectionClicked({ isQuickstart: true, showTeachingBubble: true });
|
this.container.onNewCollectionClicked({ isQuickstart: true });
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
secondaryButtonProps={{ text: "Cancel", onClick: () => this.setState({ showCoachmark: false }) }}
|
secondaryButtonProps={{ text: "Cancel", onClick: () => this.setState({ showCoachmark: false }) }}
|
||||||
|
@ -909,6 +909,7 @@ export default class DocumentsTab extends TabsBase {
|
|||||||
public static _createUploadButton(container: Explorer): CommandButtonComponentProps {
|
public static _createUploadButton(container: Explorer): CommandButtonComponentProps {
|
||||||
const label = "Upload Item";
|
const label = "Upload Item";
|
||||||
return {
|
return {
|
||||||
|
id: "uploadItemBtn",
|
||||||
iconSrc: UploadIcon,
|
iconSrc: UploadIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { CollectionTabKind } from "Contracts/ViewModels";
|
||||||
|
import { useTeachingBubble } from "hooks/useTeachingBubble";
|
||||||
import ko from "knockout";
|
import ko from "knockout";
|
||||||
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
|
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||||
import loadingIcon from "../../../images/circular_loader_black_16x16.gif";
|
import loadingIcon from "../../../images/circular_loader_black_16x16.gif";
|
||||||
@ -113,6 +115,14 @@ function TabPane({ tab, active }: { tab: Tab; active: boolean }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect((): (() => void) | void => {
|
useEffect((): (() => void) | void => {
|
||||||
|
if (
|
||||||
|
tab.tabKind === CollectionTabKind.Documents &&
|
||||||
|
tab.collection?.databaseId === "SampleDB" &&
|
||||||
|
tab.collection?.id() === "SampleContainer"
|
||||||
|
) {
|
||||||
|
useTeachingBubble.getState().setIsDocumentsTabOpened(true);
|
||||||
|
}
|
||||||
|
|
||||||
const { current: element } = ref;
|
const { current: element } = ref;
|
||||||
if (element) {
|
if (element) {
|
||||||
ko.applyBindings(tab, element);
|
ko.applyBindings(tab, element);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Callout, DirectionalHint, ICalloutProps, ILinkProps, Link, Stack, Text } from "@fluentui/react";
|
import { Callout, DirectionalHint, ICalloutProps, ILinkProps, Link, Stack, Text } from "@fluentui/react";
|
||||||
|
import { useTeachingBubble } from "hooks/useTeachingBubble";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import shallow from "zustand/shallow";
|
import shallow from "zustand/shallow";
|
||||||
import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg";
|
import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg";
|
||||||
@ -436,7 +437,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
const databaseNode: TreeNode = {
|
const databaseNode: TreeNode = {
|
||||||
label: database.id(),
|
label: database.id(),
|
||||||
iconSrc: CosmosDBIcon,
|
iconSrc: CosmosDBIcon,
|
||||||
isExpanded: false,
|
isExpanded: database.isDatabaseExpanded(),
|
||||||
className: "databaseHeader",
|
className: "databaseHeader",
|
||||||
children: [],
|
children: [],
|
||||||
isSelected: () => useSelectedNode.getState().isDataNodeSelected(database.id()),
|
isSelected: () => useSelectedNode.getState().isDataNodeSelected(database.id()),
|
||||||
@ -461,6 +462,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
|
|
||||||
if (database.isDatabaseShared()) {
|
if (database.isDatabaseShared()) {
|
||||||
databaseNode.children.push({
|
databaseNode.children.push({
|
||||||
|
id: database.id() === "SampleDB" ? "sampleScaleSettings" : "",
|
||||||
label: "Scale",
|
label: "Scale",
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
useSelectedNode
|
useSelectedNode
|
||||||
@ -497,6 +499,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
const children: TreeNode[] = [];
|
const children: TreeNode[] = [];
|
||||||
children.push({
|
children.push({
|
||||||
label: collection.getLabel(),
|
label: collection.getLabel(),
|
||||||
|
id: collection.databaseId === "SampleDB" && collection.id() === "SampleContainer" ? "sampleItems" : "",
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
collection.openTab();
|
collection.openTab();
|
||||||
// push to most recent
|
// push to most recent
|
||||||
@ -530,6 +533,10 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
|
|
||||||
if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) {
|
if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) {
|
||||||
children.push({
|
children.push({
|
||||||
|
id:
|
||||||
|
collection.databaseId === "SampleDB" && collection.id() === "SampleContainer" && !database.isDatabaseShared()
|
||||||
|
? "sampleScaleSettings"
|
||||||
|
: "",
|
||||||
label: database.isDatabaseShared() || isServerlessAccount() ? "Settings" : "Scale & Settings",
|
label: database.isDatabaseShared() || isServerlessAccount() ? "Settings" : "Scale & Settings",
|
||||||
onClick: collection.onSettingsClick.bind(collection),
|
onClick: collection.onSettingsClick.bind(collection),
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
@ -572,7 +579,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
return {
|
return {
|
||||||
label: collection.id(),
|
label: collection.id(),
|
||||||
iconSrc: CollectionIcon,
|
iconSrc: CollectionIcon,
|
||||||
isExpanded: false,
|
isExpanded: collection.isCollectionExpanded(),
|
||||||
children: children,
|
children: children,
|
||||||
className: "collectionHeader",
|
className: "collectionHeader",
|
||||||
contextMenu: ResourceTreeContextMenuButtonFactory.createCollectionContextMenuButton(container, collection),
|
contextMenu: ResourceTreeContextMenuButtonFactory.createCollectionContextMenuButton(container, collection),
|
||||||
@ -586,6 +593,10 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
onExpanded: () => {
|
onExpanded: () => {
|
||||||
|
// TODO: For testing purpose only, remove after
|
||||||
|
if (collection.databaseId === "SampleDB" && collection.id() === "SampleContainer") {
|
||||||
|
useTeachingBubble.getState().setIsSampleDBExpanded(true);
|
||||||
|
}
|
||||||
if (showScriptNodes) {
|
if (showScriptNodes) {
|
||||||
collection.loadStoredProcedures();
|
collection.loadStoredProcedures();
|
||||||
collection.loadUserDefinedFunctions();
|
collection.loadUserDefinedFunctions();
|
||||||
|
164
src/Explorer/Tutorials/QuickstartTutorial.tsx
Normal file
164
src/Explorer/Tutorials/QuickstartTutorial.tsx
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
import { TeachingBubble } from "@fluentui/react";
|
||||||
|
import { useDatabases } from "Explorer/useDatabases";
|
||||||
|
import { useTeachingBubble } from "hooks/useTeachingBubble";
|
||||||
|
import React from "react";
|
||||||
|
import { userContext } from "UserContext";
|
||||||
|
|
||||||
|
export const QuickstartTutorial: React.FC = (): JSX.Element => {
|
||||||
|
const { step, isSampleDBExpanded, isDocumentsTabOpened, setStep } = useTeachingBubble();
|
||||||
|
|
||||||
|
if (!userContext.features.enableNewQuickstart) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (step) {
|
||||||
|
case 1:
|
||||||
|
return isSampleDBExpanded ? (
|
||||||
|
<TeachingBubble
|
||||||
|
headline="View sample data"
|
||||||
|
target={"#sampleItems"}
|
||||||
|
hasCloseButton
|
||||||
|
primaryButtonProps={{
|
||||||
|
text: "Open Items",
|
||||||
|
onClick: () => {
|
||||||
|
const sampleContainer = useDatabases.getState().findCollection("SampleDB", "SampleContainer");
|
||||||
|
sampleContainer.openTab();
|
||||||
|
setStep(2);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onDismiss={() => setStep(0)}
|
||||||
|
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={() => setStep(0)}
|
||||||
|
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={() => setStep(0)}
|
||||||
|
footerContent="Step 3 of 7"
|
||||||
|
>
|
||||||
|
Add new item by copy / pasting jsons; 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={() => setStep(0)}
|
||||||
|
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={() => setStep(0)}
|
||||||
|
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: "Finish",
|
||||||
|
onClick: () => setStep(7),
|
||||||
|
}}
|
||||||
|
secondaryButtonProps={{
|
||||||
|
text: "Previous",
|
||||||
|
onClick: () => setStep(5),
|
||||||
|
}}
|
||||||
|
onDismiss={() => setStep(0)}
|
||||||
|
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: () => setStep(7),
|
||||||
|
}}
|
||||||
|
secondaryButtonProps={{
|
||||||
|
text: "Previous",
|
||||||
|
onClick: () => setStep(6),
|
||||||
|
}}
|
||||||
|
onDismiss={() => setStep(0)}
|
||||||
|
footerContent="Step 7 of 7"
|
||||||
|
>
|
||||||
|
You have finished the tour in data explorer. For next steps, you may want to launch connect and start
|
||||||
|
connecting with your current app
|
||||||
|
</TeachingBubble>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
};
|
@ -1,6 +1,7 @@
|
|||||||
// CSS Dependencies
|
// CSS Dependencies
|
||||||
import { initializeIcons } from "@fluentui/react";
|
import { initializeIcons } from "@fluentui/react";
|
||||||
import "bootstrap/dist/css/bootstrap.css";
|
import "bootstrap/dist/css/bootstrap.css";
|
||||||
|
import { QuickstartTutorial } from "Explorer/Tutorials/QuickstartTutorial";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import "../externals/jquery-ui.min.css";
|
import "../externals/jquery-ui.min.css";
|
||||||
@ -115,6 +116,7 @@ const App: React.FunctionComponent = () => {
|
|||||||
</div>
|
</div>
|
||||||
<SidePanel />
|
<SidePanel />
|
||||||
<Dialog />
|
<Dialog />
|
||||||
|
<QuickstartTutorial />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
19
src/hooks/useTeachingBubble.ts
Normal file
19
src/hooks/useTeachingBubble.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import create, { UseStore } from "zustand";
|
||||||
|
|
||||||
|
interface TeachingBubbleState {
|
||||||
|
step: number;
|
||||||
|
isSampleDBExpanded: boolean;
|
||||||
|
isDocumentsTabOpened: boolean;
|
||||||
|
setStep: (step: number) => void;
|
||||||
|
setIsSampleDBExpanded: (isReady: boolean) => void;
|
||||||
|
setIsDocumentsTabOpened: (isOpened: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTeachingBubble: UseStore<TeachingBubbleState> = create((set) => ({
|
||||||
|
step: 1,
|
||||||
|
isSampleDBExpanded: false,
|
||||||
|
isDocumentsTabOpened: false,
|
||||||
|
setStep: (step: number) => set({ step }),
|
||||||
|
setIsSampleDBExpanded: (isSampleDBExpanded: boolean) => set({ isSampleDBExpanded }),
|
||||||
|
setIsDocumentsTabOpened: (isDocumentsTabOpened: boolean) => set({ isDocumentsTabOpened }),
|
||||||
|
}));
|
Loading…
x
Reference in New Issue
Block a user