Skip to content
Snippets Groups Projects
Unverified Commit 7d87d7cf authored by Oisin Coveney's avatar Oisin Coveney Committed by GitHub
Browse files

Split View into components (#48929)

parent c712c35c
No related branches found
Tags blah
No related merge requests found
/* eslint-disable react/prop-types */
import { Component } from "react";
import { connect } from "react-redux";
import { match } from "ts-pattern";
import { t } from "ttag";
......@@ -60,28 +60,121 @@ const fadeIn = {
transitionProperty: "opacity",
};
class View extends Component {
getLeftSidebar = () => {
const {
question,
result,
isShowingChartSettingsSidebar,
isShowingChartTypeSidebar,
onCloseChartSettings,
} = this.props;
if (isShowingChartSettingsSidebar) {
const {
question,
result,
addField,
initialChartSetting,
onReplaceAllVisualizationSettings,
onOpenChartType,
visualizationSettings,
showSidebarTitle,
} = this.props;
return (
const ViewHeaderContainer = props => {
const { question, onUnarchive, onMove, onDeletePermanently } = props;
const query = question.query();
const card = question.card();
const { isNative } = Lib.queryDisplayInfo(query);
const isNewQuestion = !isNative && Lib.sourceTableOrCardId(query) === null;
return (
<QueryBuilderViewHeaderContainer>
{card.archived && (
<ArchivedEntityBanner
name={card.name}
entityType={card.type}
canWrite={card.can_write}
canRestore={card.can_restore}
canDelete={card.can_delete}
onUnarchive={() => onUnarchive(question)}
onMove={collection => onMove(question, collection)}
onDeletePermanently={() => onDeletePermanently(card.id)}
/>
)}
<BorderedViewTitleHeader
{...props}
style={{
transition: "opacity 300ms linear",
opacity: isNewQuestion ? 0 : 1,
}}
/>
{/*This is used so that the New Question Header is unmounted after the animation*/}
<Transition mounted={isNewQuestion} transition={fadeIn} duration={300}>
{style => <NewQuestionHeader className={CS.spread} style={style} />}
</Transition>
</QueryBuilderViewHeaderContainer>
);
};
const ViewMainContainer = props => {
const {
queryBuilderMode,
mode,
question,
showLeftSidebar,
showRightSidebar,
parameters,
setParameterValue,
isLiveResizable,
updateQuestion,
} = props;
if (queryBuilderMode === "notebook") {
// we need to render main only in view mode
return;
}
const queryMode = mode && mode.queryMode();
const { isNative } = Lib.queryDisplayInfo(question.query());
const isSidebarOpen = showLeftSidebar || showRightSidebar;
return (
<QueryBuilderMain
isSidebarOpen={isSidebarOpen}
data-testid="query-builder-main"
>
{isNative ? (
<ViewNativeQueryEditor {...props} />
) : (
<StyledSyncedParametersList
parameters={parameters}
setParameterValue={setParameterValue}
commitImmediately
/>
)}
<StyledDebouncedFrame enabled={!isLiveResizable}>
<QueryVisualization
{...props}
noHeader
className={CS.spread}
mode={queryMode}
/>
</StyledDebouncedFrame>
<TimeseriesChrome
question={question}
updateQuestion={updateQuestion}
className={CS.flexNoShrink}
/>
<ViewFooter className={CS.flexNoShrink} />
</QueryBuilderMain>
);
};
const ViewLeftSidebarContainer = ({
question,
result,
isShowingChartSettingsSidebar,
isShowingChartTypeSidebar,
onCloseChartSettings,
addField,
initialChartSetting,
onReplaceAllVisualizationSettings,
onOpenChartType,
visualizationSettings,
showSidebarTitle,
}) =>
match({
isShowingChartSettingsSidebar,
isShowingChartTypeSidebar,
})
.with(
{
isShowingChartSettingsSidebar: true,
},
() => (
<ChartSettingsSidebar
question={question}
result={result}
......@@ -93,493 +186,497 @@ class View extends Component {
showSidebarTitle={showSidebarTitle}
onClose={onCloseChartSettings}
/>
);
}
),
)
.with(
{
isShowingChartTypeSidebar: true,
},
() => <ChartTypeSidebar question={question} result={result} />,
)
.otherwise(() => null);
const ViewNativeQueryEditor = props => {
const {
question,
height,
isDirty,
isNativeEditorOpen,
card,
setParameterValueToDefault,
onSetDatabaseId,
} = props;
const legacyQuery = question.legacyQuery();
// Normally, when users open native models,
// they open an ad-hoc GUI question using the model as a data source
// (using the `/dataset` endpoint instead of the `/card/:id/query`)
// However, users without data permission open a real model as they can't use the `/dataset` endpoint
// So the model is opened as an underlying native question and the query editor becomes visible
// This check makes it hide the editor in this particular case
// More details: https://github.com/metabase/metabase/pull/20161
const { isEditable } = Lib.queryDisplayInfo(question.query());
if (question.type() === "model" && !isEditable) {
return null;
}
if (isShowingChartTypeSidebar) {
return <ChartTypeSidebar question={question} result={result} />;
}
return (
<NativeQueryEditorContainer>
<NativeQueryEditor
{...props}
query={legacyQuery}
viewHeight={height}
isOpen={legacyQuery.isEmpty() || isDirty}
isInitiallyOpen={isNativeEditorOpen}
datasetQuery={card && card.dataset_query}
setParameterValueToDefault={setParameterValueToDefault}
onSetDatabaseId={onSetDatabaseId}
/>
</NativeQueryEditorContainer>
);
};
return null;
};
getRightSidebarForStructuredQuery = () => {
const {
question,
timelines,
isShowingSummarySidebar,
isShowingTimelineSidebar,
isShowingQuestionInfoSidebar,
isShowingQuestionSettingsSidebar,
updateQuestion,
visibleTimelineEventIds,
selectedTimelineEventIds,
xDomain,
showTimelineEvents,
hideTimelineEvents,
selectTimelineEvents,
deselectTimelineEvents,
onOpenModal,
onCloseSummary,
onCloseTimelines,
onCloseQuestionInfo,
onSave,
} = this.props;
const isSaved = question.isSaved();
if (isShowingSummarySidebar) {
const query = question.query();
return (
const ViewRightSidebarContainer = props => {
const {
question,
deselectTimelineEvents,
hideTimelineEvents,
isShowingQuestionInfoSidebar,
isShowingQuestionSettingsSidebar,
isShowingSummarySidebar,
isShowingTimelineSidebar,
onCloseQuestionInfo,
onCloseSummary,
onCloseTimelines,
onOpenModal,
onSave,
selectTimelineEvents,
selectedTimelineEventIds,
showTimelineEvents,
timelines,
updateQuestion,
visibleTimelineEventIds,
xDomain,
} = props;
const { isNative } = Lib.queryDisplayInfo(question.query());
return !isNative ? (
<StructuredQueryRightSidebar
deselectTimelineEvents={deselectTimelineEvents}
hideTimelineEvents={hideTimelineEvents}
isShowingQuestionInfoSidebar={isShowingQuestionInfoSidebar}
isShowingQuestionSettingsSidebar={isShowingQuestionSettingsSidebar}
isShowingSummarySidebar={isShowingSummarySidebar}
isShowingTimelineSidebar={isShowingTimelineSidebar}
onCloseQuestionInfo={onCloseQuestionInfo}
onCloseSummary={onCloseSummary}
onCloseTimelines={onCloseTimelines}
onOpenModal={onOpenModal}
onSave={onSave}
question={question}
selectTimelineEvents={selectTimelineEvents}
selectedTimelineEventIds={selectedTimelineEventIds}
showTimelineEvents={showTimelineEvents}
timelines={timelines}
updateQuestion={updateQuestion}
visibleTimelineEventIds={visibleTimelineEventIds}
xDomain={xDomain}
/>
) : (
<NativeQueryRightSidebar {...props} />
);
};
const StructuredQueryRightSidebar = ({
deselectTimelineEvents,
hideTimelineEvents,
isShowingQuestionInfoSidebar,
isShowingQuestionSettingsSidebar,
isShowingSummarySidebar,
isShowingTimelineSidebar,
onCloseQuestionInfo,
onCloseSummary,
onCloseTimelines,
onOpenModal,
onSave,
question,
selectTimelineEvents,
selectedTimelineEventIds,
showTimelineEvents,
timelines,
updateQuestion,
visibleTimelineEventIds,
xDomain,
}) =>
match({
isSaved: question.isSaved(),
isShowingSummarySidebar,
isShowingTimelineSidebar,
isShowingQuestionInfoSidebar,
isShowingQuestionSettingsSidebar,
})
.with(
{
isShowingSummarySidebar: true,
},
() => (
<SummarizeSidebar
query={query}
query={question.query()}
onQueryChange={nextQuery => {
const datesetQuery = Lib.toLegacyQuery(nextQuery);
const nextQuestion = question.setDatasetQuery(datesetQuery);
updateQuestion(nextQuestion.setDefaultDisplay(), { run: true });
updateQuestion(nextQuestion.setDefaultDisplay(), {
run: true,
});
}}
onClose={onCloseSummary}
/>
);
}
if (isShowingTimelineSidebar) {
return (
<TimelineSidebar
question={question}
timelines={timelines}
visibleTimelineEventIds={visibleTimelineEventIds}
selectedTimelineEventIds={selectedTimelineEventIds}
xDomain={xDomain}
onShowTimelineEvents={showTimelineEvents}
onHideTimelineEvents={hideTimelineEvents}
onSelectTimelineEvents={selectTimelineEvents}
onDeselectTimelineEvents={deselectTimelineEvents}
onOpenModal={onOpenModal}
onClose={onCloseTimelines}
/>
);
}
if (isSaved && isShowingQuestionInfoSidebar) {
return (
),
)
.with({ isShowingTimelineSidebar: true }, () => (
<TimelineSidebar
question={question}
timelines={timelines}
visibleTimelineEventIds={visibleTimelineEventIds}
selectedTimelineEventIds={selectedTimelineEventIds}
xDomain={xDomain}
onShowTimelineEvents={showTimelineEvents}
onHideTimelineEvents={hideTimelineEvents}
onSelectTimelineEvents={selectTimelineEvents}
onDeselectTimelineEvents={deselectTimelineEvents}
onOpenModal={onOpenModal}
onClose={onCloseTimelines}
/>
))
.with(
{
isSaved: true,
isShowingQuestionInfoSidebar: true,
},
() => (
<QuestionInfoSidebar
question={question}
onSave={onSave}
onClose={onCloseQuestionInfo}
/>
);
}
if (isSaved && isShowingQuestionSettingsSidebar) {
return <QuestionSettingsSidebar question={question} />;
}
return null;
};
getRightSidebarForNativeQuery = () => {
const {
isShowingTemplateTagsEditor,
isShowingDataReference,
isShowingSnippetSidebar,
isShowingTimelineSidebar,
isShowingQuestionInfoSidebar,
isShowingQuestionSettingsSidebar,
toggleTemplateTagsEditor,
toggleDataReference,
toggleSnippetSidebar,
showTimelineEvent,
showTimelineEvents,
hideTimelineEvents,
selectTimelineEvents,
deselectTimelineEvents,
onCloseTimelines,
onCloseQuestionInfo,
onSave,
question,
} = this.props;
if (isShowingTemplateTagsEditor) {
return (
<TagEditorSidebar
{...this.props}
query={question.legacyQuery()}
onClose={toggleTemplateTagsEditor}
/>
);
}
if (isShowingDataReference) {
return <DataReference {...this.props} onClose={toggleDataReference} />;
}
if (isShowingSnippetSidebar) {
return <SnippetSidebar {...this.props} onClose={toggleSnippetSidebar} />;
}
if (isShowingTimelineSidebar) {
return (
<TimelineSidebar
{...this.props}
onShowTimelineEvent={showTimelineEvent}
onShowTimelineEvents={showTimelineEvents}
onHideTimelineEvents={hideTimelineEvents}
onSelectTimelineEvents={selectTimelineEvents}
onDeselectTimelineEvents={deselectTimelineEvents}
onClose={onCloseTimelines}
/>
);
}
if (isShowingQuestionInfoSidebar) {
return (
<QuestionInfoSidebar
question={question}
onSave={onSave}
onClose={onCloseQuestionInfo}
/>
);
}
if (isShowingQuestionSettingsSidebar) {
return <QuestionSettingsSidebar question={question} />;
}
return null;
};
getRightSidebar = () => {
const { question } = this.props;
const { isNative } = Lib.queryDisplayInfo(question.query());
),
)
.with(
{
isSaved: true,
isShowingQuestionSettingsSidebar: true,
},
() => <QuestionSettingsSidebar question={question} />,
)
.otherwise(() => null);
const NativeQueryRightSidebar = props => {
const {
question,
toggleTemplateTagsEditor,
toggleDataReference,
toggleSnippetSidebar,
showTimelineEvent,
showTimelineEvents,
hideTimelineEvents,
selectTimelineEvents,
deselectTimelineEvents,
onCloseTimelines,
onSave,
onCloseQuestionInfo,
isShowingTemplateTagsEditor,
isShowingDataReference,
isShowingSnippetSidebar,
isShowingTimelineSidebar,
isShowingQuestionInfoSidebar,
isShowingQuestionSettingsSidebar,
} = props;
return match({
isShowingTemplateTagsEditor,
isShowingDataReference,
isShowingSnippetSidebar,
isShowingTimelineSidebar,
isShowingQuestionInfoSidebar,
isShowingQuestionSettingsSidebar,
})
.with({ isShowingTemplateTagsEditor: true }, () => (
<TagEditorSidebar
{...props}
query={question.legacyQuery()}
onClose={toggleTemplateTagsEditor}
/>
))
.with({ isShowingDataReference: true }, () => (
<DataReference {...props} onClose={toggleDataReference} />
))
.with({ isShowingSnippetSidebar: true }, () => (
<SnippetSidebar {...props} onClose={toggleSnippetSidebar} />
))
.with({ isShowingTimelineSidebar: true }, () => (
<TimelineSidebar
{...props}
onShowTimelineEvent={showTimelineEvent}
onShowTimelineEvents={showTimelineEvents}
onHideTimelineEvents={hideTimelineEvents}
onSelectTimelineEvents={selectTimelineEvents}
onDeselectTimelineEvents={deselectTimelineEvents}
onClose={onCloseTimelines}
/>
))
.with({ isShowingQuestionInfoSidebar: true }, () => (
<QuestionInfoSidebar
question={question}
onSave={onSave}
onClose={onCloseQuestionInfo}
/>
))
.with({ isShowingQuestionSettingsSidebar: true }, () => (
<QuestionSettingsSidebar question={question} />
))
.otherwise(() => null);
};
return !isNative
? this.getRightSidebarForStructuredQuery()
: this.getRightSidebarForNativeQuery();
};
const View = props => {
const {
question,
result,
rawSeries,
databases,
isShowingNewbModal,
isShowingTimelineSidebar,
queryBuilderMode,
closeQbNewbModal,
onDismissToast,
onConfirmToast,
isShowingToaster,
isHeaderVisible,
updateQuestion,
reportTimezone,
readOnly,
isDirty,
isRunning,
isRunnable,
isResultDirty,
hasVisualizeButton,
runQuestionQuery,
cancelQuery,
setQueryBuilderMode,
runDirtyQuestionQuery,
isShowingQuestionInfoSidebar,
isShowingQuestionSettingsSidebar,
cancelQuestionChanges,
onCreate,
onSave,
onChangeLocation,
questionAlerts,
user,
modal,
modalContext,
card,
onCloseModal,
onOpenModal,
originalQuestion,
isShowingChartSettingsSidebar,
isShowingChartTypeSidebar,
onCloseChartSettings,
addField,
initialChartSetting,
onReplaceAllVisualizationSettings,
onOpenChartType,
visualizationSettings,
showSidebarTitle,
isShowingSummarySidebar,
isShowingTemplateTagsEditor,
isShowingDataReference,
isShowingSnippetSidebar,
} = props;
// if we don't have a question at all or no databases then we are initializing, so keep it simple
if (!question || !databases) {
return <LoadingAndErrorWrapper className={CS.fullHeight} loading />;
}
renderHeader = () => {
const { question, onUnarchive, onMove, onDeletePermanently } = this.props;
const query = question.query();
const card = question.card();
const { isNative } = Lib.queryDisplayInfo(query);
const query = question.query();
const { isNative } = Lib.queryDisplayInfo(question.query());
const isNewQuestion = !isNative && Lib.sourceTableOrCardId(query) === null;
const isNewQuestion = !isNative && Lib.sourceTableOrCardId(query) === null;
const isModel = question.type() === "model";
const isMetric = question.type() === "metric";
if ((isModel || isMetric) && queryBuilderMode === "dataset") {
return (
<QueryBuilderViewHeaderContainer>
{card.archived && (
<ArchivedEntityBanner
name={card.name}
entityType={card.type}
canWrite={card.can_write}
canRestore={card.can_restore}
canDelete={card.can_delete}
onUnarchive={() => onUnarchive(question)}
onMove={collection => onMove(question, collection)}
onDeletePermanently={() => onDeletePermanently(card.id)}
<>
{isModel && <DatasetEditor {...props} />}
{isMetric && (
<MetricEditor
question={question}
result={result}
rawSeries={rawSeries}
reportTimezone={reportTimezone}
isDirty={isDirty}
isResultDirty={isResultDirty}
isRunning={isRunning}
onChange={updateQuestion}
onCreate={async question => {
await onCreate(question);
setQueryBuilderMode("view");
}}
onSave={async question => {
await onSave(question);
setQueryBuilderMode("view");
}}
onCancel={question => {
if (question.isSaved()) {
cancelQuestionChanges();
runDirtyQuestionQuery();
setQueryBuilderMode("view");
} else {
onChangeLocation("/");
}
}}
onRunQuery={runQuestionQuery}
onCancelQuery={cancelQuery}
/>
)}
<BorderedViewTitleHeader
{...this.props}
style={{
transition: "opacity 300ms linear",
opacity: isNewQuestion ? 0 : 1,
}}
/>
{/*This is used so that the New Question Header is unmounted after the animation*/}
<Transition mounted={isNewQuestion} transition={fadeIn} duration={300}>
{style => <NewQuestionHeader className={CS.spread} style={style} />}
</Transition>
</QueryBuilderViewHeaderContainer>
);
};
renderNativeQueryEditor = () => {
const {
question,
card,
height,
isDirty,
isNativeEditorOpen,
setParameterValueToDefault,
onSetDatabaseId,
} = this.props;
const legacyQuery = question.legacyQuery();
// Normally, when users open native models,
// they open an ad-hoc GUI question using the model as a data source
// (using the `/dataset` endpoint instead of the `/card/:id/query`)
// However, users without data permission open a real model as they can't use the `/dataset` endpoint
// So the model is opened as an underlying native question and the query editor becomes visible
// This check makes it hide the editor in this particular case
// More details: https://github.com/metabase/metabase/pull/20161
const { isEditable } = Lib.queryDisplayInfo(question.query());
if (question.type() === "model" && !isEditable) {
return null;
}
return (
<NativeQueryEditorContainer>
<NativeQueryEditor
{...this.props}
query={legacyQuery}
viewHeight={height}
isOpen={legacyQuery.isEmpty() || isDirty}
isInitiallyOpen={isNativeEditorOpen}
datasetQuery={card && card.dataset_query}
setParameterValueToDefault={setParameterValueToDefault}
onSetDatabaseId={onSetDatabaseId}
<QueryModals
questionAlerts={questionAlerts}
user={user}
onSave={onSave}
onCreate={onCreate}
updateQuestion={updateQuestion}
modal={modal}
modalContext={modalContext}
card={card}
question={question}
onCloseModal={onCloseModal}
onOpenModal={onOpenModal}
setQueryBuilderMode={setQueryBuilderMode}
originalQuestion={originalQuestion}
onChangeLocation={onChangeLocation}
/>
</NativeQueryEditorContainer>
</>
);
};
renderMain = ({ leftSidebar, rightSidebar }) => {
const {
question,
mode,
parameters,
isLiveResizable,
setParameterValue,
queryBuilderMode,
} = this.props;
if (queryBuilderMode === "notebook") {
// we need to render main only in view mode
return;
}
const queryMode = mode && mode.queryMode();
const { isNative } = Lib.queryDisplayInfo(question.query());
const isSidebarOpen = leftSidebar || rightSidebar;
}
return (
<QueryBuilderMain
isSidebarOpen={isSidebarOpen}
data-testid="query-builder-main"
const isNotebookContainerOpen =
isNewQuestion || queryBuilderMode === "notebook";
const showLeftSidebar =
isShowingChartSettingsSidebar || isShowingChartTypeSidebar;
const showRightSidebar =
isShowingTimelineSidebar ||
isShowingQuestionInfoSidebar ||
isShowingQuestionSettingsSidebar ||
(!isNative && isShowingSummarySidebar) ||
(isNative &&
(isShowingTemplateTagsEditor ||
isShowingDataReference ||
isShowingSnippetSidebar));
const rightSidebarWidth = match({
isShowingTimelineSidebar,
isShowingQuestionInfoSidebar,
isShowingQuestionSettingsSidebar,
})
.with({ isShowingTimelineSidebar: true }, () => SIDEBAR_SIZES.TIMELINE)
.with({ isShowingQuestionInfoSidebar: true }, () => 0)
.with({ isShowingQuestionSettingsSidebar: true }, () => 0)
.otherwise(() => SIDEBAR_SIZES.NORMAL);
return (
<div className={CS.fullHeight}>
<QueryBuilderViewRoot
className={QueryBuilderS.QueryBuilder}
data-testid="query-builder-root"
>
{isNative ? (
this.renderNativeQueryEditor()
) : (
<StyledSyncedParametersList
parameters={parameters}
setParameterValue={setParameterValue}
commitImmediately
/>
)}
{isHeaderVisible && <ViewHeaderContainer {...props} />}
<StyledDebouncedFrame enabled={!isLiveResizable}>
<QueryVisualization
{...this.props}
noHeader
className={CS.spread}
mode={queryMode}
/>
</StyledDebouncedFrame>
<TimeseriesChrome
question={this.props.question}
updateQuestion={this.props.updateQuestion}
className={CS.flexNoShrink}
/>
<ViewFooter className={CS.flexNoShrink} />
</QueryBuilderMain>
);
};
render() {
const {
question,
result,
rawSeries,
databases,
isShowingNewbModal,
isShowingTimelineSidebar,
queryBuilderMode,
closeQbNewbModal,
onDismissToast,
onConfirmToast,
isShowingToaster,
isHeaderVisible,
updateQuestion,
reportTimezone,
readOnly,
isDirty,
isRunning,
isRunnable,
isResultDirty,
hasVisualizeButton,
runQuestionQuery,
cancelQuery,
setQueryBuilderMode,
runDirtyQuestionQuery,
isShowingQuestionInfoSidebar,
isShowingQuestionSettingsSidebar,
cancelQuestionChanges,
onCreate,
onSave,
onChangeLocation,
} = this.props;
// if we don't have a question at all or no databases then we are initializing, so keep it simple
if (!question || !databases) {
return <LoadingAndErrorWrapper className={CS.fullHeight} loading />;
}
const query = question.query();
const { isNative } = Lib.queryDisplayInfo(question.query());
const isNewQuestion = !isNative && Lib.sourceTableOrCardId(query) === null;
const isModel = question.type() === "model";
const isMetric = question.type() === "metric";
if ((isModel || isMetric) && queryBuilderMode === "dataset") {
return (
<>
{isModel && <DatasetEditor {...this.props} />}
{isMetric && (
<MetricEditor
question={question}
result={result}
rawSeries={rawSeries}
<QueryBuilderContentContainer>
{!isNative && (
<NotebookContainer
isOpen={isNotebookContainerOpen}
updateQuestion={updateQuestion}
reportTimezone={reportTimezone}
readOnly={readOnly}
question={question}
isDirty={isDirty}
isRunnable={isRunnable}
isResultDirty={isResultDirty}
isRunning={isRunning}
onChange={updateQuestion}
onCreate={async question => {
await onCreate(question);
setQueryBuilderMode("view");
}}
onSave={async question => {
await onSave(question);
setQueryBuilderMode("view");
}}
onCancel={question => {
if (question.isSaved()) {
cancelQuestionChanges();
runDirtyQuestionQuery();
setQueryBuilderMode("view");
} else {
onChangeLocation("/");
}
}}
onRunQuery={runQuestionQuery}
onCancelQuery={cancelQuery}
hasVisualizeButton={hasVisualizeButton}
runQuestionQuery={runQuestionQuery}
setQueryBuilderMode={setQueryBuilderMode}
/>
)}
<QueryModals
questionAlerts={this.props.questionAlerts}
user={this.props.user}
onSave={this.props.onSave}
onCreate={this.props.onCreate}
updateQuestion={this.props.updateQuestion}
modal={this.props.modal}
modalContext={this.props.modalContext}
card={this.props.card}
question={this.props.question}
onCloseModal={this.props.onCloseModal}
onOpenModal={this.props.onOpenModal}
setQueryBuilderMode={this.props.setQueryBuilderMode}
originalQuestion={this.props.originalQuestion}
onChangeLocation={this.props.onChangeLocation}
/>
</>
);
}
const isNotebookContainerOpen =
isNewQuestion || queryBuilderMode === "notebook";
const leftSidebar = this.getLeftSidebar();
const rightSidebar = this.getRightSidebar();
const rightSidebarWidth = match({
isShowingTimelineSidebar,
isShowingQuestionInfoSidebar,
isShowingQuestionSettingsSidebar,
})
.with({ isShowingTimelineSidebar: true }, () => SIDEBAR_SIZES.TIMELINE)
.with({ isShowingQuestionInfoSidebar: true }, () => 0)
.with({ isShowingQuestionSettingsSidebar: true }, () => 0)
.otherwise(() => SIDEBAR_SIZES.NORMAL);
return (
<div className={CS.fullHeight}>
<QueryBuilderViewRoot
className={QueryBuilderS.QueryBuilder}
data-testid="query-builder-root"
>
{isHeaderVisible && this.renderHeader()}
<QueryBuilderContentContainer>
{!isNative && (
<NotebookContainer
isOpen={isNotebookContainerOpen}
updateQuestion={updateQuestion}
reportTimezone={reportTimezone}
readOnly={readOnly}
question={question}
isDirty={isDirty}
isRunnable={isRunnable}
isResultDirty={isResultDirty}
hasVisualizeButton={hasVisualizeButton}
runQuestionQuery={runQuestionQuery}
setQueryBuilderMode={setQueryBuilderMode}
/>
)}
<ViewSidebar side="left" isOpen={!!leftSidebar}>
{leftSidebar}
</ViewSidebar>
{this.renderMain({ leftSidebar, rightSidebar })}
<ViewSidebar
side="right"
isOpen={!!rightSidebar}
width={rightSidebarWidth}
>
{rightSidebar}
</ViewSidebar>
</QueryBuilderContentContainer>
</QueryBuilderViewRoot>
{isShowingNewbModal && (
<SavedQuestionIntroModal
question={question}
isShowingNewbModal={isShowingNewbModal}
onClose={() => closeQbNewbModal()}
<ViewSidebar side="left" isOpen={showLeftSidebar}>
<ViewLeftSidebarContainer
question={question}
result={result}
isShowingChartSettingsSidebar={isShowingChartSettingsSidebar}
isShowingChartTypeSidebar={isShowingChartTypeSidebar}
onCloseChartSettings={onCloseChartSettings}
addField={addField}
initialChartSetting={initialChartSetting}
onReplaceAllVisualizationSettings={
onReplaceAllVisualizationSettings
}
onOpenChartType={onOpenChartType}
visualizationSettings={visualizationSettings}
showSidebarTitle={showSidebarTitle}
/>
</ViewSidebar>
<ViewMainContainer
showLeftSidebar={showLeftSidebar}
showRightSidebar={showRightSidebar}
{...props}
/>
)}
<QueryModals
questionAlerts={this.props.questionAlerts}
user={this.props.user}
onSave={this.props.onSave}
onCreate={this.props.onCreate}
updateQuestion={this.props.updateQuestion}
modal={this.props.modal}
modalContext={this.props.modalContext}
card={this.props.card}
question={this.props.question}
onCloseModal={this.props.onCloseModal}
onOpenModal={this.props.onOpenModal}
setQueryBuilderMode={this.props.setQueryBuilderMode}
originalQuestion={this.props.originalQuestion}
onChangeLocation={this.props.onChangeLocation}
/>
<Toaster
message={t`Would you like to be notified when this question is done loading?`}
isShown={isShowingToaster}
onDismiss={onDismissToast}
onConfirm={onConfirmToast}
fixed
<ViewSidebar
side="right"
isOpen={showRightSidebar}
width={rightSidebarWidth}
>
<ViewRightSidebarContainer {...props} />
</ViewSidebar>
</QueryBuilderContentContainer>
</QueryBuilderViewRoot>
{isShowingNewbModal && (
<SavedQuestionIntroModal
question={question}
isShowingNewbModal={isShowingNewbModal}
onClose={() => closeQbNewbModal()}
/>
</div>
);
}
}
)}
<QueryModals
questionAlerts={questionAlerts}
user={user}
onSave={onSave}
onCreate={onCreate}
updateQuestion={updateQuestion}
modal={modal}
modalContext={modalContext}
card={card}
question={question}
onCloseModal={onCloseModal}
onOpenModal={onOpenModal}
setQueryBuilderMode={setQueryBuilderMode}
originalQuestion={originalQuestion}
onChangeLocation={onChangeLocation}
/>
<Toaster
message={t`Would you like to be notified when this question is done loading?`}
isShown={isShowingToaster}
onDismiss={onDismissToast}
onConfirm={onConfirmToast}
fixed
/>
</div>
);
};
const mapDispatchToProps = dispatch => ({
onSetDatabaseId: id => dispatch(rememberLastUsedDatabase(id)),
......
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