340 lines
11 KiB
TypeScript
340 lines
11 KiB
TypeScript
/**
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you 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 { MainNav as Menu } from 'src/components/Menu';
|
|
import { t, styled, css, SupersetTheme } from '@superset-ui/core';
|
|
import { Link } from 'react-router-dom';
|
|
import Icons from 'src/components/Icons';
|
|
import findPermission from 'src/dashboard/util/findPermission';
|
|
import { useSelector } from 'react-redux';
|
|
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
|
|
import LanguagePicker from './LanguagePicker';
|
|
import DatabaseModal from '../CRUD/data/database/DatabaseModal';
|
|
import { checkUploadExtensions } from '../CRUD/utils';
|
|
import {
|
|
ExtentionConfigs,
|
|
GlobalMenuDataOptions,
|
|
RightMenuProps,
|
|
} from './types';
|
|
import { MenuObjectProps } from './Menu';
|
|
|
|
const versionInfoStyles = (theme: SupersetTheme) => css`
|
|
padding: ${theme.gridUnit * 1.5}px ${theme.gridUnit * 4}px
|
|
${theme.gridUnit * 4}px ${theme.gridUnit * 7}px;
|
|
color: ${theme.colors.grayscale.base};
|
|
font-size: ${theme.typography.sizes.xs}px;
|
|
white-space: nowrap;
|
|
`;
|
|
const StyledI = styled.div`
|
|
color: ${({ theme }) => theme.colors.primary.dark1};
|
|
`;
|
|
|
|
const StyledDiv = styled.div<{ align: string }>`
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: ${({ align }) => align};
|
|
align-items: center;
|
|
margin-right: ${({ theme }) => theme.gridUnit}px;
|
|
.ant-menu-submenu-title > svg {
|
|
top: ${({ theme }) => theme.gridUnit * 5.25}px;
|
|
}
|
|
`;
|
|
|
|
const StyledAnchor = styled.a`
|
|
padding-right: ${({ theme }) => theme.gridUnit}px;
|
|
padding-left: ${({ theme }) => theme.gridUnit}px;
|
|
`;
|
|
|
|
const { SubMenu } = Menu;
|
|
|
|
const RightMenu = ({
|
|
align,
|
|
settings,
|
|
navbarRight,
|
|
isFrontendRoute,
|
|
}: RightMenuProps) => {
|
|
const { roles } = useSelector<any, UserWithPermissionsAndRoles>(
|
|
state => state.user,
|
|
);
|
|
const {
|
|
CSV_EXTENSIONS,
|
|
COLUMNAR_EXTENSIONS,
|
|
EXCEL_EXTENSIONS,
|
|
ALLOWED_EXTENSIONS,
|
|
HAS_GSHEETS_INSTALLED,
|
|
} = useSelector<any, ExtentionConfigs>(state => state.common.conf);
|
|
|
|
const [showModal, setShowModal] = useState<boolean>(false);
|
|
const [engine, setEngine] = useState<string>('');
|
|
const canSql = findPermission('can_sqllab', 'Superset', roles);
|
|
const canDashboard = findPermission('can_write', 'Dashboard', roles);
|
|
const canChart = findPermission('can_write', 'Chart', roles);
|
|
const showActionDropdown = canSql || canChart || canDashboard;
|
|
const dropdownItems: MenuObjectProps[] = [
|
|
{
|
|
label: t('Data'),
|
|
icon: 'fa-database',
|
|
childs: [
|
|
{
|
|
label: t('Connect Database'),
|
|
name: GlobalMenuDataOptions.DB_CONNECTION,
|
|
perm: true,
|
|
},
|
|
{
|
|
label: t('Connect Google Sheet'),
|
|
name: GlobalMenuDataOptions.GOOGLE_SHEETS,
|
|
perm: HAS_GSHEETS_INSTALLED,
|
|
},
|
|
{
|
|
label: t('Upload a CSV'),
|
|
name: 'Upload a CSV',
|
|
url: '/csvtodatabaseview/form',
|
|
perm: CSV_EXTENSIONS,
|
|
},
|
|
{
|
|
label: t('Upload a Columnar File'),
|
|
name: 'Upload a Columnar file',
|
|
url: '/columnartodatabaseview/form',
|
|
perm: COLUMNAR_EXTENSIONS,
|
|
},
|
|
{
|
|
label: t('Upload Excel'),
|
|
name: 'Upload Excel',
|
|
url: '/exceltodatabaseview/form',
|
|
perm: EXCEL_EXTENSIONS,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: t('SQL query'),
|
|
url: '/superset/sqllab?new=true',
|
|
icon: 'fa-fw fa-search',
|
|
perm: 'can_sqllab',
|
|
view: 'Superset',
|
|
},
|
|
{
|
|
label: t('Chart'),
|
|
url: '/chart/add',
|
|
icon: 'fa-fw fa-bar-chart',
|
|
perm: 'can_write',
|
|
view: 'Chart',
|
|
},
|
|
{
|
|
label: t('Dashboard'),
|
|
url: '/dashboard/new',
|
|
icon: 'fa-fw fa-dashboard',
|
|
perm: 'can_write',
|
|
view: 'Dashboard',
|
|
},
|
|
];
|
|
|
|
const menuIconAndLabel = (menu: MenuObjectProps) => (
|
|
<>
|
|
<i data-test={`menu-item-${menu.label}`} className={`fa ${menu.icon}`} />
|
|
{menu.label}
|
|
</>
|
|
);
|
|
|
|
const handleMenuSelection = (itemChose: any) => {
|
|
if (itemChose.key === GlobalMenuDataOptions.DB_CONNECTION) {
|
|
setShowModal(true);
|
|
} else if (itemChose.key === GlobalMenuDataOptions.GOOGLE_SHEETS) {
|
|
setShowModal(true);
|
|
setEngine('Google Sheets');
|
|
}
|
|
};
|
|
|
|
const handleOnHideModal = () => {
|
|
setEngine('');
|
|
setShowModal(false);
|
|
};
|
|
|
|
return (
|
|
<StyledDiv align={align}>
|
|
<DatabaseModal
|
|
onHide={handleOnHideModal}
|
|
show={showModal}
|
|
dbEngine={engine}
|
|
/>
|
|
<Menu selectable={false} mode="horizontal" onClick={handleMenuSelection}>
|
|
{!navbarRight.user_is_anonymous && showActionDropdown && (
|
|
<SubMenu
|
|
data-test="new-dropdown"
|
|
title={
|
|
<StyledI data-test="new-dropdown-icon" className="fa fa-plus" />
|
|
}
|
|
icon={<Icons.TriangleDown />}
|
|
>
|
|
{dropdownItems.map(menu => {
|
|
if (menu.childs) {
|
|
return (
|
|
<SubMenu
|
|
key="sub2"
|
|
className="data-menu"
|
|
title={menuIconAndLabel(menu)}
|
|
>
|
|
{menu.childs.map((item, idx) =>
|
|
typeof item !== 'string' &&
|
|
item.name &&
|
|
checkUploadExtensions(item.perm, ALLOWED_EXTENSIONS) ? (
|
|
<>
|
|
{idx === 2 && <Menu.Divider />}
|
|
<Menu.Item key={item.name}>
|
|
{item.url ? (
|
|
<a href={item.url}> {item.label} </a>
|
|
) : (
|
|
item.label
|
|
)}
|
|
</Menu.Item>
|
|
</>
|
|
) : null,
|
|
)}
|
|
</SubMenu>
|
|
);
|
|
}
|
|
return (
|
|
findPermission(
|
|
menu.perm as string,
|
|
menu.view as string,
|
|
roles,
|
|
) && (
|
|
<Menu.Item key={menu.label}>
|
|
<a href={menu.url}>
|
|
<i
|
|
data-test={`menu-item-${menu.label}`}
|
|
className={`fa ${menu.icon}`}
|
|
/>{' '}
|
|
{menu.label}
|
|
</a>
|
|
</Menu.Item>
|
|
)
|
|
);
|
|
})}
|
|
</SubMenu>
|
|
)}
|
|
<SubMenu
|
|
title={t('Settings')}
|
|
icon={<Icons.TriangleDown iconSize="xl" />}
|
|
>
|
|
{settings.map((section, index) => [
|
|
<Menu.ItemGroup key={`${section.label}`} title={section.label}>
|
|
{section.childs?.map(child => {
|
|
if (typeof child !== 'string') {
|
|
return (
|
|
<Menu.Item key={`${child.label}`}>
|
|
{isFrontendRoute(child.url) ? (
|
|
<Link to={child.url || ''}>{child.label}</Link>
|
|
) : (
|
|
<a href={child.url}>{child.label}</a>
|
|
)}
|
|
</Menu.Item>
|
|
);
|
|
}
|
|
return null;
|
|
})}
|
|
</Menu.ItemGroup>,
|
|
index < settings.length - 1 && <Menu.Divider />,
|
|
])}
|
|
|
|
{!navbarRight.user_is_anonymous && [
|
|
<Menu.Divider key="user-divider" />,
|
|
<Menu.ItemGroup key="user-section" title={t('User')}>
|
|
{navbarRight.user_profile_url && (
|
|
<Menu.Item key="profile">
|
|
<a href={navbarRight.user_profile_url}>{t('Profile')}</a>
|
|
</Menu.Item>
|
|
)}
|
|
{navbarRight.user_info_url && (
|
|
<Menu.Item key="info">
|
|
<a href={navbarRight.user_info_url}>{t('Info')}</a>
|
|
</Menu.Item>
|
|
)}
|
|
<Menu.Item key="logout">
|
|
<a href={navbarRight.user_logout_url}>{t('Logout')}</a>
|
|
</Menu.Item>
|
|
</Menu.ItemGroup>,
|
|
]}
|
|
{(navbarRight.version_string || navbarRight.version_sha) && [
|
|
<Menu.Divider key="version-info-divider" />,
|
|
<Menu.ItemGroup key="about-section" title={t('About')}>
|
|
<div className="about-section">
|
|
{navbarRight.show_watermark && (
|
|
<div css={versionInfoStyles}>
|
|
{t('Powered by Apache Superset')}
|
|
</div>
|
|
)}
|
|
{navbarRight.version_string && (
|
|
<div css={versionInfoStyles}>
|
|
Version: {navbarRight.version_string}
|
|
</div>
|
|
)}
|
|
{navbarRight.version_sha && (
|
|
<div css={versionInfoStyles}>
|
|
SHA: {navbarRight.version_sha}
|
|
</div>
|
|
)}
|
|
{navbarRight.build_number && (
|
|
<div css={versionInfoStyles}>
|
|
Build: {navbarRight.build_number}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</Menu.ItemGroup>,
|
|
]}
|
|
</SubMenu>
|
|
{navbarRight.show_language_picker && (
|
|
<LanguagePicker
|
|
locale={navbarRight.locale}
|
|
languages={navbarRight.languages}
|
|
/>
|
|
)}
|
|
</Menu>
|
|
{navbarRight.documentation_url && (
|
|
<StyledAnchor
|
|
href={navbarRight.documentation_url}
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
title={t('Documentation')}
|
|
>
|
|
<i className="fa fa-question" />
|
|
|
|
</StyledAnchor>
|
|
)}
|
|
{navbarRight.bug_report_url && (
|
|
<StyledAnchor
|
|
href={navbarRight.bug_report_url}
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
title={t('Report a bug')}
|
|
>
|
|
<i className="fa fa-bug" />
|
|
</StyledAnchor>
|
|
)}
|
|
{navbarRight.user_is_anonymous && (
|
|
<StyledAnchor href={navbarRight.user_login_url}>
|
|
<i className="fa fa-fw fa-sign-in" />
|
|
{t('Login')}
|
|
</StyledAnchor>
|
|
)}
|
|
</StyledDiv>
|
|
);
|
|
};
|
|
|
|
export default RightMenu;
|