diff --git a/frontend/src/metabase/components/EmptyState.jsx b/frontend/src/metabase/components/EmptyState.jsx index 7d38d03d8633c7a028b76eac2aa302924d6d42eb..4e4e957d0ff82936d57c314ad5ab137daba77ff6 100644 --- a/frontend/src/metabase/components/EmptyState.jsx +++ b/frontend/src/metabase/components/EmptyState.jsx @@ -35,7 +35,12 @@ const EmptyState = ({ ...rest }) => ( <Box> - <Flex justify="center" flexDirection="column" align="center"> + <Flex + className="text-centered" + justify="center" + flexDirection="column" + align="center" + > {illustrationElement && <Box mb={[2, 3]}>{illustrationElement}</Box>} <Box> <LegacyIcon {...rest} /> diff --git a/frontend/src/metabase/query_builder/components/DataSelector.jsx b/frontend/src/metabase/query_builder/components/DataSelector.jsx index d3b28f24d32b2cdb5c942c11bceed90483640a73..2ddadd84e6da858784976871d5c1b775e47d3000 100644 --- a/frontend/src/metabase/query_builder/components/DataSelector.jsx +++ b/frontend/src/metabase/query_builder/components/DataSelector.jsx @@ -12,6 +12,7 @@ import { SAVED_QUESTIONS_VIRTUAL_DB_ID, } from "metabase/lib/saved-questions"; +import EmptyState from "metabase/components/EmptyState"; import ListSearchField from "metabase/components/ListSearchField"; import ExternalLink from "metabase/components/ExternalLink"; import Icon from "metabase/components/Icon"; @@ -39,6 +40,7 @@ import { import SavedQuestionPicker from "./saved-question-picker/SavedQuestionPicker"; import { getMetadata } from "metabase/selectors/metadata"; +import { getHasDataAccess } from "metabase/new_query/selectors"; import { DataBucketList, @@ -47,6 +49,7 @@ import { RawDataBackButton, CollectionDatasetSelectList, CollectionDatasetAllDataLink, + EmptyStateContainer, } from "./DataSelector.styled"; import "./DataSelector.css"; @@ -209,6 +212,7 @@ const FieldTriggerContent = ({ selectedDatabase, selectedField }) => { hasFetchedDatabasesWithTables: !!Databases.selectors.getList(state, { entityQuery: { include: "tables" }, }), + hasDataAccess: getHasDataAccess(state), }), { fetchDatabases: databaseQuery => Databases.actions.fetchList(databaseQuery), @@ -1011,6 +1015,11 @@ export class UnconnectedDataSelector extends Component { }[selectedDataBucketId]; }; + hasDataAccess = () => { + const { hasDataAccess, databases } = this.props; + return hasDataAccess || databases?.length > 0; + }; + render() { const { searchText, @@ -1019,6 +1028,7 @@ export class UnconnectedDataSelector extends Component { selectedTable, } = this.state; const { canChangeDatabase, selectedDatabaseId } = this.props; + const currentDatabaseId = canChangeDatabase ? null : selectedDatabaseId; const isSearchActive = searchText.trim().length >= MIN_SEARCH_LENGTH; @@ -1045,8 +1055,8 @@ export class UnconnectedDataSelector extends Component { > {this.isLoadingDatasets() ? ( <LoadingAndErrorWrapper loading /> - ) : ( - <React.Fragment> + ) : this.hasDataAccess() ? ( + <> {this.showTableSearch() && ( <ListSearchField hasClearButton @@ -1082,7 +1092,14 @@ export class UnconnectedDataSelector extends Component { ) : ( this.renderActiveStep() ))} - </React.Fragment> + </> + ) : ( + <EmptyStateContainer> + <EmptyState + message={t`To pick some data, you'll need to add some first`} + icon="database" + /> + </EmptyStateContainer> )} </PopoverWithTrigger> ); diff --git a/frontend/src/metabase/query_builder/components/DataSelector.styled.jsx b/frontend/src/metabase/query_builder/components/DataSelector.styled.jsx index c9e6822af03b60bbb995cb2a33df3c7fe0bf4a66..7f11f3ba1376b2c6036388e6a2f5c65bd921f0cf 100644 --- a/frontend/src/metabase/query_builder/components/DataSelector.styled.jsx +++ b/frontend/src/metabase/query_builder/components/DataSelector.styled.jsx @@ -148,3 +148,8 @@ CollectionDatasetAllDataLink.Content = styled.span` margin-left: ${space(0)}; } `; + +export const EmptyStateContainer = styled.div` + width: 300px; + padding: 80px 60px; +`; diff --git a/frontend/test/metabase/query_builder/components/DataSelector.unit.spec.js b/frontend/test/metabase/query_builder/components/DataSelector.unit.spec.js index ff865c212eb3ecc3967d52939b10389aff8a8743..748f4f2c97452589073cbbc7d180ce9789ad4b9e 100644 --- a/frontend/test/metabase/query_builder/components/DataSelector.unit.spec.js +++ b/frontend/test/metabase/query_builder/components/DataSelector.unit.spec.js @@ -126,6 +126,7 @@ describe("DataSelector", () => { // on initial load, we fetch databases await delay(1); expect(fetchDatabases).toHaveBeenCalled(); + rerender(<DataSelector {...props} loading />); getByText("Loading..."); // select a db @@ -300,6 +301,7 @@ describe("DataSelector", () => { <DataSelector steps={["SCHEMA", "TABLE", "FIELD"]} selectedDatabaseId={SAMPLE_DATABASE.id} + databases={[SAMPLE_DATABASE]} triggerElement={<div />} metadata={metadata} isOpen={true} @@ -315,6 +317,7 @@ describe("DataSelector", () => { <DataSelector steps={["SCHEMA", "TABLE", "FIELD"]} selectedDatabaseId={MULTI_SCHEMA_DATABASE.id} + databases={[MULTI_SCHEMA_DATABASE]} triggerElement={<div />} metadata={metadata} isOpen={true} @@ -387,6 +390,19 @@ describe("DataSelector", () => { await delay(1); getByText("Orders"); }); + + it("shows an empty state without any databases", async () => { + const { getByText } = render( + <DataSelector + steps={["DATABASE", "SCHEMA", "TABLE"]} + databases={[]} + triggerElement={<div />} + isOpen={true} + />, + ); + + getByText("To pick some data, you'll need to add some first"); + }); }); // removes associated ids from entities so we can load only some of them