1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Add support for specifying orderNumber for ClusterPageMenus (#7166)

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2023-02-17 03:55:17 -08:00 committed by GitHub
parent c94dce2c29
commit 2959e01d1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 627 additions and 7 deletions

View File

@ -4507,3 +4507,497 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
</div>
</div>
`;
exports[`cluster - sidebar and tab navigation for extensions given extension with cluster pages and cluster page menus with explicit 'orderNumber' given no state for expanded sidebar items exists, and navigated to child sidebar item, when rendered renders 1`] = `
<div>
<div
class="Animate slide-right Drawer KubeObjectDetails flex column right enter leave"
style="--size: 725px; --enter-duration: 100ms; --leave-duration: 100ms;"
>
<div
class="drawer-wrapper flex column"
>
<div
class="drawer-title flex align-center"
>
<div
class="drawer-title-text flex gaps align-center"
>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
<div>
Close
</div>
</div>
<div
class="drawer-content flex column box grow"
/>
</div>
<div
class="ResizingAnchor horizontal leading"
/>
</div>
<div
class="Notifications flex column align-flex-end"
/>
<div
class="mainLayout"
style="--sidebar-width: 200px;"
>
<div
class="sidebar"
>
<div
class="flex flex-col"
data-testid="cluster-sidebar"
>
<div
class="SidebarCluster"
>
<div
class="Avatar rounded loadingAvatar"
style="width: 40px; height: 40px;"
>
??
</div>
<div
class="loadingClusterName"
/>
</div>
<div
class="sidebarNav sidebar-active-status"
>
<div
class="SidebarItem"
data-is-active-test="true"
data-testid="sidebar-item-some-extension-name-some-parent-id"
>
<a
aria-current="page"
class="navItem active"
data-testid="sidebar-item-link-for-some-extension-name-some-parent-id"
href="/"
>
<div>
Some icon
</div>
<span>
Parent
</span>
<i
class="Icon expandIcon material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-workloads"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-workloads"
href="/"
>
<i
class="Icon svg focusable"
>
<span
class="icon"
/>
</i>
<span>
Workloads
</span>
<i
class="Icon expandIcon material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-config"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-config"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="list"
>
list
</span>
</i>
<span>
Config
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-network"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-network"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="device_hub"
>
device_hub
</span>
</i>
<span>
Network
</span>
<i
class="Icon expandIcon material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-storage"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-storage"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="storage"
>
storage
</span>
</i>
<span>
Storage
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-helm"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-helm"
href="/"
>
<i
class="Icon svg focusable"
>
<span
class="icon"
/>
</i>
<span>
Helm
</span>
<i
class="Icon expandIcon material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-user-management"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-user-management"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="security"
>
security
</span>
</i>
<span>
Access Control
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-custom-resources"
>
<a
class="navItem"
data-testid="sidebar-item-link-for-custom-resources"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="extension"
>
extension
</span>
</i>
<span>
Custom Resources
</span>
<i
class="Icon expandIcon material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
</div>
</div>
<div
class="ResizingAnchor horizontal trailing"
/>
</div>
<div
class="contents"
>
<div
class="TabLayout"
data-testid="tab-layout"
>
<div
class="Tabs center scrollable"
>
<div
class="Tab flex gaps align-center active"
data-is-active-test="true"
data-testid="tab-link-for-some-extension-name-some-child-id"
role="tab"
tabindex="0"
>
<div
class="label"
>
Child 1
</div>
</div>
<div
class="Tab flex gaps align-center"
data-is-active-test="false"
data-testid="tab-link-for-some-extension-name-some-other-child-id"
role="tab"
tabindex="0"
>
<div
class="label"
>
Child 2
</div>
</div>
</div>
<main
class=""
>
<div
data-testid="some-child-page"
>
Some child page
</div>
</main>
</div>
</div>
<div
class="footer"
>
<div
class="Dock"
tabindex="-1"
>
<div
class="ResizingAnchor vertical leading"
/>
<div
class="tabs-container flex align-center"
>
<div
class="dockTabs"
role="tablist"
>
<div
class="Tabs tabs"
>
<div
class="Tab flex gaps align-center DockTab TerminalTab active"
data-testid="dock-tab-for-terminal"
id="tab-terminal"
role="tab"
tabindex="0"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="terminal"
>
terminal
</span>
</i>
<div
class="label"
>
<div
class="flex align-center"
>
<span
class="title"
>
Terminal
</span>
<div
class="close"
>
<i
class="Icon material interactive focusable small"
data-testid="dock-tab-close-for-terminal"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
<div
data-testid="tooltip-content-for-dock-tab-close-for-terminal"
>
Close ⌘+W
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="toolbar flex gaps align-center box grow"
>
<div
class="dock-menu box grow"
>
<i
class="Icon new-dock-tab material interactive focusable"
id="menu-actions-for-dock"
tabindex="0"
>
<span
class="icon"
data-icon-name="add"
>
add
</span>
</i>
<div>
New tab
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="fullscreen"
>
fullscreen
</span>
</i>
<div>
Fit to window
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="keyboard_arrow_up"
>
keyboard_arrow_up
</span>
</i>
<div>
Open
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -21,6 +21,7 @@ import { runInAction, computed, observable } from "mobx";
import storageSaveDelayInjectable from "../../renderer/utils/create-storage/storage-save-delay.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
import { flushPromises } from "../../common/test-utils/flush-promises";
import type { ClusterPageMenuRegistration } from "../../extensions/common-api/types";
describe("cluster - sidebar and tab navigation for extensions", () => {
let applicationBuilder: ApplicationBuilder;
@ -139,15 +140,12 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
const route = windowDi
.inject(routesInjectable)
.get()
.find(
matches({
path: "/extension/some-extension-name/some-child-page-id",
}),
);
.find(matches({
path: "/extension/some-extension-name/some-child-page-id",
}));
assert(route);
navigateToRoute(route);
});
it("renders", () => {
@ -453,4 +451,131 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
});
});
});
describe("given extension with cluster pages and cluster page menus with explicit 'orderNumber'", () => {
let someObservable: IObservableValue<boolean>;
beforeEach(() => {
someObservable = observable.box(false);
const testExtension = {
id: "some-extension-id",
name: "some-extension-name",
rendererOptions: {
clusterPages: [
{
components: {
Page: () => {
throw new Error("should never come here");
},
},
},
{
id: "some-child-page-id",
components: {
Page: () => <div data-testid="some-child-page">Some child page</div>,
},
},
{
id: "some-other-child-page-id",
components: {
Page: () => (
<div data-testid="some-other-child-page">Some other child page</div>
),
},
},
],
clusterPageMenus: [
{
id: "some-parent-id",
title: "Parent",
components: {
Icon: () => <div>Some icon</div>,
},
orderNumber: -Infinity,
},
{
id: "some-child-id",
target: { pageId: "some-child-page-id" },
parentId: "some-parent-id",
title: "Child 1",
components: {
Icon: null as never,
},
},
{
id: "some-other-child-id",
target: { pageId: "some-other-child-page-id" },
parentId: "some-parent-id",
title: "Child 2",
components: {
Icon: null as never,
},
},
{
id: "some-menu-with-controlled-visibility",
title: "Some menu with controlled visibility",
visible: computed(() => someObservable.get()),
components: {
Icon: () => <div>Some icon</div>,
},
},
] as ClusterPageMenuRegistration[],
},
};
applicationBuilder.extensions.enable(testExtension);
});
describe("given no state for expanded sidebar items exists, and navigated to child sidebar item, when rendered", () => {
beforeEach(async () => {
rendered = await applicationBuilder.render();
const windowDi = applicationBuilder.applicationWindow.only.di;
const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
const route = windowDi
.inject(routesInjectable)
.get()
.find(matches({
path: "/extension/some-extension-name/some-child-page-id",
}));
assert(route);
navigateToRoute(route);
});
it("renders", () => {
expect(rendered.container).toMatchSnapshot();
});
it("renderes parent as first item in sidebar", () => {
const parent = rendered.getByTestId("sidebar-item-some-extension-name-some-parent-id");
assert(parent);
expect(parent.previousSibling).toBeNull();
});
it("parent is highlighted", () => {
const parent = rendered.getByTestId("sidebar-item-some-extension-name-some-parent-id");
expect(parent?.dataset.isActiveTest).toBe("true");
});
it("parent sidebar item is not expanded", () => {
const child = rendered.queryByTestId("sidebar-item-some-extension-name-some-child-id");
expect(child).toBeNull();
});
it("child page is shown", () => {
expect(rendered.getByTestId("some-child-page")).not.toBeNull();
});
});
});
});

View File

@ -15,6 +15,7 @@ export interface ClusterPageMenuRegistration {
title: React.ReactNode;
components: ClusterPageMenuComponents;
visible?: IComputedValue<boolean>;
orderNumber?: number;
}
export interface ClusterPageMenuComponents {

View File

@ -57,7 +57,7 @@ const extensionSidebarItemRegistratorInjectable = getInjectable({
const res: SidebarItemRegistration = {
id: `${extension.sanitizedExtensionId}-${registration.id}`,
orderNumber: 9999,
orderNumber: registration.orderNumber ?? 9999,
parentId: registration.parentId
? `${extension.sanitizedExtensionId}-${registration.parentId}`