Focus visible style refinements (#1577)
* reduces the thickness of the focus-visible
* More subtle Input style
* Updates focus-visible styles for the SimpleSelect
* Tables tab through rows and action cells only
* Refined focus visible style
* Adds the custom focus visible to the TextLink
* Moves the onClick handling to the table row rather than the cell
* Makes table row heights consistent
* Adds gap between task search bar and button
* Prevents long tag values from wrapping
* Removes unnecessary rows from table header
* Added gap between search and filters
* Fixes the schedules table pagination staying fixed to the bottom of the page
* Removed more unnecessary header table rows to prevent them being selectable
* Removed isSelected styles (not working)
* Added <tr> back to the main Table compontent
* Table row handles modifier keys
* Adds to={path} to the TableRow only
* Revert "Adds to={path} to the TableRow only"
This reverts commit 8a814d434ff85b8ab9c2305d336074f659d86094.
* Revert "Table row handles modifier keys"
This reverts commit b2394741fa2ed6b908e00673b1a395ae89ca7146.
* Table reverted to use linked cells rather than rows
* Set the tab index of a cell and style the table row when tabbed
* Tabbed row style applied to the sticky cells
* Adds isTabbableCell to each table
* Improves the spcificity of the row highlighting
* Reduces the height of the task rows to match the other tables
* Adds tab styles to fill in row dividers top and bottom
* Removed old row onClick and to props
* Removed duplicate table header row
* Creates table style variants so tables look good in the inspector panels
* Full width tables on the schedules inspector panel
* Reduce padding on Alerts page table rows
* Updates the Deploy page inspector table to the new style
* Removes the duplicate Table Row from the table headers in v2
* Adds TableRow to the EventsTable
* Adds TableRow to more tables
* Adds TableRow to more tables
* Adds TableRow to more tables
* Adds TableRow to more tables
* Fix for showing correct cursor for linked table rows
* Removed variants from some of the table components
This commit is contained in:
@@ -4,7 +4,7 @@ import { cn } from "~/utils/cn";
|
||||
import { Icon, RenderIcon } from "./Icon";
|
||||
|
||||
const containerBase =
|
||||
"has-[:focus-visible]:outline-none has-[:focus-visible]:ring-1 has-[:focus-visible]:ring-text-link has-[:focus-visible]:ring-offset-0 has-[:focus]:border-ring has-[:focus]:outline-none has-[:focus]:ring-2 has-[:focus]:ring-ring has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-50 ring-offset-background transition cursor-text";
|
||||
"has-[:focus-visible]:outline-none has-[:focus-visible]:ring-1 has-[:focus-visible]:ring-charcoal-650 has-[:focus-visible]:ring-offset-0 has-[:focus]:border-ring has-[:focus]:outline-none has-[:focus]:ring-1 has-[:focus]:ring-ring has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-50 ring-offset-background transition cursor-text";
|
||||
|
||||
const inputBase =
|
||||
"h-full w-full text-text-bright bg-transparent file:border-0 file:bg-transparent file:text-base file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0 disabled:cursor-not-allowed outline-none ring-0 border-none";
|
||||
@@ -17,27 +17,27 @@ const variants = {
|
||||
container:
|
||||
"px-1 w-full h-10 rounded-[3px] border border-charcoal-800 bg-charcoal-750 hover:border-charcoal-600 hover:bg-charcoal-650",
|
||||
input: "px-2 text-sm",
|
||||
iconSize: "h-4 w-4 ml-1",
|
||||
iconSize: "size-4 ml-1",
|
||||
shortcut: "mr-1 min-w-[22px] rounded-sm py-[3px] px-[5px] text-[0.6rem] select-none",
|
||||
},
|
||||
medium: {
|
||||
container:
|
||||
"px-1 h-8 w-full rounded border border-charcoal-800 bg-charcoal-750 hover:border-charcoal-600 hover:bg-charcoal-650",
|
||||
input: "px-1.5 rounded text-sm",
|
||||
iconSize: "h-4 w-4 ml-0.5",
|
||||
iconSize: "size-4 ml-0.5",
|
||||
shortcut: "min-w-[22px] rounded-sm py-[3px] px-[5px] text-[0.6rem]",
|
||||
},
|
||||
small: {
|
||||
container:
|
||||
"px-1 h-6 w-full rounded border border-charcoal-800 bg-charcoal-750 hover:border-charcoal-600 hover:bg-charcoal-650",
|
||||
input: "px-1 rounded text-xs",
|
||||
iconSize: "h-3 w-3 ml-0.5",
|
||||
iconSize: "size-3 ml-0.5",
|
||||
shortcut: "min-w-[22px] rounded-[2px] py-px px-[3px] text-[0.5rem]",
|
||||
},
|
||||
tertiary: {
|
||||
container: "px-1 h-6 w-full rounded hover:bg-charcoal-750",
|
||||
input: "px-1 rounded text-xs",
|
||||
iconSize: "h-3 w-3 ml-0.5",
|
||||
iconSize: "size-3 ml-0.5",
|
||||
shortcut: "min-w-[22px] rounded-[2px] py-px px-[3px] text-[0.5rem]",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ const SelectTrigger = React.forwardRef<
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"ring-offset-background focus-visible:ring-ring group flex items-center justify-between gap-x-1 rounded text-text-dimmed transition placeholder:text-text-dimmed hover:text-text-bright focus-visible:bg-tertiary focus-visible:text-text-bright focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"ring-offset-background group flex items-center justify-between gap-x-1 rounded text-text-dimmed transition placeholder:text-text-dimmed hover:text-text-bright focus-visible:focus-custom disabled:cursor-not-allowed disabled:opacity-50",
|
||||
width === "full" ? "w-full" : "w-min",
|
||||
sizeClassName,
|
||||
className
|
||||
|
||||
@@ -1,10 +1,33 @@
|
||||
import { ChevronRightIcon } from "@heroicons/react/24/solid";
|
||||
import { Link } from "@remix-run/react";
|
||||
import { ReactNode, forwardRef, useState } from "react";
|
||||
import React, { ReactNode, forwardRef, useState, useContext, createContext } from "react";
|
||||
import { cn } from "~/utils/cn";
|
||||
import { Popover, PopoverContent, PopoverVerticalEllipseTrigger } from "./Popover";
|
||||
import { InfoIconTooltip } from "./Tooltip";
|
||||
|
||||
const variants = {
|
||||
bright: {
|
||||
header: "bg-background-bright",
|
||||
cell: "group-hover/table-row:bg-charcoal-750 group-has-[[tabindex='0']:focus]/table-row:bg-charcoal-750",
|
||||
stickyCell: "bg-background-bright group-hover/table-row:bg-charcoal-750",
|
||||
menuButton:
|
||||
"bg-background-bright group-hover/table-row:bg-charcoal-750 group-hover/table-row:ring-charcoal-600/70 group-has-[[tabindex='0']:focus]/table-row:bg-charcoal-750",
|
||||
menuButtonDivider: "group-hover/table-row:border-charcoal-600/70",
|
||||
rowSelected: "bg-charcoal-750 group-hover/table-row:bg-charcoal-750",
|
||||
},
|
||||
dimmed: {
|
||||
header: "bg-background-dimmed",
|
||||
cell: "group-hover/table-row:bg-charcoal-800 group-has-[[tabindex='0']:focus]/table-row:bg-background-bright",
|
||||
stickyCell: "group-hover/table-row:bg-charcoal-800",
|
||||
menuButton:
|
||||
"bg-background-dimmed group-hover/table-row:bg-charcoal-800 group-hover/table-row:ring-grid-bright group-has-[[tabindex='0']:focus]/table-row:bg-background-bright",
|
||||
menuButtonDivider: "group-hover/table-row:border-grid-dimmed",
|
||||
rowSelected: "bg-charcoal-750 group-hover/table-row:bg-charcoal-750",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export type TableVariant = keyof typeof variants;
|
||||
|
||||
type TableProps = {
|
||||
containerClassName?: string;
|
||||
className?: string;
|
||||
@@ -12,20 +35,25 @@ type TableProps = {
|
||||
fullWidth?: boolean;
|
||||
};
|
||||
|
||||
export const Table = forwardRef<HTMLTableElement, TableProps>(
|
||||
({ className, containerClassName, children, fullWidth }, ref) => {
|
||||
// Add TableContext
|
||||
const TableContext = createContext<{ variant: TableVariant }>({ variant: "dimmed" });
|
||||
|
||||
export const Table = forwardRef<HTMLTableElement, TableProps & { variant?: TableVariant }>(
|
||||
({ className, containerClassName, children, fullWidth, variant = "dimmed" }, ref) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"overflow-x-auto whitespace-nowrap border-t border-grid-bright scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600",
|
||||
containerClassName,
|
||||
fullWidth && "w-full"
|
||||
)}
|
||||
>
|
||||
<table ref={ref} className={cn("w-full", className)}>
|
||||
{children}
|
||||
</table>
|
||||
</div>
|
||||
<TableContext.Provider value={{ variant }}>
|
||||
<div
|
||||
className={cn(
|
||||
"overflow-x-auto whitespace-nowrap border-t scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600",
|
||||
containerClassName,
|
||||
fullWidth && "w-full"
|
||||
)}
|
||||
>
|
||||
<table ref={ref} className={cn("w-full", className)}>
|
||||
{children}
|
||||
</table>
|
||||
</div>
|
||||
</TableContext.Provider>
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -37,11 +65,13 @@ type TableHeaderProps = {
|
||||
|
||||
export const TableHeader = forwardRef<HTMLTableSectionElement, TableHeaderProps>(
|
||||
({ className, children }, ref) => {
|
||||
const { variant } = useContext(TableContext);
|
||||
return (
|
||||
<thead
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"sticky top-0 z-10 bg-background-dimmed after:absolute after:bottom-0 after:left-0 after:right-0 after:h-px after:bg-grid-bright",
|
||||
"sticky top-0 z-10 after:absolute after:bottom-0 after:left-0 after:right-0 after:h-px after:bg-grid-bright",
|
||||
variants[variant].header,
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -75,13 +105,14 @@ type TableRowProps = {
|
||||
|
||||
export const TableRow = forwardRef<HTMLTableRowElement, TableRowProps>(
|
||||
({ className, disabled, isSelected, children }, ref) => {
|
||||
const { variant } = useContext(TableContext);
|
||||
return (
|
||||
<tr
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"group/table-row relative w-full after:absolute after:bottom-0 after:left-3 after:right-0 after:h-px after:bg-grid-dimmed",
|
||||
"group/table-row relative w-full outline-none after:absolute after:bottom-0 after:left-3 after:right-0 after:h-px after:bg-grid-dimmed",
|
||||
isSelected && variants[variant].rowSelected,
|
||||
disabled && "opacity-50",
|
||||
isSelected && isSelectedStyle,
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -94,7 +125,7 @@ export const TableRow = forwardRef<HTMLTableRowElement, TableRowProps>(
|
||||
type TableCellBasicProps = {
|
||||
className?: string;
|
||||
alignment?: "left" | "center" | "right";
|
||||
children: ReactNode;
|
||||
children?: ReactNode;
|
||||
colSpan?: number;
|
||||
};
|
||||
|
||||
@@ -125,6 +156,7 @@ export const TableHeaderCell = forwardRef<HTMLTableCellElement, TableHeaderCellP
|
||||
className
|
||||
)}
|
||||
colSpan={colSpan}
|
||||
tabIndex={-1}
|
||||
>
|
||||
{hiddenLabel ? (
|
||||
<span className="sr-only">{children}</span>
|
||||
@@ -147,24 +179,12 @@ type TableCellProps = TableCellBasicProps & {
|
||||
hasAction?: boolean;
|
||||
isSticky?: boolean;
|
||||
actionClassName?: string;
|
||||
rowHoverStyle?: keyof typeof rowHoverStyles;
|
||||
rowHoverStyle?: string;
|
||||
isSelected?: boolean;
|
||||
isTabbableCell?: boolean;
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
const rowHoverStyles = {
|
||||
default:
|
||||
"group-hover/table-row:bg-charcoal-800 group-hover/table-row:before:absolute group-hover/table-row:before:bg-charcoal-750 group-hover/table-row:before:top-[-1px] group-hover/table-row:before:left-0 group-hover/table-row:before:h-px group-hover/table-row:before:w-3 group-hover/table-row:after:absolute group-hover/table-row:after:bg-charcoal-750 group-hover/table-row:after:bottom-0 group-hover/table-row:after:left-0 group-hover/table-row:after:h-px group-hover/table-row:after:w-3",
|
||||
dimmed:
|
||||
"group-hover/table-row:bg-charcoal-850 group-hover/table-row:before:absolute group-hover/table-row:before:bg-charcoal-800 group-hover/table-row:before:top-[-1px] group-hover/table-row:before:left-0 group-hover/table-row:before:h-px group-hover/table-row:before:w-3 group-hover/table-row:after:absolute group-hover/table-row:after:bg-charcoal-800 group-hover/table-row:after:bottom-0 group-hover/table-row:after:left-0 group-hover/table-row:after:h-px group-hover/table-row:after:w-3",
|
||||
bright:
|
||||
"group-hover/table-row:bg-charcoal-750 group-hover/table-row:before:absolute group-hover/table-row:before:bg-charcoal-700 group-hover/table-row:before:top-[-1px] group-hover/table-row:before:left-0 group-hover/table-row:before:h-px group-hover/table-row:before:w-3 group-hover/table-row:after:absolute group-hover/table-row:after:bg-charcoal-700 group-hover/table-row:after:bottom-0 group-hover/table-row:after:left-0 group-hover/table-row:after:h-px group-hover/table-row:after:w-3",
|
||||
};
|
||||
|
||||
const stickyStyles =
|
||||
"sticky right-0 bg-background-dimmed group-hover/table-row:bg-charcoal-750 w-[--sticky-width] [&:has(.group-hover\\/table-row\\:block)]:w-auto";
|
||||
|
||||
const isSelectedStyle = "bg-charcoal-750 group-hover:bg-charcoal-750";
|
||||
|
||||
export const TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(
|
||||
(
|
||||
{
|
||||
@@ -177,8 +197,8 @@ export const TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(
|
||||
onClick,
|
||||
hasAction = false,
|
||||
isSticky = false,
|
||||
rowHoverStyle = "default",
|
||||
isSelected,
|
||||
isTabbableCell = false,
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
@@ -193,34 +213,47 @@ export const TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(
|
||||
}
|
||||
|
||||
const flexClasses = cn(
|
||||
"flex w-full whitespace-nowrap px-3 py-3 text-xs text-text-dimmed",
|
||||
"flex w-full whitespace-nowrap px-3 py-3 items-center text-xs text-text-dimmed",
|
||||
alignment === "left"
|
||||
? "justify-start text-left"
|
||||
: alignment === "center"
|
||||
? "justify-center text-center"
|
||||
: "justify-end text-right"
|
||||
);
|
||||
const { variant } = useContext(TableContext);
|
||||
|
||||
return (
|
||||
<td
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-xs text-charcoal-400",
|
||||
to || onClick || hasAction ? "cursor-pointer" : "px-3 py-3 align-middle",
|
||||
"text-xs text-charcoal-400 has-[[tabindex='0']:focus]:before:absolute has-[[tabindex='0']:focus]:before:-top-px has-[[tabindex='0']:focus]:before:left-0 has-[[tabindex='0']:focus]:before:h-px has-[[tabindex='0']:focus]:before:w-3 has-[[tabindex='0']:focus]:before:bg-grid-dimmed has-[[tabindex='0']:focus]:after:absolute has-[[tabindex='0']:focus]:after:bottom-0 has-[[tabindex='0']:focus]:after:left-0 has-[[tabindex='0']:focus]:after:right-0 has-[[tabindex='0']:focus]:after:h-px has-[[tabindex='0']:focus]:after:bg-grid-dimmed",
|
||||
variants[variant].cell,
|
||||
to || onClick || hasAction ? "cursor-pointer" : "cursor-default px-3 py-3 align-middle",
|
||||
!to && !onClick && alignmentClassName,
|
||||
isSticky && stickyStyles,
|
||||
isSelected && isSelectedStyle,
|
||||
!isSelected && rowHoverStyles[rowHoverStyle],
|
||||
isSticky &&
|
||||
"[&:has(.group-hover/table-row:block)]:w-auto sticky right-0 bg-background-dimmed",
|
||||
isSticky && variants[variant].stickyCell,
|
||||
isSelected && variants[variant].rowSelected,
|
||||
!isSelected &&
|
||||
"group-hover/table-row:before:absolute group-hover/table-row:before:left-0 group-hover/table-row:before:top-[-1px] group-hover/table-row:before:h-px group-hover/table-row:before:w-3 group-hover/table-row:before:bg-charcoal-750 group-hover/table-row:after:absolute group-hover/table-row:after:bottom-0 group-hover/table-row:after:left-0 group-hover/table-row:after:h-px group-hover/table-row:after:w-3 group-hover/table-row:after:bg-charcoal-750 group-focus-visible/table-row:bg-background-bright",
|
||||
className
|
||||
)}
|
||||
colSpan={colSpan}
|
||||
>
|
||||
{to ? (
|
||||
<Link to={to} className={cn("focus-custom", flexClasses, actionClassName)}>
|
||||
<Link
|
||||
to={to}
|
||||
className={cn("cursor-pointer focus:outline-none", flexClasses, actionClassName)}
|
||||
tabIndex={isTabbableCell ? 0 : -1}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
) : onClick ? (
|
||||
<button onClick={onClick} className={cn("focus-custom", flexClasses, actionClassName)}>
|
||||
<button
|
||||
onClick={onClick}
|
||||
className={cn("cursor-pointer focus:outline-none", flexClasses, actionClassName)}
|
||||
tabIndex={isTabbableCell ? 0 : -1}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
) : (
|
||||
@@ -258,7 +291,7 @@ export const TableCellChevron = forwardRef<
|
||||
|
||||
export const TableCellMenu = forwardRef<
|
||||
HTMLTableCellElement,
|
||||
{
|
||||
TableCellProps & {
|
||||
className?: string;
|
||||
isSticky?: boolean;
|
||||
onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
@@ -283,6 +316,7 @@ export const TableCellMenu = forwardRef<
|
||||
ref
|
||||
) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const { variant } = useContext(TableContext);
|
||||
|
||||
return (
|
||||
<TableCell
|
||||
@@ -297,15 +331,18 @@ export const TableCellMenu = forwardRef<
|
||||
<div className="relative h-full p-1">
|
||||
<div
|
||||
className={cn(
|
||||
"absolute right-0 top-1/2 mr-1 flex -translate-y-1/2 items-center justify-end gap-0.5 rounded-[0.25rem] bg-background-dimmed p-0.5 group-hover/table-row:bg-background-bright group-hover/table-row:ring-1 group-hover/table-row:ring-grid-bright",
|
||||
isSelected && isSelectedStyle,
|
||||
isSelected &&
|
||||
"group-hover/table-row:bg-charcoal-750 group-hover/table-row:ring-charcoal-600/50"
|
||||
"absolute right-0 top-1/2 mr-1 flex -translate-y-1/2 items-center justify-end gap-0.5 rounded-[0.25rem] p-0.5 group-hover/table-row:ring-1",
|
||||
variants[variant].menuButton
|
||||
)}
|
||||
>
|
||||
{/* Hidden buttons that show on hover */}
|
||||
{hiddenButtons && (
|
||||
<div className="hidden pr-0.5 group-hover/table-row:block group-hover/table-row:border-r group-hover/table-row:border-grid-dimmed">
|
||||
<div
|
||||
className={cn(
|
||||
"hidden pr-0.5 group-hover/table-row:block group-hover/table-row:border-r",
|
||||
variants[variant].menuButtonDivider
|
||||
)}
|
||||
>
|
||||
{hiddenButtons}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -4,9 +4,9 @@ import { cn } from "~/utils/cn";
|
||||
|
||||
const variations = {
|
||||
primary:
|
||||
"text-indigo-500 transition hover:text-indigo-400 inline-flex gap-0.5 items-center group",
|
||||
"text-indigo-500 transition hover:text-indigo-400 inline-flex gap-0.5 items-center group focus-visible:focus-custom",
|
||||
secondary:
|
||||
"text-text-dimmed transition underline underline-offset-2 decoration-dimmed/50 hover:decoration-dimmed inline-flex gap-0.5 items-center group",
|
||||
"text-text-dimmed transition underline underline-offset-2 decoration-dimmed/50 hover:decoration-dimmed inline-flex gap-0.5 items-center group focus-visible:focus-custom",
|
||||
} as const;
|
||||
|
||||
type TextLinkProps = {
|
||||
@@ -34,14 +34,14 @@ export function TextLink({
|
||||
<Link to={to} className={cn(classes, className)} {...props}>
|
||||
{children}{" "}
|
||||
{trailingIcon && (
|
||||
<NamedIcon name={trailingIcon} className={cn("h-4 w-4", trailingIconClassName)} />
|
||||
<NamedIcon name={trailingIcon} className={cn("size-4", trailingIconClassName)} />
|
||||
)}
|
||||
</Link>
|
||||
) : href ? (
|
||||
<a href={href} className={cn(classes, className)} {...props}>
|
||||
{children}{" "}
|
||||
{trailingIcon && (
|
||||
<NamedIcon name={trailingIcon} className={cn("h-4 w-4", trailingIconClassName)} />
|
||||
<NamedIcon name={trailingIcon} className={cn("size-4", trailingIconClassName)} />
|
||||
)}
|
||||
</a>
|
||||
) : (
|
||||
|
||||
@@ -22,7 +22,7 @@ export function RunTag({ tag }: { tag: string }) {
|
||||
<span className="flex items-center border-y border-r border-charcoal-700 bg-charcoal-800 pr-1.5 text-text-dimmed">
|
||||
{tagResult.key}
|
||||
</span>
|
||||
<span className="flex items-center rounded-r-sm border-y border-r border-charcoal-700 bg-charcoal-750 px-1.5 text-text-dimmed">
|
||||
<span className="flex items-center whitespace-nowrap rounded-r-sm border-y border-r border-charcoal-700 bg-charcoal-750 px-1.5 text-text-dimmed">
|
||||
{tagResult.value}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -93,7 +93,7 @@ export function ScheduleFilters({ possibleEnvironments, possibleTasks }: Schedul
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-row">
|
||||
<div className="flex w-full">
|
||||
<Input
|
||||
name="search"
|
||||
placeholder="Search schedule id, external id, deduplication id or CRON pattern"
|
||||
@@ -103,7 +103,7 @@ export function ScheduleFilters({ possibleEnvironments, possibleTasks }: Schedul
|
||||
defaultValue={search}
|
||||
onChange={(e) => handleSearchChange(e.target.value)}
|
||||
/>
|
||||
<SelectGroup>
|
||||
<SelectGroup className="ml-2">
|
||||
<Select name="type" value={type ?? "ALL"} onValueChange={handleTypeChange}>
|
||||
<SelectTrigger size="minimal" width="full">
|
||||
<SelectValue placeholder={"Select type"} className="ml-2 whitespace-nowrap p-0" />
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
TableHeader,
|
||||
TableHeaderCell,
|
||||
TableRow,
|
||||
TableVariant,
|
||||
} from "../../primitives/Table";
|
||||
import { CancelRunDialog } from "./CancelRunDialog";
|
||||
import { LiveTimer } from "./LiveTimer";
|
||||
@@ -58,6 +59,7 @@ type RunsTableProps = {
|
||||
runs: RunListItem[];
|
||||
isLoading?: boolean;
|
||||
allowSelection?: boolean;
|
||||
variant?: TableVariant;
|
||||
};
|
||||
|
||||
export function TaskRunsTable({
|
||||
@@ -67,6 +69,7 @@ export function TaskRunsTable({
|
||||
runs,
|
||||
isLoading = false,
|
||||
allowSelection = false,
|
||||
variant = "dimmed",
|
||||
}: RunsTableProps) {
|
||||
const user = useUser();
|
||||
const organization = useOrganization();
|
||||
@@ -104,7 +107,7 @@ export function TaskRunsTable({
|
||||
);
|
||||
|
||||
return (
|
||||
<Table className="max-h-full overflow-y-auto">
|
||||
<Table variant={variant} className="max-h-full overflow-y-auto">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{allowSelection && (
|
||||
@@ -300,7 +303,7 @@ export function TaskRunsTable({
|
||||
/>
|
||||
</TableCell>
|
||||
)}
|
||||
<TableCell to={path} alignment="right">
|
||||
<TableCell to={path} alignment="right" isTabbableCell>
|
||||
{formatNumber(run.number)}
|
||||
</TableCell>
|
||||
<TableCell to={path}>
|
||||
|
||||
+7
-7
@@ -237,7 +237,7 @@ export default function Page() {
|
||||
<div className="flex min-w-0 max-w-full flex-col">
|
||||
{!userHasTasks && <UserHasNoTasks />}
|
||||
<div className="max-h-full overflow-hidden">
|
||||
<div className="flex items-center p-2">
|
||||
<div className="flex items-center gap-1 p-2">
|
||||
<Input
|
||||
placeholder="Search tasks"
|
||||
variant="tertiary"
|
||||
@@ -295,7 +295,7 @@ export default function Page() {
|
||||
|
||||
return (
|
||||
<TableRow key={task.slug} className="group">
|
||||
<TableCell to={path}>
|
||||
<TableCell to={path} isTabbableCell>
|
||||
<div className="flex items-center gap-2">
|
||||
<SimpleTooltip
|
||||
button={<TaskTriggerSourceIcon source={task.triggerSource} />}
|
||||
@@ -304,13 +304,13 @@ export default function Page() {
|
||||
<span>{task.slug}</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell to={path} className="py-0" actionClassName="py-0">
|
||||
<TableCell to={path}>
|
||||
<TaskFunctionName
|
||||
functionName={task.exportName}
|
||||
variant="extra-extra-small"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell to={path} className="p-0">
|
||||
<TableCell to={path}>
|
||||
<Suspense
|
||||
fallback={
|
||||
<>
|
||||
@@ -326,7 +326,7 @@ export default function Page() {
|
||||
</TypedAwait>
|
||||
</Suspense>
|
||||
</TableCell>
|
||||
<TableCell to={path} className="p-0">
|
||||
<TableCell to={path}>
|
||||
<Suspense fallback={<></>}>
|
||||
<TypedAwait resolve={runningStats}>
|
||||
{(data) => {
|
||||
@@ -336,7 +336,7 @@ export default function Page() {
|
||||
</TypedAwait>
|
||||
</Suspense>
|
||||
</TableCell>
|
||||
<TableCell to={path} className="p-0" actionClassName="py-0">
|
||||
<TableCell to={path} actionClassName="py-1.5">
|
||||
<Suspense fallback={<TaskActivityBlankState />}>
|
||||
<TypedAwait resolve={activity}>
|
||||
{(data) => {
|
||||
@@ -356,7 +356,7 @@ export default function Page() {
|
||||
</TypedAwait>
|
||||
</Suspense>
|
||||
</TableCell>
|
||||
<TableCell to={path} className="p-0">
|
||||
<TableCell to={path}>
|
||||
<Suspense fallback={<></>}>
|
||||
<TypedAwait resolve={durations}>
|
||||
{(data) => {
|
||||
|
||||
+2
-1
@@ -222,7 +222,7 @@ export default function Page() {
|
||||
/>
|
||||
))}
|
||||
</TableCell>
|
||||
<TableCell className={alertChannel.enabled ? "" : "opacity-50"}>
|
||||
<TableCell className={cn("py-1", alertChannel.enabled ? "" : "opacity-50")}>
|
||||
<AlertChannelDetails alertChannel={alertChannel} />
|
||||
</TableCell>
|
||||
<TableCell className={alertChannel.enabled ? "" : "opacity-50"}>
|
||||
@@ -466,6 +466,7 @@ function AlertChannelDetails({ alertChannel }: { alertChannel: AlertChannelListP
|
||||
label={"Email"}
|
||||
description={alertChannel.properties.email}
|
||||
boxClassName="group-hover/table-row:bg-charcoal-800"
|
||||
className="h-12"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
+4
-2
@@ -195,7 +195,9 @@ function BatchesTable({ batches, hasFilters, filters }: BatchList) {
|
||||
const path = v3BatchRunsPath(organization, project, batch);
|
||||
return (
|
||||
<TableRow key={batch.id}>
|
||||
<TableCell to={path}>{batch.friendlyId}</TableCell>
|
||||
<TableCell to={path} isTabbableCell>
|
||||
{batch.friendlyId}
|
||||
</TableCell>
|
||||
<TableCell to={path}>
|
||||
<EnvironmentLabel
|
||||
environment={batch.environment}
|
||||
@@ -209,7 +211,7 @@ function BatchesTable({ batches, hasFilters, filters }: BatchList) {
|
||||
disableHoverableContent
|
||||
button={
|
||||
<span className="flex items-center gap-1">
|
||||
<ExclamationCircleIcon className="size-4 text-slate-500" />
|
||||
<ExclamationCircleIcon className="size-4 text-text-dimmed" />
|
||||
<span>Legacy batch</span>
|
||||
</span>
|
||||
}
|
||||
|
||||
+106
-96
@@ -4,7 +4,6 @@ import { typedjson, useTypedLoaderData } from "remix-typedjson";
|
||||
import { ExitIcon } from "~/assets/icons/ExitIcon";
|
||||
import { UserAvatar } from "~/components/UserProfilePhoto";
|
||||
import { AdminDebugTooltip } from "~/components/admin/debugTooltip";
|
||||
import { CodeBlock } from "~/components/code/CodeBlock";
|
||||
import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel";
|
||||
import { Badge } from "~/components/primitives/Badge";
|
||||
import { LinkButton } from "~/components/primitives/Buttons";
|
||||
@@ -108,107 +107,118 @@ export default function Page() {
|
||||
|
||||
<LinkButton
|
||||
to={`${v3DeploymentsPath(organization, project)}${page ? `?page=${page}` : ""}`}
|
||||
variant="minimal/medium"
|
||||
LeadingIcon={ExitIcon}
|
||||
variant="minimal/small"
|
||||
TrailingIcon={ExitIcon}
|
||||
shortcut={{ key: "esc" }}
|
||||
shortcutPosition="before-trailing-icon"
|
||||
className="pl-1"
|
||||
/>
|
||||
</div>
|
||||
<div className="overflow-y-auto px-3 pt-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Property.Table>
|
||||
<Property.Item>
|
||||
<Property.Label>Deploy</Property.Label>
|
||||
<Property.Value className="flex items-center gap-2">
|
||||
<span>{deployment.shortCode}</span>
|
||||
{deployment.label && <Badge variant="outline-rounded">{deployment.label}</Badge>}
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Environment</Property.Label>
|
||||
<Property.Value>
|
||||
<EnvironmentLabel environment={deployment.environment} userName={usernameForEnv} />
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Version</Property.Label>
|
||||
<Property.Value>{deployment.version}</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Status</Property.Label>
|
||||
<Property.Value>
|
||||
<DeploymentStatus
|
||||
status={deployment.status}
|
||||
isBuilt={deployment.isBuilt}
|
||||
className="text-sm"
|
||||
/>
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Tasks</Property.Label>
|
||||
<Property.Value>{deployment.tasks ? deployment.tasks.length : "–"}</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>SDK Version</Property.Label>
|
||||
<Property.Value>{deployment.sdkVersion ? deployment.sdkVersion : "–"}</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>CLI Version</Property.Label>
|
||||
<Property.Value>{deployment.cliVersion ? deployment.cliVersion : "–"}</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Started at</Property.Label>
|
||||
<Property.Value>
|
||||
<DateTimeAccurate date={deployment.createdAt} /> UTC
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Built at</Property.Label>
|
||||
<Property.Value>
|
||||
{deployment.builtAt ? (
|
||||
<>
|
||||
<DateTimeAccurate date={deployment.builtAt} /> UTC
|
||||
</>
|
||||
) : (
|
||||
"–"
|
||||
)}
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Deployed at</Property.Label>
|
||||
<Property.Value>
|
||||
{deployment.deployedAt ? (
|
||||
<>
|
||||
<DateTimeAccurate date={deployment.deployedAt} /> UTC
|
||||
</>
|
||||
) : (
|
||||
"–"
|
||||
)}
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Deployed by</Property.Label>
|
||||
<Property.Value>
|
||||
{deployment.deployedBy ? (
|
||||
<div className="flex items-center gap-1">
|
||||
<UserAvatar
|
||||
avatarUrl={deployment.deployedBy.avatarUrl}
|
||||
name={deployment.deployedBy.name ?? deployment.deployedBy.displayName}
|
||||
className="h-4 w-4"
|
||||
/>
|
||||
<Paragraph variant="small">
|
||||
{deployment.deployedBy.name ?? deployment.deployedBy.displayName}
|
||||
</Paragraph>
|
||||
</div>
|
||||
) : (
|
||||
"–"
|
||||
)}
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
</Property.Table>
|
||||
<div className="overflow-y-auto scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600">
|
||||
<div className="flex flex-col">
|
||||
<div className="p-3">
|
||||
<Property.Table>
|
||||
<Property.Item>
|
||||
<Property.Label>Deploy</Property.Label>
|
||||
<Property.Value className="flex items-center gap-2">
|
||||
<span>{deployment.shortCode}</span>
|
||||
{deployment.label && <Badge variant="outline-rounded">{deployment.label}</Badge>}
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Environment</Property.Label>
|
||||
<Property.Value>
|
||||
<EnvironmentLabel
|
||||
environment={deployment.environment}
|
||||
userName={usernameForEnv}
|
||||
/>
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Version</Property.Label>
|
||||
<Property.Value>{deployment.version}</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Status</Property.Label>
|
||||
<Property.Value>
|
||||
<DeploymentStatus
|
||||
status={deployment.status}
|
||||
isBuilt={deployment.isBuilt}
|
||||
className="text-sm"
|
||||
/>
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Tasks</Property.Label>
|
||||
<Property.Value>{deployment.tasks ? deployment.tasks.length : "–"}</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>SDK Version</Property.Label>
|
||||
<Property.Value>
|
||||
{deployment.sdkVersion ? deployment.sdkVersion : "–"}
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>CLI Version</Property.Label>
|
||||
<Property.Value>
|
||||
{deployment.cliVersion ? deployment.cliVersion : "–"}
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Started at</Property.Label>
|
||||
<Property.Value>
|
||||
<DateTimeAccurate date={deployment.createdAt} /> UTC
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Built at</Property.Label>
|
||||
<Property.Value>
|
||||
{deployment.builtAt ? (
|
||||
<>
|
||||
<DateTimeAccurate date={deployment.builtAt} /> UTC
|
||||
</>
|
||||
) : (
|
||||
"–"
|
||||
)}
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Deployed at</Property.Label>
|
||||
<Property.Value>
|
||||
{deployment.deployedAt ? (
|
||||
<>
|
||||
<DateTimeAccurate date={deployment.deployedAt} /> UTC
|
||||
</>
|
||||
) : (
|
||||
"–"
|
||||
)}
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
<Property.Item>
|
||||
<Property.Label>Deployed by</Property.Label>
|
||||
<Property.Value>
|
||||
{deployment.deployedBy ? (
|
||||
<div className="flex items-center gap-1">
|
||||
<UserAvatar
|
||||
avatarUrl={deployment.deployedBy.avatarUrl}
|
||||
name={deployment.deployedBy.name ?? deployment.deployedBy.displayName}
|
||||
className="h-4 w-4"
|
||||
/>
|
||||
<Paragraph variant="small">
|
||||
{deployment.deployedBy.name ?? deployment.deployedBy.displayName}
|
||||
</Paragraph>
|
||||
</div>
|
||||
) : (
|
||||
"–"
|
||||
)}
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
</Property.Table>
|
||||
</div>
|
||||
|
||||
{deployment.tasks ? (
|
||||
<div className="divide-y divide-charcoal-800 overflow-y-auto scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600">
|
||||
<Table>
|
||||
<Table variant="bright">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHeaderCell className="px-2">Task</TableHeaderCell>
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ export default function Page() {
|
||||
const isSelected = deploymentParam === deployment.shortCode;
|
||||
return (
|
||||
<TableRow key={deployment.id} className="group" isSelected={isSelected}>
|
||||
<TableCell to={path} isSelected={isSelected}>
|
||||
<TableCell to={path} isTabbableCell isSelected={isSelected}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Paragraph variant="extra-small">{deployment.shortCode}</Paragraph>
|
||||
{deployment.label && (
|
||||
|
||||
+58
-54
@@ -220,11 +220,12 @@ export default function Page() {
|
||||
TrailingIcon={ExitIcon}
|
||||
shortcut={{ key: "esc" }}
|
||||
shortcutPosition="before-trailing-icon"
|
||||
className="pl-1"
|
||||
/>
|
||||
</div>
|
||||
<div className="overflow-y-scroll scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600">
|
||||
<div className="p-3">
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-3">
|
||||
<div className="p-3">
|
||||
<Property.Table>
|
||||
<Property.Item>
|
||||
<Property.Label>Schedule ID</Property.Label>
|
||||
@@ -282,61 +283,64 @@ export default function Page() {
|
||||
</>
|
||||
)}
|
||||
</Property.Table>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Header3>Last 5 runs</Header3>
|
||||
<TaskRunsTable
|
||||
total={schedule.runs.length}
|
||||
hasFilters={false}
|
||||
filters={{
|
||||
tasks: [],
|
||||
versions: [],
|
||||
statuses: [],
|
||||
environments: [],
|
||||
from: undefined,
|
||||
to: undefined,
|
||||
}}
|
||||
runs={schedule.runs}
|
||||
isLoading={false}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Header3>Next 5 runs</Header3>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{!isUtc && <TableHeaderCell>{schedule.timezone}</TableHeaderCell>}
|
||||
<TableHeaderCell>UTC</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{schedule.active ? (
|
||||
schedule.nextRuns.length ? (
|
||||
schedule.nextRuns.map((run, index) => (
|
||||
<TableRow key={index}>
|
||||
{!isUtc && (
|
||||
<TableCell>
|
||||
<DateTime date={run} timeZone={schedule.timezone} />
|
||||
</TableCell>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Header3 className="pb-1 pl-3">Last 5 runs</Header3>
|
||||
<TaskRunsTable
|
||||
total={schedule.runs.length}
|
||||
hasFilters={false}
|
||||
filters={{
|
||||
tasks: [],
|
||||
versions: [],
|
||||
statuses: [],
|
||||
environments: [],
|
||||
from: undefined,
|
||||
to: undefined,
|
||||
}}
|
||||
runs={schedule.runs}
|
||||
isLoading={false}
|
||||
variant="bright"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1 pt-2">
|
||||
<Header3 className="pb-1 pl-3">Next 5 runs</Header3>
|
||||
<Table variant="bright">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{!isUtc && <TableHeaderCell>{schedule.timezone}</TableHeaderCell>}
|
||||
<TableHeaderCell>UTC</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{schedule.active ? (
|
||||
schedule.nextRuns.length ? (
|
||||
schedule.nextRuns.map((run, index) => (
|
||||
<TableRow key={index}>
|
||||
{!isUtc && (
|
||||
<TableCell>
|
||||
<DateTime date={run} timeZone="UTC" />
|
||||
<DateTime date={run} timeZone={schedule.timezone} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableBlankRow colSpan={isUtc ? 1 : 2}>
|
||||
<PlaceholderText title="You found a bug" />
|
||||
</TableBlankRow>
|
||||
)
|
||||
)}
|
||||
<TableCell>
|
||||
<DateTime date={run} timeZone="UTC" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableBlankRow colSpan={isUtc ? 1 : 2}>
|
||||
<PlaceholderText title="Schedule disabled" />
|
||||
<PlaceholderText title="You found a bug" />
|
||||
</TableBlankRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
{!isImperative && (
|
||||
)
|
||||
) : (
|
||||
<TableBlankRow colSpan={isUtc ? 1 : 2}>
|
||||
<PlaceholderText title="Schedule disabled" />
|
||||
</TableBlankRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
{!isImperative && (
|
||||
<div className="p-3">
|
||||
<InfoPanel
|
||||
title="Editing declarative schedules"
|
||||
icon={BookOpenIcon}
|
||||
@@ -349,8 +353,8 @@ export default function Page() {
|
||||
You can only edit a declarative schedule by updating your schedules.task and then
|
||||
running the CLI dev and deploy commands.
|
||||
</InfoPanel>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{isImperative && (
|
||||
|
||||
+14
-3
@@ -65,6 +65,7 @@ import {
|
||||
import { useCurrentPlan } from "../_app.orgs.$organizationSlug/route";
|
||||
import { ArrowUpCircleIcon } from "@heroicons/react/24/outline";
|
||||
import { SimpleTooltip } from "~/components/primitives/Tooltip";
|
||||
import { cn } from "~/utils/cn";
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
return [
|
||||
@@ -218,9 +219,19 @@ export default function Page() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="h-fit max-h-full overflow-x-auto">
|
||||
<div
|
||||
className={cn(
|
||||
"grid h-fit max-h-full min-h-full overflow-x-auto",
|
||||
totalPages > 1 ? "grid-rows-[1fr_auto]" : "grid-rows-[1fr]"
|
||||
)}
|
||||
>
|
||||
<SchedulesTable schedules={schedules} hasFilters={hasFilters} />
|
||||
<div className="flex justify-end py-3">
|
||||
<div
|
||||
className={cn(
|
||||
"flex min-h-full",
|
||||
totalPages > 1 && "justify-end border-t border-grid-dimmed px-2 py-3"
|
||||
)}
|
||||
>
|
||||
<PaginationControls currentPage={currentPage} totalPages={totalPages} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -451,7 +462,7 @@ function SchedulesTable({
|
||||
const cellClass = schedule.active ? "" : "opacity-50";
|
||||
return (
|
||||
<TableRow key={schedule.id} className={isSelected ? "bg-grid-dimmed" : undefined}>
|
||||
<TableCell to={path} className={cellClass}>
|
||||
<TableCell to={path} isTabbableCell className={cellClass}>
|
||||
{schedule.friendlyId}
|
||||
</TableCell>
|
||||
<TableCell to={path} className={cellClass}>
|
||||
|
||||
+1
@@ -281,6 +281,7 @@ function TaskRow({ task, environmentSlug }: { task: TaskListItem; environmentSlu
|
||||
</TableCell>
|
||||
<TableCell
|
||||
to={path}
|
||||
isTabbableCell
|
||||
actionClassName="pl-1 pr-2 py-1.5"
|
||||
className={cn((isActive || isPending) && "group-hover/table-row:bg-indigo-500/5")}
|
||||
>
|
||||
|
||||
@@ -212,10 +212,10 @@ module.exports = {
|
||||
prod: prodEnv,
|
||||
},
|
||||
focusStyles: {
|
||||
outline: "2px solid",
|
||||
outline: "1px solid",
|
||||
outlineOffset: "0px",
|
||||
outlineColor: textLink,
|
||||
borderRadius: "2px",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
borderRadius: {
|
||||
lg: radius,
|
||||
|
||||
Reference in New Issue
Block a user