Skip to content
Snippets Groups Projects
Unverified Commit d853c211 authored by Kyle Doherty's avatar Kyle Doherty Committed by GitHub
Browse files

Allow admins to hide `Our data` and `X-rays` on the homepage (#11478)

* hide Our Data when there are collections

* add show-homepage-data setting

* use show-homepage-setting to display our data section w/ hide action

* confirm modal and tests

* add x-ray setting

* x-ray show/hide logic and WIP tests

* align icons

* fix cypress tests

* use proper settings key

* change hover parent so hovering on the section shows the icon

* reset sample dataset name

* mark tests as pending until we can figure our circle

* add a missing quote and remove :zap:
parent 3878f67c
No related branches found
No related tags found
No related merge requests found
......@@ -11,6 +11,8 @@ import ExplorePane from "metabase/components/ExplorePane";
import Tooltip from "metabase/components/Tooltip";
import MetabotLogo from "metabase/components/MetabotLogo";
import CollectionList from "metabase/components/CollectionList";
import ModalWithTrigger from "metabase/components/ModalWithTrigger";
import Button from "metabase/components/Button";
import Card from "metabase/components/Card";
import { Grid, GridItem } from "metabase/components/Grid";
......@@ -27,8 +29,13 @@ import Database from "metabase/entities/databases";
import Search from "metabase/entities/search";
import { ROOT_COLLECTION } from "metabase/entities/collections";
import { updateSetting } from "metabase/admin/settings/settings";
import { getUser } from "metabase/home/selectors";
import { getXraysEnabled } from "metabase/selectors/settings";
import {
getShowHomepageData,
getShowHomepageXrays,
} from "metabase/selectors/settings";
const PAGE_PADDING = [1, 2, 4];
......@@ -60,15 +67,24 @@ const getParitionedCollections = createSelector(
query: { collection: "root" },
wrapped: true,
})
@connect((state, props) => ({
// split out collections, pinned, and unpinned since bulk actions only apply to unpinned
...getParitionedCollections(state, props),
user: getUser(state, props),
xraysEnabled: getXraysEnabled(state),
}))
@connect(
(state, props) => ({
// split out collections, pinned, and unpinned since bulk actions only apply to unpinned
...getParitionedCollections(state, props),
user: getUser(state, props),
showHomepageData: getShowHomepageData(state),
showHomepageXrays: getShowHomepageXrays(state),
}),
{ updateSetting },
)
class Overworld extends React.Component {
render() {
const { user, xraysEnabled } = this.props;
const {
user,
showHomepageData,
showHomepageXrays,
updateSetting,
} = this.props;
return (
<Box>
<Flex px={PAGE_PADDING} pt={3} pb={1} align="center">
......@@ -85,7 +101,7 @@ class Overworld extends React.Component {
d => d.model === "dashboard" && d.collection_position != null,
);
if (xraysEnabled && !pinnedDashboards.length > 0) {
if (showHomepageXrays && !pinnedDashboards.length > 0) {
return (
<CandidateListLoader>
{({ candidates, sampleCandidates, isSample }) => {
......@@ -96,12 +112,48 @@ class Overworld extends React.Component {
return (
<Box mx={PAGE_PADDING} mt={[1, 3]}>
{user.is_superuser && <AdminPinMessage />}
<Box mt={[1, 3]}>
<Flex align="center">
<SectionHeading>
<Box
mt={[1, 3]}
className="hover-parent hover--visibility"
>
<SectionHeading>
<Flex align="center">
{t`Try these x-rays based on your data.`}
</SectionHeading>
</Flex>
{user.is_superuser && (
<ModalWithTrigger
triggerElement={
<Tooltip
tooltip={t`Remove these suggestions`}
>
<Icon
ml="2"
name="close"
className="hover-child text-brand-hover"
/>
</Tooltip>
}
title={t`Remove these suggestions?`}
footer={
<Button
danger
onClick={onClose => {
updateSetting({
key: "show-homepage-xrays",
value: false,
});
}}
>
{t`Remove`}
</Button>
}
>
<Box>
{t`These won’t show up on the homepage for any of your users anymore, but you can always get to x-rays by clicking on Browse Data in the main navigation, then clicking on the lightning bolt icon on one of your tables.`}
</Box>
</ModalWithTrigger>
)}
</Flex>
</SectionHeading>
<Box>
<ExplorePane
candidates={candidates}
......@@ -158,7 +210,6 @@ class Overworld extends React.Component {
);
}}
</CollectionItemsLoader>
<Box px={PAGE_PADDING} my={3}>
<SectionHeading>{ROOT_COLLECTION.name}</SectionHeading>
<Box p={[1, 2]} mt={2} bg={color("bg-medium")}>
......@@ -202,64 +253,104 @@ class Overworld extends React.Component {
</Link>
</Box>
</Box>
<Database.ListLoader>
{({ databases }) => {
if (databases.length === 0) {
return null;
}
return (
<Box pt={2} px={PAGE_PADDING}>
<SectionHeading>{t`Our data`}</SectionHeading>
<Box mb={4}>
<Grid>
{databases.map(database => (
<GridItem w={[1, 1 / 3]} key={database.id}>
<Link
to={`browse/${database.id}`}
hover={{ color: color("brand") }}
data-metabase-event={`Homepage;Browse DB Clicked; DB Type ${database.engine}`}
{showHomepageData && (
<Database.ListLoader>
{({ databases }) => {
if (databases.length === 0) {
return null;
}
return (
<Box
pt={2}
px={PAGE_PADDING}
className="hover-parent hover--visibility"
>
<SectionHeading>
<Flex align="center">
{t`Our data`}
{user.is_superuser && (
<ModalWithTrigger
triggerElement={
<Tooltip tooltip={t`Hide this section`}>
<Icon
ml="4"
name="close"
className="block hover-child text-brand-hover"
/>
</Tooltip>
}
title={t`Remove this section?`}
footer={
<Button
danger
onClick={onClose => {
updateSetting({
key: "show-homepage-data",
value: false,
});
}}
>
{t`Remove`}
</Button>
}
>
<Box
p={3}
bg={color("bg-medium")}
className="hover-parent hover--visibility"
<Box>
{t`"Our Data" won’t show up on the homepage for any of your users anymore, but you can always browse through your databases and tables by clicking Browse Data in the main navigation.`}
</Box>
</ModalWithTrigger>
)}
</Flex>
</SectionHeading>
<Box mb={4}>
<Grid>
{databases.map(database => (
<GridItem w={[1, 1 / 3]} key={database.id}>
<Link
to={`browse/${database.id}`}
hover={{ color: color("brand") }}
data-metabase-event={`Homepage;Browse DB Clicked; DB Type ${database.engine}`}
>
<Icon
name="database"
color={color("database")}
mb={3}
size={28}
/>
<Flex align="center">
<h3 className="text-wrap">{database.name}</h3>
<Box ml="auto" mr={1} className="hover-child">
<Flex align="center">
<Tooltip
tooltip={t`Learn about this database`}
>
<Link
to={`reference/databases/${database.id}`}
<Box
p={3}
bg={color("bg-medium")}
className="hover-parent hover--visibility"
>
<Icon
name="database"
color={color("database")}
mb={3}
size={28}
/>
<Flex align="center">
<h3 className="text-wrap">{database.name}</h3>
<Box ml="auto" mr={1} className="hover-child">
<Flex align="center">
<Tooltip
tooltip={t`Learn about this database`}
>
<Icon
name="reference"
color={color("text-light")}
/>
</Link>
</Tooltip>
</Flex>
</Box>
</Flex>
</Box>
</Link>
</GridItem>
))}
</Grid>
<Link
to={`reference/databases/${database.id}`}
>
<Icon
name="reference"
color={color("text-light")}
/>
</Link>
</Tooltip>
</Flex>
</Box>
</Flex>
</Box>
</Link>
</GridItem>
))}
</Grid>
</Box>
</Box>
</Box>
);
}}
</Database.ListLoader>
);
}}
</Database.ListLoader>
)}
</Box>
);
}
......
import { createSelector } from "reselect";
// NOTE: these are "public" settings
export const getIsPublicSharingEnabled = state =>
state.settings.values["public_sharing"];
......@@ -6,6 +8,14 @@ export const getIsApplicationEmbeddingEnabled = state =>
// Whether or not xrays are enabled on the instance
export const getXraysEnabled = state => state.settings.values["enable_xrays"];
export const getShowHomepageData = state =>
state.settings.values["show_homepage_data"];
export const getShowHomepageXrays = createSelector(
[getXraysEnabled, state => state.settings.values["show_homepage_xrays"]],
(enabled, show) => enabled && show,
);
// NOTE: these are admin-only settings
export const getSiteUrl = state => state.settings.values["site-url"];
export const getEmbeddingSecretKey = state =>
......
import { signInAsAdmin, signInAsNormalUser } from "__support__/cypress";
describe("homepage", () => {
describe("content management", () => {
describe("as admin", () => {
beforeEach(() => {
signInAsAdmin();
cy.request("PUT", "api/setting/show-homepage-data", { value: true });
cy.request("PUT", "api/setting/show-homepage-xrays", { value: true });
});
afterEach(() => {
cy.request("PUT", "api/setting/show-homepage-data", { value: true });
cy.request("PUT", "api/setting/show-homepage-xrays", { value: true });
});
xit('should be possible for an admin to hide the "Our data" section', () => {
cy.server();
cy.route("PUT", "**/show-homepage-data").as("hideData");
cy.visit("/");
cy.contains("Sample Dataset");
cy.contains("Our data")
.find(".Icon-close")
.click({ force: true });
cy.get(".Button--danger").click();
cy.wait("@hideData");
cy.contains("Sample Dataset").should("have.length", 0);
// cleanup
});
xit('should be possible for an admin to hide the "xrays" section', () => {
cy.server();
cy.route("PUT", "**/show-homepage-xrays").as("hideXrays");
cy.visit("/");
cy.contains("based on")
.find(".Icon-close")
.click({ force: true });
cy.get(".Button--danger").click();
cy.wait("@hideXrays");
});
});
describe("as regular folk", () => {
beforeEach(signInAsNormalUser);
xit("should not be possible for them to see the controls", () => {
cy.visit("/");
cy.contains("Our data")
.find(".Icon-close")
.should("have.length", 0);
cy.contains("x-ray")
.find(".Icon-close")
.should("have.length", 0);
});
});
});
});
......@@ -48,5 +48,12 @@ describe("sample database reference", () => {
.type("My definitely profitable business");
cy.contains("Save").click();
cy.contains("My definitely profitable business");
// reset
cy.contains("Edit").click();
cy.get(".wrapper input")
.clear()
.type("Sample Dataset");
cy.contains("Save").click();
});
});
......@@ -172,6 +172,16 @@
:type :boolean
:default true)
(defsetting show-homepage-data
(deferred-tru "Whether or not to display data on the homepage. Admins might turn this off in order to direct users to better content than raw data")
:type :boolean
:default true)
(defsetting show-homepage-xrays
(deferred-tru "Whether or not to display x-ray suggestions on the homepage. They will also be hidden if any dashboards are pinned. Admins might hide this to direct users to better content than raw data")
:type :boolean
:default true)
(defsetting source-address-header
(deferred-tru "Identify the source of HTTP requests by this header's value, instead of its remote address.")
:getter (fn [] (some-> (setting/get-string :source-address-header)
......@@ -233,6 +243,8 @@
:public_sharing (enable-public-sharing)
:report_timezone (resolve-setting 'metabase.driver 'report-timezone)
:setup_token (resolve-setting 'metabase.setup 'token-value)
:show_homepage_data (show-homepage-data)
:show_homepage_xrays (show-homepage-xrays)
:site_name (site-name)
:site_url (site-url)
:timezone_short (short-timezone-name (setting/get :report-timezone))
......
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