From db6ff5084a3f91d9bcdc1533065c73bcbcdb52f0 Mon Sep 17 00:00:00 2001 From: Devansu Yadav Date: Wed, 8 Feb 2023 13:38:30 +0000 Subject: [PATCH 1/4] update(nav menu): Set active state for admin menu --- components/dashboard/src/menu/Menu.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/components/dashboard/src/menu/Menu.tsx b/components/dashboard/src/menu/Menu.tsx index ebd8333da88b22..f74ec06fabb04f 100644 --- a/components/dashboard/src/menu/Menu.tsx +++ b/components/dashboard/src/menu/Menu.tsx @@ -133,6 +133,11 @@ export default function Menu() { userBillingMode, ]); + const adminMenu: Entry = { + title: "Admin", + link: "/admin", + }; + const handleFeedbackFormClick = () => { setFeedbackFormVisible(true); }; @@ -172,7 +177,11 @@ export default function Menu() {
  • {user?.rolesOrPermissions?.includes("admin") && (
  • - +
  • )} {isGitpodIo() && ( From 104cc86e0e71eadbe357aa00c7d3cf7feb21a5cd Mon Sep 17 00:00:00 2001 From: Devansu Yadav Date: Fri, 10 Feb 2023 10:15:47 +0000 Subject: [PATCH 2/4] minor: fix active state for admin menu --- components/dashboard/src/menu/Menu.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/dashboard/src/menu/Menu.tsx b/components/dashboard/src/menu/Menu.tsx index f74ec06fabb04f..ff8b4877d8e5df 100644 --- a/components/dashboard/src/menu/Menu.tsx +++ b/components/dashboard/src/menu/Menu.tsx @@ -136,6 +136,7 @@ export default function Menu() { const adminMenu: Entry = { title: "Admin", link: "/admin", + alternatives: ["/admin/users"], }; const handleFeedbackFormClick = () => { From c1b02ea095ce568df4476afbb43e150bcec20c7e Mon Sep 17 00:00:00 2001 From: Devansu Yadav Date: Fri, 10 Feb 2023 12:32:39 +0000 Subject: [PATCH 3/4] major: update page header and use tabs --- .../dashboard/src/admin/AdminPageHeader.tsx | 23 +++++++++++++++++++ .../src/admin/BlockedRepositories.tsx | 6 ++--- components/dashboard/src/admin/License.tsx | 6 ++--- .../src/admin/PageWithAdminSubMenu.tsx | 22 ------------------ .../dashboard/src/admin/ProjectsSearch.tsx | 6 ++--- components/dashboard/src/admin/Settings.tsx | 6 ++--- .../dashboard/src/admin/TeamsSearch.tsx | 6 ++--- components/dashboard/src/admin/UserDetail.tsx | 6 ++--- components/dashboard/src/admin/UserSearch.tsx | 6 ++--- .../dashboard/src/admin/WorkspacesSearch.tsx | 6 ++--- .../admin/{admin-menu.ts => admin.routes.ts} | 18 ++++++++------- 11 files changed, 57 insertions(+), 54 deletions(-) create mode 100644 components/dashboard/src/admin/AdminPageHeader.tsx delete mode 100644 components/dashboard/src/admin/PageWithAdminSubMenu.tsx rename components/dashboard/src/admin/{admin-menu.ts => admin.routes.ts} (60%) diff --git a/components/dashboard/src/admin/AdminPageHeader.tsx b/components/dashboard/src/admin/AdminPageHeader.tsx new file mode 100644 index 00000000000000..55f92fbfc7467a --- /dev/null +++ b/components/dashboard/src/admin/AdminPageHeader.tsx @@ -0,0 +1,23 @@ +/** + * 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 Header from "../components/Header"; +import { getAdminTabs } from "./admin.routes"; + +export interface AdminPageHeaderProps { + title: string; + subtitle: string; + children: React.ReactNode; +} + +export function AdminPageHeader({ title, subtitle, children }: AdminPageHeaderProps) { + return ( + <> +
    + {children} + + ); +} diff --git a/components/dashboard/src/admin/BlockedRepositories.tsx b/components/dashboard/src/admin/BlockedRepositories.tsx index 506e5ca2bf1635..2ede5ae7b0e9ab 100644 --- a/components/dashboard/src/admin/BlockedRepositories.tsx +++ b/components/dashboard/src/admin/BlockedRepositories.tsx @@ -7,7 +7,7 @@ import { AdminGetListResult } from "@gitpod/gitpod-protocol"; import { useEffect, useRef, useState } from "react"; import { getGitpodService } from "../service/service"; -import { PageWithAdminSubMenu } from "./PageWithAdminSubMenu"; +import { AdminPageHeader } from "./AdminPageHeader"; import { BlockedRepository } from "@gitpod/gitpod-protocol/lib/blocked-repositories-protocol"; import ConfirmationModal from "../components/ConfirmationModal"; import Modal from "../components/Modal"; @@ -18,9 +18,9 @@ import Alert from "../components/Alert"; export function BlockedRepositories() { return ( - + - + ); } diff --git a/components/dashboard/src/admin/License.tsx b/components/dashboard/src/admin/License.tsx index 2313f9eeb63bc2..34c598556d8e40 100644 --- a/components/dashboard/src/admin/License.tsx +++ b/components/dashboard/src/admin/License.tsx @@ -17,7 +17,7 @@ import { ReactComponent as LinkSvg } from "../images/external-link.svg"; import SolidCard from "../components/SolidCard"; import Card from "../components/Card"; import { isGitpodIo } from "../utils"; -import { PageWithAdminSubMenu } from "./PageWithAdminSubMenu"; +import { AdminPageHeader } from "./AdminPageHeader"; export default function License() { const { license, setLicense } = useContext(LicenseContext); @@ -42,7 +42,7 @@ export default function License() { return (
    - +
    @@ -85,7 +85,7 @@ export default function License() {
    -
    +
    ); } diff --git a/components/dashboard/src/admin/PageWithAdminSubMenu.tsx b/components/dashboard/src/admin/PageWithAdminSubMenu.tsx deleted file mode 100644 index fd806ca474b167..00000000000000 --- a/components/dashboard/src/admin/PageWithAdminSubMenu.tsx +++ /dev/null @@ -1,22 +0,0 @@ -/** - * 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 { PageWithSubMenu } from "../components/PageWithSubMenu"; -import { getAdminMenu } from "./admin-menu"; - -export interface PageWithAdminSubMenuProps { - title: string; - subtitle: string; - children: React.ReactNode; -} - -export function PageWithAdminSubMenu({ title, subtitle, children }: PageWithAdminSubMenuProps) { - return ( - - {children} - - ); -} diff --git a/components/dashboard/src/admin/ProjectsSearch.tsx b/components/dashboard/src/admin/ProjectsSearch.tsx index 3c2f5ccd47475c..8e150f03b93fcb 100644 --- a/components/dashboard/src/admin/ProjectsSearch.tsx +++ b/components/dashboard/src/admin/ProjectsSearch.tsx @@ -12,14 +12,14 @@ import { useState, useEffect } from "react"; import ProjectDetail from "./ProjectDetail"; import { getGitpodService } from "../service/service"; import { AdminGetListResult, Project } from "@gitpod/gitpod-protocol"; -import { PageWithAdminSubMenu } from "./PageWithAdminSubMenu"; +import { AdminPageHeader } from "./AdminPageHeader"; import Pagination from "../Pagination/Pagination"; export default function ProjectsSearchPage() { return ( - + - + ); } diff --git a/components/dashboard/src/admin/Settings.tsx b/components/dashboard/src/admin/Settings.tsx index a54bf6d6884a0e..a4187cc0744003 100644 --- a/components/dashboard/src/admin/Settings.tsx +++ b/components/dashboard/src/admin/Settings.tsx @@ -12,7 +12,7 @@ import { getGitpodService } from "../service/service"; import { useEffect, useState } from "react"; import InfoBox from "../components/InfoBox"; import { isGitpodIo } from "../utils"; -import { PageWithAdminSubMenu } from "./PageWithAdminSubMenu"; +import { AdminPageHeader } from "./AdminPageHeader"; export default function Settings() { const { adminSettings, setAdminSettings } = useContext(AdminContext); @@ -38,7 +38,7 @@ export default function Settings() { return (
    - +

    Usage Statistics

    We collect usage telemetry to gain insights on how you use your Gitpod instance, so we can provide a @@ -84,7 +84,7 @@ export default function Settings() {

    {JSON.stringify(telemetryData, null, 2)}
    -
    +
    ); } diff --git a/components/dashboard/src/admin/TeamsSearch.tsx b/components/dashboard/src/admin/TeamsSearch.tsx index 996ae74b69031c..5ba7def213b8cc 100644 --- a/components/dashboard/src/admin/TeamsSearch.tsx +++ b/components/dashboard/src/admin/TeamsSearch.tsx @@ -13,14 +13,14 @@ import { Link } from "react-router-dom"; import { getGitpodService } from "../service/service"; import { AdminGetListResult, Team } from "@gitpod/gitpod-protocol"; import Label from "./Label"; -import { PageWithAdminSubMenu } from "./PageWithAdminSubMenu"; +import { AdminPageHeader } from "./AdminPageHeader"; import Pagination from "../Pagination/Pagination"; export default function TeamsSearchPage() { return ( - + - + ); } diff --git a/components/dashboard/src/admin/UserDetail.tsx b/components/dashboard/src/admin/UserDetail.tsx index 81976da05a40fa..390bb2665c1da1 100644 --- a/components/dashboard/src/admin/UserDetail.tsx +++ b/components/dashboard/src/admin/UserDetail.tsx @@ -21,7 +21,7 @@ import Modal from "../components/Modal"; import { getGitpodService } from "../service/service"; import { WorkspaceSearch } from "./WorkspacesSearch"; import Property from "./Property"; -import { PageWithAdminSubMenu } from "./PageWithAdminSubMenu"; +import { AdminPageHeader } from "./AdminPageHeader"; import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode"; import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution"; import CaretDown from "../icons/CaretDown.svg"; @@ -258,7 +258,7 @@ export default function UserDetail(p: { user: User }) { return ( <> - +
    @@ -326,7 +326,7 @@ export default function UserDetail(p: { user: User }) {
    - + setEditSpendingLimit(false)} diff --git a/components/dashboard/src/admin/UserSearch.tsx b/components/dashboard/src/admin/UserSearch.tsx index d295b217075be6..78bdcb6f3fa066 100644 --- a/components/dashboard/src/admin/UserSearch.tsx +++ b/components/dashboard/src/admin/UserSearch.tsx @@ -11,7 +11,7 @@ import { useLocation } from "react-router"; import { Link } from "react-router-dom"; import Pagination from "../Pagination/Pagination"; import { getGitpodService } from "../service/service"; -import { PageWithAdminSubMenu } from "./PageWithAdminSubMenu"; +import { AdminPageHeader } from "./AdminPageHeader"; import UserDetail from "./UserDetail"; export default function UserSearch() { @@ -61,7 +61,7 @@ export default function UserSearch() { } }; return ( - +
    @@ -123,7 +123,7 @@ export default function UserSearch() { setPage={search} totalNumberOfPages={Math.ceil(searchResult.total / pageLength)} /> - + ); } diff --git a/components/dashboard/src/admin/WorkspacesSearch.tsx b/components/dashboard/src/admin/WorkspacesSearch.tsx index 722d4165062665..769c81bf542f0a 100644 --- a/components/dashboard/src/admin/WorkspacesSearch.tsx +++ b/components/dashboard/src/admin/WorkspacesSearch.tsx @@ -23,7 +23,7 @@ import Pagination from "../Pagination/Pagination"; import { getGitpodService } from "../service/service"; import { getProjectPath } from "../workspaces/WorkspaceEntryNew"; import WorkspaceDetail from "./WorkspaceDetail"; -import { PageWithAdminSubMenu } from "./PageWithAdminSubMenu"; +import { AdminPageHeader } from "./AdminPageHeader"; import Alert from "../components/Alert"; import { isGitpodIo } from "../utils"; import { WorkspaceStatusIndicator } from "../workspaces/WorkspaceStatusIndicator"; @@ -34,9 +34,9 @@ interface Props { export default function WorkspaceSearchPage() { return ( - + - + ); } diff --git a/components/dashboard/src/admin/admin-menu.ts b/components/dashboard/src/admin/admin.routes.ts similarity index 60% rename from components/dashboard/src/admin/admin-menu.ts rename to components/dashboard/src/admin/admin.routes.ts index cf9ee07aebf06a..d809ca032c0963 100644 --- a/components/dashboard/src/admin/admin-menu.ts +++ b/components/dashboard/src/admin/admin.routes.ts @@ -3,36 +3,38 @@ * Licensed under the GNU Affero General Public License (AGPL). * See License.AGPL.txt in the project root for license information. */ +import { TabEntry } from "../components/Header"; -export function getAdminMenu() { +export function getAdminTabs(): TabEntry[] { return [ { title: "Users", - link: ["/admin/users", "/admin"], + link: "/admin/users", + alternatives: ["/admin"], }, { title: "Workspaces", - link: ["/admin/workspaces"], + link: "/admin/workspaces", }, { title: "Projects", - link: ["/admin/projects"], + link: "/admin/projects", }, { title: "Organizations", - link: ["/admin/orgs"], + link: "/admin/orgs", }, { title: "Blocked Repositories", - link: ["/admin/blocked-repositories"], + link: "/admin/blocked-repositories", }, { title: "License", - link: ["/admin/license"], + link: "/admin/license", }, { title: "Settings", - link: ["/admin/settings"], + link: "/admin/settings", }, ]; } From 4948609646f6bb5f886db1c39af8f000fbd925d5 Mon Sep 17 00:00:00 2001 From: Devansu Yadav Date: Sun, 12 Feb 2023 08:05:06 +0000 Subject: [PATCH 4/4] update: fix width, top margin and active state --- .../src/admin/BlockedRepositories.tsx | 134 +++++++++--------- components/dashboard/src/admin/License.tsx | 84 +++++------ .../dashboard/src/admin/ProjectsSearch.tsx | 108 +++++++------- components/dashboard/src/admin/Settings.tsx | 92 ++++++------ .../dashboard/src/admin/TeamsSearch.tsx | 4 +- components/dashboard/src/admin/UserDetail.tsx | 118 +++++++-------- components/dashboard/src/admin/UserSearch.tsx | 112 ++++++++------- .../dashboard/src/admin/WorkspacesSearch.tsx | 116 +++++++-------- components/dashboard/src/menu/Menu.tsx | 3 +- 9 files changed, 396 insertions(+), 375 deletions(-) diff --git a/components/dashboard/src/admin/BlockedRepositories.tsx b/components/dashboard/src/admin/BlockedRepositories.tsx index 2ede5ae7b0e9ab..04f4425f9b6629 100644 --- a/components/dashboard/src/admin/BlockedRepositories.tsx +++ b/components/dashboard/src/admin/BlockedRepositories.tsx @@ -99,78 +99,80 @@ export function BlockedRepositoriesList(props: Props) { return ( <> - {isAddModalVisible && ( - setAddModalVisible(false)} - /> - )} - {isDeleteModalVisible && ( - deleteBlockedRepository(currentBlockedRepository)} - onClose={() => setDeleteModalVisible(false)} - /> - )} -
    -
    -
    -
    - {searching ? ( - - - + {isAddModalVisible && ( + setAddModalVisible(false)} + /> + )} + {isDeleteModalVisible && ( + deleteBlockedRepository(currentBlockedRepository)} + onClose={() => setDeleteModalVisible(false)} + /> + )} +
    +
    +
    +
    + {searching ? ( + + + + + + ) : ( + + - - - ) : ( - - - - )} + + )} +
    + ke.key === "Enter" && search()} + onChange={(v) => { + setQueryTerm(v.target.value.trim()); + }} + /> +
    +
    +
    - ke.key === "Enter" && search()} - onChange={(v) => { - setQueryTerm(v.target.value.trim()); - }} - /> -
    -
    -
    -
    - - Search entries by their repository URL RegEx. - -
    -
    -
    Repository URL (RegEx)
    -
    Block Users
    -
    + + Search entries by their repository URL RegEx. + +
    +
    +
    Repository URL (RegEx)
    +
    Block Users
    +
    +
    + {searchResult.rows.map((br) => ( + + ))}
    - {searchResult.rows.map((br) => ( - - ))}
    ); diff --git a/components/dashboard/src/admin/License.tsx b/components/dashboard/src/admin/License.tsx index 34c598556d8e40..92c7a3199af9e4 100644 --- a/components/dashboard/src/admin/License.tsx +++ b/components/dashboard/src/admin/License.tsx @@ -43,47 +43,51 @@ export default function License() { return (
    -
    - - - {licenseLevel} - {paid} -
    Available features:
    -
    - {features && - features.map((feat: string) => ( - - {featureList?.includes(feat) ? ( - - ) : ( - - )} - {capitalizeInitials(feat)} - - ))} -
    -
    -
    - - -
    {statusMessage}
    -

    Registered Users

    - {license?.userCount || 0} - / {userLimit} -

    License Type

    -

    {capitalizeInitials(license?.type || "")}

    - - Compare Plans -
    - +
    +
    + + + {licenseLevel} + {paid} +
    Available features:
    +
    + {features && + features.map((feat: string) => ( + + {featureList?.includes(feat) ? ( + + ) : ( + + )} + {capitalizeInitials(feat)} + + ))}
    -
    - - + + + + +
    {statusMessage}
    +

    Registered Users

    + {license?.userCount || 0} + / {userLimit} +

    License Type

    +

    + {capitalizeInitials(license?.type || "")} +

    + + Compare Plans +
    + +
    +
    +
    +
    +
    diff --git a/components/dashboard/src/admin/ProjectsSearch.tsx b/components/dashboard/src/admin/ProjectsSearch.tsx index 8e150f03b93fcb..93fd13819eb9d0 100644 --- a/components/dashboard/src/admin/ProjectsSearch.tsx +++ b/components/dashboard/src/admin/ProjectsSearch.tsx @@ -92,65 +92,67 @@ export function ProjectsSearch() { return ( <> -
    -
    -
    -
    - {searching ? ( - - - +
    +
    +
    +
    + {searching ? ( + + + + + + ) : ( + + - - - ) : ( - - - - )} + + )} +
    + k.key === "Enter" && search()} + onChange={(v) => { + setSearchTerm(v.target.value.trim()); + }} + />
    - k.key === "Enter" && search()} - onChange={(v) => { - setSearchTerm(v.target.value.trim()); - }} - /> +
    -
    -
    -
    -
    -
    Name
    -
    Clone URL
    -
    Created
    +
    +
    +
    Name
    +
    Clone URL
    +
    Created
    +
    + {searchResult.rows.map((project) => ( + + ))}
    - {searchResult.rows.map((project) => ( - - ))} +
    - ); diff --git a/components/dashboard/src/admin/Settings.tsx b/components/dashboard/src/admin/Settings.tsx index a4187cc0744003..d9320c45631974 100644 --- a/components/dashboard/src/admin/Settings.tsx +++ b/components/dashboard/src/admin/Settings.tsx @@ -39,51 +39,53 @@ export default function Settings() { return (
    -

    Usage Statistics

    -

    - We collect usage telemetry to gain insights on how you use your Gitpod instance, so we can provide a - better overall experience. -

    -

    - - Read our Privacy Policy - -

    - - Enable usage telemetry on your Gitpod instance. A preview of your telemetry is available - below. - - } - checked={adminSettings?.sendTelemetry ?? false} - onChange={(evt) => - actuallySetTelemetryPrefs({ - ...adminSettings, - sendTelemetry: evt.target.checked, - } as InstallationAdminSettings) - } - /> - - Include an optional customer ID in usage telemetry to provide individualized support. - - } - checked={adminSettings?.sendCustomerID ?? false} - onChange={(evt) => - actuallySetTelemetryPrefs({ - ...adminSettings, - sendCustomerID: evt.target.checked, - } as InstallationAdminSettings) - } - /> -

    Telemetry preview

    - -
    {JSON.stringify(telemetryData, null, 2)}
    -
    +
    +

    Usage Statistics

    +

    + We collect usage telemetry to gain insights on how you use your Gitpod instance, so we can + provide a better overall experience. +

    +

    + + Read our Privacy Policy + +

    + + Enable usage telemetry on your Gitpod instance. A preview of your telemetry is available + below. + + } + checked={adminSettings?.sendTelemetry ?? false} + onChange={(evt) => + actuallySetTelemetryPrefs({ + ...adminSettings, + sendTelemetry: evt.target.checked, + } as InstallationAdminSettings) + } + /> + + Include an optional customer ID in usage telemetry to provide individualized support. + + } + checked={adminSettings?.sendCustomerID ?? false} + onChange={(evt) => + actuallySetTelemetryPrefs({ + ...adminSettings, + sendCustomerID: evt.target.checked, + } as InstallationAdminSettings) + } + /> +

    Telemetry preview

    + +
    {JSON.stringify(telemetryData, null, 2)}
    +
    +
    ); diff --git a/components/dashboard/src/admin/TeamsSearch.tsx b/components/dashboard/src/admin/TeamsSearch.tsx index 5ba7def213b8cc..813c6df39fa872 100644 --- a/components/dashboard/src/admin/TeamsSearch.tsx +++ b/components/dashboard/src/admin/TeamsSearch.tsx @@ -19,7 +19,9 @@ import Pagination from "../Pagination/Pagination"; export default function TeamsSearchPage() { return ( - +
    + +
    ); } diff --git a/components/dashboard/src/admin/UserDetail.tsx b/components/dashboard/src/admin/UserDetail.tsx index 390bb2665c1da1..2c7912d788ccae 100644 --- a/components/dashboard/src/admin/UserDetail.tsx +++ b/components/dashboard/src/admin/UserDetail.tsx @@ -259,69 +259,73 @@ export default function UserDetail(p: { user: User }) { return ( <> -
    -
    -
    -

    {user.fullName}

    - {user.blocked ?