Path: blob/main/components/dashboard/src/prebuilds/list/PrebuildTable.tsx
2501 views
/**1* Copyright (c) 2024 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import { FC } from "react";7import { Table, TableBody, TableHead, TableHeader, TableRow } from "@podkit/tables/Table";8import { PrebuildListItem } from "./PrebuildListItem";9import { LoadingButton } from "@podkit/buttons/LoadingButton";10import { TextMuted } from "@podkit/typography/TextMuted";11import { Subheading } from "@podkit/typography/Headings";12import { cn } from "@podkit/lib/cn";13import { LoadingState } from "@podkit/loading/LoadingState";14import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@podkit/select/Select";15import { Prebuild } from "@gitpod/public-api/lib/gitpod/v1/prebuild_pb";16import { Filter, Sort, SortField, StatusOption } from "./PrebuildList";17import { SortCallback, SortableTableHead, TableSortOrder } from "@podkit/tables/SortableTable";18import { ConfigurationDropdown } from "../configuration-input/ConfigurationInput";19import { Button } from "@podkit/buttons/Button";2021type Props = {22prebuilds: Prebuild[];23filter?: Filter;24sort: Sort;25hasNextPage: boolean;26hasMoreThanOnePage: boolean;27isSearching: boolean;28isFetchingNextPage: boolean;29/**30* If true, the configuration dropdown and the "Run Prebuild" button will be hidden.31*/32hideOrgSpecificControls: boolean;33onFilterChange: (val: Filter) => void;34onLoadNextPage: () => void;35onSort: (columnName: SortField, direction: TableSortOrder) => void;36onTriggerPrebuild: () => void;37};38export const PrebuildsTable: FC<Props> = ({39prebuilds,40hasNextPage,41hasMoreThanOnePage,42isSearching,43isFetchingNextPage,44filter,45sort,46hideOrgSpecificControls,47onFilterChange,48onLoadNextPage,49onSort,50onTriggerPrebuild,51}) => {52return (53<>54{/* Search/Filter bar */}55<div className="flex flex-col-reverse md:flex-row flex-wrap justify-between items-center gap-2">56<div className="flex flex-row flex-wrap gap-2 items-center w-full md:w-auto">57{!hideOrgSpecificControls && (58<ConfigurationDropdown59selectedConfigurationId={filter?.configurationId}60onChange={(configurationId) => {61onFilterChange({ ...filter, configurationId });62}}63/>64)}65<Select66value={filter?.status ?? "any"}67onValueChange={(status) => {68if (status === "any") {69onFilterChange({ ...filter, status: undefined });70return;71}72onFilterChange({ ...filter, status: status as StatusOption });73}}74>75<SelectTrigger className="w-[120px]">76<SelectValue placeholder="Status" />77</SelectTrigger>78<SelectContent>79<SelectItem value="any">All</SelectItem>80<SelectItem value="failed">Failing</SelectItem>81<SelectItem value="succeeded">Successful</SelectItem>82<SelectItem value="unfinished">In progress</SelectItem>83</SelectContent>84</Select>85</div>86{!hideOrgSpecificControls && (87<Button className="w-full md:w-auto" onClick={onTriggerPrebuild}>88Run prebuild89</Button>90)}91</div>92<div className="relative w-full overflow-auto mt-4">93{prebuilds.length > 0 ? (94<Table>95<TableHeader>96<TableRow>97<TableHead className="w-52">Repository</TableHead>98<TableHead hideOnSmallScreen>Commit</TableHead>99<SortableTableHead100columnName={sort.sortBy}101sortOrder={sort.sortOrder}102onSort={onSort as SortCallback}103className="w-40"104hideOnSmallScreen105>106Triggered107</SortableTableHead>108<TableHead className="w-24">Status</TableHead>109{/* Action column, loading status in header */}110<TableHead className="w-24 text-right">111{isSearching && (112<div className="flex flex-right justify-end items-center">113<LoadingState delay={false} size={16} />114</div>115)}116</TableHead>117</TableRow>118</TableHeader>119<TableBody>120{prebuilds.map((configuration) => (121<PrebuildListItem key={configuration.id} prebuild={configuration} />122))}123</TableBody>124</Table>125) : (126<div127className={cn(128"w-full flex justify-center rounded-xl bg-pk-surface-secondary px-4 py-10 animate-fade-in-fast",129)}130>131<Subheading className="max-w-md">No results found. Try adjusting your search terms.</Subheading>132</div>133)}134{prebuilds.length > 1 && (135<div className="mt-4 mb-8 flex flex-row justify-center">136{hasNextPage ? (137<LoadingButton variant="secondary" onClick={onLoadNextPage} loading={isFetchingNextPage}>138Load more139</LoadingButton>140) : (141hasMoreThanOnePage && <TextMuted>All prebuilds are loaded</TextMuted>142)}143</div>144)}145</div>146</>147);148};149150151