From b6073d25d77680832789eb2b56ff7947d322b148 Mon Sep 17 00:00:00 2001 From: CuriousCorrelation Date: Thu, 16 Jun 2022 15:54:14 +0530 Subject: [PATCH 1/2] fix(dashboard): Tab menu visible for urls trailing '/' --- components/dashboard/src/Menu.tsx | 8 ++++---- components/dashboard/src/utils.ts | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/components/dashboard/src/Menu.tsx b/components/dashboard/src/Menu.tsx index e5ba7007f86640..bdc9207320581f 100644 --- a/components/dashboard/src/Menu.tsx +++ b/components/dashboard/src/Menu.tsx @@ -25,7 +25,7 @@ import { getProjectSettingsMenu } from "./projects/ProjectSettings"; import { ProjectContext } from "./projects/project-context"; import { PaymentContext } from "./payment-context"; import FeedbackFormModal from "./feedback-form/FeedbackModal"; -import { isGitpodIo } from "./utils"; +import { inResource, isGitpodIo } from "./utils"; import { getExperimentsClient } from "./experiments/client"; interface Entry { @@ -105,9 +105,9 @@ export default function Menu() { } // Hide most of the top menu when in a full-page form. - const isMinimalUI = ["/new", "/teams/new", "/open"].includes(location.pathname); - const isWorkspacesUI = ["/workspaces"].includes(location.pathname); - const isAdminUI = window.location.pathname.startsWith("/admin"); + const isMinimalUI = inResource(location.pathname, ["new", "teams/new", "open"]); + const isWorkspacesUI = inResource(location.pathname, ["workspaces"]); + const isAdminUI = inResource(window.location.pathname, ["admin"]); const [teamMembers, setTeamMembers] = useState>({}); useEffect(() => { diff --git a/components/dashboard/src/utils.ts b/components/dashboard/src/utils.ts index 671e45fa875800..8c14ffe76a0b7c 100644 --- a/components/dashboard/src/utils.ts +++ b/components/dashboard/src/utils.ts @@ -57,3 +57,21 @@ export function isGitpodIo() { window.location.hostname.endsWith("gitpod-io-dev.com") ); } + +function trimResource(resource: string): string { + return resource.split('/').filter(Boolean).join('/'); +} + +// Returns 'true' if a 'pathname' is a part of 'resources' provided. +// `inResource("/app/testing/", ["new", "app", "teams"])` will return true +// because '/app/testing' is a part of root 'app' +// +// 'pathname' arg can be provided via `location.pathname`. +export function inResource(pathname: string, resources: string[]): boolean { + // Removes leading and trailing '/' + const trimmedResource = trimResource(pathname) + + // Checks if a path is part of a resource. + // E.g. "api/userspace/resource" path is a part of resource "api/userspace" + return resources.map(res => trimmedResource.startsWith(trimResource(res))).some(Boolean) +} From e2d85089c85030fad178069464f8a365611a2c46 Mon Sep 17 00:00:00 2001 From: CuriousCorrelation Date: Sat, 25 Jun 2022 18:08:58 +0530 Subject: [PATCH 2/2] [dashboard]: Add test for 'inResource' --- components/dashboard/src/utils.test.ts | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 components/dashboard/src/utils.test.ts diff --git a/components/dashboard/src/utils.test.ts b/components/dashboard/src/utils.test.ts new file mode 100644 index 00000000000000..3717821a4c0fee --- /dev/null +++ b/components/dashboard/src/utils.test.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2022 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License-AGPL.txt in the project root for license information. + */ + +import { inResource } from "./utils"; + +test("inResource", () => { + + // Given root path is a part of resources specified + expect(inResource("/app", ["new", "app", "teams"])).toBe(true); + + // Given path is a part of resources specified + expect(inResource("/app/testing", ["new", "app", "teams"])).toBe(true); + + // Empty resources + expect(inResource("/just/a/path", [])).toBe(false); + + // Both resources starting with '/' + expect(inResource("/app", ["/app"])).toBe(true); + + // Both resources ending with '/' + expect(inResource("app/", ["app/"])).toBe(true); + + // Both resources containing path with subdirectories + expect(inResource("/admin/teams/someTeam/somePerson", ["/admin/teams"])).toBe(true); + +});