Skip to content

Commit

Permalink
pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
laushinka committed Jul 20, 2022
1 parent 4df9c3e commit 0b1d4ca
Show file tree
Hide file tree
Showing 10 changed files with 388 additions and 34 deletions.
8 changes: 7 additions & 1 deletion components/dashboard/src/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,17 @@ export default function Menu() {
link: `/t/${team.slug}/members`,
},
];
if (showUsageBasedUI) {
teamSettingsList.push({
title: "Usage",
link: `/t/${team.slug}/usage`,
});
}
if (currentUserInTeam?.role === "owner") {
teamSettingsList.push({
title: "Settings",
link: `/t/${team.slug}/settings`,
alternatives: getTeamSettingsMenu({ team, showPaymentUI, showUsageBasedUI }).flatMap((e) => e.link),
alternatives: getTeamSettingsMenu({ team, showPaymentUI }).flatMap((e) => e.link),
});
}

Expand Down
16 changes: 13 additions & 3 deletions components/dashboard/src/components/Arrow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,22 @@
* See License-AGPL.txt in the project root for license information.
*/

function Arrow(props: { up: boolean; customBorderClasses?: string }) {
function Arrow(props: { direction: string; customBorderClasses?: string }) {
const { direction, customBorderClasses } = props;

// Using any because of known TS bug with bracket notation:
// https://github.com/microsoft/TypeScript/issues/10530
const directionMap: any = {
up: "-135deg",
down: "45deg",
left: "135deg",
right: "315deg",
};
return (
<span
className={
"mx-2 " +
(props.customBorderClasses ||
(customBorderClasses ||
"border-gray-400 dark:border-gray-500 group-hover:border-gray-600 dark:group-hover:border-gray-400")
}
style={{
Expand All @@ -18,7 +28,7 @@ function Arrow(props: { up: boolean; customBorderClasses?: string }) {
padding: 3,
borderWidth: "0 2px 2px 0",
display: "inline-block",
transform: `rotate(${props.up ? "-135deg" : "45deg"})`,
transform: `rotate(${directionMap[direction]})`,
}}
></span>
);
Expand Down
2 changes: 1 addition & 1 deletion components/dashboard/src/components/DropDown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function DropDown(props: DropDownProps) {
>
{props.prefix}
{current}
<Arrow up={false} customBorderClasses={props.renderAsLink ? asLinkArrowBorder : undefined} />
<Arrow direction={"down"} customBorderClasses={props.renderAsLink ? asLinkArrowBorder : undefined} />
</span>
</ContextMenu>
);
Expand Down
50 changes: 50 additions & 0 deletions components/dashboard/src/components/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* 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 Arrow from "./Arrow";

function Pagination(props: { numberOfPages: number; currentPage: number; setCurrentPage: any }) {
const { numberOfPages, currentPage, setCurrentPage } = props;
const availablePageNumbers = [...Array(numberOfPages + 1).keys()].slice(1);

const nextPage = () => {
if (currentPage !== numberOfPages) setCurrentPage(currentPage + 1);
};
const prevPage = () => {
if (currentPage !== 1) setCurrentPage(currentPage - 1);
};

return (
<nav className="mt-16">
<ul className="flex justify-center space-x-4">
<li className="text-gray-400 cursor-pointer">
<span onClick={prevPage}>
<Arrow direction={"left"} />
Previous
</span>
</li>
{availablePageNumbers.map((pn) => (
<li
key={pn}
className={`text-gray-500 cursor-pointer w-8 text-center rounded-md ${
currentPage === pn ? "bg-gray-200" : ""
} `}
>
<span onClick={() => setCurrentPage(pn)}>{pn}</span>
</li>
))}
<li className="text-gray-400 cursor-pointer">
<span onClick={nextPage}>
Next
<Arrow direction={"right"} />
</span>
</li>
</ul>
</nav>
);
}

export default Pagination;
2 changes: 1 addition & 1 deletion components/dashboard/src/start/StartWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ export default class StartWorkspace extends React.Component<StartWorkspaceProps,
>
<button className="secondary">
More Actions...
<Arrow up={false} />
<Arrow direction={"down"} />
</button>
</ContextMenu>
<button
Expand Down
4 changes: 2 additions & 2 deletions components/dashboard/src/teams/TeamBilling.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function TeamBilling() {
const team = getCurrentTeam(location, teams);
const [members, setMembers] = useState<TeamMemberInfo[]>([]);
const [teamSubscription, setTeamSubscription] = useState<TeamSubscription2 | undefined>();
const { showPaymentUI, showUsageBasedUI, currency, setCurrency } = useContext(PaymentContext);
const { showPaymentUI, currency, setCurrency } = useContext(PaymentContext);
const [pendingTeamPlan, setPendingTeamPlan] = useState<PendingPlan | undefined>();
const [pollTeamSubscriptionTimeout, setPollTeamSubscriptionTimeout] = useState<NodeJS.Timeout | undefined>();

Expand Down Expand Up @@ -140,7 +140,7 @@ export default function TeamBilling() {

return (
<PageWithSubMenu
subMenu={getTeamSettingsMenu({ team, showPaymentUI, showUsageBasedUI })}
subMenu={getTeamSettingsMenu({ team, showPaymentUI })}
title="Billing"
subtitle="Manage team billing and plans."
>
Expand Down
16 changes: 4 additions & 12 deletions components/dashboard/src/teams/TeamSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import { getGitpodService, gitpodHostUrl } from "../service/service";
import { UserContext } from "../user-context";
import { getCurrentTeam, TeamsContext } from "./teams-context";

export function getTeamSettingsMenu(params: { team?: Team; showPaymentUI?: boolean; showUsageBasedUI?: boolean }) {
const { team, showPaymentUI, showUsageBasedUI } = params;
export function getTeamSettingsMenu(params: { team?: Team; showPaymentUI?: boolean }) {
const { team, showPaymentUI } = params;
return [
{
title: "General",
Expand All @@ -30,14 +30,6 @@ export function getTeamSettingsMenu(params: { team?: Team; showPaymentUI?: boole
},
]
: []),
...(showUsageBasedUI
? [
{
title: "Usage",
link: [`/t/${team?.slug}/usage`],
},
]
: []),
];
}

Expand All @@ -49,7 +41,7 @@ export default function TeamSettings() {
const { user } = useContext(UserContext);
const location = useLocation();
const team = getCurrentTeam(location, teams);
const { showPaymentUI, showUsageBasedUI } = useContext(PaymentContext);
const { showPaymentUI } = useContext(PaymentContext);

const close = () => setModal(false);

Expand All @@ -76,7 +68,7 @@ export default function TeamSettings() {
return (
<>
<PageWithSubMenu
subMenu={getTeamSettingsMenu({ team, showPaymentUI, showUsageBasedUI })}
subMenu={getTeamSettingsMenu({ team, showPaymentUI })}
title="Settings"
subtitle="Manage general team settings."
>
Expand Down
107 changes: 96 additions & 11 deletions components/dashboard/src/teams/TeamUsage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@

import { useContext, useEffect, useState } from "react";
import { Redirect, useLocation } from "react-router";
import { PageWithSubMenu } from "../components/PageWithSubMenu";
import { getCurrentTeam, TeamsContext } from "./teams-context";
import { getTeamSettingsMenu } from "./TeamSettings";
import { PaymentContext } from "../payment-context";
import { getGitpodService } from "../service/service";
import { BillableSession, BillableWorkspaceType } from "@gitpod/gitpod-protocol/lib/usage";
import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution";
import { Item, ItemField, ItemsList } from "../components/ItemsList";
import moment from "moment";
import Property from "../admin/Property";
import Arrow from "../components/Arrow";
import Pagination from "../components/Pagination";
import Header from "../components/Header";

function TeamUsage() {
const { teams } = useContext(TeamsContext);
const { showPaymentUI, showUsageBasedUI } = useContext(PaymentContext);
const { showUsageBasedUI } = useContext(PaymentContext);
const location = useLocation();
const team = getCurrentTeam(location, teams);
const [billedUsage, setBilledUsage] = useState<BillableSession[]>([]);
const [currentPage, setCurrentPage] = useState(1);
const [resultsPerPage] = useState(10);

useEffect(() => {
if (!team) {
Expand All @@ -47,13 +47,23 @@ function TeamUsage() {
return "Prebuild";
};

const getHours = (endTime: number | undefined, startTime: number) => {
if (!endTime) return "";
const getMinutes = (endTime: number, startTime: number) => {
return Math.floor(endTime - startTime) / (1000 * 60) + " min";
};

return ((endTime - startTime) / (1000 * 60 * 60)).toFixed(1) + "hrs";
const calculateTotalUsage = () => {
let totalCredits = 0;
billedUsage.forEach((session) => (totalCredits += session.credits));
return totalCredits;
};

const lastResultOnCurrentPage = currentPage * resultsPerPage;
const firstResultOnCurrentPage = lastResultOnCurrentPage - resultsPerPage;
const numberOfPages = Math.ceil(billedUsage.length / resultsPerPage);
const currentPaginatedResults = billedUsage.slice(firstResultOnCurrentPage, lastResultOnCurrentPage);

return (
<<<<<<< HEAD
<PageWithSubMenu
subMenu={getTeamSettingsMenu({ team, showPaymentUI, showUsageBasedUI })}
title="Usage"
Expand Down Expand Up @@ -113,11 +123,86 @@ function TeamUsage() {
</div>
<div className="pr-2">
<Arrow up={false} />
=======
<>
<Header title="Usage" subtitle="Manage team usage." />
<div className="app-container">
<div className="flex space-x-16">
<div className="flex">
<div className="space-y-8 mt-6 mb-6">
<div className="flex flex-col truncate">
<div className="text-base text-gray-500 truncate">Period</div>
<div className="mr-3 text-lg text-gray-600 font-semibold truncate">June 2022</div>
</div>
<div className="flex flex-col truncate">
<div className="text-base text-gray-500 truncate">Monthly usage</div>
<div className="mr-3 text-lg text-gray-600 font-semibold truncate">
{calculateTotalUsage()} Total Credits
</div>
</div>
>>>>>>> f119f0fdc (pagination)
</div>
</div>
))}
</ItemsList>
</PageWithSubMenu>
<div className="flex flex-col w-full mb-8">
<h3>All Usage</h3>
<span className="text-gray-500 mb-5">View usage details of all team members.</span>
<ItemsList className="mt-2 text-gray-500">
<Item header={false} className="grid grid-cols-5 bg-gray-100 mb-5">
<ItemField className="my-auto">
<span>Type</span>
</ItemField>
<ItemField className="my-auto">
<span>Class</span>
</ItemField>
<ItemField className="my-auto">
<span>Usage</span>
</ItemField>
<ItemField className="my-auto">
<span>Credits</span>
</ItemField>
<ItemField className="my-auto" />
</Item>
{currentPaginatedResults.map((usage) => (
<div
key={usage.instanceId}
className="flex p-3 grid grid-cols-5 justify-between transition ease-in-out rounded-xl focus:bg-gitpod-kumquat-light"
>
<div className="my-auto">
<span>{getType(usage.workspaceType)}</span>
</div>
<div className="my-auto">
<span className="text-gray-400">{usage.workspaceClass}</span>
</div>
<div className="my-auto">
<span className="text-gray-700">
{getMinutes(
new Date(usage.endTime).getTime(),
new Date(usage.startTime).getTime(),
)}
</span>
</div>
<div className="my-auto">
<span className="text-gray-700">{usage.credits.toFixed(1)}</span>
</div>
<div className="my-auto">
<span className="text-gray-400">
{moment(new Date(usage.startTime).toDateString()).fromNow()}
</span>
</div>
</div>
))}
</ItemsList>
{billedUsage.length > resultsPerPage && (
<Pagination
currentPage={currentPage}
setCurrentPage={setCurrentPage}
numberOfPages={numberOfPages}
/>
)}
</div>
</div>
</div>
</>
);
}

Expand Down
4 changes: 2 additions & 2 deletions components/dashboard/src/workspaces/Workspaces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export default function () {
className="flex cursor-pointer py-6 px-6 flex-row text-gray-400 bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 rounded-xl mb-2"
>
<div className="pr-2">
<Arrow up={!!showInactive} />
<Arrow direction={showInactive ? "up" : "down"} />
</div>
<div className="flex flex-grow flex-col ">
<div className="font-medium text-gray-500 dark:text-gray-200 truncate">
Expand All @@ -168,7 +168,7 @@ export default function () {
</span>
</div>
<div className="text-sm flex-auto">
Workspaces that have been stopped for more than 24 hours. Inactive
Workspaces that have been stopped for more than 24 hours. Inactive
workspaces are automatically deleted after 14 days.{" "}
<a
className="gp-link"
Expand Down
Loading

0 comments on commit 0b1d4ca

Please sign in to comment.