Skip to content
Snippets Groups Projects
Commit a382ed7d authored by Atte Keinänen's avatar Atte Keinänen
Browse files

Button reorganization

parent 03bd0d76
No related branches found
No related tags found
No related merge requests found
......@@ -5,18 +5,24 @@ import ReactDOM from "react-dom";
import AggregationWidget from './AggregationWidget.jsx';
import BreakoutWidget from './BreakoutWidget.jsx';
import DataSelector from './DataSelector.jsx';
import ExtendedOptions from "./ExtendedOptions.jsx";
import FilterList from './filters/FilterList.jsx';
import FilterPopover from './filters/FilterPopover.jsx';
import Icon from "metabase/components/Icon.jsx";
import IconBorder from 'metabase/components/IconBorder.jsx';
import PopoverWithTrigger from "metabase/components/PopoverWithTrigger.jsx";
import { duration } from "metabase/lib/formatting";
import Query from "metabase/lib/query";
import MetabaseSettings from "metabase/lib/settings";
import cx from "classnames";
import _ from "underscore";
import AddButton from "metabase/components/AddButton";
import QueryModeButton from "metabase/query_builder/components/QueryModeButton";
import ButtonBar from "metabase/components/ButtonBar";
import QueryDownloadWidget from "metabase/query_builder/components/QueryDownloadWidget";
import QuestionEmbedWidget from "metabase/query_builder/containers/QuestionEmbedWidget";
import {REFRESH_TOOLTIP_THRESHOLD} from "metabase/query_builder/components/QueryVisualization";
import RunButton from "metabase/query_builder/components/RunButton";
import Tooltip from "metabase/components/Tooltip";
export default class CardEditor extends Component {
......@@ -229,7 +235,7 @@ export default class CardEditor extends Component {
renderDataSection() {
return (
<div className={"GuiBuilder-section GuiBuilder-data flex align-center arrow-right"}>
<div className="GuiBuilder-section GuiBuilder-data flex align-center arrow-right">
<span className="GuiBuilder-section-label Query-label">Data</span>
{ this.props.features.data ?
<DataSelector
......@@ -264,19 +270,91 @@ export default class CardEditor extends Component {
);
}
renderViewSection() {
renderMetricSection = () => {
const { features } = this.props;
if (!features.aggregation && !features.breakout) {
return;
}
return this.renderAggregation();
};
renderButtons = () => {
// NOTE: Most of stuff is replicated from QueryVisualization header
const { isResultDirty, isAdmin, card, result, setQueryModeFn, tableMetadata, isRunnable, isRunning, runQuery, cancelQuery } = this.props;
const isSaved = card.id != null;
const isPublicLinksEnabled = MetabaseSettings.get("public_sharing");
const isEmbeddingEnabled = MetabaseSettings.get("embedding");
const getQueryModeButton = () =>
<QueryModeButton
key="queryModeToggle"
mode={card.dataset_query.type}
allowNativeToQuery={false}
allowQueryToNative={false}
/*allowNativeToQuery={isNew && !isDirty}
allowQueryToNative={tableMetadata ?
// if a table is selected, only enable if user has native write permissions for THAT database
tableMetadata.db && tableMetadata.db.native_permissions === "write" :
// if no table is selected, only enable if user has native write permissions for ANY database
_.any(databases, (db) => db.native_permissions === "write")
}*/
nativeForm={result && result.data && result.data.native_form}
onSetMode={setQueryModeFn}
tableMetadata={tableMetadata}
/>;
const getQueryDownloadWidget = () =>
<QueryDownloadWidget
key="querydownload"
className="hide sm-show"
card={card}
result={result}
/>;
const getQueryEmbedWidget = () =>
<QuestionEmbedWidget key="questionembed" className="hide sm-show" card={card} />;
const getRunButton = () => {
const runQueryByIgnoringCache = () => runQuery(null, { ignoreCache: true });
let runButtonTooltip;
if (!isResultDirty && result && result.cached && result.average_execution_time > REFRESH_TOOLTIP_THRESHOLD) {
runButtonTooltip = `This question will take approximately ${duration(result.average_execution_time)} to refresh`;
}
return (
<Tooltip key="runbutton" tooltip={runButtonTooltip}>
<RunButton
isRunnable={isRunnable}
isDirty={isResultDirty}
isRunning={isRunning}
onRun={runQueryByIgnoringCache}
onCancel={cancelQuery}
/>
</Tooltip>
)
}
const queryHasCleanResult = !isResultDirty && result && !result.error;
const isEmbeddable = isSaved && (
(isPublicLinksEnabled && (isAdmin || card.public_uuid)) ||
(isEmbeddingEnabled && isAdmin)
);
const buttons = [
getQueryModeButton(),
isEmbeddable && getQueryEmbedWidget(),
queryHasCleanResult && getQueryDownloadWidget(),
getRunButton()
].filter(_.isObject);
return (
<div className="GuiBuilder-section GuiBuilder-view flex align-center px1 pr2" ref="viewSection">
<span className="GuiBuilder-section-label Query-label">View</span>
{this.renderAggregation()}
</div>
<ButtonBar buttons={buttons.map(b => [b])} className="borderless pr1 mr2" />
);
}
};
renderGroupedBySection() {
const { features } = this.props;
......@@ -319,20 +397,29 @@ export default class CardEditor extends Component {
}
return (
<div className={cx("GuiBuilder rounded shadowed", { "GuiBuilder--expand": this.state.expanded, disabled: readOnly })} ref="guiBuilder">
<div className="GuiBuilder-row flex">
{this.renderDataSection()}
{this.renderFilterSection()}
<div className={cx("GuiBuilder rounded shadowed flex", {
"GuiBuilder--expand": this.state.expanded,
disabled: readOnly
})} ref="guiBuilder">
<div className="GuiBuilder-section flex-full flex align-center px1 pr2" ref="viewSection">
{this.renderMetricSection()}
</div>
<div className="GuiBuilder-row flex flex-full">
{this.renderViewSection()}
{this.renderGroupedBySection()}
<div className="flex-full"></div>
{this.props.children}
<ExtendedOptions
{...this.props}
/>
<div className="GuiBuilder-section flex align-center justify-end">
{this.renderButtons()}
</div>
{/*<div className="GuiBuilder-row flex">
{this.renderDataSection()}
{this.renderFilterSection()}
</div>
<div className="GuiBuilder-row flex flex-full">
{this.renderMetricSection()}
{this.renderGroupedBySection()}
<div className="flex-full"></div>
{this.props.children}
<ExtendedOptions
{...this.props}
/>
</div>*/}
</div>
);
}
......
......@@ -2,8 +2,6 @@ import React, { Component } from "react";
import PropTypes from "prop-types";
import { Link } from "react-router";
import QueryModeButton from "./QueryModeButton.jsx";
import ActionButton from 'metabase/components/ActionButton.jsx';
import AddToDashSelectDashModal from 'metabase/containers/AddToDashSelectDashModal.jsx';
import ButtonBar from "metabase/components/ButtonBar.jsx";
......@@ -30,7 +28,6 @@ import cx from "classnames";
import _ from "underscore";
import Button from "metabase/components/Button";
export default class CardHeader extends Component {
constructor(props, context) {
super(props, context);
......@@ -166,10 +163,11 @@ export default class CardHeader extends Component {
};
getHeaderButtons = () => {
const { card ,isNew, isDirty, isEditing, tableMetadata, databases } = this.props;
const { card ,isNew, isDirty, isEditing, databases } = this.props;
const database = _.findWhere(databases, { id: card && card.dataset_query && card.dataset_query.database });
const SaveNewCardButton = () =>
// Don't treat as functional component due to refs
const getSaveNewCardButton = () =>
<ModalWithTrigger
form
key="save"
......@@ -225,7 +223,8 @@ export default class CardHeader extends Component {
const DeleteCardButton = () =>
<ArchiveQuestionModal questionId={this.props.card.id}/>;
const MoveQuestionToCollectionButton = () =>
// Don't treat as functional component due to refs
const getMoveQuestionToCollectionButton = () =>
<ModalWithTrigger
ref="move"
key="move"
......@@ -267,7 +266,8 @@ export default class CardHeader extends Component {
</span>
</Tooltip>;
const SaveNewCardAndAddToDashboardButton = () =>
// Don't treat as functional component due to refs
const getSaveNewCardAndAddToDashboardButton = () =>
<Tooltip key="addtodashsave" tooltip="Add to dashboard">
<ModalWithTrigger
ref="addToDashSaveModal"
......@@ -292,7 +292,8 @@ export default class CardHeader extends Component {
</ModalWithTrigger>
</Tooltip>;
const HistoryRevisionsButton = () =>
// Don't treat as functional component due to refs
const getHistoryRevisionsButton = () =>
<Tooltip key="history" tooltip="Revision history">
<ModalWithTrigger
ref="cardHistory"
......@@ -310,24 +311,8 @@ export default class CardHeader extends Component {
</ModalWithTrigger>
</Tooltip>;
const QueryModeToggleButton = () =>
<QueryModeButton
key="queryModeToggle"
mode={this.props.card.dataset_query.type}
allowNativeToQuery={isNew && !isDirty}
allowQueryToNative={tableMetadata ?
// if a table is selected, only enable if user has native write permissions for THAT database
tableMetadata.db && tableMetadata.db.native_permissions === "write" :
// if no table is selected, only enable if user has native write permissions for ANY database
_.any(databases, (db) => db.native_permissions === "write")
}
nativeForm={this.props.result && this.props.result.data && this.props.result.data.native_form}
onSetMode={this.props.setQueryModeFn}
tableMetadata={tableMetadata}
/>;
const DataReferenceButton = () => {
const dataReferenceButtonClasses = cx('mr1 transition-color', {
const dataReferenceButtonClasses = cx('transition-color', {
'text-brand': this.props.isShowingDataReference,
'text-brand-hover': !this.state.isShowingDataReference
});
......@@ -353,14 +338,14 @@ export default class CardHeader extends Component {
if (this.state.recentlySaved) {
return [ <ConfirmationOfSavedCard /> ];
} else {
return [ <EditCardButton /> ];
return [ <EditCardButton key="edit" /> ];
}
} else {
return [
<SaveEditedCardButton />,
<CancelEditingButton />,
<DeleteCardButton />,
<MoveQuestionToCollectionButton />
getMoveQuestionToCollectionButton()
]
}
} else {
......@@ -369,20 +354,20 @@ export default class CardHeader extends Component {
};
const buttons = [
isNewCardThatCanBeSaved && <SaveNewCardButton />,
isNewCardThatCanBeSaved && getSaveNewCardButton(),
...getPersistenceButtons(),
isNativeQueryWithParameters && <ToggleTemplateTagsEditorButton />,
isSaved && !isEditing && <AddSavedCardToDashboardButton />,
isNewCardThatCanBeSaved && <SaveNewCardAndAddToDashboardButton />,
isSaved && !isEditing && <AddSavedCardToDashboardButton key="addtodash" />,
isNewCardThatCanBeSaved && getSaveNewCardAndAddToDashboardButton(),
// TODO: See what kind of modifications the revisions feature requires
// isSaved && <HistoryRevisionsButton />,
isSaved && getHistoryRevisionsButton(),
// TODO: See how SQL will be supported and move this to the CardEditor banner
// <QueryModeToggleButton />,
<DataReferenceButton />
<DataReferenceButton key="datareference" />
].filter(_.isObject);
return (
<ButtonBar buttons={buttons.map(b => [b])} className="Header-buttonSection borderless" />
<ButtonBar buttons={buttons.map(b => [b])} className="mr2 pr1 borderless" />
);
};
......
......@@ -26,7 +26,7 @@ import cx from "classnames";
import _ from "underscore";
import moment from "moment";
const REFRESH_TOOLTIP_THRESHOLD = 30 * 1000; // 30 seconds
export const REFRESH_TOOLTIP_THRESHOLD = 30 * 1000; // 30 seconds
export default class QueryVisualization extends Component {
constructor(props, context) {
......
......@@ -48,6 +48,8 @@ import { push } from "react-router-redux";
import { MetabaseApi } from "metabase/services";
import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper";
import VisualizationSettings from "metabase/query_builder/components/VisualizationSettings";
import ActionsWidget from "metabase/query_builder/components/ActionsWidget";
function cellIsClickable(queryResult, rowIndex, columnIndex) {
if (!queryResult) return false;
......@@ -214,23 +216,29 @@ export default class CardBuilder extends Component {
</div>
<div ref="viz" id="react_qb_viz" className="flex z1" style={{ "transition": "opacity 0.25s ease-in-out" }}>
<QueryVisualization {...this.props} className="full wrapper mb2 z1" />
<QueryVisualization {...this.props} noHeader className="full wrapper mb2 z1" />
</div>
<div className="z4 absolute left bottom hide sm-show mb3 ml4">
{ !this.props.isObjectDetail && <VisualizationSettings ref="settings" {...this.props} /> }
</div>
{ ModeFooter &&
<ModeFooter {...this.props} className="flex-no-shrink" />
<ModeFooter {...this.props} className="flex-no-shrink" />
}
</div>
<div className={cx("SideDrawer hide sm-show", { "SideDrawer--show": showDrawer })}>
{ uiControls.isShowingDataReference &&
<DataReference {...this.props} onClose={() => this.props.toggleDataReference()} />
<DataReference {...this.props} onClose={() => this.props.toggleDataReference()} />
}
{ uiControls.isShowingTemplateTagsEditor &&
<TagEditorSidebar {...this.props} onClose={() => this.props.toggleTemplateTagsEditor()} />
<TagEditorSidebar {...this.props} onClose={() => this.props.toggleTemplateTagsEditor()} />
}
</div>
<ActionsWidget {...this.props} className="z2 absolute bottom right" />
</div>
}
</LoadingAndErrorWrapper>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment