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

Split and convert ViewFooter elements to TS (#47126)

parent bd2d8479
No related branches found
No related tags found
No related merge requests found
Showing
with 299 additions and 171 deletions
......@@ -12,7 +12,7 @@ import type {
VisualizationSettings,
} from "metabase-types/api";
type UseDownloadDataParams = {
export type UseDownloadDataParams = {
question: Question;
result: Dataset;
dashboardId?: DashboardId;
......
......@@ -4,27 +4,18 @@ import { t } from "ttag";
import { ViewFooterButton } from "metabase/components/ViewFooterButton";
import { PLUGIN_FEATURE_LEVEL_PERMISSIONS } from "metabase/plugins";
import { Flex, Popover } from "metabase/ui";
import type Question from "metabase-lib/v1/Question";
import type {
DashCardId,
DashboardId,
Dataset,
VisualizationSettings,
} from "metabase-types/api";
import type { Dataset } from "metabase-types/api";
import { QueryDownloadPopover } from "../QueryDownloadPopover";
import { useDownloadData } from "../QueryDownloadPopover/use-download-data";
import {
type UseDownloadDataParams,
useDownloadData,
} from "../QueryDownloadPopover/use-download-data";
interface QueryDownloadWidgetProps {
export type QueryDownloadWidgetProps = {
className?: string;
question: Question;
result: Dataset;
uuid?: string;
token?: string;
visualizationSettings?: VisualizationSettings;
dashcardId?: DashCardId;
dashboardId?: DashboardId;
}
} & Pick<UseDownloadDataParams, "question" | "result"> &
Partial<Omit<UseDownloadDataParams, "question" | "result">>;
const QueryDownloadWidget = ({
className,
......
......@@ -6,7 +6,7 @@ import type Question from "metabase-lib/v1/Question";
import { ToggleIcon, Well } from "./QuestionDisplayToggle.styled";
interface QuestionDisplayToggleProps {
export interface QuestionDisplayToggleProps {
className?: string;
question: Question;
isShowingRawTable: boolean;
......
// eslint-disable-next-line import/no-default-export -- deprecated usage
export { default } from "./QuestionDisplayToggle";
export {
default,
type QuestionDisplayToggleProps,
} from "./QuestionDisplayToggle";
......@@ -2,15 +2,18 @@ import { c } from "ttag";
import ErrorBoundary from "metabase/ErrorBoundary";
import { FixedSizeIcon, Flex, type FlexProps, Tooltip } from "metabase/ui";
import type { Dataset } from "metabase-types/api";
import { getAbbreviatedRelativeTimeStrings, getTimePassedSince } from "./utils";
export type QuestionLastUpdatedProps = {
result: Pick<Dataset, "cached">;
} & FlexProps;
export const QuestionLastUpdated = ({
result,
...flexProps
}: {
result: { cached?: string | null };
} & FlexProps) => {
}: QuestionLastUpdatedProps) => {
if (!result) {
return null;
}
......@@ -53,5 +56,5 @@ const QuestionLastUpdatedBody = ({
);
};
QuestionLastUpdated.shouldRender = ({ result }: { result: any }) =>
QuestionLastUpdated.shouldRender = ({ result }: QuestionLastUpdatedProps) =>
result && result.cached;
......@@ -191,13 +191,12 @@ const ConnectedQuestionRowCount = _.compose(
}),
)(QuestionRowCount);
function shouldRender({
result,
isObjectDetail,
}: {
export type QuestionRowCountOpts = {
result?: Dataset;
isObjectDetail: boolean;
}) {
};
function shouldRender({ result, isObjectDetail }: QuestionRowCountOpts) {
return result?.data && !isObjectDetail;
}
......
......@@ -43,7 +43,7 @@ import {
StyledDebouncedFrame,
StyledSyncedParametersList,
} from "./View.styled";
import ViewFooter from "./ViewFooter";
import { ViewFooter } from "./ViewFooter";
import ViewSidebar from "./ViewSidebar";
import ChartSettingsSidebar from "./sidebars/ChartSettingsSidebar";
import ChartTypeSidebar from "./sidebars/ChartTypeSidebar";
......@@ -356,7 +356,31 @@ class View extends Component {
updateQuestion={this.props.updateQuestion}
className={CS.flexNoShrink}
/>
<ViewFooter {...this.props} className={CS.flexNoShrink} />
<ViewFooter
question={this.props.question}
result={this.props.result}
isShowingChartTypeSidebar={this.props.isShowingChartTypeSidebar}
isShowingChartSettingsSidebar={
this.props.isShowingChartSettingsSidebar
}
isShowingRawTable={this.props.isShowingRawTable}
onOpenChartType={this.props.onOpenChartType}
onOpenModal={this.props.onOpenModal}
onCloseChartType={this.props.onCloseChartType}
onOpenChartSettings={this.props.onOpenChartSettings}
onCloseChartSettings={this.props.onCloseChartSettings}
setUIControls={this.props.setUIControls}
isObjectDetail={this.props.isObjectDetail}
questionAlerts={this.props.questionAlerts}
visualizationSettings={this.props.visualizationSettings}
canManageSubscriptions={this.props.canManageSubscriptions}
isVisualized={this.props.isVisualized}
isTimeseries={this.props.isTimeseries}
isShowingTimelineSidebar={this.props.isShowingTimelineSidebar}
onOpenTimelines={this.props.onOpenTimelines}
onCloseTimelines={this.props.onCloseTimelines}
className={CS.flexNoShrink}
/>
</QueryBuilderMain>
);
};
......
/* eslint-disable react/prop-types */
import cx from "classnames";
import { t } from "ttag";
import ButtonBar from "metabase/components/ButtonBar";
import CS from "metabase/css/core/index.css";
import QueryDownloadWidget from "metabase/query_builder/components/QueryDownloadWidget";
import { Group } from "metabase/ui";
import * as Lib from "metabase-lib";
import { ExecutionTime } from "./ExecutionTime";
import QuestionDisplayToggle from "./QuestionDisplayToggle";
import { QuestionLastUpdated } from "./QuestionLastUpdated/QuestionLastUpdated";
import QuestionRowCount from "./QuestionRowCount";
import QuestionTimelineWidget from "./QuestionTimelineWidget";
import ViewButton from "./ViewButton";
import { FooterButtonGroup, ViewFooterRoot } from "./ViewFooter.styled";
const ViewFooter = ({
question,
result,
className,
isShowingChartTypeSidebar,
isShowingChartSettingsSidebar,
isShowingRawTable,
onOpenChartType,
onCloseChartType,
onOpenChartSettings,
onCloseChartSettings,
setUIControls,
isObjectDetail,
visualizationSettings,
isVisualized,
isTimeseries,
isShowingTimelineSidebar,
onOpenTimelines,
onCloseTimelines,
}) => {
if (!result) {
return null;
}
const { isEditable } = Lib.queryDisplayInfo(question.query());
const hideChartSettings =
(result.error && !isEditable) || question.isArchived();
return (
<ViewFooterRoot
className={cx(className, CS.textMedium, CS.borderTop)}
data-testid="view-footer"
>
<ButtonBar
className={CS.flexFull}
left={[
!hideChartSettings && (
<FooterButtonGroup>
<ViewButton
medium
labelBreakpoint="sm"
data-testid="viz-type-button"
active={isShowingChartTypeSidebar}
onClick={
isShowingChartTypeSidebar
? () => onCloseChartType()
: () => onOpenChartType()
}
>
{t`Visualization`}
</ViewButton>
<ViewButton
active={isShowingChartSettingsSidebar}
icon="gear"
iconSize={16}
medium
onlyIcon
labelBreakpoint="sm"
data-testid="viz-settings-button"
onClick={
isShowingChartSettingsSidebar
? () => onCloseChartSettings()
: () => onOpenChartSettings()
}
/>
</FooterButtonGroup>
),
]}
center={
isVisualized && (
<QuestionDisplayToggle
key="viz-table-toggle"
className={CS.mx1}
question={question}
isShowingRawTable={isShowingRawTable}
onToggleRawTable={isShowingRawTable => {
setUIControls({ isShowingRawTable });
}}
/>
)
}
right={[
QuestionRowCount.shouldRender({
result,
isObjectDetail,
}) && <QuestionRowCount key="row_count" />,
ExecutionTime.shouldRender({ result }) && (
<ExecutionTime key="execution_time" time={result.running_time} />
),
<Group key="button-group" spacing="sm" noWrap>
{QuestionLastUpdated.shouldRender({ result }) && (
<QuestionLastUpdated
className={cx(CS.hide, CS.smShow)}
result={result}
/>
)}
{QueryDownloadWidget.shouldRender({ result }) && (
<QueryDownloadWidget
className={cx(CS.hide, CS.smShow)}
question={question}
result={result}
visualizationSettings={visualizationSettings}
dashcardId={question.card().dashcardId}
dashboardId={question.card().dashboardId}
/>
)}
{QuestionTimelineWidget.shouldRender({ isTimeseries }) && (
<QuestionTimelineWidget
className={cx(CS.hide, CS.smShow)}
isShowingTimelineSidebar={isShowingTimelineSidebar}
onOpenTimelines={onOpenTimelines}
onCloseTimelines={onCloseTimelines}
/>
)}
</Group>,
]}
/>
</ViewFooterRoot>
);
};
export default ViewFooter;
import CS from "metabase/css/core/index.css";
import type { QueryBuilderUIControls } from "metabase-types/store";
import type { QuestionDisplayToggleProps } from "../QuestionDisplayToggle";
import QuestionDisplayToggle from "../QuestionDisplayToggle";
export type CenterViewFooterButtonGroupProps = {
setUIControls: (uiControls: Partial<QueryBuilderUIControls>) => void;
} & Pick<QuestionDisplayToggleProps, "question" | "isShowingRawTable">;
export const CenterViewFooterButtonGroup = ({
question,
isShowingRawTable,
setUIControls,
}: CenterViewFooterButtonGroupProps) => (
<QuestionDisplayToggle
className={CS.mx1}
question={question}
isShowingRawTable={isShowingRawTable}
onToggleRawTable={isShowingRawTable => {
setUIControls({ isShowingRawTable });
}}
/>
);
import { t } from "ttag";
import ViewButton from "metabase/query_builder/components/view/ViewButton";
import { FooterButtonGroup } from "metabase/query_builder/components/view/ViewFooter.styled";
export type LeftViewFooterButtonGroupProps = {
isShowingChartTypeSidebar: boolean;
isShowingChartSettingsSidebar: boolean;
onCloseChartType: () => void;
onOpenChartType: () => void;
onCloseChartSettings: () => void;
onOpenChartSettings: () => void;
};
export const LeftViewFooterButtonGroup = ({
isShowingChartTypeSidebar,
isShowingChartSettingsSidebar,
onCloseChartType,
onOpenChartType,
onCloseChartSettings,
onOpenChartSettings,
}: LeftViewFooterButtonGroupProps) => (
<FooterButtonGroup>
<ViewButton
medium
labelBreakpoint="sm"
data-testid="viz-type-button"
active={isShowingChartTypeSidebar}
onClick={
isShowingChartTypeSidebar
? () => onCloseChartType()
: () => onOpenChartType()
}
>
{t`Visualization`}
</ViewButton>
<ViewButton
active={isShowingChartSettingsSidebar}
icon="gear"
iconSize={16}
medium
onlyIcon
labelBreakpoint="sm"
data-testid="viz-settings-button"
onClick={
isShowingChartSettingsSidebar
? () => onCloseChartSettings()
: () => onOpenChartSettings()
}
/>
</FooterButtonGroup>
);
import cx from "classnames";
import CS from "metabase/css/core/index.css";
import QueryDownloadWidget from "metabase/query_builder/components/QueryDownloadWidget";
import { Group } from "metabase/ui";
import type { QueryDownloadWidgetProps } from "../../QueryDownloadWidget/QueryDownloadWidget";
import { ExecutionTime } from "../ExecutionTime";
import {
QuestionLastUpdated,
type QuestionLastUpdatedProps,
} from "../QuestionLastUpdated/QuestionLastUpdated";
import QuestionRowCount from "../QuestionRowCount";
import type { QuestionRowCountOpts } from "../QuestionRowCount/QuestionRowCount";
import QuestionTimelineWidget from "../QuestionTimelineWidget";
import type {
QuestionTimelineWidgetOpts,
QuestionTimelineWidgetProps,
} from "../QuestionTimelineWidget/QuestionTimelineWidget";
export type RightViewFooterButtonGroupProps = QuestionTimelineWidgetProps &
QuestionTimelineWidgetOpts &
QueryDownloadWidgetProps &
QuestionLastUpdatedProps &
QuestionRowCountOpts;
export const RightViewFooterButtonGroup = ({
result,
isObjectDetail,
question,
visualizationSettings,
isTimeseries,
isShowingTimelineSidebar,
onOpenTimelines,
onCloseTimelines,
}: RightViewFooterButtonGroupProps) => (
<>
{QuestionRowCount.shouldRender({
result,
isObjectDetail,
}) && <QuestionRowCount />}
{ExecutionTime.shouldRender({ result }) && (
<ExecutionTime time={result.running_time} />
)}
<Group spacing="sm" noWrap>
{QuestionLastUpdated.shouldRender({ result }) && (
<QuestionLastUpdated
className={cx(CS.hide, CS.smShow)}
result={result}
/>
)}
{QueryDownloadWidget.shouldRender({ result }) && (
<QueryDownloadWidget
className={cx(CS.hide, CS.smShow)}
question={question}
result={result}
visualizationSettings={visualizationSettings}
dashcardId={question.card().dashcardId}
dashboardId={question.card().dashboardId}
/>
)}
{QuestionTimelineWidget.shouldRender({ isTimeseries }) && (
<QuestionTimelineWidget
className={cx(CS.hide, CS.smShow)}
isShowingTimelineSidebar={isShowingTimelineSidebar}
onOpenTimelines={onOpenTimelines}
onCloseTimelines={onCloseTimelines}
/>
)}
</Group>
</>
);
import cx from "classnames";
import ButtonBar from "metabase/components/ButtonBar";
import CS from "metabase/css/core/index.css";
import { useSelector } from "metabase/lib/redux";
import { getIsVisualized } from "metabase/query_builder/selectors";
import * as Lib from "metabase-lib";
import { ViewFooterRoot } from "../ViewFooter.styled";
import {
CenterViewFooterButtonGroup,
type CenterViewFooterButtonGroupProps,
} from "./CenterViewFooterButtonGroup";
import {
LeftViewFooterButtonGroup,
type LeftViewFooterButtonGroupProps,
} from "./LeftViewFooterButtonGroup";
import {
RightViewFooterButtonGroup,
type RightViewFooterButtonGroupProps,
} from "./RightViewFooterButtonGroup";
type ViewFooterProps = LeftViewFooterButtonGroupProps &
CenterViewFooterButtonGroupProps &
RightViewFooterButtonGroupProps;
export const ViewFooter = ({
question,
result,
className,
isShowingChartTypeSidebar,
isShowingChartSettingsSidebar,
isShowingRawTable,
onOpenChartType,
onCloseChartType,
onOpenChartSettings,
onCloseChartSettings,
setUIControls,
isObjectDetail,
isTimeseries,
visualizationSettings,
isShowingTimelineSidebar,
onOpenTimelines,
onCloseTimelines,
}: ViewFooterProps) => {
const isVisualized = useSelector(getIsVisualized);
if (!result) {
return null;
}
const { isEditable } = Lib.queryDisplayInfo(question.query());
const hideChartSettings =
(result.error && !isEditable) || question.isArchived();
return (
<ViewFooterRoot
className={cx(className, CS.textMedium, CS.borderTop)}
data-testid="view-footer"
>
<ButtonBar
className={CS.flexFull}
left={
!hideChartSettings && (
<LeftViewFooterButtonGroup
isShowingChartTypeSidebar={isShowingChartTypeSidebar}
isShowingChartSettingsSidebar={isShowingChartSettingsSidebar}
onCloseChartType={onCloseChartType}
onOpenChartType={onOpenChartType}
onCloseChartSettings={onCloseChartSettings}
onOpenChartSettings={onOpenChartSettings}
/>
)
}
center={
isVisualized && (
<CenterViewFooterButtonGroup
setUIControls={setUIControls}
question={question}
isShowingRawTable={isShowingRawTable}
/>
)
}
right={
<RightViewFooterButtonGroup
question={question}
result={result}
isObjectDetail={isObjectDetail}
isTimeseries={isTimeseries}
visualizationSettings={visualizationSettings}
isShowingTimelineSidebar={isShowingTimelineSidebar}
onOpenTimelines={onOpenTimelines}
onCloseTimelines={onCloseTimelines}
/>
}
/>
</ViewFooterRoot>
);
};
export * from "./ViewFooter";
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