Skip to content

UI updates to admin dashboard #16307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions components/dashboard/src/admin/AdminPageHeader.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<Header title={title} subtitle={subtitle} tabs={getAdminTabs()} />
{children}
</>
);
}
140 changes: 71 additions & 69 deletions components/dashboard/src/admin/BlockedRepositories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -18,9 +18,9 @@ import Alert from "../components/Alert";

export function BlockedRepositories() {
return (
<PageWithAdminSubMenu title="Blocked Repositories" subtitle="Search and manage all blocked repositories.">
<AdminPageHeader title="Admin" subtitle="Configure and manage instance settings.">
<BlockedRepositoriesList />
</PageWithAdminSubMenu>
</AdminPageHeader>
);
}

Expand Down Expand Up @@ -99,78 +99,80 @@ export function BlockedRepositoriesList(props: Props) {

return (
<>
{isAddModalVisible && (
<AddBlockedRepositoryModal
blockedRepository={currentBlockedRepository}
validate={validate}
save={save}
onClose={() => setAddModalVisible(false)}
/>
)}
{isDeleteModalVisible && (
<DeleteBlockedRepositoryModal
blockedRepository={currentBlockedRepository}
deleteBlockedRepository={() => deleteBlockedRepository(currentBlockedRepository)}
onClose={() => setDeleteModalVisible(false)}
/>
)}
<div className="pt-8 flex">
<div className="flex justify-between w-full">
<div className="flex">
<div className="py-4">
{searching ? (
<svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path
fill="#A8A29E"
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
>
<animateTransform
attributeName="transform"
type="rotate"
dur="0.75s"
values="0 12 12;360 12 12"
repeatCount="indefinite"
<div className="app-container">
{isAddModalVisible && (
<AddBlockedRepositoryModal
blockedRepository={currentBlockedRepository}
validate={validate}
save={save}
onClose={() => setAddModalVisible(false)}
/>
)}
{isDeleteModalVisible && (
<DeleteBlockedRepositoryModal
blockedRepository={currentBlockedRepository}
deleteBlockedRepository={() => deleteBlockedRepository(currentBlockedRepository)}
onClose={() => setDeleteModalVisible(false)}
/>
)}
<div className="pt-8 flex">
<div className="flex justify-between w-full">
<div className="flex">
<div className="py-4">
{searching ? (
<svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path
fill="#A8A29E"
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
>
<animateTransform
attributeName="transform"
type="rotate"
dur="0.75s"
values="0 12 12;360 12 12"
repeatCount="indefinite"
/>
</path>
</svg>
) : (
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6 2a4 4 0 100 8 4 4 0 000-8zM0 6a6 6 0 1110.89 3.477l4.817 4.816a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 010 6z"
fill="#A8A29E"
/>
</path>
</svg>
) : (
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6 2a4 4 0 100 8 4 4 0 000-8zM0 6a6 6 0 1110.89 3.477l4.817 4.816a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 010 6z"
fill="#A8A29E"
/>
</svg>
)}
</svg>
)}
</div>
<input
type="search"
placeholder="Search by URL RegEx"
onKeyDown={(ke) => ke.key === "Enter" && search()}
onChange={(v) => {
setQueryTerm(v.target.value.trim());
}}
/>
</div>
<div className="flex space-x-2">
<button onClick={add}>New Blocked Repository</button>
</div>
<input
type="search"
placeholder="Search by URL RegEx"
onKeyDown={(ke) => ke.key === "Enter" && search()}
onChange={(v) => {
setQueryTerm(v.target.value.trim());
}}
/>
</div>
<div className="flex space-x-2">
<button onClick={add}>New Blocked Repository</button>
</div>
</div>
</div>

<Alert type={"info"} closable={false} showIcon={true} className="flex rounded p-2 mb-2 w-full">
Search entries by their repository URL <abbr title="regular expression">RegEx</abbr>.
</Alert>
<div className="flex flex-col space-y-2">
<div className="px-6 py-3 flex justify-between text-sm text-gray-400 border-t border-b border-gray-200 dark:border-gray-800 mb-2">
<div className="w-9/12">Repository URL (RegEx)</div>
<div className="w-1/12">Block Users</div>
<div className="w-1/12"></div>
<Alert type={"info"} closable={false} showIcon={true} className="flex rounded p-2 mb-2 w-full">
Search entries by their repository URL <abbr title="regular expression">RegEx</abbr>.
</Alert>
<div className="flex flex-col space-y-2">
<div className="px-6 py-3 flex justify-between text-sm text-gray-400 border-t border-b border-gray-200 dark:border-gray-800 mb-2">
<div className="w-9/12">Repository URL (RegEx)</div>
<div className="w-1/12">Block Users</div>
<div className="w-1/12"></div>
</div>
{searchResult.rows.map((br) => (
<BlockedRepositoryEntry br={br} confirmedDelete={confirmDeleteBlockedRepository} />
))}
</div>
{searchResult.rows.map((br) => (
<BlockedRepositoryEntry br={br} confirmedDelete={confirmDeleteBlockedRepository} />
))}
</div>
</>
);
Expand Down
90 changes: 47 additions & 43 deletions components/dashboard/src/admin/License.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -42,50 +42,54 @@ export default function License() {

return (
<div>
<PageWithAdminSubMenu title="License" subtitle="License associated with your Gitpod installation">
<div className="flex flex-row space-x-4">
<Card className="w-72 h-64">
<span>
{licenseLevel}
{paid}
<div className="mt-4 font-semibold text-sm">Available features:</div>
<div className="flex flex-col items-start text-sm">
{features &&
features.map((feat: string) => (
<span className="inline-flex space-x-1">
{featureList?.includes(feat) ? (
<CheckSvg fill="currentColor" className="self-center mt-1" />
) : (
<XSvg fill="currentColor" className="self-center h-2 mt-1" />
)}
<span>{capitalizeInitials(feat)}</span>
</span>
))}
</div>
</span>
</Card>
<SolidCard className="w-72 h-64">
<span>
<div className="my-2">{statusMessage}</div>
<p className="dark:text-gray-500 font-semibold">Registered Users</p>
<span className="dark:text-gray-300 text-lg">{license?.userCount || 0}</span>
<span className="dark:text-gray-500 text-gray-400 pt-1 text-lg"> / {userLimit} </span>
<p className="dark:text-gray-500 pt-2 font-semibold">License Type</p>
<h4 className="dark:text-gray-300 text-lg">{capitalizeInitials(license?.type || "")}</h4>
<a
className="gp-link flex flex-row mr-2 justify-end font-semibold space-x-2 mt-6"
href="https://www.gitpod.io/self-hosted"
target="_blank"
>
<span className="text-sm">Compare Plans</span>
<div className="self-end">
<LinkSvg />
<AdminPageHeader title="Admin" subtitle="Configure and manage instance settings.">
<div className="app-container mt-8">
<div className="flex flex-row space-x-4">
<Card className="w-72 h-64">
<span>
{licenseLevel}
{paid}
<div className="mt-4 font-semibold text-sm">Available features:</div>
<div className="flex flex-col items-start text-sm">
{features &&
features.map((feat: string) => (
<span className="inline-flex space-x-1">
{featureList?.includes(feat) ? (
<CheckSvg fill="currentColor" className="self-center mt-1" />
) : (
<XSvg fill="currentColor" className="self-center h-2 mt-1" />
)}
<span>{capitalizeInitials(feat)}</span>
</span>
))}
</div>
</a>
</span>
</SolidCard>
</span>
</Card>
<SolidCard className="w-72 h-64">
<span>
<div className="my-2">{statusMessage}</div>
<p className="dark:text-gray-500 font-semibold">Registered Users</p>
<span className="dark:text-gray-300 text-lg">{license?.userCount || 0}</span>
<span className="dark:text-gray-500 text-gray-400 pt-1 text-lg"> / {userLimit} </span>
<p className="dark:text-gray-500 pt-2 font-semibold">License Type</p>
<h4 className="dark:text-gray-300 text-lg">
{capitalizeInitials(license?.type || "")}
</h4>
<a
className="gp-link flex flex-row mr-2 justify-end font-semibold space-x-2 mt-6"
href="https://www.gitpod.io/self-hosted"
target="_blank"
>
<span className="text-sm">Compare Plans</span>
<div className="self-end">
<LinkSvg />
</div>
</a>
</span>
</SolidCard>
</div>
</div>
</PageWithAdminSubMenu>
</AdminPageHeader>
</div>
);
}
Expand Down
22 changes: 0 additions & 22 deletions components/dashboard/src/admin/PageWithAdminSubMenu.tsx

This file was deleted.

Loading