Skip to content

Commit

Permalink
Merge pull request #16 from easyops-cn/steve/fix-nav
Browse files Browse the repository at this point in the history
fix(): ignore blocked items for launchpad config
  • Loading branch information
qiaofengxi authored Jan 20, 2025
2 parents f7bf173 + b65a460 commit 597904d
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 42 deletions.
16 changes: 8 additions & 8 deletions bricks/nav/src/launchpad-config/MenuGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ export function MenuGroup({
customUrlTemplate,
onActionClick,
}: MenuGroupProps) {
// Make it compatible
data.type ??= "group";
const { name, items } = data;
const [dropdownActive, setDropdownActive] = useState(false);

const filteredActions = useMemo(
() =>
__secret_internals.legacyDoTransform(
data,
actions?.filter((item) => checkIfByTransform(item, data))
) as MenuAction[] | undefined,
[actions, data]
);
const filteredActions = useMemo(() => {
return __secret_internals.legacyDoTransform(
data,
actions?.filter((item) => checkIfByTransform(item, data))
) as MenuAction[] | undefined;
}, [actions, data]);

const handleActionClick = useCallback(
(event: CustomEvent<SimpleAction>) => {
Expand Down
125 changes: 125 additions & 0 deletions bricks/nav/src/launchpad-config/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ import type { LaunchpadConfig } from "./index.js";

jest.mock("@next-core/theme", () => ({}));

jest.mock("@next-core/easyops-runtime", () => ({
auth: {
isBlockedPath(path: string) {
return path.includes("blocked");
},
isBlockedHref(href: string) {
return href.includes("blocked");
},
},
}));

class WithShadowElement extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({ mode: "open" });
Expand Down Expand Up @@ -91,6 +102,120 @@ describe("nav.launchpad-config", () => {
expect(element.shadowRoot?.childNodes.length).toBe(0);
});

test("launchpad config with license blocking", async () => {
const element = document.createElement(
"nav.launchpad-config"
) as LaunchpadConfig;
element.menuGroups = [
{
instanceId: "g-1",
name: "My Group 1",
items: [
{
instanceId: "i-2",
id: "my-app-2",
type: "app",
name: "My App 2",
},
{
instanceId: "i-3",
id: "my-app-3",
type: "app",
name: "My App 3",
url: "/my-app",
},
{
instanceId: "i-4",
id: "my-app-4",
type: "app",
name: "My App 4",
url: "/blocked-url",
},
{
instanceId: "i-5",
type: "dir",
items: [
{
instanceId: "i-2",
id: "my-custom-2",
type: "custom",
name: "My Custom 2",
},
{
instanceId: "i-3",
id: "my-custom-3",
type: "custom",
name: "My Custom 3",
url: "/my-custom",
},
{
instanceId: "i-4",
id: "my-custom-4",
type: "custom",
name: "My Custom 4",
url: "/blocked-url",
},
],
},
],
},
{
instanceId: "g-2",
name: "My Group 2",
items: [
{
instanceId: "i-3",
id: "my-custom-3",
type: "custom",
name: "My Custom 3",
url: "/blocked-url",
},
{
instanceId: "i-4",
id: "my-app-4",
type: "app",
name: "My App 4",
url: "/blocked-url-2",
},
{
instanceId: "i-5",
type: "dir",
items: [
{
instanceId: "i-3",
id: "my-custom-3",
type: "custom",
name: "My Custom 3",
url: "/blocked-url",
},
{
instanceId: "i-4",
id: "my-app-4",
type: "app",
name: "My App 4",
url: "/blocked-url-2",
},
],
},
],
},
] as any;

act(() => {
document.body.appendChild(element);
});

expect(element.shadowRoot?.querySelectorAll(".menu-group").length).toBe(1);
expect(
element.shadowRoot?.querySelectorAll(".menu-item.folder").length
).toBe(1);
expect(element.shadowRoot?.querySelectorAll(".menu-item").length).toBe(5);

act(() => {
document.body.removeChild(element);
});
});

test("menu config", async () => {
const element = document.createElement(
"nav.launchpad-config"
Expand Down
103 changes: 69 additions & 34 deletions bricks/nav/src/launchpad-config/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useMemo } from "react";
import { EventEmitter, createDecorators } from "@next-core/element";
import { ReactNextElement } from "@next-core/react-element";
import { auth } from "@next-core/easyops-runtime";
import "@next-core/theme";
import type {
ConfigMenuGroup,
Expand Down Expand Up @@ -81,7 +82,7 @@ class LaunchpadConfig extends ReactNextElement implements LaunchpadConfigProps {
<LaunchpadConfigComponent
menuGroups={this.menuGroups}
actions={this.actions}
variant={this.variant}
variant={this.variant ?? "launchpad-config"}
urlTemplate={this.urlTemplate}
customUrlTemplate={this.customUrlTemplate}
blacklist={this.blacklist}
Expand All @@ -98,6 +99,10 @@ export interface LaunchpadConfigProps {
urlTemplate?: string;
customUrlTemplate?: string;
blacklist?: string[];
}

export interface LaunchpadConfigComponentProps extends LaunchpadConfigProps {
variant: ConfigVariant;
onActionClick?: (detail: MenuActionEventDetail) => void;
}

Expand All @@ -109,45 +114,47 @@ export function LaunchpadConfigComponent({
customUrlTemplate,
blacklist,
onActionClick,
}: LaunchpadConfigProps) {
const menuGroupsWithBlockedInfo = useMemo<
ConfigMenuGroup[] | undefined
>(() => {
if (variant !== "blacklist-config") {
}: LaunchpadConfigComponentProps) {
const processedMenuGroup = useMemo<ConfigMenuGroup[] | undefined>(() => {
if (variant === "blacklist-config") {
return menuGroups?.map((group) => {
const items = group.items.map((item) =>
getMenuItemWithBlockInfo(item, blacklist)
);
const blockable = items.some((item) => item.blockable);
const hasBlocked = blockable && items.some((item) => item.hasBlocked);
const hasUnblocked =
blockable && items.some((item) => item.hasUnblocked);
const allBlocked =
items.length > 0 && items.every((item) => item.allBlocked);
const blockableUrls = items.flatMap((item) =>
item.blockable
? ((item as ConfigMenuItemDir).blockableUrls ??
(item as ConfigMenuItemCustom).blockableUrl ??
(item as ConfigMenuItemApp).url)
: []
);
return {
...group,
type: "group",
items,
blockable,
hasBlocked,
hasUnblocked,
allBlocked,
blockableUrls,
};
});
} else if (variant === "launchpad-config") {
return getMenuGroupsWithoutBlockedItems(menuGroups)?.filter(Boolean);
} else {
return menuGroups;
}
return menuGroups?.map((group) => {
const items = group.items.map((item) =>
getMenuItemWithBlockInfo(item, blacklist)
);
const blockable = items.some((item) => item.blockable);
const hasBlocked = blockable && items.some((item) => item.hasBlocked);
const hasUnblocked = blockable && items.some((item) => item.hasUnblocked);
const allBlocked =
items.length > 0 && items.every((item) => item.allBlocked);
const blockableUrls = items.flatMap((item) =>
item.blockable
? ((item as ConfigMenuItemDir).blockableUrls ??
(item as ConfigMenuItemCustom).blockableUrl ??
(item as ConfigMenuItemApp).url)
: []
);
return {
...group,
type: "group",
items,
blockable,
hasBlocked,
hasUnblocked,
allBlocked,
blockableUrls,
};
});
}, [variant, menuGroups, blacklist]);

return (
<ul className="menu-groups">
{menuGroupsWithBlockedInfo?.map((group) => (
{processedMenuGroup?.map((group) => (
<MenuGroup
key={group.instanceId}
data={group}
Expand All @@ -162,6 +169,34 @@ export function LaunchpadConfigComponent({
);
}

function getMenuGroupsWithoutBlockedItems<T extends ConfigMenuGroup>(
menuGroups: T[] | undefined
): T[] | undefined {
return menuGroups
?.map<T | null>((group) => {
const items = group.items
.map((item) => getMenuItemWithoutBlockedItems(item))
.filter(Boolean) as ConfigMenuItem[];
return items.length > 0 ? { ...group, items } : null;
})
.filter(Boolean) as T[];
}

function getMenuItemWithoutBlockedItems<T extends ConfigMenuItem>(
item: T
): T | null {
if (item.type === "dir") {
const subItems = item.items
.map((subItem) => getMenuItemWithoutBlockedItems(subItem))
.filter(Boolean) as T[];
return subItems.length > 0 ? { ...item, items: subItems } : null;
}
if (item.type === "app") {
return item.url && auth.isBlockedPath(item.url) ? null : item;
}
return item.url && auth.isBlockedHref(item.url) ? null : item;
}

function getMenuItemWithBlockInfo<T extends ConfigMenuItem>(
item: T,
blacklist: string[] | undefined
Expand Down
1 change: 1 addition & 0 deletions bricks/nav/src/launchpad-config/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,6 @@ export interface MenuActionEventDetail {

export type ConfigVariant =
| "launchpad-config"
| "factory-launchpad-config"
| "menu-config"
| "blacklist-config";

0 comments on commit 597904d

Please sign in to comment.