mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-19 17:01:13 +00:00
Improve quickstart teaching bubble telemetries and make the home page a tab (#1299)
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { CollectionTabKind } from "Contracts/ViewModels";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
import { SplashScreen } from "Explorer/SplashScreen/SplashScreen";
|
||||
import { ConnectTab } from "Explorer/Tabs/ConnectTab";
|
||||
import { useTeachingBubble } from "hooks/useTeachingBubble";
|
||||
import ko from "knockout";
|
||||
@@ -6,28 +8,33 @@ import React, { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||
import loadingIcon from "../../../images/circular_loader_black_16x16.gif";
|
||||
import errorIcon from "../../../images/close-black.svg";
|
||||
import { useObservable } from "../../hooks/useObservable";
|
||||
import { useTabs } from "../../hooks/useTabs";
|
||||
import { ReactTabKind, useTabs } from "../../hooks/useTabs";
|
||||
import TabsBase from "./TabsBase";
|
||||
|
||||
type Tab = TabsBase | (TabsBase & { render: () => JSX.Element });
|
||||
|
||||
export const Tabs = (): JSX.Element => {
|
||||
const { openedTabs, activeTab } = useTabs();
|
||||
const isConnectTabOpen = useTabs((state) => state.isConnectTabOpen);
|
||||
const isConnectTabActive = useTabs((state) => state.isConnectTabActive);
|
||||
interface TabsProps {
|
||||
explorer: Explorer;
|
||||
}
|
||||
|
||||
export const Tabs = ({ explorer }: TabsProps): JSX.Element => {
|
||||
const { openedTabs, openedReactTabs, activeTab, activeReactTab } = useTabs();
|
||||
|
||||
return (
|
||||
<div className="tabsManagerContainer">
|
||||
<div id="content" className="flexContainer hideOverflows">
|
||||
<div className="nav-tabs-margin">
|
||||
<ul className="nav nav-tabs level navTabHeight" id="navTabs" role="tablist">
|
||||
{isConnectTabOpen && <TabNav key="connect" tab={undefined} active={isConnectTabActive} />}
|
||||
{openedReactTabs.map((tab) => (
|
||||
<TabNav key={ReactTabKind[tab]} active={activeReactTab === tab} tabKind={tab} />
|
||||
))}
|
||||
{openedTabs.map((tab) => (
|
||||
<TabNav key={tab.tabId} tab={tab} active={activeTab === tab} />
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="tabPanesContainer">
|
||||
{isConnectTabActive && <ConnectTab />}
|
||||
{activeReactTab !== undefined && getReactTabContent(activeReactTab, explorer)}
|
||||
{openedTabs.map((tab) => (
|
||||
<TabPane key={tab.tabId} tab={tab} active={activeTab === tab} />
|
||||
))}
|
||||
@@ -37,7 +44,7 @@ export const Tabs = (): JSX.Element => {
|
||||
);
|
||||
};
|
||||
|
||||
function TabNav({ tab, active }: { tab: Tab; active: boolean }) {
|
||||
function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?: ReactTabKind }) {
|
||||
const [hovering, setHovering] = useState(false);
|
||||
const focusTab = useRef<HTMLLIElement>() as MutableRefObject<HTMLLIElement>;
|
||||
const tabId = tab ? tab.tabId : "connect";
|
||||
@@ -51,8 +58,20 @@ function TabNav({ tab, active }: { tab: Tab; active: boolean }) {
|
||||
<li
|
||||
onMouseOver={() => setHovering(true)}
|
||||
onMouseLeave={() => setHovering(false)}
|
||||
onClick={() => (tab ? tab.onTabClick() : useTabs.getState().activateConnectTab())}
|
||||
onKeyPress={({ nativeEvent: e }) => (tab ? tab.onKeyPressActivate(undefined, e) : onKeyPressConnectTab(e))}
|
||||
onClick={() => {
|
||||
if (tab) {
|
||||
tab.onTabClick();
|
||||
} else if (tabKind !== undefined) {
|
||||
useTabs.getState().activateReactTab(tabKind);
|
||||
}
|
||||
}}
|
||||
onKeyPress={({ nativeEvent: e }) => {
|
||||
if (tab) {
|
||||
tab.onKeyPressActivate(undefined, e);
|
||||
} else if (tabKind !== undefined) {
|
||||
onKeyPressReactTab(e, tabKind);
|
||||
}
|
||||
}}
|
||||
className={active ? "active tabList" : "tabList"}
|
||||
title={useObservable(tab?.tabPath || ko.observable(""))}
|
||||
aria-selected={active}
|
||||
@@ -65,16 +84,18 @@ function TabNav({ tab, active }: { tab: Tab; active: boolean }) {
|
||||
<span className="tabNavContentContainer">
|
||||
<a data-toggle="tab" href={"#" + tabId} tabIndex={-1}>
|
||||
<div className="tab_Content">
|
||||
<span className="statusIconContainer">
|
||||
<span className="statusIconContainer" style={{ width: tabKind === ReactTabKind.Home ? 0 : 18 }}>
|
||||
{useObservable(tab?.isExecutionError || ko.observable(false)) && <ErrorIcon tab={tab} active={active} />}
|
||||
{useObservable(tab?.isExecuting || ko.observable(false)) && (
|
||||
<img className="loadingIcon" title="Loading" src={loadingIcon} alt="Loading" />
|
||||
)}
|
||||
</span>
|
||||
<span className="tabNavText">{useObservable(tab?.tabTitle || ko.observable("Connect"))}</span>
|
||||
<span className="tabIconSection">
|
||||
<CloseButton tab={tab} active={active} hovering={hovering} />
|
||||
</span>
|
||||
<span className="tabNavText">{useObservable(tab?.tabTitle || ko.observable(ReactTabKind[tabKind]))}</span>
|
||||
{tabKind !== ReactTabKind.Home && (
|
||||
<span className="tabIconSection">
|
||||
<CloseButton tab={tab} active={active} hovering={hovering} tabKind={tabKind} />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</a>
|
||||
</span>
|
||||
@@ -82,14 +103,24 @@ function TabNav({ tab, active }: { tab: Tab; active: boolean }) {
|
||||
);
|
||||
}
|
||||
|
||||
const CloseButton = ({ tab, active, hovering }: { tab: Tab; active: boolean; hovering: boolean }) => (
|
||||
const CloseButton = ({
|
||||
tab,
|
||||
active,
|
||||
hovering,
|
||||
tabKind,
|
||||
}: {
|
||||
tab: Tab;
|
||||
active: boolean;
|
||||
hovering: boolean;
|
||||
tabKind?: ReactTabKind;
|
||||
}) => (
|
||||
<span
|
||||
style={{ display: hovering || active ? undefined : "none" }}
|
||||
title="Close"
|
||||
role="button"
|
||||
aria-label="Close Tab"
|
||||
className="cancelButton"
|
||||
onClick={() => (tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeConnectTab())}
|
||||
onClick={() => (tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeReactTab(tabKind))}
|
||||
tabIndex={active ? 0 : undefined}
|
||||
onKeyPress={({ nativeEvent: e }) => tab.onKeyPressClose(undefined, e)}
|
||||
>
|
||||
@@ -144,9 +175,20 @@ function TabPane({ tab, active }: { tab: Tab; active: boolean }) {
|
||||
return <div {...attrs} ref={ref} data-bind="html:html" />;
|
||||
}
|
||||
|
||||
const onKeyPressConnectTab = (e: KeyboardEvent): void => {
|
||||
const onKeyPressReactTab = (e: KeyboardEvent, tabKind: ReactTabKind): void => {
|
||||
if (e.key === "Enter" || e.key === "Space") {
|
||||
useTabs.getState().activateConnectTab();
|
||||
useTabs.getState().activateReactTab(tabKind);
|
||||
e.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): JSX.Element => {
|
||||
switch (activeReactTab) {
|
||||
case ReactTabKind.Connect:
|
||||
return <ConnectTab />;
|
||||
case ReactTabKind.Home:
|
||||
return <SplashScreen explorer={explorer} />;
|
||||
default:
|
||||
throw Error(`Unsupported tab kind ${ReactTabKind[activeReactTab]}`);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user