Openstatus www.openstatus.dev
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: play checker (#991)

* chore: small stuff

* chore: switch column header to button click

* chore: text align and input filter

* style: adjust tabs height

* fix: text align and remove columns

* ci: apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

authored by

Maximilian Kaske
autofix-ci[bot]
and committed by
GitHub
c5cb867c 117b2347

+156 -102
+2 -2
apps/web/src/app/play/checker/_components/checker-form.tsx
··· 66 66 { 67 67 ssr: false, 68 68 loading: () => <></>, 69 - } 69 + }, 70 70 ); 71 71 72 72 /** ··· 190 190 `Checking ${regionFormatter(_result[0].region, "long")} (${latencyFormatter(_result[0].latency)})`, 191 191 { 192 192 id: toastId, 193 - } 193 + }, 194 194 ); 195 195 } 196 196 }
+3 -3
apps/web/src/app/play/checker/_components/global-monitoring.tsx
··· 18 18 }[] = [ 19 19 { 20 20 icon: "gauge", 21 - catchline: "Speed Test for Websites", 21 + catchline: "Speed Test", 22 22 description: 23 - "Enter your URL and get a website speed check. Get insights on page load, header details and timing phases (DNS, Connect, TLS, TTFB) of the response.", 23 + "Enter your URL and get a website speed check. Get insights on page load, header details and timing phases (DNS, Connect, TLS, TTFB, Transfer) of the response.", 24 24 }, 25 25 { 26 26 icon: "globe", ··· 32 32 icon: "link", 33 33 catchline: "Share the Results", 34 34 description: 35 - "Quickly share the results of your website speed test with your team or clients. We share the results for 7 days, so you can easily collaborate on performance.", 35 + "Quickly share the results of your website speed test with your team or clients. The results expire after 7 days, so you can easily collaborate on performance.", 36 36 }, 37 37 ]; 38 38 export const GlobalMonitoring = () => {
+33 -45
apps/web/src/components/data-table/data-table-column-header.tsx
··· 1 1 import type { Column } from "@tanstack/react-table"; 2 - import { ArrowDown, ArrowUp, ChevronsUpDown } from "lucide-react"; 2 + import { ChevronDown, ChevronUp } from "lucide-react"; 3 3 4 - import { 5 - Button, 6 - DropdownMenu, 7 - DropdownMenuContent, 8 - DropdownMenuItem, 9 - DropdownMenuTrigger, 10 - } from "@openstatus/ui"; 4 + import { Button, type ButtonProps } from "@openstatus/ui"; 11 5 12 6 import { cn } from "@/lib/utils"; 13 7 14 - interface DataTableColumnHeaderProps<TData, TValue> 15 - extends React.HTMLAttributes<HTMLDivElement> { 8 + interface DataTableColumnHeaderProps<TData, TValue> extends ButtonProps { 16 9 column: Column<TData, TValue>; 17 10 title: string; 18 11 } ··· 21 14 column, 22 15 title, 23 16 className, 17 + ...props 24 18 }: DataTableColumnHeaderProps<TData, TValue>) { 25 19 if (!column.getCanSort()) { 26 20 return <div className={cn(className)}>{title}</div>; 27 21 } 28 22 29 23 return ( 30 - <div className={cn("flex items-center space-x-2", className)}> 31 - <DropdownMenu> 32 - <DropdownMenuTrigger asChild> 33 - <Button 34 - variant="ghost" 35 - size="sm" 36 - className="-ml-3 h-8 data-[state=open]:bg-accent" 37 - > 38 - <span>{title}</span> 39 - {column.getIsSorted() === "desc" ? ( 40 - <ArrowUp className="ml-2 h-4 w-4" /> 41 - ) : column.getIsSorted() === "asc" ? ( 42 - <ArrowDown className="ml-2 h-4 w-4" /> 43 - ) : ( 44 - <ChevronsUpDown className="ml-2 h-4 w-4" /> 45 - )} 46 - </Button> 47 - </DropdownMenuTrigger> 48 - <DropdownMenuContent align="start"> 49 - <DropdownMenuItem onClick={() => column.toggleSorting(false)}> 50 - <ArrowDown className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" /> 51 - Asc 52 - </DropdownMenuItem> 53 - <DropdownMenuItem onClick={() => column.toggleSorting(true)}> 54 - <ArrowUp className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" /> 55 - Desc 56 - </DropdownMenuItem> 57 - {/* <DropdownMenuSeparator /> 58 - <DropdownMenuItem onClick={() => column.toggleVisibility(false)}> 59 - <EyeOff className="text-muted-foreground/70 mr-2 h-3.5 w-3.5" /> 60 - Hide 61 - </DropdownMenuItem> */} 62 - </DropdownMenuContent> 63 - </DropdownMenu> 64 - </div> 24 + <Button 25 + variant="ghost" 26 + size="sm" 27 + onClick={() => { 28 + column.toggleSorting(undefined); 29 + }} 30 + className={className} 31 + {...props} 32 + > 33 + <span>{title}</span> 34 + <span className="ml-2 flex flex-col"> 35 + <ChevronUp 36 + className={cn( 37 + "-mb-0.5 h-3 w-3", 38 + column.getIsSorted() === "asc" || !column.getIsSorted() 39 + ? "text-accent-foreground" 40 + : "text-muted-foreground/70", 41 + )} 42 + /> 43 + <ChevronDown 44 + className={cn( 45 + "-mt-0.5 h-3 w-3", 46 + column.getIsSorted() === "desc" || !column.getIsSorted() 47 + ? "text-accent-foreground" 48 + : "text-muted-foreground/70", 49 + )} 50 + /> 51 + </span> 52 + </Button> 65 53 ); 66 54 }
+5 -5
apps/web/src/components/marketing/card.tsx
··· 96 96 const FeatureIcon = Icons[props.icon]; 97 97 return ( 98 98 <li> 99 - <p className="flex flex-col"> 100 - <span> 101 - <FeatureIcon className="mr-1.5 mb-1 inline-flex h-4 w-4 text-foreground/80" /> 99 + <div className="grid gap-1"> 100 + <p className="flex items-center gap-2"> 101 + <FeatureIcon className="h-4 w-4 text-foreground/80" /> 102 102 <span className="font-medium text-foreground"> 103 103 {props.catchline.replace(".", "")} 104 104 </span>{" "} 105 - </span> 105 + </p> 106 106 <span className="text-muted-foreground">{props.description}</span> 107 - </p> 107 + </div> 108 108 {props.badge ? ( 109 109 <Badge variant="secondary" className="-ml-2 mt-1"> 110 110 {props.badge}
+1 -1
apps/web/src/components/marketing/hero.tsx
··· 29 29 <h1 30 30 className={cn( 31 31 "font-cal text-4xl text-foreground md:text-6xl", 32 - "bg-gradient-to-tl from-0% from-[hsl(var(--muted))] to-40% to-[hsl(var(--foreground))] bg-clip-text text-transparent" 32 + "bg-gradient-to-tl from-0% from-[hsl(var(--muted))] to-40% to-[hsl(var(--foreground))] bg-clip-text text-transparent", 33 33 )} 34 34 > 35 35 A better way to monitor your services.
+84 -31
apps/web/src/components/ping-response-analysis/columns.tsx
··· 6 6 continentFormatter, 7 7 latencyFormatter, 8 8 regionFormatter, 9 - timestampFormatter, 10 9 } from "./utils"; 11 10 11 + import { flyRegionsDict } from "@openstatus/utils"; 12 12 import { format } from "date-fns"; 13 13 import { utcToZonedTime } from "date-fns-tz"; 14 14 import { DataTableColumnHeader } from "../data-table/data-table-column-header"; ··· 26 26 }, 27 27 { 28 28 accessorKey: "region", 29 + accessorFn: (row) => row.region, 29 30 header: "Region", 30 31 cell: ({ row }) => { 31 32 return ( ··· 34 35 </div> 35 36 ); 36 37 }, 37 - }, 38 - { 39 - id: "continent", 40 - accessorFn: (row) => continentFormatter(row.region), 41 - header: ({ column }) => { 42 - return <DataTableColumnHeader column={column} title="Continent" />; 43 - }, 44 - cell: ({ row }) => { 45 - return <div>{row.getValue("continent")}</div>; 38 + filterFn: (row, _id, filterValue) => { 39 + const region = regionFormatter(row.original.region, "long").toLowerCase(); 40 + const continent = 41 + flyRegionsDict[row.original.region].continent.toLocaleLowerCase(); 42 + return `${region} ${continent}`.includes(filterValue.toLowerCase()); 46 43 }, 47 44 }, 48 45 { ··· 55 52 { 56 53 id: "DNS", 57 54 header: ({ column }) => { 58 - return <DataTableColumnHeader column={column} title="DNS" />; 55 + return ( 56 + <DataTableColumnHeader 57 + column={column} 58 + title="DNS" 59 + className="pr-0 text-right" 60 + /> 61 + ); 59 62 }, 60 63 accessorFn: (row) => `${row.timing.dnsDone - row.timing.dnsStart}`, 61 64 cell: ({ row, column }) => { 62 65 return ( 63 - <div className="font-mono"> 66 + <div className="text-right font-mono"> 64 67 {latencyFormatter(row.getValue(column.id))} 65 68 </div> 66 69 ); 67 70 }, 71 + meta: { 72 + headerClassName: "text-right", 73 + }, 68 74 }, 69 75 { 70 76 id: "connect", 71 77 accessorFn: (row) => `${row.timing.connectDone - row.timing.connectStart}`, 72 78 header: ({ column }) => { 73 - return <DataTableColumnHeader column={column} title="Connect" />; 79 + return ( 80 + <DataTableColumnHeader 81 + column={column} 82 + title="Connect" 83 + className="pr-0 text-right" 84 + /> 85 + ); 74 86 }, 75 87 cell: ({ row, column }) => { 76 88 return ( 77 - <div className="font-mono"> 89 + <div className="text-right font-mono"> 78 90 {latencyFormatter(row.getValue(column.id))} 79 91 </div> 80 92 ); 81 93 }, 94 + meta: { 95 + headerClassName: "text-right", 96 + }, 82 97 }, 83 98 { 84 99 id: "TLS", 85 - 86 100 accessorFn: (row) => 87 101 `${row.timing.tlsHandshakeDone - row.timing.tlsHandshakeStart}`, 88 102 header: ({ column }) => { 89 - return <DataTableColumnHeader column={column} title="TLS" />; 103 + return ( 104 + <DataTableColumnHeader 105 + column={column} 106 + title="TLS" 107 + className="pr-0 text-right" 108 + /> 109 + ); 90 110 }, 91 111 cell: ({ row, column }) => { 92 112 return ( 93 - <div className="font-mono"> 113 + <div className="text-right font-mono"> 94 114 {latencyFormatter(row.getValue(column.id))} 95 115 </div> 96 116 ); 97 117 }, 118 + meta: { 119 + headerClassName: "text-right", 120 + }, 98 121 }, 99 122 { 100 123 id: "TTFB", 101 124 accessorFn: (row) => 102 125 `${row.timing.firstByteDone - row.timing.firstByteStart}`, 103 126 header: ({ column }) => { 104 - return <DataTableColumnHeader column={column} title="TTFB" />; 127 + return ( 128 + <DataTableColumnHeader 129 + column={column} 130 + title="TTFB" 131 + className="pr-0 text-right" 132 + /> 133 + ); 105 134 }, 106 135 cell: ({ row, column }) => { 107 136 return ( 108 - <div className="font-mono"> 137 + <div className="text-right font-mono"> 109 138 {latencyFormatter(row.getValue(column.id))} 110 139 </div> 111 140 ); 141 + }, 142 + meta: { 143 + headerClassName: "text-right", 112 144 }, 113 145 }, 114 146 { 115 - accessorKey: "latency", 147 + accessorKey: "transfer", 148 + accessorFn: (row) => 149 + `${row.timing.transferDone - row.timing.transferStart}`, 116 150 header: ({ column }) => { 117 - return <DataTableColumnHeader column={column} title="Latency" />; 151 + return ( 152 + <DataTableColumnHeader 153 + column={column} 154 + title="Transfer" 155 + className="pr-0 text-right" 156 + /> 157 + ); 118 158 }, 119 - cell: ({ row }) => { 159 + cell: ({ row, column }) => { 120 160 return ( 121 - <div className="font-mono"> 122 - {latencyFormatter(row.original.latency)} 161 + <div className="text-right font-mono"> 162 + {latencyFormatter(row.getValue(column.id))} 123 163 </div> 124 164 ); 165 + }, 166 + meta: { 167 + headerClassName: "text-right", 125 168 }, 126 169 }, 127 170 { 128 - id: "Time (UTC)", 129 - accessorFn: (row) => row.time, 171 + accessorKey: "latency", 172 + header: ({ column }) => { 173 + return ( 174 + <DataTableColumnHeader 175 + column={column} 176 + title="Latency" 177 + className="pr-0 text-right" 178 + /> 179 + ); 180 + }, 130 181 cell: ({ row }) => { 131 - const date = format( 132 - utcToZonedTime(row.original.time, "UTC"), 133 - "dd LLL hh:mm a", 182 + return ( 183 + <div className="text-right font-mono"> 184 + {latencyFormatter(row.original.latency)} 185 + </div> 134 186 ); 135 - 136 - return <div className="whitespace-nowrap">{date}</div>; 187 + }, 188 + meta: { 189 + headerClassName: "text-right", 137 190 }, 138 191 }, 139 192 ];
+18 -9
apps/web/src/components/ping-response-analysis/multi-region-table.tsx
··· 10 10 TableRow, 11 11 } from "@openstatus/ui/src/components/table"; 12 12 13 + import { Input } from "@openstatus/ui"; 13 14 import { 14 15 type ColumnDef, 16 + type ColumnFiltersState, 15 17 type ExpandedState, 16 18 type Row, 17 19 type SortingState, ··· 19 21 flexRender, 20 22 getCoreRowModel, 21 23 getExpandedRowModel, 24 + getFilteredRowModel, 22 25 getSortedRowModel, 23 26 useReactTable, 24 27 } from "@tanstack/react-table"; ··· 47 50 { id: "latency", desc: false }, 48 51 ]); 49 52 const [expanded, setExpanded] = useState<ExpandedState>({}); 50 - const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({ 51 - continent: false, 52 - "Time (UTC)": false, 53 - }); 53 + const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({}); 54 + const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]); 54 55 55 56 const table = useReactTable({ 56 57 data, ··· 58 59 onSortingChange: setSorting, 59 60 onExpandedChange: setExpanded, 60 61 onColumnVisibilityChange: setColumnVisibility, 62 + onColumnFiltersChange: setColumnFilters, 61 63 getCoreRowModel: getCoreRowModel(), 62 64 getSortedRowModel: getSortedRowModel(), 63 65 getExpandedRowModel: getExpandedRowModel(), 66 + getFilteredRowModel: getFilteredRowModel(), 64 67 getRowCanExpand, 65 68 autoResetExpanded, 66 69 state: { 67 70 sorting, 68 71 expanded, 69 72 columnVisibility, 73 + columnFilters, 70 74 }, 71 75 }); 72 76 73 77 return ( 74 78 <div className="grid gap-4"> 75 79 <div className="flex items-end justify-between gap-2"> 76 - <p className="text-muted-foreground text-xs"> 77 - Select a row to expand the response details. 78 - </p> 80 + <Input 81 + placeholder="Filter regions, continents, flags..." 82 + value={(table.getColumn("region")?.getFilterValue() as string) ?? ""} 83 + onChange={(event) => 84 + table.getColumn("region")?.setFilterValue(event.target.value) 85 + } 86 + className="h-8 max-w-[325px] truncate" 87 + /> 79 88 <div className="flex items-center justify-end gap-2"> 80 89 <DataTableCollapseButton table={table} /> 81 90 <DataTableViewOptions table={table} /> ··· 96 105 ? null 97 106 : flexRender( 98 107 header.column.columnDef.header, 99 - header.getContext() 108 + header.getContext(), 100 109 )} 101 110 </TableHead> 102 111 ); ··· 119 128 <TableCell key={cell.id}> 120 129 {flexRender( 121 130 cell.column.columnDef.cell, 122 - cell.getContext() 131 + cell.getContext(), 123 132 )} 124 133 </TableCell> 125 134 ))}
+10 -6
apps/web/src/components/ping-response-analysis/multi-region-tabs.tsx
··· 20 20 }) { 21 21 return ( 22 22 <Tabs defaultValue="table"> 23 - <div className="flex items-center justify-between"> 24 - <TabsList> 25 - <TabsTrigger value="table">Table</TabsTrigger> 26 - <TabsTrigger value="chart">Chart</TabsTrigger> 23 + <div className="flex items-center justify-between gap-2"> 24 + <TabsList className="h-8 p-0.5"> 25 + <TabsTrigger value="table" className="h-7"> 26 + Table 27 + </TabsTrigger> 28 + <TabsTrigger value="chart" className="h-7"> 29 + Chart 30 + </TabsTrigger> 27 31 </TabsList> 28 32 <RegionsPreset 29 33 regions={regions.map((i) => i.region)} ··· 31 35 size="sm" 32 36 /> 33 37 </div> 34 - <TabsContent value="chart"> 38 + <TabsContent value="chart" className="mt-3"> 35 39 <MultiRegionChart 36 40 regions={regions.filter((i) => selectedRegions?.includes(i.region))} 37 41 /> 38 42 </TabsContent> 39 - <TabsContent value="table"> 43 + <TabsContent value="table" className="mt-3"> 40 44 <MultiRegionTable 41 45 data={regions.filter((i) => selectedRegions?.includes(i.region))} 42 46 columns={columns}