mirror of
https://github.com/apache/superset.git
synced 2024-09-12 00:29:39 -04:00
refactor: Replace react-bootstrap MenuItems with Antd Menu (#11487)
* Remove MenuItem from CopyToClipboard * Refactor DateFilterControl * fixup! Remove MenuItem from CopyToClipboard * Remove console log * Refactor LanguagePicker * Refactor HeaderActionsDropdown * Remove dir with Menu component * Add imports to common/components/index * Fix after rebase
This commit is contained in:
parent
69810170f7
commit
ad98981d9d
@ -72,9 +72,10 @@ describe('Dashboard top-level controls', () => {
|
|||||||
.trigger('click', { force: true });
|
.trigger('click', { force: true });
|
||||||
|
|
||||||
// not allow dashboard level force refresh when any chart is loading
|
// not allow dashboard level force refresh when any chart is loading
|
||||||
cy.get('[data-test="refresh-dashboard-menu-item"]')
|
cy.get('[data-test="refresh-dashboard-menu-item"]').should(
|
||||||
.parent()
|
'have.class',
|
||||||
.should('have.class', 'disabled');
|
'ant-menu-item-disabled',
|
||||||
|
);
|
||||||
// not allow chart level force refresh when it is loading
|
// not allow chart level force refresh when it is loading
|
||||||
cy.get(`#slice_${mapId}-controls`)
|
cy.get(`#slice_${mapId}-controls`)
|
||||||
.next()
|
.next()
|
||||||
@ -84,25 +85,28 @@ describe('Dashboard top-level controls', () => {
|
|||||||
.should('have.class', 'disabled');
|
.should('have.class', 'disabled');
|
||||||
|
|
||||||
cy.wait(`@postJson_${mapId}_force`);
|
cy.wait(`@postJson_${mapId}_force`);
|
||||||
cy.get('[data-test="refresh-dashboard-menu-item"]')
|
cy.get('[data-test="refresh-dashboard-menu-item"]').should(
|
||||||
.parent()
|
'not.have.class',
|
||||||
.not('have.class', 'disabled');
|
'ant-menu-item-disabled',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow dashboard level force refresh', () => {
|
it('should allow dashboard level force refresh', () => {
|
||||||
// when charts are not start loading, for example, under a secondary tab,
|
// when charts are not start loading, for example, under a secondary tab,
|
||||||
// should allow force refresh
|
// should allow force refresh
|
||||||
cy.get('[data-test="more-horiz"]').click();
|
cy.get('[data-test="more-horiz"]').click();
|
||||||
cy.get('[data-test="refresh-dashboard-menu-item"]')
|
cy.get('[data-test="refresh-dashboard-menu-item"]').should(
|
||||||
.parent()
|
'not.have.class',
|
||||||
.not('have.class', 'disabled');
|
'ant-menu-item-disabled',
|
||||||
|
);
|
||||||
|
|
||||||
// wait the all dash finish loading.
|
// wait the all dash finish loading.
|
||||||
cy.wait(sliceRequests);
|
cy.wait(sliceRequests);
|
||||||
cy.get('[data-test="refresh-dashboard-menu-item"]').click();
|
cy.get('[data-test="refresh-dashboard-menu-item"]').click();
|
||||||
cy.get('[data-test="refresh-dashboard-menu-item"]')
|
cy.get('[data-test="refresh-dashboard-menu-item"]').should(
|
||||||
.parent()
|
'have.class',
|
||||||
.should('have.class', 'disabled');
|
'ant-menu-item-disabled',
|
||||||
|
);
|
||||||
|
|
||||||
// wait all charts force refreshed
|
// wait all charts force refreshed
|
||||||
cy.wait(forceRefreshRequests, { responseTimeout: 15000 }).then(xhrs => {
|
cy.wait(forceRefreshRequests, { responseTimeout: 15000 }).then(xhrs => {
|
||||||
@ -115,8 +119,9 @@ describe('Dashboard top-level controls', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
cy.get('[data-test="more-horiz"]').click();
|
cy.get('[data-test="more-horiz"]').click();
|
||||||
cy.get('[data-test="refresh-dashboard-menu-item"]')
|
cy.get('[data-test="refresh-dashboard-menu-item"]').should(
|
||||||
.parent()
|
'not.have.class',
|
||||||
.not('have.class', 'disabled');
|
'ant-menu-item-disabled',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import { DropdownButton, MenuItem } from 'react-bootstrap';
|
import { DropdownButton } from 'react-bootstrap';
|
||||||
|
import { Menu } from 'src/common/components';
|
||||||
import RefreshIntervalModal from 'src/dashboard/components/RefreshIntervalModal';
|
import RefreshIntervalModal from 'src/dashboard/components/RefreshIntervalModal';
|
||||||
import URLShortLinkModal from 'src/components/URLShortLinkModal';
|
import URLShortLinkModal from 'src/components/URLShortLinkModal';
|
||||||
import HeaderActionsDropdown from 'src/dashboard/components/HeaderActionsDropdown';
|
import HeaderActionsDropdown from 'src/dashboard/components/HeaderActionsDropdown';
|
||||||
@ -72,9 +73,9 @@ describe('HeaderActionsDropdown', () => {
|
|||||||
expect(wrapper.find(SaveModal)).not.toExist();
|
expect(wrapper.find(SaveModal)).not.toExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render four MenuItems', () => {
|
it('should render five Menu items', () => {
|
||||||
const wrapper = setup(overrideProps);
|
const wrapper = setup(overrideProps);
|
||||||
expect(wrapper.find(MenuItem)).toHaveLength(4);
|
expect(wrapper.find(Menu.Item)).toHaveLength(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render the RefreshIntervalModal', () => {
|
it('should render the RefreshIntervalModal', () => {
|
||||||
@ -106,9 +107,9 @@ describe('HeaderActionsDropdown', () => {
|
|||||||
expect(wrapper.find(SaveModal)).toExist();
|
expect(wrapper.find(SaveModal)).toExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render four MenuItems', () => {
|
it('should render six Menu items', () => {
|
||||||
const wrapper = setup(overrideProps);
|
const wrapper = setup(overrideProps);
|
||||||
expect(wrapper.find(MenuItem)).toHaveLength(4);
|
expect(wrapper.find(Menu.Item)).toHaveLength(6);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render the RefreshIntervalModal', () => {
|
it('should render the RefreshIntervalModal', () => {
|
||||||
@ -140,9 +141,9 @@ describe('HeaderActionsDropdown', () => {
|
|||||||
expect(wrapper.find(SaveModal)).toExist();
|
expect(wrapper.find(SaveModal)).toExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render three MenuItems', () => {
|
it('should render seven MenuItems', () => {
|
||||||
const wrapper = setup(overrideProps);
|
const wrapper = setup(overrideProps);
|
||||||
expect(wrapper.find(MenuItem)).toHaveLength(3);
|
expect(wrapper.find(Menu.Item)).toHaveLength(7);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render the RefreshIntervalModal', () => {
|
it('should render the RefreshIntervalModal', () => {
|
||||||
|
@ -33,8 +33,10 @@ export {
|
|||||||
DatePicker,
|
DatePicker,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
Empty,
|
Empty,
|
||||||
|
Input,
|
||||||
Modal,
|
Modal,
|
||||||
Popover,
|
Popover,
|
||||||
|
Select,
|
||||||
Skeleton,
|
Skeleton,
|
||||||
Tabs,
|
Tabs,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Tooltip, OverlayTrigger, MenuItem } from 'react-bootstrap';
|
import { Tooltip, OverlayTrigger } from 'react-bootstrap';
|
||||||
import { t } from '@superset-ui/core';
|
import { t } from '@superset-ui/core';
|
||||||
import withToasts from 'src/messageToasts/enhancers/withToasts';
|
import withToasts from 'src/messageToasts/enhancers/withToasts';
|
||||||
|
|
||||||
@ -28,7 +28,6 @@ const propTypes = {
|
|||||||
onCopyEnd: PropTypes.func,
|
onCopyEnd: PropTypes.func,
|
||||||
shouldShowText: PropTypes.bool,
|
shouldShowText: PropTypes.bool,
|
||||||
text: PropTypes.string,
|
text: PropTypes.string,
|
||||||
inMenu: PropTypes.bool,
|
|
||||||
wrapped: PropTypes.bool,
|
wrapped: PropTypes.bool,
|
||||||
tooltipText: PropTypes.string,
|
tooltipText: PropTypes.string,
|
||||||
addDangerToast: PropTypes.func.isRequired,
|
addDangerToast: PropTypes.func.isRequired,
|
||||||
@ -38,7 +37,6 @@ const defaultProps = {
|
|||||||
copyNode: <span>Copy</span>,
|
copyNode: <span>Copy</span>,
|
||||||
onCopyEnd: () => {},
|
onCopyEnd: () => {},
|
||||||
shouldShowText: true,
|
shouldShowText: true,
|
||||||
inMenu: false,
|
|
||||||
wrapped: true,
|
wrapped: true,
|
||||||
tooltipText: t('Copy to clipboard'),
|
tooltipText: t('Copy to clipboard'),
|
||||||
};
|
};
|
||||||
@ -160,27 +158,6 @@ class CopyToClipboard extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderInMenu() {
|
|
||||||
return (
|
|
||||||
<OverlayTrigger
|
|
||||||
placement="top"
|
|
||||||
overlay={this.renderTooltip()}
|
|
||||||
trigger={['hover']}
|
|
||||||
>
|
|
||||||
<MenuItem>
|
|
||||||
<span
|
|
||||||
role="button"
|
|
||||||
tabIndex={0}
|
|
||||||
onClick={this.onClick}
|
|
||||||
onMouseOut={this.onMouseOut}
|
|
||||||
>
|
|
||||||
{this.props.copyNode}
|
|
||||||
</span>
|
|
||||||
</MenuItem>
|
|
||||||
</OverlayTrigger>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTooltip() {
|
renderTooltip() {
|
||||||
return (
|
return (
|
||||||
<Tooltip id="copy-to-clipboard-tooltip">{this.tooltipText()}</Tooltip>
|
<Tooltip id="copy-to-clipboard-tooltip">{this.tooltipText()}</Tooltip>
|
||||||
@ -188,11 +165,11 @@ class CopyToClipboard extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { wrapped, inMenu } = this.props;
|
const { wrapped } = this.props;
|
||||||
if (!wrapped) {
|
if (!wrapped) {
|
||||||
return this.renderNotWrapped();
|
return this.renderNotWrapped();
|
||||||
}
|
}
|
||||||
return inMenu ? this.renderInMenu() : this.renderLink();
|
return this.renderLink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MenuItem } from 'react-bootstrap';
|
import { Menu } from 'src/common/components';
|
||||||
import NavDropdown from 'src/components/NavDropdown';
|
import NavDropdown from 'src/components/NavDropdown';
|
||||||
|
|
||||||
export interface Languages {
|
export interface Languages {
|
||||||
@ -46,17 +46,23 @@ export default function LanguagePicker({
|
|||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{Object.keys(languages).map(langKey =>
|
<Menu
|
||||||
langKey === locale ? null : (
|
onSelect={({ key }) => {
|
||||||
<MenuItem key={langKey} href={languages[langKey].url}>
|
window.location.href = languages[key].url;
|
||||||
{' '}
|
}}
|
||||||
<div className="f16">
|
>
|
||||||
<i className={`flag ${languages[langKey].flag}`} /> -{' '}
|
{Object.keys(languages).map(langKey =>
|
||||||
{languages[langKey].name}
|
langKey === locale ? null : (
|
||||||
</div>
|
<Menu.Item key={langKey}>
|
||||||
</MenuItem>
|
{' '}
|
||||||
),
|
<div className="f16">
|
||||||
)}
|
<i className={`flag ${languages[langKey].flag}`} /> -{' '}
|
||||||
|
{languages[langKey].name}
|
||||||
|
</div>
|
||||||
|
</Menu.Item>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</Menu>
|
||||||
</NavDropdown>
|
</NavDropdown>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,6 @@ class CssEditor extends React.PureComponent {
|
|||||||
<ModalTrigger
|
<ModalTrigger
|
||||||
triggerNode={this.props.triggerNode}
|
triggerNode={this.props.triggerNode}
|
||||||
modalTitle={t('CSS')}
|
modalTitle={t('CSS')}
|
||||||
isMenuItem
|
|
||||||
modalBody={
|
modalBody={
|
||||||
<div>
|
<div>
|
||||||
{this.renderTemplateSelector()}
|
{this.renderTemplateSelector()}
|
||||||
|
@ -20,8 +20,9 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { SupersetClient, t } from '@superset-ui/core';
|
import { SupersetClient, t } from '@superset-ui/core';
|
||||||
import { DropdownButton, MenuItem } from 'react-bootstrap';
|
import { DropdownButton } from 'react-bootstrap';
|
||||||
|
|
||||||
|
import { Menu } from 'src/common/components';
|
||||||
import Icon from 'src/components/Icon';
|
import Icon from 'src/components/Icon';
|
||||||
|
|
||||||
import CssEditor from './CssEditor';
|
import CssEditor from './CssEditor';
|
||||||
@ -71,6 +72,18 @@ const defaultProps = {
|
|||||||
refreshWarning: null,
|
refreshWarning: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MENU_KEYS = {
|
||||||
|
SAVE_MODAL: 'save-modal',
|
||||||
|
SHARE_DASHBOARD: 'share-dashboard',
|
||||||
|
REFRESH_DASHBOARD: 'refresh-dashboard',
|
||||||
|
AUTOREFRESH_MODAL: 'autorefresh-modal',
|
||||||
|
SET_FILTER_MAPPING: 'set-filter-mapping',
|
||||||
|
EDIT_PROPERTIES: 'edit-properties',
|
||||||
|
EDIT_CSS: 'edit-css',
|
||||||
|
DOWNLOAD_AS_IMAGE: 'download-as-image',
|
||||||
|
TOGGLE_FULLSCREEN: 'toggle-fullscreen',
|
||||||
|
};
|
||||||
|
|
||||||
class HeaderActionsDropdown extends React.PureComponent {
|
class HeaderActionsDropdown extends React.PureComponent {
|
||||||
static discardChanges() {
|
static discardChanges() {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
@ -85,6 +98,7 @@ class HeaderActionsDropdown extends React.PureComponent {
|
|||||||
|
|
||||||
this.changeCss = this.changeCss.bind(this);
|
this.changeCss = this.changeCss.bind(this);
|
||||||
this.changeRefreshInterval = this.changeRefreshInterval.bind(this);
|
this.changeRefreshInterval = this.changeRefreshInterval.bind(this);
|
||||||
|
this.handleMenuClick = this.handleMenuClick.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillMount() {
|
UNSAFE_componentWillMount() {
|
||||||
@ -119,12 +133,40 @@ class HeaderActionsDropdown extends React.PureComponent {
|
|||||||
this.props.startPeriodicRender(refreshInterval * 1000);
|
this.props.startPeriodicRender(refreshInterval * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleMenuClick({ key, domEvent }) {
|
||||||
|
switch (key) {
|
||||||
|
case MENU_KEYS.REFRESH_DASHBOARD:
|
||||||
|
this.props.forceRefreshAllCharts();
|
||||||
|
break;
|
||||||
|
case MENU_KEYS.EDIT_PROPERTIES:
|
||||||
|
this.props.showPropertiesModal();
|
||||||
|
break;
|
||||||
|
case MENU_KEYS.DOWNLOAD_AS_IMAGE:
|
||||||
|
downloadAsImage('.dashboard', this.props.dashboardTitle)(domEvent);
|
||||||
|
break;
|
||||||
|
case MENU_KEYS.TOGGLE_FULLSCREEN: {
|
||||||
|
const hasStandalone = window.location.search.includes(
|
||||||
|
'standalone=true',
|
||||||
|
);
|
||||||
|
const url = getDashboardUrl(
|
||||||
|
window.location.pathname,
|
||||||
|
getActiveFilters(),
|
||||||
|
window.location.hash,
|
||||||
|
!hasStandalone,
|
||||||
|
);
|
||||||
|
window.location.replace(url);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
dashboardTitle,
|
dashboardTitle,
|
||||||
dashboardId,
|
dashboardId,
|
||||||
dashboardInfo,
|
dashboardInfo,
|
||||||
forceRefreshAllCharts,
|
|
||||||
refreshFrequency,
|
refreshFrequency,
|
||||||
shouldPersistRefreshFrequency,
|
shouldPersistRefreshFrequency,
|
||||||
editMode,
|
editMode,
|
||||||
@ -155,105 +197,102 @@ class HeaderActionsDropdown extends React.PureComponent {
|
|||||||
style={{ border: 'none', padding: 0, marginLeft: '4px' }}
|
style={{ border: 'none', padding: 0, marginLeft: '4px' }}
|
||||||
pullRight
|
pullRight
|
||||||
>
|
>
|
||||||
{userCanSave && (
|
<Menu onClick={this.handleMenuClick} selectable={false}>
|
||||||
<>
|
{userCanSave && (
|
||||||
<SaveModal
|
<Menu.Item key={MENU_KEYS.SAVE_MODAL}>
|
||||||
addSuccessToast={this.props.addSuccessToast}
|
<SaveModal
|
||||||
addDangerToast={this.props.addDangerToast}
|
addSuccessToast={this.props.addSuccessToast}
|
||||||
dashboardId={dashboardId}
|
addDangerToast={this.props.addDangerToast}
|
||||||
dashboardTitle={dashboardTitle}
|
dashboardId={dashboardId}
|
||||||
dashboardInfo={dashboardInfo}
|
dashboardTitle={dashboardTitle}
|
||||||
saveType={SAVE_TYPE_NEWDASHBOARD}
|
dashboardInfo={dashboardInfo}
|
||||||
layout={layout}
|
saveType={SAVE_TYPE_NEWDASHBOARD}
|
||||||
expandedSlices={expandedSlices}
|
layout={layout}
|
||||||
refreshFrequency={refreshFrequency}
|
expandedSlices={expandedSlices}
|
||||||
shouldPersistRefreshFrequency={shouldPersistRefreshFrequency}
|
refreshFrequency={refreshFrequency}
|
||||||
lastModifiedTime={lastModifiedTime}
|
shouldPersistRefreshFrequency={shouldPersistRefreshFrequency}
|
||||||
customCss={customCss}
|
lastModifiedTime={lastModifiedTime}
|
||||||
colorNamespace={colorNamespace}
|
customCss={customCss}
|
||||||
colorScheme={colorScheme}
|
colorNamespace={colorNamespace}
|
||||||
onSave={onSave}
|
colorScheme={colorScheme}
|
||||||
isMenuItem
|
onSave={onSave}
|
||||||
triggerNode={
|
triggerNode={
|
||||||
<span data-test="save-as-menu-item">{t('Save as')}</span>
|
<span data-test="save-as-menu-item">{t('Save as')}</span>
|
||||||
}
|
}
|
||||||
canOverwrite={userCanEdit}
|
canOverwrite={userCanEdit}
|
||||||
/>
|
/>
|
||||||
</>
|
</Menu.Item>
|
||||||
)}
|
|
||||||
<URLShortLinkModal
|
|
||||||
url={getDashboardUrl(
|
|
||||||
window.location.pathname,
|
|
||||||
getActiveFilters(),
|
|
||||||
window.location.hash,
|
|
||||||
)}
|
)}
|
||||||
emailSubject={emailSubject}
|
<Menu.Item key={MENU_KEYS.SHARE_DASHBOARD}>
|
||||||
emailContent={emailBody}
|
<URLShortLinkModal
|
||||||
addDangerToast={this.props.addDangerToast}
|
url={getDashboardUrl(
|
||||||
isMenuItem
|
|
||||||
triggerNode={<span>{t('Share dashboard')}</span>}
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
data-test="refresh-dashboard-menu-item"
|
|
||||||
onClick={forceRefreshAllCharts}
|
|
||||||
disabled={isLoading}
|
|
||||||
>
|
|
||||||
{t('Refresh dashboard')}
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem divider />
|
|
||||||
<RefreshIntervalModal
|
|
||||||
refreshFrequency={refreshFrequency}
|
|
||||||
refreshLimit={refreshLimit}
|
|
||||||
refreshWarning={refreshWarning}
|
|
||||||
onChange={this.changeRefreshInterval}
|
|
||||||
editMode={editMode}
|
|
||||||
triggerNode={<span>{t('Set auto-refresh interval')}</span>}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{editMode && (
|
|
||||||
<>
|
|
||||||
<FilterScopeModal
|
|
||||||
className="m-r-5"
|
|
||||||
triggerNode={
|
|
||||||
<MenuItem bsSize="small">{t('Set filter mapping')}</MenuItem>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<MenuItem onClick={this.props.showPropertiesModal}>
|
|
||||||
{t('Edit dashboard properties')}
|
|
||||||
</MenuItem>
|
|
||||||
<CssEditor
|
|
||||||
triggerNode={<span>{t('Edit CSS')}</span>}
|
|
||||||
initialCss={this.state.css}
|
|
||||||
templates={this.state.cssTemplates}
|
|
||||||
onChange={this.changeCss}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!editMode && (
|
|
||||||
<MenuItem onClick={downloadAsImage('.dashboard', dashboardTitle)}>
|
|
||||||
{t('Download as image')}
|
|
||||||
</MenuItem>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!editMode && (
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
const hasStandalone = window.location.search.includes(
|
|
||||||
'standalone=true',
|
|
||||||
);
|
|
||||||
const url = getDashboardUrl(
|
|
||||||
window.location.pathname,
|
window.location.pathname,
|
||||||
getActiveFilters(),
|
getActiveFilters(),
|
||||||
window.location.hash,
|
window.location.hash,
|
||||||
!hasStandalone,
|
)}
|
||||||
);
|
emailSubject={emailSubject}
|
||||||
window.location.replace(url);
|
emailContent={emailBody}
|
||||||
}}
|
addDangerToast={this.props.addDangerToast}
|
||||||
|
triggerNode={<span>{t('Share dashboard')}</span>}
|
||||||
|
/>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item
|
||||||
|
key={MENU_KEYS.REFRESH_DASHBOARD}
|
||||||
|
data-test="refresh-dashboard-menu-item"
|
||||||
|
disabled={isLoading}
|
||||||
>
|
>
|
||||||
{t('Toggle FullScreen')}
|
{t('Refresh dashboard')}
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
)}
|
<Menu.Divider />
|
||||||
|
<Menu.Item key={MENU_KEYS.AUTOREFRESH_MODAL}>
|
||||||
|
<RefreshIntervalModal
|
||||||
|
refreshFrequency={refreshFrequency}
|
||||||
|
refreshLimit={refreshLimit}
|
||||||
|
refreshWarning={refreshWarning}
|
||||||
|
onChange={this.changeRefreshInterval}
|
||||||
|
editMode={editMode}
|
||||||
|
triggerNode={<span>{t('Set auto-refresh interval')}</span>}
|
||||||
|
/>
|
||||||
|
</Menu.Item>
|
||||||
|
|
||||||
|
{editMode && (
|
||||||
|
<Menu.Item key={MENU_KEYS.SET_FILTER_MAPPING}>
|
||||||
|
<FilterScopeModal
|
||||||
|
className="m-r-5"
|
||||||
|
triggerNode={t('Set filter mapping')}
|
||||||
|
/>
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{editMode && (
|
||||||
|
<Menu.Item key={MENU_KEYS.EDIT_PROPERTIES}>
|
||||||
|
{t('Edit dashboard properties')}
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{editMode && (
|
||||||
|
<Menu.Item key={MENU_KEYS.EDIT_CSS}>
|
||||||
|
<CssEditor
|
||||||
|
triggerNode={<span>{t('Edit CSS')}</span>}
|
||||||
|
initialCss={this.state.css}
|
||||||
|
templates={this.state.cssTemplates}
|
||||||
|
onChange={this.changeCss}
|
||||||
|
/>
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!editMode && (
|
||||||
|
<Menu.Item key={MENU_KEYS.DOWNLOAD_AS_IMAGE}>
|
||||||
|
{t('Download as image')}
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!editMode && (
|
||||||
|
<Menu.Item key={MENU_KEYS.TOGGLE_FULLSCREEN}>
|
||||||
|
{t('Toggle FullScreen')}
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
</Menu>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,6 @@ class RefreshIntervalModal extends React.PureComponent {
|
|||||||
<ModalTrigger
|
<ModalTrigger
|
||||||
ref={this.modalRef}
|
ref={this.modalRef}
|
||||||
triggerNode={this.props.triggerNode}
|
triggerNode={this.props.triggerNode}
|
||||||
isMenuItem
|
|
||||||
modalTitle={t('Refresh Interval')}
|
modalTitle={t('Refresh Interval')}
|
||||||
modalBody={
|
modalBody={
|
||||||
<div>
|
<div>
|
||||||
|
@ -41,14 +41,12 @@ const propTypes = {
|
|||||||
colorNamespace: PropTypes.string,
|
colorNamespace: PropTypes.string,
|
||||||
colorScheme: PropTypes.string,
|
colorScheme: PropTypes.string,
|
||||||
onSave: PropTypes.func.isRequired,
|
onSave: PropTypes.func.isRequired,
|
||||||
isMenuItem: PropTypes.bool,
|
|
||||||
canOverwrite: PropTypes.bool.isRequired,
|
canOverwrite: PropTypes.bool.isRequired,
|
||||||
refreshFrequency: PropTypes.number.isRequired,
|
refreshFrequency: PropTypes.number.isRequired,
|
||||||
lastModifiedTime: PropTypes.number.isRequired,
|
lastModifiedTime: PropTypes.number.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
isMenuItem: false,
|
|
||||||
saveType: SAVE_TYPE_OVERWRITE,
|
saveType: SAVE_TYPE_OVERWRITE,
|
||||||
colorNamespace: undefined,
|
colorNamespace: undefined,
|
||||||
colorScheme: undefined,
|
colorScheme: undefined,
|
||||||
@ -157,7 +155,6 @@ class SaveModal extends React.PureComponent {
|
|||||||
return (
|
return (
|
||||||
<ModalTrigger
|
<ModalTrigger
|
||||||
ref={this.setModalRef}
|
ref={this.setModalRef}
|
||||||
isMenuItem={this.props.isMenuItem}
|
|
||||||
triggerNode={this.props.triggerNode}
|
triggerNode={this.props.triggerNode}
|
||||||
modalTitle={t('Save Dashboard')}
|
modalTitle={t('Save Dashboard')}
|
||||||
modalBody={
|
modalBody={
|
||||||
|
@ -19,16 +19,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
DropdownButton,
|
|
||||||
FormControl,
|
FormControl,
|
||||||
FormGroup,
|
FormGroup,
|
||||||
InputGroup,
|
InputGroup,
|
||||||
MenuItem,
|
|
||||||
OverlayTrigger,
|
OverlayTrigger,
|
||||||
Radio,
|
Radio,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from 'react-bootstrap';
|
} from 'react-bootstrap';
|
||||||
import Popover from 'src/common/components/Popover';
|
import Popover from 'src/common/components/Popover';
|
||||||
|
import { Select, Input } from 'src/common/components';
|
||||||
import Button from 'src/components/Button';
|
import Button from 'src/components/Button';
|
||||||
import Datetime from 'react-datetime';
|
import Datetime from 'react-datetime';
|
||||||
import 'react-datetime/css/react-datetime.css';
|
import 'react-datetime/css/react-datetime.css';
|
||||||
@ -387,15 +386,13 @@ class DateFilterControl extends React.Component {
|
|||||||
|
|
||||||
renderPopover() {
|
renderPopover() {
|
||||||
const grainOptions = TIME_GRAIN_OPTIONS.map(grain => (
|
const grainOptions = TIME_GRAIN_OPTIONS.map(grain => (
|
||||||
<MenuItem
|
<Select.Option
|
||||||
onSelect={value => this.setCustomRange('grain', value)}
|
|
||||||
key={grain}
|
key={grain}
|
||||||
eventKey={grain}
|
value={grain}
|
||||||
active={grain === this.state.grain}
|
active={grain === this.state.grain}
|
||||||
fullWidth={false}
|
|
||||||
>
|
>
|
||||||
{grain}
|
{grain}
|
||||||
</MenuItem>
|
</Select.Option>
|
||||||
));
|
));
|
||||||
const timeFrames = COMMON_TIME_FRAMES.map(timeFrame => {
|
const timeFrames = COMMON_TIME_FRAMES.map(timeFrame => {
|
||||||
const nextState = getStateFromCommonTimeFrame(timeFrame);
|
const nextState = getStateFromCommonTimeFrame(timeFrame);
|
||||||
@ -425,6 +422,7 @@ class DateFilterControl extends React.Component {
|
|||||||
</Styles>
|
</Styles>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="filter-popover"
|
id="filter-popover"
|
||||||
@ -453,66 +451,45 @@ class DateFilterControl extends React.Component {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="clearfix centered"
|
className="clearfix centered"
|
||||||
style={{ marginTop: '12px' }}
|
style={{ marginTop: '8px', display: 'flex' }}
|
||||||
>
|
>
|
||||||
<div
|
<div className="input-inline">
|
||||||
style={{ width: '60px', marginTop: '-4px' }}
|
<Select
|
||||||
className="input-inline"
|
value={this.state.rel}
|
||||||
>
|
onSelect={value => this.setCustomRange('rel', value)}
|
||||||
<DropdownButton
|
|
||||||
bsSize="small"
|
|
||||||
componentClass={InputGroup.Button}
|
|
||||||
id="input-dropdown-rel"
|
|
||||||
title={this.state.rel}
|
|
||||||
onFocus={this.setTypeCustomRange}
|
onFocus={this.setTypeCustomRange}
|
||||||
>
|
>
|
||||||
<MenuItem
|
<Select.Option value={RELATIVE_TIME_OPTIONS.LAST}>
|
||||||
onSelect={value => this.setCustomRange('rel', value)}
|
|
||||||
key={RELATIVE_TIME_OPTIONS.LAST}
|
|
||||||
eventKey={RELATIVE_TIME_OPTIONS.LAST}
|
|
||||||
active={this.state.rel === RELATIVE_TIME_OPTIONS.LAST}
|
|
||||||
>
|
|
||||||
Last
|
Last
|
||||||
</MenuItem>
|
</Select.Option>
|
||||||
<MenuItem
|
<Select.Option value={RELATIVE_TIME_OPTIONS.NEXT}>
|
||||||
onSelect={value => this.setCustomRange('rel', value)}
|
|
||||||
key={RELATIVE_TIME_OPTIONS.NEXT}
|
|
||||||
eventKey={RELATIVE_TIME_OPTIONS.NEXT}
|
|
||||||
active={this.state.rel === RELATIVE_TIME_OPTIONS.NEXT}
|
|
||||||
>
|
|
||||||
Next
|
Next
|
||||||
</MenuItem>
|
</Select.Option>
|
||||||
</DropdownButton>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{ width: '60px', marginTop: '-4px' }}
|
style={{ width: '60px' }}
|
||||||
className="input-inline m-l-5 m-r-3"
|
className="input-inline m-l-5 m-r-3"
|
||||||
>
|
>
|
||||||
<FormControl
|
<Input
|
||||||
bsSize="small"
|
|
||||||
type="text"
|
type="text"
|
||||||
onChange={event =>
|
onChange={event =>
|
||||||
this.setCustomRange('num', event.target.value)
|
this.setCustomRange('num', event.target.value)
|
||||||
}
|
}
|
||||||
onFocus={this.setTypeCustomRange}
|
onFocus={this.setTypeCustomRange}
|
||||||
onKeyPress={this.onEnter}
|
onPressEnter={this.close}
|
||||||
value={this.state.num}
|
value={this.state.num}
|
||||||
style={{ height: '30px' }}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="input-inline">
|
||||||
style={{ width: '90px', marginTop: '-4px' }}
|
<Select
|
||||||
className="input-inline"
|
value={this.state.grain}
|
||||||
>
|
|
||||||
<DropdownButton
|
|
||||||
bsSize="small"
|
|
||||||
componentClass={InputGroup.Button}
|
|
||||||
id="input-dropdown-grain"
|
|
||||||
title={this.state.grain}
|
|
||||||
onFocus={this.setTypeCustomRange}
|
onFocus={this.setTypeCustomRange}
|
||||||
|
onSelect={value => this.setCustomRange('grain', value)}
|
||||||
|
dropdownMatchSelectWidth={false}
|
||||||
>
|
>
|
||||||
{grainOptions}
|
{grainOptions}
|
||||||
</DropdownButton>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PopoverSection>
|
</PopoverSection>
|
||||||
|
Loading…
Reference in New Issue
Block a user