mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-04 21:32:16 +00:00
Enhanced Tour feature (#2082)
* Enhanced Tour feature * Fix: #2182 - Tour steps getting skipped * Fix: #2180 - Stat links deactivated on browser back from Tour route * Addressing comments * Addressing comments * Adding license
This commit is contained in:
parent
ad362a31fd
commit
b29fdd3ccc
@ -12,7 +12,7 @@
|
||||
"directory": "openmetadata-ui/src/main/resources/ui"
|
||||
},
|
||||
"dependencies": {
|
||||
"@deuex-solutions/react-tour": "^1.0.0",
|
||||
"@deuex-solutions/react-tour": "^1.1.1",
|
||||
"@deuex-solutions/redoc": "2.0.0-rc.31",
|
||||
"autoprefixer": "^9.8.6",
|
||||
"axios": "^0.21.1",
|
||||
|
@ -451,7 +451,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
</div>
|
||||
)}
|
||||
{activeTab === 2 && (
|
||||
<div>
|
||||
<div id="sampleDataDetails">
|
||||
<SampleDataTable sampleData={getSampleDataWithType()} />
|
||||
</div>
|
||||
)}
|
||||
|
@ -127,9 +127,7 @@ const MyAssetStats: FunctionComponent<Props> = ({
|
||||
className="tw-font-medium tw-pl-2"
|
||||
data-testid={data.dataTestId}
|
||||
to={data.link}>
|
||||
<button
|
||||
className="tw-text-grey-body hover:tw-text-primary-hover hover:tw-underline"
|
||||
disabled={AppState.isTourOpen}>
|
||||
<button className="tw-text-grey-body hover:tw-text-primary-hover hover:tw-underline">
|
||||
{data.data}
|
||||
</button>
|
||||
</Link>
|
||||
|
@ -17,47 +17,34 @@ import { isEmpty } from 'lodash';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Match } from 'Models';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Link,
|
||||
NavLink,
|
||||
useHistory,
|
||||
useLocation,
|
||||
useRouteMatch,
|
||||
} from 'react-router-dom';
|
||||
import { useHistory, useLocation, useRouteMatch } from 'react-router-dom';
|
||||
import appState from '../../AppState';
|
||||
import { getVersion } from '../../axiosAPIs/miscAPI';
|
||||
import {
|
||||
getExplorePathWithSearch,
|
||||
navLinkSettings,
|
||||
ROUTES,
|
||||
TOUR_SEARCH_TERM,
|
||||
} from '../../constants/constants';
|
||||
import { urlGitbookDocs, urlJoinSlack } from '../../constants/url.const';
|
||||
import { CurrentTourPageType } from '../../enums/tour.enum';
|
||||
import { useAuth } from '../../hooks/authHooks';
|
||||
import { userSignOut } from '../../utils/AuthUtils';
|
||||
import { addToRecentSearched } from '../../utils/CommonUtils';
|
||||
import {
|
||||
inPageSearchOptions,
|
||||
isInPageSearchAllowed,
|
||||
} from '../../utils/RouterUtils';
|
||||
import { activeLink, normalLink } from '../../utils/styleconstant';
|
||||
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||
import PopOver from '../common/popover/PopOver';
|
||||
import DropDown from '../dropdown/DropDown';
|
||||
import { WhatsNewModal } from '../Modals/WhatsNewModal';
|
||||
import { COOKIE_VERSION } from '../Modals/WhatsNewModal/whatsNewData';
|
||||
import { ReactComponent as IconDefaultUserProfile } from './../../assets/svg/ic-default-profile.svg';
|
||||
import SearchOptions from './SearchOptions';
|
||||
import Suggestions from './Suggestions';
|
||||
import NavBar from '../nav-bar/NavBar';
|
||||
|
||||
const cookieStorage = new CookieStorage();
|
||||
|
||||
const Appbar: React.FC = (): JSX.Element => {
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
const { isAuthenticatedRoute, isSignedIn, isFirstTimeUser, isAuthDisabled } =
|
||||
useAuth(location.pathname);
|
||||
const {
|
||||
isAuthenticatedRoute,
|
||||
isSignedIn,
|
||||
isFirstTimeUser,
|
||||
isAuthDisabled,
|
||||
isTourRoute,
|
||||
} = useAuth(location.pathname);
|
||||
const match: Match | null = useRouteMatch({
|
||||
path: ROUTES.EXPLORE_WITH_SEARCH,
|
||||
});
|
||||
@ -65,18 +52,15 @@ const Appbar: React.FC = (): JSX.Element => {
|
||||
const [searchValue, setSearchValue] = useState(searchQuery);
|
||||
const [isOpen, setIsOpen] = useState<boolean>(true);
|
||||
const [isFeatureModalOpen, setIsFeatureModalOpen] = useState<boolean>(false);
|
||||
const [searchIcon, setSearchIcon] = useState<string>('icon-searchv1');
|
||||
|
||||
const [version, setVersion] = useState<string>('');
|
||||
|
||||
const navStyle = (value: boolean) => {
|
||||
if (value) return { color: activeLink };
|
||||
|
||||
return { color: normalLink };
|
||||
const handleFeatureModal = (value: boolean) => {
|
||||
setIsFeatureModalOpen(value);
|
||||
};
|
||||
|
||||
const openModal = () => {
|
||||
setIsFeatureModalOpen(true);
|
||||
const handleSearchChange = (value: string) => {
|
||||
setSearchValue(value);
|
||||
};
|
||||
|
||||
const supportLinks = [
|
||||
@ -156,6 +140,40 @@ const Appbar: React.FC = (): JSX.Element => {
|
||||
);
|
||||
};
|
||||
|
||||
const profileDropdown = [
|
||||
{
|
||||
name: getUserDisplayName(),
|
||||
to: '',
|
||||
disabled: false,
|
||||
icon: <></>,
|
||||
isText: true,
|
||||
},
|
||||
{
|
||||
name: 'Logout',
|
||||
to: '#/action-1',
|
||||
disabled: false,
|
||||
method: userSignOut,
|
||||
},
|
||||
];
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
const target = e.target as HTMLInputElement;
|
||||
if (e.key === 'Enter') {
|
||||
setIsOpen(false);
|
||||
|
||||
addToRecentSearched(target.value);
|
||||
history.push(
|
||||
getExplorePathWithSearch(
|
||||
target.value,
|
||||
// this is for if user is searching from another page
|
||||
location.pathname.startsWith(ROUTES.EXPLORE)
|
||||
? appState.explorePageTab
|
||||
: 'tables'
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setSearchValue(searchQuery);
|
||||
}, [searchQuery]);
|
||||
@ -183,217 +201,20 @@ const Appbar: React.FC = (): JSX.Element => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{isAuthenticatedRoute && isSignedIn ? (
|
||||
<div className="tw-h-16 tw-py-3 tw-border-b-2 tw-border-separator">
|
||||
<div className="tw-flex tw-items-center tw-flex-row tw-justify-between tw-flex-nowrap tw-px-6 centered-layout">
|
||||
<div className="tw-flex tw-items-center tw-flex-row tw-justify-between tw-flex-nowrap">
|
||||
<NavLink id="openmetadata_logo" to="/">
|
||||
<SVGIcons
|
||||
alt="OpenMetadata Logo"
|
||||
icon={Icons.LOGO}
|
||||
width="90"
|
||||
/>
|
||||
</NavLink>
|
||||
<div className="tw-ml-5">
|
||||
<NavLink
|
||||
className="tw-nav focus:tw-no-underline"
|
||||
data-testid="appbar-item"
|
||||
id="explore"
|
||||
style={navStyle(location.pathname.startsWith('/explore'))}
|
||||
to={{
|
||||
pathname: '/explore/tables',
|
||||
}}>
|
||||
Explore
|
||||
</NavLink>
|
||||
<DropDown
|
||||
dropDownList={navLinkSettings}
|
||||
label="Settings"
|
||||
type="link"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="tw-flex-none tw-relative tw-justify-items-center tw-ml-auto"
|
||||
data-testid="appbar-item">
|
||||
<SVGIcons
|
||||
alt="icon-search"
|
||||
className="tw-absolute tw-block tw-z-10 tw-w-4 tw-h-4 tw-right-2.5 tw-top-2.5 tw-leading-8 tw-text-center tw-pointer-events-none"
|
||||
icon={searchIcon}
|
||||
/>
|
||||
<input
|
||||
autoComplete="off"
|
||||
className="tw-relative search-grey tw-rounded tw-border tw-border-main focus:tw-outline-none tw-pl-2 tw-pt-2 tw-pb-1.5 tw-form-inputs"
|
||||
data-testid="searchBox"
|
||||
id="searchBox"
|
||||
placeholder="Search for Table, Topics, Dashboards and Pipeline"
|
||||
type="text"
|
||||
value={searchValue || ''}
|
||||
onBlur={() => setSearchIcon('icon-searchv1')}
|
||||
onChange={(e) => {
|
||||
setSearchValue(e.target.value);
|
||||
}}
|
||||
onFocus={() => setSearchIcon('icon-searchv1color')}
|
||||
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
const target = e.target as HTMLInputElement;
|
||||
if (e.key === 'Enter') {
|
||||
setIsOpen(false);
|
||||
// below code is for tour feature
|
||||
if (location.pathname.includes(ROUTES.TOUR)) {
|
||||
if (searchValue === TOUR_SEARCH_TERM) {
|
||||
appState.currentTourPage =
|
||||
CurrentTourPageType.EXPLORE_PAGE;
|
||||
setSearchValue('');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
addToRecentSearched(target.value);
|
||||
history.push(
|
||||
getExplorePathWithSearch(
|
||||
target.value,
|
||||
// this is for if user is searching from another page
|
||||
location.pathname.startsWith(ROUTES.EXPLORE)
|
||||
? appState.explorePageTab
|
||||
: 'tables'
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{!location.pathname.includes(ROUTES.TOUR) &&
|
||||
searchValue &&
|
||||
(isInPageSearchAllowed(location.pathname) ? (
|
||||
<SearchOptions
|
||||
isOpen={isOpen}
|
||||
options={inPageSearchOptions(location.pathname)}
|
||||
searchText={searchValue}
|
||||
selectOption={(text) => {
|
||||
appState.inPageSearchText = text;
|
||||
}}
|
||||
setIsOpen={setIsOpen}
|
||||
/>
|
||||
) : (
|
||||
<Suggestions
|
||||
isOpen={isOpen}
|
||||
searchText={searchValue}
|
||||
setIsOpen={setIsOpen}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="tw-flex tw-ml-auto tw-pl-36">
|
||||
<button
|
||||
className="tw-nav focus:tw-no-underline hover:tw-underline"
|
||||
data-testid="whatsnew-modal"
|
||||
onClick={openModal}>
|
||||
<PopOver
|
||||
position="bottom"
|
||||
title="What's new?"
|
||||
trigger="mouseenter">
|
||||
<SVGIcons
|
||||
alt="Doc icon"
|
||||
className="tw-align-middle tw-mr-1"
|
||||
icon={Icons.WHATS_NEW}
|
||||
width="20"
|
||||
/>
|
||||
</PopOver>
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="tw-nav focus:tw-no-underline hover:tw-underline"
|
||||
data-testid="tour">
|
||||
<PopOver
|
||||
position="bottom"
|
||||
title="Take a tour"
|
||||
trigger="mouseenter">
|
||||
<Link to={ROUTES.TOUR}>
|
||||
<SVGIcons
|
||||
alt="tour icon"
|
||||
className="tw-align-middle tw-mr-0.5"
|
||||
icon={Icons.TOUR}
|
||||
width="20"
|
||||
/>
|
||||
</Link>
|
||||
</PopOver>
|
||||
</button>
|
||||
<div>
|
||||
<DropDown
|
||||
dropDownList={supportLinks}
|
||||
icon={
|
||||
<PopOver
|
||||
position="bottom"
|
||||
title="Help"
|
||||
trigger="mouseenter">
|
||||
<SVGIcons
|
||||
alt="Doc icon"
|
||||
className="tw-align-middle tw-mt-0.5 tw-mr-1"
|
||||
icon={Icons.HELP_CIRCLE}
|
||||
width="20"
|
||||
/>
|
||||
</PopOver>
|
||||
}
|
||||
isDropDownIconVisible={false}
|
||||
isLableVisible={false}
|
||||
label="Need Help"
|
||||
type="link"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div data-testid="dropdown-profile">
|
||||
<DropDown
|
||||
dropDownList={[
|
||||
{
|
||||
name: getUserDisplayName(),
|
||||
to: '',
|
||||
disabled: false,
|
||||
icon: <></>,
|
||||
isText: true,
|
||||
},
|
||||
{
|
||||
name: 'Logout',
|
||||
to: '#/action-1',
|
||||
disabled: false,
|
||||
method: userSignOut,
|
||||
},
|
||||
]}
|
||||
icon={
|
||||
<>
|
||||
<PopOver
|
||||
position="bottom"
|
||||
title="Profile"
|
||||
trigger="mouseenter">
|
||||
{appState?.userDetails?.profile?.images?.image512 ? (
|
||||
<div className="profile-image tw--mr-2">
|
||||
<img
|
||||
alt="user"
|
||||
src={appState.userDetails.profile.images.image512}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<IconDefaultUserProfile
|
||||
className="tw--mr-2"
|
||||
style={{
|
||||
height: '22px',
|
||||
width: '22px',
|
||||
borderRadius: '50%',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</PopOver>
|
||||
</>
|
||||
}
|
||||
isDropDownIconVisible={false}
|
||||
type="link"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{isFeatureModalOpen && (
|
||||
<WhatsNewModal
|
||||
header="What’s new!"
|
||||
onCancel={() => setIsFeatureModalOpen(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{isAuthenticatedRoute && isSignedIn && !isTourRoute ? (
|
||||
<NavBar
|
||||
handleFeatureModal={handleFeatureModal}
|
||||
handleKeyDown={handleKeyDown}
|
||||
handleSearchBoxOpen={setIsOpen}
|
||||
handleSearchChange={handleSearchChange}
|
||||
isFeatureModalOpen={isFeatureModalOpen}
|
||||
isSearchBoxOpen={isOpen}
|
||||
pathname={location.pathname}
|
||||
profileDropdown={profileDropdown}
|
||||
searchValue={searchValue || ''}
|
||||
settingDropdown={navLinkSettings}
|
||||
supportDropdown={supportLinks}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
|
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { isNil, lowerCase } from 'lodash';
|
||||
import { camelCase, isNil } from 'lodash';
|
||||
import React from 'react';
|
||||
import { TITLE_FOR_NON_OWNER_ACTION } from '../../../constants/constants';
|
||||
import { getCountBadge } from '../../../utils/CommonUtils';
|
||||
@ -58,7 +58,7 @@ const TabsPane = ({ activeTab, setActiveTab, tabs, className = '' }: Props) => {
|
||||
<button
|
||||
className={getTabClasses(tab.position, activeTab)}
|
||||
data-testid="tab"
|
||||
id={lowerCase(tab.name)}
|
||||
id={camelCase(tab.name)}
|
||||
onClick={() => setActiveTab?.(tab.position)}>
|
||||
<SVGIcons
|
||||
alt={tab.icon.alt}
|
||||
@ -77,7 +77,7 @@ const TabsPane = ({ activeTab, setActiveTab, tabs, className = '' }: Props) => {
|
||||
<button
|
||||
className={getTabClasses(tab.position, activeTab)}
|
||||
data-testid="tab"
|
||||
id={lowerCase(tab.name)}
|
||||
id={camelCase(tab.name)}
|
||||
key={tab.position}
|
||||
onClick={() => setActiveTab?.(tab.position)}>
|
||||
<SVGIcons
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DropDownListItem } from '../dropdown/types';
|
||||
|
||||
export interface NavBarProps {
|
||||
settingDropdown: DropDownListItem[];
|
||||
supportDropdown: DropDownListItem[];
|
||||
profileDropdown: DropDownListItem[];
|
||||
searchValue: string;
|
||||
isTourRoute?: boolean;
|
||||
isFeatureModalOpen: boolean;
|
||||
pathname: string;
|
||||
isSearchBoxOpen: boolean;
|
||||
handleSearchBoxOpen: (value: boolean) => void;
|
||||
handleFeatureModal: (value: boolean) => void;
|
||||
handleSearchChange: (value: string) => void;
|
||||
handleKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
||||
}
|
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Link, NavLink } from 'react-router-dom';
|
||||
import AppState from '../../AppState';
|
||||
import { ROUTES } from '../../constants/constants';
|
||||
import {
|
||||
inPageSearchOptions,
|
||||
isInPageSearchAllowed,
|
||||
} from '../../utils/RouterUtils';
|
||||
import { activeLink, normalLink } from '../../utils/styleconstant';
|
||||
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||
import SearchOptions from '../app-bar/SearchOptions';
|
||||
import Suggestions from '../app-bar/Suggestions';
|
||||
import PopOver from '../common/popover/PopOver';
|
||||
import DropDown from '../dropdown/DropDown';
|
||||
import { WhatsNewModal } from '../Modals/WhatsNewModal';
|
||||
import { ReactComponent as IconDefaultUserProfile } from './../../assets/svg/ic-default-profile.svg';
|
||||
import { NavBarProps } from './NavBar.interface';
|
||||
|
||||
const NavBar = ({
|
||||
settingDropdown,
|
||||
supportDropdown,
|
||||
profileDropdown,
|
||||
searchValue,
|
||||
isFeatureModalOpen,
|
||||
isTourRoute = false,
|
||||
pathname,
|
||||
isSearchBoxOpen,
|
||||
handleSearchBoxOpen,
|
||||
handleFeatureModal,
|
||||
handleSearchChange,
|
||||
handleKeyDown,
|
||||
}: NavBarProps) => {
|
||||
const [searchIcon, setSearchIcon] = useState<string>('icon-searchv1');
|
||||
const navStyle = (value: boolean) => {
|
||||
if (value) return { color: activeLink };
|
||||
|
||||
return { color: normalLink };
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="tw-h-16 tw-py-3 tw-border-b-2 tw-border-separator">
|
||||
<div className="tw-flex tw-items-center tw-flex-row tw-justify-between tw-flex-nowrap tw-px-6 centered-layout">
|
||||
<div className="tw-flex tw-items-center tw-flex-row tw-justify-between tw-flex-nowrap">
|
||||
<NavLink id="openmetadata_logo" to="/">
|
||||
<SVGIcons alt="OpenMetadata Logo" icon={Icons.LOGO} width="90" />
|
||||
</NavLink>
|
||||
<div className="tw-ml-5">
|
||||
<NavLink
|
||||
className="tw-nav focus:tw-no-underline"
|
||||
data-testid="appbar-item"
|
||||
id="explore"
|
||||
style={navStyle(pathname.startsWith('/explore'))}
|
||||
to={{
|
||||
pathname: '/explore/tables',
|
||||
}}>
|
||||
Explore
|
||||
</NavLink>
|
||||
<DropDown
|
||||
dropDownList={settingDropdown}
|
||||
label="Settings"
|
||||
type="link"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="tw-flex-none tw-relative tw-justify-items-center tw-ml-auto"
|
||||
data-testid="appbar-item">
|
||||
<SVGIcons
|
||||
alt="icon-search"
|
||||
className="tw-absolute tw-block tw-z-10 tw-w-4 tw-h-4 tw-right-2.5 tw-top-2.5 tw-leading-8 tw-text-center tw-pointer-events-none"
|
||||
icon={searchIcon}
|
||||
/>
|
||||
<input
|
||||
autoComplete="off"
|
||||
className="tw-relative search-grey tw-rounded tw-border tw-border-main focus:tw-outline-none tw-pl-2 tw-pt-2 tw-pb-1.5 tw-form-inputs"
|
||||
data-testid="searchBox"
|
||||
id="searchBox"
|
||||
placeholder="Search for Table, Topics, Dashboards and Pipeline"
|
||||
type="text"
|
||||
value={searchValue}
|
||||
onBlur={() => setSearchIcon('icon-searchv1')}
|
||||
onChange={(e) => {
|
||||
handleSearchChange(e.target.value);
|
||||
}}
|
||||
onFocus={() => setSearchIcon('icon-searchv1color')}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
{!isTourRoute &&
|
||||
searchValue &&
|
||||
(isInPageSearchAllowed(pathname) ? (
|
||||
<SearchOptions
|
||||
isOpen={isSearchBoxOpen}
|
||||
options={inPageSearchOptions(pathname)}
|
||||
searchText={searchValue}
|
||||
selectOption={(text) => {
|
||||
AppState.inPageSearchText = text;
|
||||
}}
|
||||
setIsOpen={handleSearchBoxOpen}
|
||||
/>
|
||||
) : (
|
||||
<Suggestions
|
||||
isOpen={isSearchBoxOpen}
|
||||
searchText={searchValue}
|
||||
setIsOpen={handleSearchBoxOpen}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="tw-flex tw-ml-auto tw-pl-36">
|
||||
<button
|
||||
className="tw-nav focus:tw-no-underline hover:tw-underline"
|
||||
data-testid="whatsnew-modal"
|
||||
onClick={() => handleFeatureModal(true)}>
|
||||
<PopOver
|
||||
position="bottom"
|
||||
title="What's new?"
|
||||
trigger="mouseenter">
|
||||
<SVGIcons
|
||||
alt="Doc icon"
|
||||
className="tw-align-middle tw-mr-1"
|
||||
icon={Icons.WHATS_NEW}
|
||||
width="20"
|
||||
/>
|
||||
</PopOver>
|
||||
</button>
|
||||
<button
|
||||
className="tw-nav focus:tw-no-underline hover:tw-underline"
|
||||
data-testid="tour">
|
||||
<PopOver
|
||||
position="bottom"
|
||||
title="Take a tour"
|
||||
trigger="mouseenter">
|
||||
<Link to={ROUTES.TOUR}>
|
||||
<SVGIcons
|
||||
alt="tour icon"
|
||||
className="tw-align-middle tw-mr-0.5"
|
||||
icon={Icons.TOUR}
|
||||
width="20"
|
||||
/>
|
||||
</Link>
|
||||
</PopOver>
|
||||
</button>
|
||||
<div>
|
||||
<DropDown
|
||||
dropDownList={supportDropdown}
|
||||
icon={
|
||||
<PopOver position="bottom" title="Help" trigger="mouseenter">
|
||||
<SVGIcons
|
||||
alt="Doc icon"
|
||||
className="tw-align-middle tw-mt-0.5 tw-mr-1"
|
||||
icon={Icons.HELP_CIRCLE}
|
||||
width="20"
|
||||
/>
|
||||
</PopOver>
|
||||
}
|
||||
isDropDownIconVisible={false}
|
||||
isLableVisible={false}
|
||||
label="Need Help"
|
||||
type="link"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div data-testid="dropdown-profile">
|
||||
<DropDown
|
||||
dropDownList={profileDropdown}
|
||||
icon={
|
||||
<>
|
||||
<PopOver
|
||||
position="bottom"
|
||||
title="Profile"
|
||||
trigger="mouseenter">
|
||||
{AppState?.userDetails?.profile?.images?.image512 ? (
|
||||
<div className="profile-image tw--mr-2">
|
||||
<img
|
||||
alt="user"
|
||||
src={AppState.userDetails.profile.images.image512}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<IconDefaultUserProfile
|
||||
className="tw--mr-2"
|
||||
style={{
|
||||
height: '22px',
|
||||
width: '22px',
|
||||
borderRadius: '50%',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</PopOver>
|
||||
</>
|
||||
}
|
||||
isDropDownIconVisible={false}
|
||||
type="link"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{isFeatureModalOpen && (
|
||||
<WhatsNewModal
|
||||
header="What’s new!"
|
||||
onCancel={() => handleFeatureModal(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavBar;
|
@ -13,210 +13,14 @@
|
||||
|
||||
import ReactTutorial from '@deuex-solutions/react-tour';
|
||||
import { observer } from 'mobx-react';
|
||||
import { TourSteps } from 'Models';
|
||||
import React, { useState } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import AppState from '../../AppState';
|
||||
import { TOUR_SEARCH_TERM } from '../../constants/constants';
|
||||
import { CurrentTourPageType } from '../../enums/tour.enum';
|
||||
import { useTour } from '../../hooks/useTour';
|
||||
import TourEndModal from '../Modals/TourEndModal/TourEndModal';
|
||||
|
||||
type Steps = {
|
||||
content?: string | React.ReactNode;
|
||||
actionType?: string;
|
||||
position?: string | number[];
|
||||
selector?: string;
|
||||
userTypeText?: string;
|
||||
waitTimer?: number;
|
||||
};
|
||||
|
||||
const getSteps = (value: string) => {
|
||||
const modifiedValue = value.substr(0, 6);
|
||||
|
||||
return [
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Discover all your data assets in a single place with{' '}
|
||||
<strong>OpenMetadata</strong>, a centralized metadata store.
|
||||
Collaborate with your team and get a holistic picture of the data in
|
||||
your organization.
|
||||
</p>
|
||||
),
|
||||
position: [5, 360],
|
||||
stepInteraction: false,
|
||||
selector: '#assetStatsCount',
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
<strong>Activity Feeds</strong> help you understand how the data is
|
||||
changing in your organization.
|
||||
</p>
|
||||
),
|
||||
position: [540, 540],
|
||||
selector: '#feedData',
|
||||
stepInteraction: false,
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Look up for matching data assets by "name",
|
||||
"description", "column name", and so on from the{' '}
|
||||
<strong>search</strong> box.
|
||||
</p>
|
||||
),
|
||||
position: [535, 70],
|
||||
selector: '#searchBox',
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
In the search box, type <strong>"{modifiedValue}"</strong>.
|
||||
Hit <strong>Enter.</strong>
|
||||
</p>
|
||||
),
|
||||
actionType: 'enter',
|
||||
userTypeText: modifiedValue,
|
||||
position: [535, 70],
|
||||
selector: '#searchBox',
|
||||
beforeNext: () => {
|
||||
AppState.currentTourPage = CurrentTourPageType.EXPLORE_PAGE;
|
||||
},
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.currentTourPage = CurrentTourPageType.MY_DATA_PAGE;
|
||||
},
|
||||
content: () => (
|
||||
<p>
|
||||
From the <strong>"Explore"</strong> page, get to know the
|
||||
details on the table entity, tier, usage, and database information
|
||||
</p>
|
||||
),
|
||||
selector: '#tabledatacard0',
|
||||
stepInteraction: false,
|
||||
position: [550, 310],
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>title of the asset</strong> to view more details.
|
||||
</p>
|
||||
),
|
||||
actionType: 'click',
|
||||
selector: '#tabledatacard0Title',
|
||||
position: [210, 190],
|
||||
beforeNext: () => {
|
||||
AppState.currentTourPage = CurrentTourPageType.DATASET_PAGE;
|
||||
},
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.currentTourPage = CurrentTourPageType.EXPLORE_PAGE;
|
||||
},
|
||||
content: () => (
|
||||
<p>
|
||||
{' '}
|
||||
Get to know the table <strong>schema.</strong> Add a description.
|
||||
</p>
|
||||
),
|
||||
stepInteraction: false,
|
||||
position: [540, 65],
|
||||
arrowPosition: 'bottom',
|
||||
selector: '#schemaDetails',
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.activeTabforTourDatasetPage = 1;
|
||||
},
|
||||
beforeNext: () => {
|
||||
AppState.activeTabforTourDatasetPage = 2;
|
||||
},
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>"Profiler"</strong> tab.
|
||||
</p>
|
||||
),
|
||||
position: [20, 240],
|
||||
selector: '#profiler',
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Discover assets with the <strong>Data Profiler</strong>. Get to know
|
||||
the table usage stats, check for null values and duplicates, and
|
||||
understand the column data distributions.
|
||||
</p>
|
||||
),
|
||||
arrowPosition: 'bottom',
|
||||
stepInteraction: false,
|
||||
position: [530, 20],
|
||||
selector: '#profilerDetails',
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.activeTabforTourDatasetPage = 2;
|
||||
},
|
||||
beforeNext: () => {
|
||||
AppState.activeTabforTourDatasetPage = 3;
|
||||
},
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>"Lineage"</strong> tab
|
||||
</p>
|
||||
),
|
||||
position: [140, 240],
|
||||
selector: '#lineage',
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
With <strong>Lineage</strong>, trace the path of data across tables,
|
||||
pipelines, & dashboards.
|
||||
</p>
|
||||
),
|
||||
position: [530, 45],
|
||||
stepInteraction: false,
|
||||
arrowPosition: 'bottom',
|
||||
selector: '#lineageDetails',
|
||||
},
|
||||
{
|
||||
beforeNext: () => {
|
||||
AppState.activeTabforTourDatasetPage = 5;
|
||||
},
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>"Manage"</strong> tab
|
||||
</p>
|
||||
),
|
||||
position: [260, 240],
|
||||
selector: '#manage',
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.activeTabforTourDatasetPage = 3;
|
||||
},
|
||||
content: () => (
|
||||
<p>
|
||||
From <strong>"Manage"</strong>, you can claim ownership, and
|
||||
set the tiers.
|
||||
</p>
|
||||
),
|
||||
position: [560, 60],
|
||||
arrowPosition: 'bottom',
|
||||
stepInteraction: false,
|
||||
selector: '#manageTabDetails',
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const Tour = () => {
|
||||
const Tour = ({ steps }: { steps: TourSteps[] }) => {
|
||||
const { isTourOpen, handleIsTourOpen } = useTour();
|
||||
const [steps] = useState<Steps[]>(getSteps(TOUR_SEARCH_TERM));
|
||||
const [showTourEndModal, setShowTourEndModal] = useState(false);
|
||||
const history = useHistory();
|
||||
|
||||
@ -230,6 +34,7 @@ const Tour = () => {
|
||||
<ReactTutorial
|
||||
disableDotsNavigation
|
||||
disableKeyboardNavigation
|
||||
showCloseButton
|
||||
showNumber
|
||||
accentColor="#7147E8"
|
||||
inViewThreshold={200}
|
||||
@ -251,9 +56,10 @@ const Tour = () => {
|
||||
}
|
||||
maskColor="#302E36"
|
||||
playTour={isTourOpen}
|
||||
stepWaitTimer={100}
|
||||
stepWaitTimer={300}
|
||||
steps={steps}
|
||||
onRequestClose={() => handleIsTourOpen(false)}
|
||||
onRequestSkip={handleModalSubmit}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
|
@ -1,3 +1,16 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
export const mockFeedData = [
|
||||
|
@ -21,6 +21,7 @@ export const useAuth = (pathname = '') => {
|
||||
pathname !== ROUTES.SIGNUP &&
|
||||
pathname !== ROUTES.SIGNIN &&
|
||||
pathname !== ROUTES.CALLBACK;
|
||||
const isTourRoute = pathname === ROUTES.TOUR;
|
||||
|
||||
return {
|
||||
isSigningIn: authProvider.signingIn,
|
||||
@ -31,9 +32,10 @@ export const useAuth = (pathname = '') => {
|
||||
!authProvider.signingIn &&
|
||||
isEmpty(userDetails) &&
|
||||
isEmpty(newUser),
|
||||
isAuthenticatedRoute: isAuthenticatedRoute,
|
||||
isAuthenticatedRoute,
|
||||
isAuthDisabled: authDisabled,
|
||||
isAdminUser: userDetails?.isAdmin,
|
||||
isFirstTimeUser: !isEmpty(userDetails) && !isEmpty(newUser),
|
||||
isTourRoute,
|
||||
};
|
||||
};
|
||||
|
@ -423,6 +423,15 @@ declare module 'Models' {
|
||||
showLabel?: boolean;
|
||||
};
|
||||
|
||||
export type TourSteps = {
|
||||
content?: string | React.ReactNode;
|
||||
actionType?: string;
|
||||
position?: string | number[];
|
||||
selector?: string;
|
||||
userTypeText?: string;
|
||||
waitTimer?: number;
|
||||
};
|
||||
|
||||
export interface FormErrorData {
|
||||
[key: string]: string | undefined;
|
||||
}
|
||||
|
@ -1,6 +1,20 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { observer } from 'mobx-react';
|
||||
import { LeafNodes, SearchResponse } from 'Models';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import AppState from '../../AppState';
|
||||
import DatasetDetails from '../../components/DatasetDetails/DatasetDetails.component';
|
||||
import { DatasetOwner } from '../../components/DatasetDetails/DatasetDetails.interface';
|
||||
@ -8,7 +22,9 @@ import Explore from '../../components/Explore/Explore.component';
|
||||
import { ExploreSearchData } from '../../components/Explore/explore.interface';
|
||||
import MyData from '../../components/MyData/MyData.component';
|
||||
import { MyDataProps } from '../../components/MyData/MyData.interface';
|
||||
import NavBar from '../../components/nav-bar/NavBar';
|
||||
import Tour from '../../components/tour/Tour';
|
||||
import { ROUTES, TOUR_SEARCH_TERM } from '../../constants/constants';
|
||||
import {
|
||||
mockDatasetData,
|
||||
mockFeedData,
|
||||
@ -22,6 +38,7 @@ import {
|
||||
} from '../../generated/entity/data/table';
|
||||
import { TagLabel } from '../../generated/type/tagLabel';
|
||||
import { useTour } from '../../hooks/useTour';
|
||||
import { getSteps } from '../../utils/TourUtils';
|
||||
|
||||
const mockData = {
|
||||
data: { hits: { hits: [] } },
|
||||
@ -36,6 +53,7 @@ const exploreCount = {
|
||||
};
|
||||
|
||||
const TourPage = () => {
|
||||
const location = useLocation();
|
||||
const { handleIsTourOpen } = useTour();
|
||||
const [currentPage, setCurrentPage] = useState<CurrentTourPageType>(
|
||||
AppState.currentTourPage
|
||||
@ -47,11 +65,29 @@ const TourPage = () => {
|
||||
AppState.activeTabforTourDatasetPage
|
||||
);
|
||||
const [explorePageCounts, setExplorePageCounts] = useState(exploreCount);
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
|
||||
const handleCountChange = () => {
|
||||
setExplorePageCounts(exploreCount);
|
||||
};
|
||||
|
||||
const clearSearchTerm = () => {
|
||||
setSearchValue('');
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Enter') {
|
||||
if (location.pathname.includes(ROUTES.TOUR)) {
|
||||
if (searchValue === TOUR_SEARCH_TERM) {
|
||||
AppState.currentTourPage = CurrentTourPageType.EXPLORE_PAGE;
|
||||
clearSearchTerm();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
handleIsTourOpen(true);
|
||||
AppState.currentTourPage = CurrentTourPageType.MY_DATA_PAGE;
|
||||
@ -164,7 +200,21 @@ const TourPage = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Tour />
|
||||
<NavBar
|
||||
isTourRoute
|
||||
handleFeatureModal={handleCountChange}
|
||||
handleKeyDown={handleKeyDown}
|
||||
handleSearchBoxOpen={handleCountChange}
|
||||
handleSearchChange={(value) => setSearchValue(value)}
|
||||
isFeatureModalOpen={false}
|
||||
isSearchBoxOpen={false}
|
||||
pathname={location.pathname}
|
||||
profileDropdown={[]}
|
||||
searchValue={searchValue}
|
||||
settingDropdown={[]}
|
||||
supportDropdown={[]}
|
||||
/>
|
||||
<Tour steps={getSteps(TOUR_SEARCH_TERM, clearSearchTerm)} />
|
||||
{getCurrentPage(currentPage)}
|
||||
</div>
|
||||
);
|
||||
|
232
openmetadata-ui/src/main/resources/ui/src/utils/TourUtils.tsx
Normal file
232
openmetadata-ui/src/main/resources/ui/src/utils/TourUtils.tsx
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import AppState from '../AppState';
|
||||
import { CurrentTourPageType } from '../enums/tour.enum';
|
||||
|
||||
export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
return [
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Discover all your data assets in a single place with{' '}
|
||||
<strong>OpenMetadata</strong>, a centralized metadata store.
|
||||
Collaborate with your team and get a holistic picture of the data in
|
||||
your organization.
|
||||
</p>
|
||||
),
|
||||
position: [5, 360],
|
||||
stepInteraction: false,
|
||||
selector: '#assetStatsCount',
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
<strong>Activity Feeds</strong> help you understand how the data is
|
||||
changing in your organization.
|
||||
</p>
|
||||
),
|
||||
position: [540, 540],
|
||||
selector: '#feedData',
|
||||
stepInteraction: false,
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Search for matching data assets by "name",
|
||||
"description", "column name", and so on from the{' '}
|
||||
<strong>Search</strong> box.
|
||||
</p>
|
||||
),
|
||||
position: [535, 70],
|
||||
selector: '#searchBox',
|
||||
stepInteraction: false,
|
||||
beforeNext: clearSearchTerm,
|
||||
},
|
||||
{
|
||||
beforePrev: clearSearchTerm,
|
||||
content: () => (
|
||||
<p>
|
||||
In the search box, type <strong>"{value}"</strong>. Hit{' '}
|
||||
<strong>Enter.</strong>
|
||||
</p>
|
||||
),
|
||||
actionType: 'enter',
|
||||
userTypeText: value,
|
||||
position: [535, 70],
|
||||
selector: '#searchBox',
|
||||
beforeNext: () => {
|
||||
clearSearchTerm();
|
||||
AppState.currentTourPage = CurrentTourPageType.EXPLORE_PAGE;
|
||||
},
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.currentTourPage = CurrentTourPageType.MY_DATA_PAGE;
|
||||
},
|
||||
content: () => (
|
||||
<p>
|
||||
From the <strong>"Explore"</strong> page, view a summary of
|
||||
each asset, including: title, description, owner, tier (importance),
|
||||
usage, and location.
|
||||
</p>
|
||||
),
|
||||
selector: '#tabledatacard0',
|
||||
stepInteraction: false,
|
||||
position: [550, 310],
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>title of the asset</strong> to view more details.
|
||||
</p>
|
||||
),
|
||||
actionType: 'click',
|
||||
selector: '#tabledatacard0Title',
|
||||
position: [210, 190],
|
||||
beforeNext: () => {
|
||||
AppState.currentTourPage = CurrentTourPageType.DATASET_PAGE;
|
||||
},
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.currentTourPage = CurrentTourPageType.EXPLORE_PAGE;
|
||||
},
|
||||
content: () => (
|
||||
<p>
|
||||
{' '}
|
||||
Get to know the table <strong>Schema</strong>, including column names
|
||||
and data types as well as column descriptions and tags. You can even
|
||||
view metadata for complex types such as structs.
|
||||
</p>
|
||||
),
|
||||
stepInteraction: false,
|
||||
position: [540, 23],
|
||||
arrowPosition: 'bottom',
|
||||
selector: '#schemaDetails',
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.activeTabforTourDatasetPage = 1;
|
||||
},
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>"Sample Data"</strong> tab.
|
||||
</p>
|
||||
),
|
||||
position: [70, 240],
|
||||
selector: '#sampleData',
|
||||
beforeNext: () => {
|
||||
AppState.activeTabforTourDatasetPage = 2;
|
||||
},
|
||||
},
|
||||
{
|
||||
arrowPosition: 'bottom',
|
||||
content: () => (
|
||||
<p>
|
||||
Take a look at the <strong>Sample Data</strong> to get a feel for what
|
||||
the table contains and how you might use it.
|
||||
</p>
|
||||
),
|
||||
position: [530, 60],
|
||||
selector: '#sampleDataDetails',
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.activeTabforTourDatasetPage = 2;
|
||||
},
|
||||
beforeNext: () => {
|
||||
AppState.activeTabforTourDatasetPage = 3;
|
||||
},
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>"Profiler"</strong> tab.
|
||||
</p>
|
||||
),
|
||||
position: [200, 240],
|
||||
selector: '#profiler',
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Discover assets with the <strong>Data Profiler</strong>. Get to know
|
||||
the table usage stats, check for null values and duplicates, and
|
||||
understand the column data distributions.
|
||||
</p>
|
||||
),
|
||||
arrowPosition: 'bottom',
|
||||
stepInteraction: false,
|
||||
position: [530, 20],
|
||||
selector: '#profilerDetails',
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.activeTabforTourDatasetPage = 3;
|
||||
},
|
||||
beforeNext: () => {
|
||||
AppState.activeTabforTourDatasetPage = 4;
|
||||
},
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>"Lineage"</strong> tab
|
||||
</p>
|
||||
),
|
||||
position: [320, 240],
|
||||
selector: '#lineage',
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
With <strong>Lineage</strong>, trace the path of data across tables,
|
||||
pipelines, & dashboards.
|
||||
</p>
|
||||
),
|
||||
position: [530, 45],
|
||||
stepInteraction: false,
|
||||
arrowPosition: 'bottom',
|
||||
selector: '#lineageDetails',
|
||||
},
|
||||
{
|
||||
beforeNext: () => {
|
||||
AppState.activeTabforTourDatasetPage = 6;
|
||||
},
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>"Manage"</strong> tab
|
||||
</p>
|
||||
),
|
||||
position: [440, 240],
|
||||
selector: '#manage',
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.activeTabforTourDatasetPage = 4;
|
||||
},
|
||||
content: () => (
|
||||
<p>
|
||||
From <strong>"Manage"</strong>, you can claim ownership, and
|
||||
set the tier.
|
||||
</p>
|
||||
),
|
||||
position: [560, 60],
|
||||
arrowPosition: 'bottom',
|
||||
stepInteraction: false,
|
||||
selector: '#manageTabDetails',
|
||||
},
|
||||
];
|
||||
};
|
@ -996,10 +996,10 @@
|
||||
exec-sh "^0.3.2"
|
||||
minimist "^1.2.0"
|
||||
|
||||
"@deuex-solutions/react-tour@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@deuex-solutions/react-tour/-/react-tour-1.0.0.tgz#5714dd38cf3f89fc781cc7f53965b08400e68a13"
|
||||
integrity sha512-oSprYz81nejf3ZqgZAy6dgyuyEEujJvGs5b+YB2Pnfui9i0vyOEseTtIoamYV+eRTjBsPhwv2wUa7RkdcJUcSQ==
|
||||
"@deuex-solutions/react-tour@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@deuex-solutions/react-tour/-/react-tour-1.1.1.tgz#ad96bf0bcd651916a6e44d5e9c3bdc60e5fac036"
|
||||
integrity sha512-BIw1zlGprOEtCoGexdyQl97bvBdeZb9ZPcB6e90fV+x2s9h+YDeZwEC+qisTQodLkBwovSRO990K2Quc6p39Aw==
|
||||
dependencies:
|
||||
classnames "^2.2.6"
|
||||
lodash "^4.17.15"
|
||||
|
Loading…
x
Reference in New Issue
Block a user