Skip to content
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

Added functionality of filtering of Status page data #527

Merged
merged 11 commits into from
May 20, 2024
1 change: 1 addition & 0 deletions website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@nivo/line": "^0.83.0",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slot": "^1.0.2",
"bytes": "^3.1.2",
"class-variance-authority": "^0.7.0",
Expand Down
174 changes: 174 additions & 0 deletions website/src/components/ui/select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
Copyright 2023 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import * as React from "react"
import * as SelectPrimitive from "@radix-ui/react-select"
import { Check, ChevronDown, ChevronUp } from "lucide-react"

import { cn } from "@/library/utils"

const Select = SelectPrimitive.Root

const SelectGroup = SelectPrimitive.Group

const SelectValue = SelectPrimitive.Value

const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDown className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
))
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName

const SelectScrollUpButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollUpButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
)}
{...props}
>
<ChevronUp className="h-4 w-4" />
</SelectPrimitive.ScrollUpButton>
))
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName

const SelectScrollDownButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollDownButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
)}
{...props}
>
<ChevronDown className="h-4 w-4" />
</SelectPrimitive.ScrollDownButton>
))
SelectScrollDownButton.displayName =
SelectPrimitive.ScrollDownButton.displayName

const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
))
SelectContent.displayName = SelectPrimitive.Content.displayName

const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
{...props}
/>
))
SelectLabel.displayName = SelectPrimitive.Label.displayName

const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>

<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))
SelectItem.displayName = SelectPrimitive.Item.displayName

const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName

export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
}
176 changes: 149 additions & 27 deletions website/src/pages/StatusPage/StatusPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,35 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React from "react";
import React, { useState } from "react";
import RingLoader from "react-spinners/RingLoader";
import useApiCall from "../../utils/Hook";
import { statusDataTypes } from "@/types";

import Hero from "./components/Hero";
import ExecutionQueue from "./components/PreviousExecutions";
import PreviousExecutions from "./components/PreviousExecutions";
import datas from "./data.json";

import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";

interface dataTypes {
uuid: string;
git_ref: string;
source: string;
started_at: string;
finished_at: string;
type_of: string;
pull_nb?: number;
golang_version: string;
status: string;
}


export default function StatusPage() {
Expand All @@ -34,41 +55,142 @@ export default function StatusPage() {
`${import.meta.env.VITE_API_URL}recent`
);

const [filters, setFilters] = useState({
type: "",
status: "",
source: "",
});

const filterData = (data: dataTypes[]) => {
return data.filter((item) => {
const itemType = item.type_of ? item.type_of.toString() : "";
const itemSource = item.source ? item.source.toString() : "";
const itemStatus = item.status ? item.status.toString() : "";

const matchesType =
filters.type === "" ||
filters.type === "All" ||
itemType === filters.type;
const matchesSource =
filters.source === "" ||
filters.source === "All" ||
itemSource === filters.source;
const matchesStatus =
filters.status === "" ||
filters.status === "All" ||
itemStatus === filters.status;

return matchesType && matchesSource && matchesStatus;
});
};

const handleFilterChange = (name: string, value: string) => {
setFilters((prevFilters) => ({
...prevFilters,
[name]: value === "" ? "" : value,
}));
};

const filteredDataQueue = filterData(dataQueue) as dataTypes[];
const filteredPreviousDataExe = filterData(dataPreviousExe) as dataTypes[];

return (
<>
<Hero />

<div className="border-accent border mt-5" />

{/* EXECUTION QUEUE */}
{!isLoadingQueue && dataQueue && dataQueue.length > 0 && (
<ExecutionQueue data={dataQueue} title={"Execution Queue"} />
)}

{/* PREVIOUS EXECUTIONS */}
{!isLoadingPreviousExe &&
dataPreviousExe &&
dataPreviousExe.length > 0 && (
<PreviousExecutions
data={dataPreviousExe}
title={"Previous Executions"}
/>
)}
{/* FILTERS OPTIONS*/}
<div className="flex flex-col items-center">
<div className="flex p-5 gap-4 ">
<Select
value={filters.type}
onValueChange={(value) => handleFilterChange("type", value)}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="All">All</SelectItem>
{[
...new Set(dataPreviousExe.map((item: any) => item.type_of)),
].map((type) => (
<SelectItem key={type} value={type}>
{type}
</SelectItem>
))}
</SelectContent>
</Select>

<Select
onValueChange={(value) => handleFilterChange("source", value)}
value={filters.source}
>
<SelectTrigger className="w-[200px]">
<SelectValue placeholder="Sources" />
</SelectTrigger>
<SelectContent>
<SelectItem value="All">All</SelectItem>
{[
...new Set(dataPreviousExe.map((item: any) => item.source)),
].map((source) => (
<SelectItem key={source} value={source}>
{source}
</SelectItem>
))}
</SelectContent>
</Select>

{/* SHOW LOADER BENEATH IF EITHER IS LOADING */}
{(isLoadingPreviousExe || isLoadingQueue) && (
<div className="flex justify-center w-full my-16">
<RingLoader
loading={isLoadingPreviousExe || isLoadingQueue}
color="#E77002"
size={300}
/>
<Select
onValueChange={(value) => handleFilterChange("status", value)}
value={filters.status}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Status" />
</SelectTrigger>
<SelectContent>
<SelectItem value="All">All</SelectItem>
{[
...new Set(dataPreviousExe.map((item: any) => item.status)),
].map((status) => (
<SelectItem key={status} value={status}>
{status}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
)}

{errorQueue && (
<div className="my-10 text-center text-red-500">{errorQueue}</div>
)}
{/* EXECUTION QUEUE */}
{!isLoadingQueue && dataQueue && dataQueue.length > 0 && (
<ExecutionQueue data={filteredDataQueue} title={"Execution Queue"} />
)}

{/* PREVIOUS EXECUTIONS */}
{!isLoadingPreviousExe &&
dataPreviousExe &&
dataPreviousExe.length > 0 && (
<PreviousExecutions
data={filteredPreviousDataExe}
title={"Previous Executions"}
/>
)}

{/* SHOW LOADER BENEATH IF EITHER IS LOADING */}
{(isLoadingPreviousExe || isLoadingQueue) && (
<div className="flex justify-center w-full my-16">
<RingLoader
loading={isLoadingPreviousExe || isLoadingQueue}
color="#E77002"
size={300}
/>
</div>
)}

{errorQueue && (
<div className="my-10 text-center text-red-500">{errorQueue}</div>
)}
</div>
</>
);
}
Loading
Loading