Skip to content
Snippets Groups Projects
Unverified Commit 54ec54b7 authored by Nick Fitzpatrick's avatar Nick Fitzpatrick Committed by GitHub
Browse files

change command palette to use moderation icon from ee (#49224)

parent 91a7e4d9
No related branches found
No related tags found
No related merge requests found
......@@ -2,6 +2,7 @@ import { ORDERS_COUNT_QUESTION_ID } from "e2e/support/cypress_sample_instance_da
import {
closeCommandPalette,
commandPalette,
commandPaletteInput,
commandPaletteSearch,
createModerationReview,
describeEE,
......@@ -91,6 +92,10 @@ describeEE("scenarios > premium > content verification", () => {
// 3. Recently viewed list
openCommandPalette();
commandPalette()
.findByRole("option", { name: "Orders, Count" })
.find(".Icon-verified_filled");
commandPaletteInput().type("Orders");
commandPalette()
.findByRole("option", { name: "Orders, Count" })
.find(".Icon-verified_filled");
......@@ -130,6 +135,11 @@ describeEE("scenarios > premium > content verification", () => {
// 3. Recently viewed list
openCommandPalette();
commandPalette()
.findByRole("option", { name: "Orders, Count" })
.find(".Icon-verified_filled")
.should("not.exist");
commandPaletteInput().type("Orders");
commandPalette()
.findByRole("option", { name: "Orders, Count" })
.find(".Icon-verified_filled")
......@@ -232,6 +242,18 @@ describeEE("scenarios > premium > content verification", () => {
});
cy.findByLabelText("Close").click();
openCommandPalette();
commandPalette()
.findByRole("option", { name: "Orders, Count" })
.find(".Icon-verified_filled")
.should("not.exist");
commandPaletteInput().type("Orders");
commandPalette()
.findByRole("option", { name: "Orders, Count" })
.find(".Icon-verified_filled")
.should("not.exist");
closeCommandPalette();
commandPaletteSearch("orders");
cy.log(
"The question lost the verification status and does not appear high in search results anymore",
......
......@@ -49,7 +49,7 @@ export type RecentCollectionItem = BaseRecentItem & {
database_id?: DatabaseId; // for models and questions
parent_collection: Pick<Collection, "id" | "name" | "authority_level">;
authority_level?: "official" | null; // for collections
moderated_status?: "verified" | null; // for models
moderated_status?: "verified" | null; // for cards / models / dashboards
display?: CardDisplayType; // for questions
};
......@@ -58,6 +58,11 @@ export type RecentItem = RecentTableItem | RecentCollectionItem;
export const isRecentTableItem = (item: RecentItem): item is RecentTableItem =>
item.model === "table";
export const isRecentCollectionItem = (
item: RecentItem,
): item is RecentCollectionItem =>
["collection", "dashboard", "card", "dataset", "metric"].includes(item.model);
export interface RecentItemsResponse {
recent_views: RecentItem[];
}
......
......@@ -2,6 +2,7 @@ import { t } from "ttag";
import ExternalLink from "metabase/core/components/ExternalLink";
import Link from "metabase/core/components/Link";
import { PLUGIN_MODERATION } from "metabase/plugins";
import { Box, Flex, Icon, Text } from "metabase/ui";
import type { PaletteActionImpl } from "../types";
......@@ -70,16 +71,18 @@ export const PaletteResultItem = ({ item, active }: PaletteResultItemProps) => {
<Text component="span" c="inherit" lh="1rem">
{item.name}
</Text>
{item.extra?.isVerified && (
<Icon
name="verified_filled"
{item.extra?.moderatedStatus && (
<PLUGIN_MODERATION.ModerationStatusIcon
status={item.extra.moderatedStatus}
filled
size={14}
color={
active ? "var(--mb-color-text-white)" : "var(--mb-color-brand)"
}
style={{
verticalAlign: "sub",
marginLeft: "0.25rem",
verticalAlign: "text-bottom",
}}
ml="0.5rem"
/>
)}
{subtext && (
......
import _ from "underscore";
import { screen, within } from "__support__/ui";
import { type CommonSetupProps, commonSetup } from "./setup";
const setup = (props: CommonSetupProps = {}) => {
commonSetup({ ...props, isEE: true });
};
describe("PaletteResults EE", () => {
describe("content verification", () => {
it("should show verified badges for recents", async () => {
setup();
//Foo Question should be displayed with a verified badge
expect(
await within(
await screen.findByRole("option", { name: "Foo Question" }),
).findByRole("img", { name: /verified_filled/ }),
).toBeInTheDocument();
});
it("should show verified badges for search results", async () => {
setup({ query: "ques" });
//Foo Question should be displayed with a verified badge
expect(
await within(
await screen.findByRole("option", { name: "Foo Question" }),
).findByRole("img", { name: /verified_filled/ }),
).toBeInTheDocument();
});
});
});
import fetchMock from "fetch-mock";
import { useKBar } from "kbar";
import { useEffect } from "react";
import { Route, type WithRouterProps, withRouter } from "react-router";
import _ from "underscore";
import { screen, waitFor, within } from "__support__/ui";
import {
setupDatabasesEndpoints,
setupRecentViewsEndpoints,
setupSearchEndpoints,
} from "__support__/server-mocks";
import {
mockScrollIntoView,
mockScrollTo,
renderWithProviders,
screen,
waitFor,
within,
} from "__support__/ui";
import { getAdminPaths } from "metabase/admin/app/reducers";
import type { RecentItem, Settings } from "metabase-types/api";
import {
createMockCollection,
createMockCollectionItem,
createMockDatabase,
createMockRecentCollectionItem,
createMockRecentTableItem,
} from "metabase-types/api/mocks";
import {
createMockAdminAppState,
createMockAdminState,
createMockSettingsState,
} from "metabase-types/store/mocks";
import { useCommandPaletteBasicActions } from "../hooks/useCommandPaletteBasicActions";
import { PaletteResults } from "./PaletteResults";
const TestComponent = withRouter(
({ q, ...props }: WithRouterProps & { q?: string; isLoggedIn: boolean }) => {
useCommandPaletteBasicActions(props);
const { query } = useKBar();
useEffect(() => {
if (q) {
query.setSearch(q);
}
}, [q, query]);
return <PaletteResults />;
},
);
const DATABASE = createMockDatabase();
const collection_1 = createMockCollection({
name: "lame collection",
id: 3,
});
//Verified, but no collection details present
const model_1 = createMockCollectionItem({
model: "dataset",
name: "Foo Question",
moderated_status: "verified",
id: 1,
});
const model_2 = createMockCollectionItem({
model: "dataset",
name: "Bar Question",
collection: collection_1,
id: 2,
});
const dashboard = createMockCollectionItem({
model: "dashboard",
name: "Bar Dashboard",
collection: collection_1,
description: "Such Bar. Much Wow.",
});
const recents_1 = createMockRecentCollectionItem({
..._.pick(model_1, "id", "name"),
model: "dataset",
moderated_status: "verified",
parent_collection: {
id: "root",
name: "Our analytics",
},
});
const recents_2 = createMockRecentCollectionItem({
..._.pick(dashboard, "id", "name"),
model: "dashboard",
parent_collection: {
id: dashboard.collection?.id as number,
name: dashboard.collection?.name as string,
},
});
mockScrollTo();
mockScrollIntoView();
import { type CommonSetupProps, commonSetup } from "./setup";
const setup = ({
query,
settings = {},
recents = [recents_1, recents_2],
}: {
query?: string;
settings?: Partial<Settings>;
recents?: RecentItem[];
} = {}) => {
setupDatabasesEndpoints([DATABASE]);
setupSearchEndpoints([model_1, model_2, dashboard]);
setupRecentViewsEndpoints(recents);
renderWithProviders(
<Route path="/" component={() => <TestComponent q={query} isLoggedIn />} />,
{
withKBar: true,
withRouter: true,
storeInitialState: {
admin: createMockAdminState({
app: createMockAdminAppState({
paths: getAdminPaths(),
}),
}),
settings: createMockSettingsState(settings),
},
},
);
const setup = (props: CommonSetupProps = {}) => {
commonSetup({ ...props, isEE: false });
};
describe("PaletteResults", () => {
......@@ -163,12 +44,12 @@ describe("PaletteResults", () => {
await screen.findByRole("option", { name: "Foo Question" }),
).toHaveTextContent("Our analytics");
//Foo Question should be displayed with a verified badge
//Foo Question should be not be displayed with a verified badge in OSS
expect(
await within(
within(
await screen.findByRole("option", { name: "Foo Question" }),
).findByRole("img", { name: /verified_filled/ }),
).toBeInTheDocument();
).queryByRole("img", { name: /verified_filled/ }),
).not.toBeInTheDocument();
});
it("should show recent items with the same name", async () => {
......@@ -220,17 +101,19 @@ describe("PaletteResults", () => {
});
it("should display collections that search results are from", async () => {
setup({ query: "ques" });
setup({
query: "ques",
});
expect(
await screen.findByRole("option", { name: "Foo Question" }),
).toHaveTextContent("Our analytics");
//Foo Question should be displayed with a verified badge
//Foo Question should not be displayed with a verified badge in OSS
expect(
await within(
within(
await screen.findByRole("option", { name: "Foo Question" }),
).findByRole("img", { name: /verified_filled/ }),
).toBeInTheDocument();
).queryByRole("img", { name: /verified_filled/ }),
).not.toBeInTheDocument();
expect(
await screen.findByRole("option", { name: "Bar Question" }),
......
import { useKBar } from "kbar";
import { useEffect } from "react";
import { Route, type WithRouterProps, withRouter } from "react-router";
import _ from "underscore";
import { setupEnterprisePlugins } from "__support__/enterprise";
import {
setupDatabasesEndpoints,
setupRecentViewsEndpoints,
setupSearchEndpoints,
} from "__support__/server-mocks";
import { mockSettings } from "__support__/settings";
import {
mockScrollIntoView,
mockScrollTo,
renderWithProviders,
} from "__support__/ui";
import { getAdminPaths } from "metabase/admin/app/reducers";
import { useCommandPaletteBasicActions } from "metabase/palette/hooks/useCommandPaletteBasicActions";
import type { RecentItem, Settings } from "metabase-types/api";
import {
createMockCollection,
createMockCollectionItem,
createMockDatabase,
createMockRecentCollectionItem,
createMockTokenFeatures,
} from "metabase-types/api/mocks";
import {
createMockAdminAppState,
createMockAdminState,
createMockState,
} from "metabase-types/store/mocks";
import { PaletteResults } from "../../PaletteResults";
const TestComponent = withRouter(
({ q, ...props }: WithRouterProps & { q?: string; isLoggedIn: boolean }) => {
useCommandPaletteBasicActions(props);
const { query } = useKBar();
useEffect(() => {
if (q) {
query.setSearch(q);
}
}, [q, query]);
return <PaletteResults />;
},
);
const DATABASE = createMockDatabase();
const collection_1 = createMockCollection({
name: "lame collection",
id: 3,
});
//Verified, but no collection details present
const model_1 = createMockCollectionItem({
model: "dataset",
name: "Foo Question",
moderated_status: "verified",
id: 1,
});
const model_2 = createMockCollectionItem({
model: "dataset",
name: "Bar Question",
collection: collection_1,
id: 2,
});
const dashboard = createMockCollectionItem({
model: "dashboard",
name: "Bar Dashboard",
collection: collection_1,
description: "Such Bar. Much Wow.",
});
const recents_1 = createMockRecentCollectionItem({
..._.pick(model_1, "id", "name"),
model: "dataset",
moderated_status: "verified",
parent_collection: {
id: "root",
name: "Our analytics",
},
});
const recents_2 = createMockRecentCollectionItem({
..._.pick(dashboard, "id", "name"),
model: "dashboard",
parent_collection: {
id: dashboard.collection?.id as number,
name: dashboard.collection?.name as string,
},
});
mockScrollTo();
mockScrollIntoView();
const TOKEN_FEATURES = createMockTokenFeatures({ content_verification: true });
export interface CommonSetupProps {
query?: string;
settings?: Partial<Settings>;
recents?: RecentItem[];
isEE?: boolean;
}
export const commonSetup = ({
query,
settings = {},
recents = [recents_1, recents_2],
isEE,
}: CommonSetupProps = {}) => {
setupDatabasesEndpoints([DATABASE]);
setupSearchEndpoints([model_1, model_2, dashboard]);
setupRecentViewsEndpoints(recents);
const storeInitialState = createMockState({
admin: createMockAdminState({
app: createMockAdminAppState({
paths: getAdminPaths(),
}),
}),
settings: mockSettings({ ...settings, "token-features": TOKEN_FEATURES }),
});
if (isEE) {
setupEnterprisePlugins();
}
renderWithProviders(
<Route path="/" component={() => <TestComponent q={query} isLoggedIn />} />,
{
withKBar: true,
withRouter: true,
storeInitialState,
},
);
};
......@@ -26,7 +26,11 @@ import {
} from "metabase/selectors/settings";
import { getShowMetabaseLinks } from "metabase/selectors/whitelabel";
import { Icon, type IconName } from "metabase/ui";
import { type RecentItem, isRecentTableItem } from "metabase-types/api";
import {
type RecentItem,
isRecentCollectionItem,
isRecentTableItem,
} from "metabase-types/api";
import type { PaletteAction } from "../types";
import { filterRecentItems } from "../utils";
......@@ -189,7 +193,7 @@ export const useCommandPalette = ({
trackSearchClick("item", index, "command-palette");
},
extra: {
isVerified: result.moderated_status === "verified",
moderatedStatus: result.moderated_status,
href: wrappedResult.getUrl(),
iconColor: icon.color,
subtext: getSearchResultSubtext(wrappedResult),
......@@ -234,8 +238,9 @@ export const useCommandPalette = ({
section: "recent",
perform: () => {},
extra: {
isVerified:
item.model !== "table" && item.moderated_status === "verified",
moderatedStatus: isRecentCollectionItem(item)
? item.moderated_status
: null,
href: Urls.modelToUrl(item),
iconColor: icon.color,
subtext: getRecentItemSubtext(item),
......
......@@ -2,11 +2,12 @@ import type { LocationDescriptor } from "history";
import type { Action, ActionImpl } from "kbar";
import type { IconName } from "metabase/ui";
import type { ModerationReviewStatus } from "metabase-types/api";
interface PaletteActionExtras {
extra?: {
/** isVerified: If true, will show a verified badge next to the item name */
isVerified?: boolean;
moderatedStatus?: ModerationReviewStatus;
/**
* href: If defined, the palette item will be wrapped in a link. This allows for
* browser interactions to open items in new tabs/windows
......
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