mirror of
https://github.com/hatchet-dev/hatchet.git
synced 2026-03-12 21:19:38 -05:00
chore(frontend): setup eslint and prettier with better defaults (#15)
This commit is contained in:
@@ -1,18 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
59
frontend/app/.eslintrc.json
Normal file
59
frontend/app/.eslintrc.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2020": true
|
||||
},
|
||||
"extends": [
|
||||
"airbnb-typescript",
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"dist"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"plugins": [
|
||||
"react-refresh",
|
||||
"import",
|
||||
"unused-imports",
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-shadow": "off",
|
||||
"@typescript-eslint/no-throw-literal": "off",
|
||||
"no-use-before-define": "off",
|
||||
"react/prop-types": "off",
|
||||
"react/no-unescaped-entities": "off",
|
||||
"@typescript-eslint/no-use-before-define": "off",
|
||||
"import/extensions": "off",
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"react-refresh/only-export-components": [
|
||||
"warn",
|
||||
{
|
||||
"allowConstantExport": true
|
||||
}
|
||||
],
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
"no-unused-vars": "off",
|
||||
"prettier/prettier": "error",
|
||||
"@typescript-eslint/no-unused-vars": "warn",
|
||||
"curly": "error",
|
||||
"import/prefer-default-export": "off",
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": [
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
1
frontend/app/.prettierignore
Normal file
1
frontend/app/.prettierignore
Normal file
@@ -0,0 +1 @@
|
||||
src/lib/api/generated/
|
||||
4
frontend/app/.prettierrc
Normal file
4
frontend/app/.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
2091
frontend/app/package-lock.json
generated
2091
frontend/app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,12 @@
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"lint:check": "npm run eslint:check && npm run prettier:check",
|
||||
"lint:fix": "npm run eslint:fix && npm run prettier:fix",
|
||||
"eslint:check": "eslint \"{src,apps,libs,test}/**/*.{ts,tsx,js}\"",
|
||||
"eslint:fix": "eslint \"{src,apps,libs,test}/**/*.{ts,tsx,js}\" --fix",
|
||||
"prettier:check": "prettier \"src/**/*.{ts,tsx}\" --list-different",
|
||||
"prettier:fix": "prettier \"src/**/*.{ts,tsx}\" --write",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -69,12 +74,21 @@
|
||||
"@typescript-eslint/parser": "^6.10.0",
|
||||
"@vitejs/plugin-react": "^4.2.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"eslint": "^8.53.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-airbnb-typescript": "^17.1.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-prettier": "^5.0.1",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.4",
|
||||
"eslint-plugin-unused-imports": "^3.0.0",
|
||||
"postcss": "^8.4.31",
|
||||
"prettier": "^3.1.1",
|
||||
"tailwindcss": "^3.3.5",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.0.0"
|
||||
"vite": "^5.0.0",
|
||||
"vite-plugin-eslint": "^1.8.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import React from "react";
|
||||
import { Group } from "@visx/group";
|
||||
import { AreaClosed } from "@visx/shape";
|
||||
import { AxisLeft, AxisBottom, AxisScale } from "@visx/axis";
|
||||
import { LinearGradient } from "@visx/gradient";
|
||||
import { curveMonotoneX } from "@visx/curve";
|
||||
import { AppleStock } from "@visx/mock-data/lib/mocks/appleStock";
|
||||
import React from 'react';
|
||||
import { Group } from '@visx/group';
|
||||
import { AreaClosed } from '@visx/shape';
|
||||
import { AxisLeft, AxisBottom, AxisScale } from '@visx/axis';
|
||||
import { LinearGradient } from '@visx/gradient';
|
||||
import { curveMonotoneX } from '@visx/curve';
|
||||
import { AppleStock } from '@visx/mock-data/lib/mocks/appleStock';
|
||||
|
||||
// Initialize some variables
|
||||
const axisColor = "#fff";
|
||||
const axisColor = '#fff';
|
||||
const axisBottomTickLabelProps = {
|
||||
textAnchor: "middle" as const,
|
||||
fontFamily: "Arial",
|
||||
textAnchor: 'middle' as const,
|
||||
fontFamily: 'Arial',
|
||||
fontSize: 10,
|
||||
fill: axisColor,
|
||||
};
|
||||
const axisLeftTickLabelProps = {
|
||||
dx: "-0.25em",
|
||||
dy: "0.25em",
|
||||
fontFamily: "Arial",
|
||||
dx: '-0.25em',
|
||||
dy: '0.25em',
|
||||
fontFamily: 'Arial',
|
||||
fontSize: 10,
|
||||
textAnchor: "end" as const,
|
||||
textAnchor: 'end' as const,
|
||||
fill: axisColor,
|
||||
};
|
||||
|
||||
@@ -54,7 +54,9 @@ export default function AreaChart({
|
||||
left?: number;
|
||||
children?: React.ReactNode;
|
||||
}) {
|
||||
if (width < 10) return null;
|
||||
if (width < 10) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Group left={left || margin.left} top={top || margin.top}>
|
||||
<LinearGradient
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
/* eslint-disable @typescript-eslint/no-use-before-define */
|
||||
import { useRef, useState, useMemo } from "react";
|
||||
import { scaleTime, scaleLinear } from "@visx/scale";
|
||||
import appleStock, { AppleStock } from "@visx/mock-data/lib/mocks/appleStock";
|
||||
import { Brush } from "@visx/brush";
|
||||
import { Bounds } from "@visx/brush/lib/types";
|
||||
import { useRef, useState, useMemo } from 'react';
|
||||
import { scaleTime, scaleLinear } from '@visx/scale';
|
||||
import appleStock, { AppleStock } from '@visx/mock-data/lib/mocks/appleStock';
|
||||
import { Brush } from '@visx/brush';
|
||||
import { Bounds } from '@visx/brush/lib/types';
|
||||
import BaseBrush, {
|
||||
BaseBrushState,
|
||||
UpdateBrush,
|
||||
} from "@visx/brush/lib/BaseBrush";
|
||||
import { PatternLines } from "@visx/pattern";
|
||||
import { Group } from "@visx/group";
|
||||
import { max, extent } from "@visx/vendor/d3-array";
|
||||
import { BrushHandleRenderProps } from "@visx/brush/lib/BrushHandle";
|
||||
import AreaChart from "./area-chart";
|
||||
import { Button } from "@/components/ui/button";
|
||||
} from '@visx/brush/lib/BaseBrush';
|
||||
import { PatternLines } from '@visx/pattern';
|
||||
import { Group } from '@visx/group';
|
||||
import { max, extent } from '@visx/vendor/d3-array';
|
||||
import { BrushHandleRenderProps } from '@visx/brush/lib/BrushHandle';
|
||||
import AreaChart from './area-chart';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
// Initialize some variables
|
||||
const stock = appleStock.slice(1000);
|
||||
const brushMargin = { top: 10, bottom: 15, left: 50, right: 20 };
|
||||
const chartSeparation = 30;
|
||||
const PATTERN_ID = "brush_pattern";
|
||||
export const accentColor = "#ffffff44";
|
||||
export const background = "#1E293B";
|
||||
export const background2 = "#8c77e0";
|
||||
const PATTERN_ID = 'brush_pattern';
|
||||
export const accentColor = '#ffffff44';
|
||||
export const background = '#1E293B';
|
||||
export const background2 = '#8c77e0';
|
||||
const selectedBrushStyle = {
|
||||
fill: `url(#${PATTERN_ID})`,
|
||||
stroke: "white",
|
||||
stroke: 'white',
|
||||
};
|
||||
|
||||
// accessors
|
||||
@@ -54,7 +54,9 @@ function BrushChart({
|
||||
const [filteredStock, setFilteredStock] = useState(stock);
|
||||
|
||||
const onBrushChange = (domain: Bounds | null) => {
|
||||
if (!domain) return;
|
||||
if (!domain) {
|
||||
return;
|
||||
}
|
||||
const { x0, x1, y0, y1 } = domain;
|
||||
const stockCopy = stock.filter((s) => {
|
||||
const x = getDate(s).getTime();
|
||||
@@ -77,7 +79,7 @@ function BrushChart({
|
||||
const xBrushMax = Math.max(width - brushMargin.left - brushMargin.right, 0);
|
||||
const yBrushMax = Math.max(
|
||||
bottomChartHeight - brushMargin.top - brushMargin.bottom,
|
||||
0
|
||||
0,
|
||||
);
|
||||
|
||||
// scales
|
||||
@@ -87,7 +89,7 @@ function BrushChart({
|
||||
range: [0, xMax],
|
||||
domain: extent(filteredStock, getDate) as [Date, Date],
|
||||
}),
|
||||
[xMax, filteredStock]
|
||||
[xMax, filteredStock],
|
||||
);
|
||||
const stockScale = useMemo(
|
||||
() =>
|
||||
@@ -96,7 +98,7 @@ function BrushChart({
|
||||
domain: [0, max(filteredStock, getStockValue) || 0],
|
||||
nice: true,
|
||||
}),
|
||||
[yMax, filteredStock]
|
||||
[yMax, filteredStock],
|
||||
);
|
||||
const brushDateScale = useMemo(
|
||||
() =>
|
||||
@@ -104,7 +106,7 @@ function BrushChart({
|
||||
range: [0, xBrushMax],
|
||||
domain: extent(stock, getDate) as [Date, Date],
|
||||
}),
|
||||
[xBrushMax]
|
||||
[xBrushMax],
|
||||
);
|
||||
const brushStockScale = useMemo(
|
||||
() =>
|
||||
@@ -113,7 +115,7 @@ function BrushChart({
|
||||
domain: [0, max(stock, getStockValue) || 0],
|
||||
nice: true,
|
||||
}),
|
||||
[yBrushMax]
|
||||
[yBrushMax],
|
||||
);
|
||||
|
||||
const initialBrushPosition = useMemo(
|
||||
@@ -121,7 +123,7 @@ function BrushChart({
|
||||
start: { x: brushDateScale(getDate(stock[50])) },
|
||||
end: { x: brushDateScale(getDate(stock[100])) },
|
||||
}),
|
||||
[brushDateScale]
|
||||
[brushDateScale],
|
||||
);
|
||||
|
||||
// event handlers
|
||||
@@ -137,7 +139,7 @@ function BrushChart({
|
||||
const updater: UpdateBrush = (prevBrush) => {
|
||||
const newExtent = brushRef.current!.getExtent(
|
||||
initialBrushPosition.start,
|
||||
initialBrushPosition.end
|
||||
initialBrushPosition.end,
|
||||
);
|
||||
|
||||
const newState: BaseBrushState = {
|
||||
@@ -198,7 +200,7 @@ function BrushChart({
|
||||
width={8}
|
||||
stroke={accentColor}
|
||||
strokeWidth={1}
|
||||
orientation={["diagonal"]}
|
||||
orientation={['diagonal']}
|
||||
/>
|
||||
<Brush
|
||||
xScale={brushDateScale}
|
||||
@@ -208,7 +210,7 @@ function BrushChart({
|
||||
margin={brushMargin}
|
||||
handleSize={8}
|
||||
innerRef={brushRef}
|
||||
resizeTriggerAreas={["left", "right"]}
|
||||
resizeTriggerAreas={['left', 'right']}
|
||||
brushDirection="horizontal"
|
||||
initialBrushPosition={initialBrushPosition}
|
||||
onChange={onBrushChange}
|
||||
@@ -242,7 +244,7 @@ function BrushHandle({ x, height, isBrushActive }: BrushHandleRenderProps) {
|
||||
d="M -4.5 0.5 L 3.5 0.5 L 3.5 15.5 L -4.5 15.5 L -4.5 0.5 M -1.5 4 L -1.5 12 M 0.5 4 L 0.5 12"
|
||||
stroke="#999999"
|
||||
strokeWidth="1"
|
||||
style={{ cursor: "ew-resize" }}
|
||||
style={{ cursor: 'ew-resize' }}
|
||||
/>
|
||||
</Group>
|
||||
);
|
||||
|
||||
@@ -3,18 +3,18 @@ import {
|
||||
ArrowUpIcon,
|
||||
CaretSortIcon,
|
||||
EyeNoneIcon,
|
||||
} from "@radix-ui/react-icons";
|
||||
import { Column } from "@tanstack/react-table";
|
||||
} from '@radix-ui/react-icons';
|
||||
import { Column } from '@tanstack/react-table';
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
|
||||
interface DataTableColumnHeaderProps<TData, TValue>
|
||||
extends React.HTMLAttributes<HTMLDivElement> {
|
||||
@@ -28,11 +28,11 @@ export function DataTableColumnHeader<TData, TValue>({
|
||||
className,
|
||||
}: DataTableColumnHeaderProps<TData, TValue>) {
|
||||
if (!column.getCanSort()) {
|
||||
return <div className={cn(className, "text-xs")}>{title}</div>;
|
||||
return <div className={cn(className, 'text-xs')}>{title}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn("flex items-center space-x-2", className)}>
|
||||
<div className={cn('flex items-center space-x-2', className)}>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
@@ -41,9 +41,9 @@ export function DataTableColumnHeader<TData, TValue>({
|
||||
className="-ml-3 h-8 data-[state=open]:bg-accent"
|
||||
>
|
||||
<span>{title}</span>
|
||||
{column.getIsSorted() === "desc" ? (
|
||||
{column.getIsSorted() === 'desc' ? (
|
||||
<ArrowDownIcon className="ml-2 h-4 w-4" />
|
||||
) : column.getIsSorted() === "asc" ? (
|
||||
) : column.getIsSorted() === 'asc' ? (
|
||||
<ArrowUpIcon className="ml-2 h-4 w-4" />
|
||||
) : (
|
||||
<CaretSortIcon className="ml-2 h-4 w-4" />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as React from "react";
|
||||
import { CheckIcon, PlusCircledIcon } from "@radix-ui/react-icons";
|
||||
import { Column } from "@tanstack/react-table";
|
||||
import * as React from 'react';
|
||||
import { CheckIcon, PlusCircledIcon } from '@radix-ui/react-icons';
|
||||
import { Column } from '@tanstack/react-table';
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
@@ -13,13 +13,13 @@ import {
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
} from "@/components/ui/command";
|
||||
} from '@/components/ui/command';
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
} from '@/components/ui/popover';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
|
||||
interface DataTableFacetedFilterProps<TData, TValue> {
|
||||
column?: Column<TData, TValue>;
|
||||
@@ -99,19 +99,19 @@ export function DataTableFacetedFilter<TData, TValue>({
|
||||
}
|
||||
const filterValues = Array.from(selectedValues);
|
||||
column?.setFilterValue(
|
||||
filterValues.length ? filterValues : undefined
|
||||
filterValues.length ? filterValues : undefined,
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
|
||||
'mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary',
|
||||
isSelected
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "opacity-50 [&_svg]:invisible"
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'opacity-50 [&_svg]:invisible',
|
||||
)}
|
||||
>
|
||||
<CheckIcon className={cn("h-4 w-4")} />
|
||||
<CheckIcon className={cn('h-4 w-4')} />
|
||||
</div>
|
||||
{option.icon && (
|
||||
<option.icon className="mr-2 h-4 w-4 text-muted-foreground" />
|
||||
|
||||
@@ -3,17 +3,17 @@ import {
|
||||
ChevronRightIcon,
|
||||
DoubleArrowLeftIcon,
|
||||
DoubleArrowRightIcon,
|
||||
} from "@radix-ui/react-icons";
|
||||
import { Table } from "@tanstack/react-table";
|
||||
} from '@radix-ui/react-icons';
|
||||
import { Table } from '@tanstack/react-table';
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
} from '@/components/ui/select';
|
||||
|
||||
interface DataTablePaginationProps<TData> {
|
||||
table: Table<TData>;
|
||||
@@ -29,7 +29,7 @@ export function DataTablePagination<TData>({
|
||||
return (
|
||||
<div className="flex items-center justify-between px-2">
|
||||
<div className="flex-1 text-sm text-muted-foreground">
|
||||
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
||||
{table.getFilteredSelectedRowModel().rows.length} of{' '}
|
||||
{table.getFilteredRowModel().rows.length} row(s) selected.
|
||||
</div>
|
||||
<div className="flex items-center space-x-6 lg:space-x-8">
|
||||
@@ -39,7 +39,9 @@ export function DataTablePagination<TData>({
|
||||
value={`${pagination.pageSize}`}
|
||||
onValueChange={(value) => {
|
||||
table.setPageSize(Number(value));
|
||||
onSetPageSize && onSetPageSize(Number(value));
|
||||
if (onSetPageSize) {
|
||||
onSetPageSize(Number(value));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="h-8 w-[70px]">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DotsHorizontalIcon } from "@radix-ui/react-icons";
|
||||
import { Row } from "@tanstack/react-table";
|
||||
import { DotsHorizontalIcon } from '@radix-ui/react-icons';
|
||||
import { Row } from '@tanstack/react-table';
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -14,9 +14,9 @@ import {
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
|
||||
import { IDGetter } from "./data-table";
|
||||
import { IDGetter } from './data-table';
|
||||
|
||||
interface Label {
|
||||
label: string;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Cross2Icon } from "@radix-ui/react-icons";
|
||||
import { Table } from "@tanstack/react-table";
|
||||
import { Cross2Icon } from '@radix-ui/react-icons';
|
||||
import { Table } from '@tanstack/react-table';
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { DataTableViewOptions } from "./data-table-view-options";
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { DataTableViewOptions } from './data-table-view-options';
|
||||
|
||||
import { DataTableFacetedFilter } from "./data-table-faceted-filter";
|
||||
import { DataTableFacetedFilter } from './data-table-faceted-filter';
|
||||
|
||||
export interface FilterOption {
|
||||
label: string;
|
||||
@@ -51,7 +51,7 @@ export function DataTableToolbar<TData>({
|
||||
title={filter.title}
|
||||
options={filter.options}
|
||||
/>
|
||||
)
|
||||
),
|
||||
)}
|
||||
{isFiltered && (
|
||||
<Button
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu";
|
||||
import { MixerHorizontalIcon } from "@radix-ui/react-icons";
|
||||
import { Table } from "@tanstack/react-table";
|
||||
import { DropdownMenuTrigger } from '@radix-ui/react-dropdown-menu';
|
||||
import { MixerHorizontalIcon } from '@radix-ui/react-icons';
|
||||
import { Table } from '@tanstack/react-table';
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
|
||||
interface DataTableViewOptionsProps<TData> {
|
||||
table: Table<TData>;
|
||||
@@ -37,7 +37,7 @@ export function DataTableViewOptions<TData>({
|
||||
.getAllColumns()
|
||||
.filter(
|
||||
(column) =>
|
||||
typeof column.accessorFn !== "undefined" && column.getCanHide()
|
||||
typeof column.accessorFn !== 'undefined' && column.getCanHide(),
|
||||
)
|
||||
.map((column) => {
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as React from "react";
|
||||
import * as React from 'react';
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
} from '@tanstack/react-table';
|
||||
|
||||
import {
|
||||
Table,
|
||||
@@ -25,12 +25,12 @@ import {
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
} from '@/components/ui/table';
|
||||
|
||||
import { DataTablePagination } from "./data-table-pagination";
|
||||
import { DataTableToolbar, ToolbarFilters } from "./data-table-toolbar";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { DataTablePagination } from './data-table-pagination';
|
||||
import { DataTableToolbar, ToolbarFilters } from './data-table-toolbar';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export interface IDGetter {
|
||||
metadata: {
|
||||
@@ -64,7 +64,7 @@ interface DataTableProps<TData extends IDGetter, TValue> {
|
||||
| ((
|
||||
originalRow: TData,
|
||||
index: number,
|
||||
parent?: Row<TData> | undefined
|
||||
parent?: Row<TData> | undefined,
|
||||
) => string)
|
||||
| undefined;
|
||||
}
|
||||
@@ -91,7 +91,7 @@ export function DataTable<TData extends IDGetter, TValue>({
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
const tableData = React.useMemo(
|
||||
() => (isLoading ? Array(10).fill({}) : data),
|
||||
[isLoading, data]
|
||||
[isLoading, data],
|
||||
);
|
||||
|
||||
const tableColumns = React.useMemo(
|
||||
@@ -102,7 +102,7 @@ export function DataTable<TData extends IDGetter, TValue>({
|
||||
cell: () => <Skeleton className="h-4 w-[100px]" />,
|
||||
}))
|
||||
: columns,
|
||||
[isLoading, columns]
|
||||
[isLoading, columns],
|
||||
);
|
||||
|
||||
const table = useReactTable({
|
||||
@@ -142,9 +142,9 @@ export function DataTable<TData extends IDGetter, TValue>({
|
||||
return (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
data-state={row.getIsSelected() && 'selected'}
|
||||
className={cn(
|
||||
row.original.isExpandable && "cursor-pointer hover:bg-muted"
|
||||
row.original.isExpandable && 'cursor-pointer hover:bg-muted',
|
||||
)}
|
||||
onClick={row.original.onClick}
|
||||
>
|
||||
@@ -174,7 +174,7 @@ export function DataTable<TData extends IDGetter, TValue>({
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
header.getContext(),
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createContext, useContext, useEffect, useState } from "react";
|
||||
import { createContext, useContext, useEffect, useState } from 'react';
|
||||
|
||||
type Theme = "dark" | "light" | "system";
|
||||
type Theme = 'dark' | 'light' | 'system';
|
||||
|
||||
type ThemeProviderProps = {
|
||||
children: React.ReactNode;
|
||||
@@ -14,7 +14,7 @@ type ThemeProviderState = {
|
||||
};
|
||||
|
||||
const initialState: ThemeProviderState = {
|
||||
theme: "system",
|
||||
theme: 'system',
|
||||
setTheme: () => null,
|
||||
};
|
||||
|
||||
@@ -22,24 +22,24 @@ const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
|
||||
|
||||
export function ThemeProvider({
|
||||
children,
|
||||
defaultTheme = "system",
|
||||
storageKey = "vite-ui-theme",
|
||||
defaultTheme = 'system',
|
||||
storageKey = 'vite-ui-theme',
|
||||
...props
|
||||
}: ThemeProviderProps) {
|
||||
const [theme, setTheme] = useState<Theme>(
|
||||
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme
|
||||
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const root = window.document.documentElement;
|
||||
|
||||
root.classList.remove("light", "dark");
|
||||
root.classList.remove('light', 'dark');
|
||||
|
||||
if (theme === "system") {
|
||||
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
|
||||
if (theme === 'system') {
|
||||
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
.matches
|
||||
? "dark"
|
||||
: "light";
|
||||
? 'dark'
|
||||
: 'light';
|
||||
|
||||
root.classList.add(systemTheme);
|
||||
return;
|
||||
@@ -66,8 +66,9 @@ export function ThemeProvider({
|
||||
export const useTheme = () => {
|
||||
const context = useContext(ThemeProviderContext);
|
||||
|
||||
if (context === undefined)
|
||||
throw new Error("useTheme must be used within a ThemeProvider");
|
||||
if (context === undefined) {
|
||||
throw new Error('useTheme must be used within a ThemeProvider');
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as React from "react"
|
||||
import * as AccordionPrimitive from "@radix-ui/react-accordion"
|
||||
import { ChevronDownIcon } from "@radix-ui/react-icons"
|
||||
import * as React from 'react';
|
||||
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
||||
import { ChevronDownIcon } from '@radix-ui/react-icons';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const Accordion = AccordionPrimitive.Root
|
||||
const Accordion = AccordionPrimitive.Root;
|
||||
|
||||
const AccordionItem = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Item>,
|
||||
@@ -12,11 +12,11 @@ const AccordionItem = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AccordionPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn("border-b", className)}
|
||||
className={cn('border-b', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AccordionItem.displayName = "AccordionItem"
|
||||
));
|
||||
AccordionItem.displayName = 'AccordionItem';
|
||||
|
||||
const AccordionTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
||||
@@ -26,8 +26,8 @@ const AccordionTrigger = React.forwardRef<
|
||||
<AccordionPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
|
||||
className
|
||||
'flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -35,8 +35,8 @@ const AccordionTrigger = React.forwardRef<
|
||||
<ChevronDownIcon className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
|
||||
</AccordionPrimitive.Trigger>
|
||||
</AccordionPrimitive.Header>
|
||||
))
|
||||
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
|
||||
));
|
||||
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
|
||||
|
||||
const AccordionContent = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Content>,
|
||||
@@ -47,9 +47,9 @@ const AccordionContent = React.forwardRef<
|
||||
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
||||
{...props}
|
||||
>
|
||||
<div className={cn("pb-4 pt-0", className)}>{children}</div>
|
||||
<div className={cn('pb-4 pt-0', className)}>{children}</div>
|
||||
</AccordionPrimitive.Content>
|
||||
))
|
||||
AccordionContent.displayName = AccordionPrimitive.Content.displayName
|
||||
));
|
||||
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
|
||||
|
||||
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|
||||
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from "react"
|
||||
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
||||
import * as React from 'react';
|
||||
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const Avatar = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Root>,
|
||||
@@ -10,13 +10,13 @@ const Avatar = React.forwardRef<
|
||||
<AvatarPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
||||
className
|
||||
'relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Avatar.displayName = AvatarPrimitive.Root.displayName
|
||||
));
|
||||
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
||||
|
||||
const AvatarImage = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Image>,
|
||||
@@ -24,11 +24,11 @@ const AvatarImage = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AvatarPrimitive.Image
|
||||
ref={ref}
|
||||
className={cn("aspect-square h-full w-full", className)}
|
||||
className={cn('aspect-square h-full w-full', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName
|
||||
));
|
||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
|
||||
|
||||
const AvatarFallback = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
||||
@@ -37,12 +37,12 @@ const AvatarFallback = React.forwardRef<
|
||||
<AvatarPrimitive.Fallback
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
||||
className
|
||||
'flex h-full w-full items-center justify-center rounded-full bg-muted',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
|
||||
));
|
||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
|
||||
|
||||
export { Avatar, AvatarImage, AvatarFallback }
|
||||
export { Avatar, AvatarImage, AvatarFallback };
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
import * as React from "react";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import * as React from 'react';
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
||||
'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
|
||||
secondary:
|
||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',
|
||||
outline: 'text-foreground',
|
||||
successful:
|
||||
"border-transparent rounded-sm px-1 font-normal text-green-400 bg-green-500/20 ring-green-500/30",
|
||||
'border-transparent rounded-sm px-1 font-normal text-green-400 bg-green-500/20 ring-green-500/30',
|
||||
failed:
|
||||
"border-transparent rounded-sm px-1 font-normal text-red-400 bg-red-500/20 ring-red-500/30",
|
||||
'border-transparent rounded-sm px-1 font-normal text-red-400 bg-red-500/20 ring-red-500/30',
|
||||
inProgress:
|
||||
"border-transparent rounded-sm px-1 font-normal text-yellow-400 bg-yellow-500/20 ring-yellow-500/30",
|
||||
'border-transparent rounded-sm px-1 font-normal text-yellow-400 bg-yellow-500/20 ring-yellow-500/30',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
variant: 'default',
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
|
||||
@@ -1,57 +1,57 @@
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import * as React from 'react';
|
||||
import { Slot } from '@radix-ui/react-slot';
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
||||
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
'bg-primary text-primary-foreground shadow hover:bg-primary/90',
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
|
||||
outline:
|
||||
"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
'border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground',
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
default: 'h-9 px-4 py-2',
|
||||
sm: 'h-8 rounded-md px-3 text-xs',
|
||||
lg: 'h-10 rounded-md px-8',
|
||||
icon: 'h-9 w-9',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
},
|
||||
}
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
const Comp = asChild ? Slot : 'button';
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = "Button"
|
||||
);
|
||||
},
|
||||
);
|
||||
Button.displayName = 'Button';
|
||||
|
||||
export { Button, buttonVariants }
|
||||
export { Button, buttonVariants };
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from "react"
|
||||
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
||||
import { CheckIcon } from "@radix-ui/react-icons"
|
||||
import * as React from 'react';
|
||||
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
||||
import { CheckIcon } from '@radix-ui/react-icons';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const Checkbox = React.forwardRef<
|
||||
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
||||
@@ -11,18 +11,18 @@ const Checkbox = React.forwardRef<
|
||||
<CheckboxPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||
className
|
||||
'peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<CheckboxPrimitive.Indicator
|
||||
className={cn("flex items-center justify-center text-current")}
|
||||
className={cn('flex items-center justify-center text-current')}
|
||||
>
|
||||
<CheckIcon className="h-4 w-4" />
|
||||
</CheckboxPrimitive.Indicator>
|
||||
</CheckboxPrimitive.Root>
|
||||
))
|
||||
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
||||
));
|
||||
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
||||
|
||||
export { Checkbox }
|
||||
export { Checkbox };
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Light as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||
|
||||
import typescript from "react-syntax-highlighter/dist/esm/languages/hljs/typescript";
|
||||
import yaml from "react-syntax-highlighter/dist/esm/languages/hljs/yaml";
|
||||
import json from "react-syntax-highlighter/dist/esm/languages/hljs/json";
|
||||
import typescript from 'react-syntax-highlighter/dist/esm/languages/hljs/typescript';
|
||||
import yaml from 'react-syntax-highlighter/dist/esm/languages/hljs/yaml';
|
||||
import json from 'react-syntax-highlighter/dist/esm/languages/hljs/json';
|
||||
|
||||
import { anOldHope } from "react-syntax-highlighter/dist/esm/styles/hljs";
|
||||
import { anOldHope } from 'react-syntax-highlighter/dist/esm/styles/hljs';
|
||||
|
||||
SyntaxHighlighter.registerLanguage("typescript", typescript);
|
||||
SyntaxHighlighter.registerLanguage("yaml", yaml);
|
||||
SyntaxHighlighter.registerLanguage("json", json);
|
||||
SyntaxHighlighter.registerLanguage('typescript', typescript);
|
||||
SyntaxHighlighter.registerLanguage('yaml', yaml);
|
||||
SyntaxHighlighter.registerLanguage('json', json);
|
||||
|
||||
export function Code({
|
||||
children,
|
||||
@@ -23,19 +23,20 @@ export function Code({
|
||||
maxHeight?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={cn("text-xs", className)}>
|
||||
<div className={cn('text-xs', className)}>
|
||||
<SyntaxHighlighter
|
||||
children={children.trim()}
|
||||
language={language}
|
||||
style={anOldHope}
|
||||
customStyle={{
|
||||
background: "hsl(var(--muted) / 0.5)",
|
||||
borderRadius: "0.5rem",
|
||||
background: 'hsl(var(--muted) / 0.5)',
|
||||
borderRadius: '0.5rem',
|
||||
maxHeight: maxHeight,
|
||||
fontFamily:
|
||||
"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
|
||||
}}
|
||||
/>
|
||||
>
|
||||
{children.trim()}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as React from "react"
|
||||
import { type DialogProps } from "@radix-ui/react-dialog"
|
||||
import { MagnifyingGlassIcon } from "@radix-ui/react-icons"
|
||||
import { Command as CommandPrimitive } from "cmdk"
|
||||
import * as React from 'react';
|
||||
import { type DialogProps } from '@radix-ui/react-dialog';
|
||||
import { MagnifyingGlassIcon } from '@radix-ui/react-icons';
|
||||
import { Command as CommandPrimitive } from 'cmdk';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Dialog, DialogContent } from '@/components/ui/dialog';
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
@@ -13,13 +13,13 @@ const Command = React.forwardRef<
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
||||
className
|
||||
'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Command.displayName = CommandPrimitive.displayName
|
||||
));
|
||||
Command.displayName = CommandPrimitive.displayName;
|
||||
|
||||
interface CommandDialogProps extends DialogProps {}
|
||||
|
||||
@@ -32,27 +32,31 @@ const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const CommandInput = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||
<MagnifyingGlassIcon className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
>(({ className, ...props }, ref) => {
|
||||
// noinspection HtmlUnknownAttribute
|
||||
return (
|
||||
// eslint-disable-next-line react/no-unknown-property
|
||||
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||
<MagnifyingGlassIcon className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||
CommandInput.displayName = CommandPrimitive.Input.displayName;
|
||||
|
||||
const CommandList = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.List>,
|
||||
@@ -60,12 +64,12 @@ const CommandList = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||
className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
));
|
||||
|
||||
CommandList.displayName = CommandPrimitive.List.displayName
|
||||
CommandList.displayName = CommandPrimitive.List.displayName;
|
||||
|
||||
const CommandEmpty = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||
@@ -76,9 +80,9 @@ const CommandEmpty = React.forwardRef<
|
||||
className="py-6 text-center text-sm"
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
));
|
||||
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
|
||||
|
||||
const CommandGroup = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||
@@ -87,14 +91,14 @@ const CommandGroup = React.forwardRef<
|
||||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
||||
className
|
||||
'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
));
|
||||
|
||||
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||
CommandGroup.displayName = CommandPrimitive.Group.displayName;
|
||||
|
||||
const CommandSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||
@@ -102,11 +106,11 @@ const CommandSeparator = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 h-px bg-border", className)}
|
||||
className={cn('-mx-1 h-px bg-border', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||
));
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
|
||||
|
||||
const CommandItem = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||
@@ -115,14 +119,14 @@ const CommandItem = React.forwardRef<
|
||||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
));
|
||||
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName;
|
||||
|
||||
const CommandShortcut = ({
|
||||
className,
|
||||
@@ -131,14 +135,14 @@ const CommandShortcut = ({
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||
className
|
||||
'ml-auto text-xs tracking-widest text-muted-foreground',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
CommandShortcut.displayName = "CommandShortcut"
|
||||
);
|
||||
};
|
||||
CommandShortcut.displayName = 'CommandShortcut';
|
||||
|
||||
export {
|
||||
Command,
|
||||
@@ -150,4 +154,4 @@ export {
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandSeparator,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import * as React from "react"
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
||||
import { Cross2Icon } from "@radix-ui/react-icons"
|
||||
import * as React from 'react';
|
||||
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
||||
import { Cross2Icon } from '@radix-ui/react-icons';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const Dialog = DialogPrimitive.Root
|
||||
const Dialog = DialogPrimitive.Root;
|
||||
|
||||
const DialogTrigger = DialogPrimitive.Trigger
|
||||
const DialogTrigger = DialogPrimitive.Trigger;
|
||||
|
||||
const DialogPortal = DialogPrimitive.Portal
|
||||
const DialogPortal = DialogPrimitive.Portal;
|
||||
|
||||
const DialogClose = DialogPrimitive.Close
|
||||
const DialogClose = DialogPrimitive.Close;
|
||||
|
||||
const DialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||
@@ -19,13 +19,13 @@ const DialogOverlay = React.forwardRef<
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
||||
));
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
@@ -36,8 +36,8 @@ const DialogContent = React.forwardRef<
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -48,8 +48,8 @@ const DialogContent = React.forwardRef<
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
))
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName
|
||||
));
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||
|
||||
const DialogHeader = ({
|
||||
className,
|
||||
@@ -57,13 +57,13 @@ const DialogHeader = ({
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-1.5 text-center sm:text-left",
|
||||
className
|
||||
'flex flex-col space-y-1.5 text-center sm:text-left',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogHeader.displayName = "DialogHeader"
|
||||
);
|
||||
DialogHeader.displayName = 'DialogHeader';
|
||||
|
||||
const DialogFooter = ({
|
||||
className,
|
||||
@@ -71,13 +71,13 @@ const DialogFooter = ({
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogFooter.displayName = "DialogFooter"
|
||||
);
|
||||
DialogFooter.displayName = 'DialogFooter';
|
||||
|
||||
const DialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||
@@ -86,13 +86,13 @@ const DialogTitle = React.forwardRef<
|
||||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-lg font-semibold leading-none tracking-tight",
|
||||
className
|
||||
'text-lg font-semibold leading-none tracking-tight',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
||||
));
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
||||
|
||||
const DialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
@@ -100,11 +100,11 @@ const DialogDescription = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
className={cn('text-sm text-muted-foreground', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
||||
));
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
@@ -117,4 +117,4 @@ export {
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
import * as React from "react"
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
||||
import * as React from 'react';
|
||||
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
||||
import {
|
||||
CheckIcon,
|
||||
ChevronRightIcon,
|
||||
DotFilledIcon,
|
||||
} from "@radix-ui/react-icons"
|
||||
} from '@radix-ui/react-icons';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const DropdownMenu = DropdownMenuPrimitive.Root
|
||||
const DropdownMenu = DropdownMenuPrimitive.Root;
|
||||
|
||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
|
||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
||||
|
||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group
|
||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
||||
|
||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
|
||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
||||
|
||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub
|
||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
||||
|
||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
|
||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
||||
|
||||
const DropdownMenuSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
|
||||
inset && "pl-8",
|
||||
className
|
||||
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
|
||||
inset && 'pl-8',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRightIcon className="ml-auto h-4 w-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
))
|
||||
));
|
||||
DropdownMenuSubTrigger.displayName =
|
||||
DropdownMenuPrimitive.SubTrigger.displayName
|
||||
DropdownMenuPrimitive.SubTrigger.displayName;
|
||||
|
||||
const DropdownMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
@@ -49,14 +49,14 @@ const DropdownMenuSubContent = React.forwardRef<
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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",
|
||||
className
|
||||
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
));
|
||||
DropdownMenuSubContent.displayName =
|
||||
DropdownMenuPrimitive.SubContent.displayName
|
||||
DropdownMenuPrimitive.SubContent.displayName;
|
||||
|
||||
const DropdownMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
@@ -67,33 +67,33 @@ const DropdownMenuContent = React.forwardRef<
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 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",
|
||||
className
|
||||
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 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',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
))
|
||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
||||
));
|
||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
||||
|
||||
const DropdownMenuItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
className
|
||||
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
inset && 'pl-8',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
||||
));
|
||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
||||
|
||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||
@@ -102,8 +102,8 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
@@ -115,9 +115,9 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
))
|
||||
));
|
||||
DropdownMenuCheckboxItem.displayName =
|
||||
DropdownMenuPrimitive.CheckboxItem.displayName
|
||||
DropdownMenuPrimitive.CheckboxItem.displayName;
|
||||
|
||||
const DropdownMenuRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||
@@ -126,8 +126,8 @@ const DropdownMenuRadioItem = React.forwardRef<
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -138,26 +138,26 @@ const DropdownMenuRadioItem = React.forwardRef<
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
))
|
||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
||||
));
|
||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
||||
|
||||
const DropdownMenuLabel = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold",
|
||||
inset && "pl-8",
|
||||
className
|
||||
'px-2 py-1.5 text-sm font-semibold',
|
||||
inset && 'pl-8',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
||||
));
|
||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
||||
|
||||
const DropdownMenuSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||
@@ -165,11 +165,11 @@ const DropdownMenuSeparator = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
||||
));
|
||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
||||
|
||||
const DropdownMenuShortcut = ({
|
||||
className,
|
||||
@@ -177,12 +177,12 @@ const DropdownMenuShortcut = ({
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
||||
className={cn('ml-auto text-xs tracking-widest opacity-60', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
|
||||
);
|
||||
};
|
||||
DropdownMenuShortcut.displayName = 'DropdownMenuShortcut';
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
@@ -200,4 +200,4 @@ export {
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
import * as React from "react"
|
||||
import * as HoverCardPrimitive from "@radix-ui/react-hover-card"
|
||||
import * as React from 'react';
|
||||
import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const HoverCard = HoverCardPrimitive.Root
|
||||
const HoverCard = HoverCardPrimitive.Root;
|
||||
|
||||
const HoverCardTrigger = HoverCardPrimitive.Trigger
|
||||
const HoverCardTrigger = HoverCardPrimitive.Trigger;
|
||||
|
||||
const HoverCardContent = React.forwardRef<
|
||||
React.ElementRef<typeof HoverCardPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
|
||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
|
||||
<HoverCardPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none 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",
|
||||
className
|
||||
'z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none 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',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName
|
||||
));
|
||||
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
|
||||
|
||||
export { HoverCard, HoverCardTrigger, HoverCardContent }
|
||||
export { HoverCard, HoverCardTrigger, HoverCardContent };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from "react"
|
||||
import * as React from 'react';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export interface InputProps
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
@@ -11,15 +11,15 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Input.displayName = "Input"
|
||||
);
|
||||
},
|
||||
);
|
||||
Input.displayName = 'Input';
|
||||
|
||||
export { Input }
|
||||
export { Input };
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import * as React from "react"
|
||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import * as React from 'react';
|
||||
import * as LabelPrimitive from '@radix-ui/react-label';
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
)
|
||||
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
||||
);
|
||||
|
||||
const Label = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
@@ -18,7 +18,7 @@ const Label = React.forwardRef<
|
||||
className={cn(labelVariants(), className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Label.displayName = LabelPrimitive.Root.displayName
|
||||
));
|
||||
Label.displayName = LabelPrimitive.Root.displayName;
|
||||
|
||||
export { Label }
|
||||
export { Label };
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import * as React from "react"
|
||||
import * as React from 'react';
|
||||
import {
|
||||
CheckIcon,
|
||||
ChevronRightIcon,
|
||||
DotFilledIcon,
|
||||
} from "@radix-ui/react-icons"
|
||||
import * as MenubarPrimitive from "@radix-ui/react-menubar"
|
||||
} from '@radix-ui/react-icons';
|
||||
import * as MenubarPrimitive from '@radix-ui/react-menubar';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const MenubarMenu = MenubarPrimitive.Menu
|
||||
const MenubarMenu = MenubarPrimitive.Menu;
|
||||
|
||||
const MenubarGroup = MenubarPrimitive.Group
|
||||
const MenubarGroup = MenubarPrimitive.Group;
|
||||
|
||||
const MenubarPortal = MenubarPrimitive.Portal
|
||||
const MenubarPortal = MenubarPrimitive.Portal;
|
||||
|
||||
const MenubarSub = MenubarPrimitive.Sub
|
||||
const MenubarSub = MenubarPrimitive.Sub;
|
||||
|
||||
const MenubarRadioGroup = MenubarPrimitive.RadioGroup
|
||||
const MenubarRadioGroup = MenubarPrimitive.RadioGroup;
|
||||
|
||||
const Menubar = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Root>,
|
||||
@@ -25,13 +25,13 @@ const Menubar = React.forwardRef<
|
||||
<MenubarPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-9 items-center space-x-1 rounded-md border bg-background p-1 shadow-sm",
|
||||
className
|
||||
'flex h-9 items-center space-x-1 rounded-md border bg-background p-1 shadow-sm',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Menubar.displayName = MenubarPrimitive.Root.displayName
|
||||
));
|
||||
Menubar.displayName = MenubarPrimitive.Root.displayName;
|
||||
|
||||
const MenubarTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Trigger>,
|
||||
@@ -40,34 +40,34 @@ const MenubarTrigger = React.forwardRef<
|
||||
<MenubarPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-3 py-1 text-sm font-medium outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
||||
className
|
||||
'flex cursor-default select-none items-center rounded-sm px-3 py-1 text-sm font-medium outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName
|
||||
));
|
||||
MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName;
|
||||
|
||||
const MenubarSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, children, ...props }, ref) => (
|
||||
<MenubarPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
||||
inset && "pl-8",
|
||||
className
|
||||
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
|
||||
inset && 'pl-8',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRightIcon className="ml-auto h-4 w-4" />
|
||||
</MenubarPrimitive.SubTrigger>
|
||||
))
|
||||
MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName
|
||||
));
|
||||
MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName;
|
||||
|
||||
const MenubarSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.SubContent>,
|
||||
@@ -76,21 +76,21 @@ const MenubarSubContent = React.forwardRef<
|
||||
<MenubarPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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",
|
||||
className
|
||||
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName
|
||||
));
|
||||
MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName;
|
||||
|
||||
const MenubarContent = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>
|
||||
>(
|
||||
(
|
||||
{ className, align = "start", alignOffset = -4, sideOffset = 8, ...props },
|
||||
ref
|
||||
{ className, align = 'start', alignOffset = -4, sideOffset = 8, ...props },
|
||||
ref,
|
||||
) => (
|
||||
<MenubarPrimitive.Portal>
|
||||
<MenubarPrimitive.Content
|
||||
@@ -99,33 +99,33 @@ const MenubarContent = React.forwardRef<
|
||||
alignOffset={alignOffset}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in 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",
|
||||
className
|
||||
'z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in 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',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</MenubarPrimitive.Portal>
|
||||
)
|
||||
)
|
||||
MenubarContent.displayName = MenubarPrimitive.Content.displayName
|
||||
),
|
||||
);
|
||||
MenubarContent.displayName = MenubarPrimitive.Content.displayName;
|
||||
|
||||
const MenubarItem = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<MenubarPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
className
|
||||
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
inset && 'pl-8',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
MenubarItem.displayName = MenubarPrimitive.Item.displayName
|
||||
));
|
||||
MenubarItem.displayName = MenubarPrimitive.Item.displayName;
|
||||
|
||||
const MenubarCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.CheckboxItem>,
|
||||
@@ -134,8 +134,8 @@ const MenubarCheckboxItem = React.forwardRef<
|
||||
<MenubarPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex 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
|
||||
'relative flex 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,
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
@@ -147,8 +147,8 @@ const MenubarCheckboxItem = React.forwardRef<
|
||||
</span>
|
||||
{children}
|
||||
</MenubarPrimitive.CheckboxItem>
|
||||
))
|
||||
MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName
|
||||
));
|
||||
MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName;
|
||||
|
||||
const MenubarRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.RadioItem>,
|
||||
@@ -157,8 +157,8 @@ const MenubarRadioItem = React.forwardRef<
|
||||
<MenubarPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex 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
|
||||
'relative flex 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}
|
||||
>
|
||||
@@ -169,26 +169,26 @@ const MenubarRadioItem = React.forwardRef<
|
||||
</span>
|
||||
{children}
|
||||
</MenubarPrimitive.RadioItem>
|
||||
))
|
||||
MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName
|
||||
));
|
||||
MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName;
|
||||
|
||||
const MenubarLabel = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<MenubarPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold",
|
||||
inset && "pl-8",
|
||||
className
|
||||
'px-2 py-1.5 text-sm font-semibold',
|
||||
inset && 'pl-8',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
MenubarLabel.displayName = MenubarPrimitive.Label.displayName
|
||||
));
|
||||
MenubarLabel.displayName = MenubarPrimitive.Label.displayName;
|
||||
|
||||
const MenubarSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Separator>,
|
||||
@@ -196,11 +196,11 @@ const MenubarSeparator = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenubarPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName
|
||||
));
|
||||
MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName;
|
||||
|
||||
const MenubarShortcut = ({
|
||||
className,
|
||||
@@ -209,14 +209,14 @@ const MenubarShortcut = ({
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||
className
|
||||
'ml-auto text-xs tracking-widest text-muted-foreground',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
MenubarShortcut.displayname = "MenubarShortcut"
|
||||
);
|
||||
};
|
||||
MenubarShortcut.displayname = 'MenubarShortcut';
|
||||
|
||||
export {
|
||||
Menubar,
|
||||
@@ -235,4 +235,4 @@ export {
|
||||
MenubarGroup,
|
||||
MenubarSub,
|
||||
MenubarShortcut,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
import * as React from 'react';
|
||||
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const Popover = PopoverPrimitive.Root
|
||||
const Popover = PopoverPrimitive.Root;
|
||||
|
||||
const PopoverTrigger = PopoverPrimitive.Trigger
|
||||
const PopoverTrigger = PopoverPrimitive.Trigger;
|
||||
|
||||
const PopoverContent = React.forwardRef<
|
||||
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none 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",
|
||||
className
|
||||
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none 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',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
))
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
||||
));
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent }
|
||||
export { Popover, PopoverTrigger, PopoverContent };
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import * as React from "react"
|
||||
import * as React from 'react';
|
||||
import {
|
||||
CaretSortIcon,
|
||||
CheckIcon,
|
||||
ChevronDownIcon,
|
||||
ChevronUpIcon,
|
||||
} from "@radix-ui/react-icons"
|
||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||
} from '@radix-ui/react-icons';
|
||||
import * as SelectPrimitive from '@radix-ui/react-select';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const Select = SelectPrimitive.Root
|
||||
const Select = SelectPrimitive.Root;
|
||||
|
||||
const SelectGroup = SelectPrimitive.Group
|
||||
const SelectGroup = SelectPrimitive.Group;
|
||||
|
||||
const SelectValue = SelectPrimitive.Value
|
||||
const SelectValue = SelectPrimitive.Value;
|
||||
|
||||
const SelectTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||
@@ -22,8 +22,8 @@ const SelectTrigger = React.forwardRef<
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||
className
|
||||
'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -32,8 +32,8 @@ const SelectTrigger = React.forwardRef<
|
||||
<CaretSortIcon className="h-4 w-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
))
|
||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
||||
));
|
||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||
|
||||
const SelectScrollUpButton = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||
@@ -42,15 +42,15 @@ const SelectScrollUpButton = React.forwardRef<
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
'flex cursor-default items-center justify-center py-1',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUpIcon />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
))
|
||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
||||
));
|
||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
||||
|
||||
const SelectScrollDownButton = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||
@@ -59,29 +59,29 @@ const SelectScrollDownButton = React.forwardRef<
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
'flex cursor-default items-center justify-center py-1',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDownIcon />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
))
|
||||
));
|
||||
SelectScrollDownButton.displayName =
|
||||
SelectPrimitive.ScrollDownButton.displayName
|
||||
SelectPrimitive.ScrollDownButton.displayName;
|
||||
|
||||
const SelectContent = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||
>(({ className, children, position = "popper", ...props }, ref) => (
|
||||
>(({ 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
|
||||
'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}
|
||||
@@ -89,9 +89,9 @@ const SelectContent = React.forwardRef<
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
||||
'p-1',
|
||||
position === 'popper' &&
|
||||
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
@@ -99,8 +99,8 @@ const SelectContent = React.forwardRef<
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
))
|
||||
SelectContent.displayName = SelectPrimitive.Content.displayName
|
||||
));
|
||||
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
||||
|
||||
const SelectLabel = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||
@@ -108,11 +108,11 @@ const SelectLabel = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
|
||||
className={cn('px-2 py-1.5 text-sm font-semibold', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
||||
));
|
||||
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
||||
|
||||
const SelectItem = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||
@@ -121,8 +121,8 @@ const SelectItem = React.forwardRef<
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -133,8 +133,8 @@ const SelectItem = React.forwardRef<
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
))
|
||||
SelectItem.displayName = SelectPrimitive.Item.displayName
|
||||
));
|
||||
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
||||
|
||||
const SelectSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||
@@ -142,11 +142,11 @@ const SelectSeparator = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
||||
));
|
||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
||||
|
||||
export {
|
||||
Select,
|
||||
@@ -159,4 +159,4 @@ export {
|
||||
SelectSeparator,
|
||||
SelectScrollUpButton,
|
||||
SelectScrollDownButton,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import * as React from "react"
|
||||
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
||||
import * as React from 'react';
|
||||
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const Separator = React.forwardRef<
|
||||
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
|
||||
>(
|
||||
(
|
||||
{ className, orientation = "horizontal", decorative = true, ...props },
|
||||
ref
|
||||
{ className, orientation = 'horizontal', decorative = true, ...props },
|
||||
ref,
|
||||
) => (
|
||||
<SeparatorPrimitive.Root
|
||||
ref={ref}
|
||||
decorative={decorative}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"shrink-0 bg-border",
|
||||
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
||||
className
|
||||
'shrink-0 bg-border',
|
||||
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
Separator.displayName = SeparatorPrimitive.Root.displayName
|
||||
),
|
||||
);
|
||||
Separator.displayName = SeparatorPrimitive.Root.displayName;
|
||||
|
||||
export { Separator }
|
||||
export { Separator };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
function Skeleton({
|
||||
className,
|
||||
@@ -6,10 +6,10 @@ function Skeleton({
|
||||
}: React.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div
|
||||
className={cn("animate-pulse rounded-md bg-primary/10", className)}
|
||||
className={cn('animate-pulse rounded-md bg-primary/10', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export { Skeleton }
|
||||
export { Skeleton };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from "react"
|
||||
import * as React from 'react';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const Table = React.forwardRef<
|
||||
HTMLTableElement,
|
||||
@@ -9,20 +9,20 @@ const Table = React.forwardRef<
|
||||
<div className="relative w-full overflow-auto">
|
||||
<table
|
||||
ref={ref}
|
||||
className={cn("w-full caption-bottom text-sm", className)}
|
||||
className={cn('w-full caption-bottom text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
Table.displayName = "Table"
|
||||
));
|
||||
Table.displayName = 'Table';
|
||||
|
||||
const TableHeader = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
||||
))
|
||||
TableHeader.displayName = "TableHeader"
|
||||
<thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />
|
||||
));
|
||||
TableHeader.displayName = 'TableHeader';
|
||||
|
||||
const TableBody = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
@@ -30,11 +30,11 @@ const TableBody = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tbody
|
||||
ref={ref}
|
||||
className={cn("[&_tr:last-child]:border-0", className)}
|
||||
className={cn('[&_tr:last-child]:border-0', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableBody.displayName = "TableBody"
|
||||
));
|
||||
TableBody.displayName = 'TableBody';
|
||||
|
||||
const TableFooter = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
@@ -43,13 +43,13 @@ const TableFooter = React.forwardRef<
|
||||
<tfoot
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
||||
className
|
||||
'border-t bg-muted/50 font-medium [&>tr]:last:border-b-0',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableFooter.displayName = "TableFooter"
|
||||
));
|
||||
TableFooter.displayName = 'TableFooter';
|
||||
|
||||
const TableRow = React.forwardRef<
|
||||
HTMLTableRowElement,
|
||||
@@ -58,13 +58,13 @@ const TableRow = React.forwardRef<
|
||||
<tr
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||
className
|
||||
'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableRow.displayName = "TableRow"
|
||||
));
|
||||
TableRow.displayName = 'TableRow';
|
||||
|
||||
const TableHead = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
@@ -73,13 +73,13 @@ const TableHead = React.forwardRef<
|
||||
<th
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className
|
||||
'h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableHead.displayName = "TableHead"
|
||||
));
|
||||
TableHead.displayName = 'TableHead';
|
||||
|
||||
const TableCell = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
@@ -88,13 +88,13 @@ const TableCell = React.forwardRef<
|
||||
<td
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className
|
||||
'p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableCell.displayName = "TableCell"
|
||||
));
|
||||
TableCell.displayName = 'TableCell';
|
||||
|
||||
const TableCaption = React.forwardRef<
|
||||
HTMLTableCaptionElement,
|
||||
@@ -102,11 +102,11 @@ const TableCaption = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<caption
|
||||
ref={ref}
|
||||
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
||||
className={cn('mt-4 text-sm text-muted-foreground', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableCaption.displayName = "TableCaption"
|
||||
));
|
||||
TableCaption.displayName = 'TableCaption';
|
||||
|
||||
export {
|
||||
Table,
|
||||
@@ -117,4 +117,4 @@ export {
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableCaption,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as React from "react"
|
||||
import { Cross2Icon } from "@radix-ui/react-icons"
|
||||
import * as ToastPrimitives from "@radix-ui/react-toast"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import * as React from 'react';
|
||||
import { Cross2Icon } from '@radix-ui/react-icons';
|
||||
import * as ToastPrimitives from '@radix-ui/react-toast';
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const ToastProvider = ToastPrimitives.Provider
|
||||
const ToastProvider = ToastPrimitives.Provider;
|
||||
|
||||
const ToastViewport = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Viewport>,
|
||||
@@ -14,29 +14,29 @@ const ToastViewport = React.forwardRef<
|
||||
<ToastPrimitives.Viewport
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
|
||||
className
|
||||
'fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ToastViewport.displayName = ToastPrimitives.Viewport.displayName
|
||||
));
|
||||
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
|
||||
|
||||
const toastVariants = cva(
|
||||
"group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
|
||||
'group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "border bg-background text-foreground",
|
||||
default: 'border bg-background text-foreground',
|
||||
destructive:
|
||||
"destructive group border-destructive bg-destructive text-destructive-foreground",
|
||||
'destructive group border-destructive bg-destructive text-destructive-foreground',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
variant: 'default',
|
||||
},
|
||||
}
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
const Toast = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Root>,
|
||||
@@ -49,9 +49,9 @@ const Toast = React.forwardRef<
|
||||
className={cn(toastVariants({ variant }), className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
Toast.displayName = ToastPrimitives.Root.displayName
|
||||
);
|
||||
});
|
||||
Toast.displayName = ToastPrimitives.Root.displayName;
|
||||
|
||||
const ToastAction = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Action>,
|
||||
@@ -60,13 +60,13 @@ const ToastAction = React.forwardRef<
|
||||
<ToastPrimitives.Action
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
|
||||
className
|
||||
'inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ToastAction.displayName = ToastPrimitives.Action.displayName
|
||||
));
|
||||
ToastAction.displayName = ToastPrimitives.Action.displayName;
|
||||
|
||||
const ToastClose = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Close>,
|
||||
@@ -75,16 +75,16 @@ const ToastClose = React.forwardRef<
|
||||
<ToastPrimitives.Close
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
|
||||
className
|
||||
'absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600',
|
||||
className,
|
||||
)}
|
||||
toast-close=""
|
||||
{...props}
|
||||
>
|
||||
<Cross2Icon className="h-4 w-4" />
|
||||
</ToastPrimitives.Close>
|
||||
))
|
||||
ToastClose.displayName = ToastPrimitives.Close.displayName
|
||||
));
|
||||
ToastClose.displayName = ToastPrimitives.Close.displayName;
|
||||
|
||||
const ToastTitle = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Title>,
|
||||
@@ -92,11 +92,11 @@ const ToastTitle = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Title
|
||||
ref={ref}
|
||||
className={cn("text-sm font-semibold [&+div]:text-xs", className)}
|
||||
className={cn('text-sm font-semibold [&+div]:text-xs', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ToastTitle.displayName = ToastPrimitives.Title.displayName
|
||||
));
|
||||
ToastTitle.displayName = ToastPrimitives.Title.displayName;
|
||||
|
||||
const ToastDescription = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Description>,
|
||||
@@ -104,15 +104,15 @@ const ToastDescription = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm opacity-90", className)}
|
||||
className={cn('text-sm opacity-90', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ToastDescription.displayName = ToastPrimitives.Description.displayName
|
||||
));
|
||||
ToastDescription.displayName = ToastPrimitives.Description.displayName;
|
||||
|
||||
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
|
||||
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
|
||||
|
||||
type ToastActionElement = React.ReactElement<typeof ToastAction>
|
||||
type ToastActionElement = React.ReactElement<typeof ToastAction>;
|
||||
|
||||
export {
|
||||
type ToastProps,
|
||||
@@ -124,4 +124,4 @@ export {
|
||||
ToastDescription,
|
||||
ToastClose,
|
||||
ToastAction,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,11 +5,11 @@ import {
|
||||
ToastProvider,
|
||||
ToastTitle,
|
||||
ToastViewport,
|
||||
} from "@/components/ui/toast"
|
||||
import { useToast } from "@/components/ui/use-toast"
|
||||
} from '@/components/ui/toast';
|
||||
import { useToast } from '@/components/ui/use-toast';
|
||||
|
||||
export function Toaster() {
|
||||
const { toasts } = useToast()
|
||||
const { toasts } = useToast();
|
||||
|
||||
return (
|
||||
<ToastProvider>
|
||||
@@ -25,9 +25,9 @@ export function Toaster() {
|
||||
{action}
|
||||
<ToastClose />
|
||||
</Toast>
|
||||
)
|
||||
);
|
||||
})}
|
||||
<ToastViewport />
|
||||
</ToastProvider>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,104 +1,101 @@
|
||||
// Inspired by react-hot-toast library
|
||||
import * as React from "react"
|
||||
import * as React from 'react';
|
||||
|
||||
import type {
|
||||
ToastActionElement,
|
||||
ToastProps,
|
||||
} from "@/components/ui/toast"
|
||||
import type { ToastActionElement, ToastProps } from '@/components/ui/toast';
|
||||
|
||||
const TOAST_LIMIT = 1
|
||||
const TOAST_REMOVE_DELAY = 1000000
|
||||
const TOAST_LIMIT = 1;
|
||||
const TOAST_REMOVE_DELAY = 1000000;
|
||||
|
||||
type ToasterToast = ToastProps & {
|
||||
id: string
|
||||
title?: React.ReactNode
|
||||
description?: React.ReactNode
|
||||
action?: ToastActionElement
|
||||
}
|
||||
id: string;
|
||||
title?: React.ReactNode;
|
||||
description?: React.ReactNode;
|
||||
action?: ToastActionElement;
|
||||
};
|
||||
|
||||
const actionTypes = {
|
||||
ADD_TOAST: "ADD_TOAST",
|
||||
UPDATE_TOAST: "UPDATE_TOAST",
|
||||
DISMISS_TOAST: "DISMISS_TOAST",
|
||||
REMOVE_TOAST: "REMOVE_TOAST",
|
||||
} as const
|
||||
ADD_TOAST: 'ADD_TOAST',
|
||||
UPDATE_TOAST: 'UPDATE_TOAST',
|
||||
DISMISS_TOAST: 'DISMISS_TOAST',
|
||||
REMOVE_TOAST: 'REMOVE_TOAST',
|
||||
} as const;
|
||||
|
||||
let count = 0
|
||||
let count = 0;
|
||||
|
||||
function genId() {
|
||||
count = (count + 1) % Number.MAX_SAFE_INTEGER
|
||||
return count.toString()
|
||||
count = (count + 1) % Number.MAX_SAFE_INTEGER;
|
||||
return count.toString();
|
||||
}
|
||||
|
||||
type ActionType = typeof actionTypes
|
||||
type ActionType = typeof actionTypes;
|
||||
|
||||
type Action =
|
||||
| {
|
||||
type: ActionType["ADD_TOAST"]
|
||||
toast: ToasterToast
|
||||
type: ActionType['ADD_TOAST'];
|
||||
toast: ToasterToast;
|
||||
}
|
||||
| {
|
||||
type: ActionType["UPDATE_TOAST"]
|
||||
toast: Partial<ToasterToast>
|
||||
type: ActionType['UPDATE_TOAST'];
|
||||
toast: Partial<ToasterToast>;
|
||||
}
|
||||
| {
|
||||
type: ActionType["DISMISS_TOAST"]
|
||||
toastId?: ToasterToast["id"]
|
||||
type: ActionType['DISMISS_TOAST'];
|
||||
toastId?: ToasterToast['id'];
|
||||
}
|
||||
| {
|
||||
type: ActionType["REMOVE_TOAST"]
|
||||
toastId?: ToasterToast["id"]
|
||||
}
|
||||
type: ActionType['REMOVE_TOAST'];
|
||||
toastId?: ToasterToast['id'];
|
||||
};
|
||||
|
||||
interface State {
|
||||
toasts: ToasterToast[]
|
||||
toasts: ToasterToast[];
|
||||
}
|
||||
|
||||
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
|
||||
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
|
||||
|
||||
const addToRemoveQueue = (toastId: string) => {
|
||||
if (toastTimeouts.has(toastId)) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
toastTimeouts.delete(toastId)
|
||||
toastTimeouts.delete(toastId);
|
||||
dispatch({
|
||||
type: "REMOVE_TOAST",
|
||||
type: 'REMOVE_TOAST',
|
||||
toastId: toastId,
|
||||
})
|
||||
}, TOAST_REMOVE_DELAY)
|
||||
});
|
||||
}, TOAST_REMOVE_DELAY);
|
||||
|
||||
toastTimeouts.set(toastId, timeout)
|
||||
}
|
||||
toastTimeouts.set(toastId, timeout);
|
||||
};
|
||||
|
||||
export const reducer = (state: State, action: Action): State => {
|
||||
switch (action.type) {
|
||||
case "ADD_TOAST":
|
||||
case 'ADD_TOAST':
|
||||
return {
|
||||
...state,
|
||||
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
|
||||
}
|
||||
};
|
||||
|
||||
case "UPDATE_TOAST":
|
||||
case 'UPDATE_TOAST':
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === action.toast.id ? { ...t, ...action.toast } : t
|
||||
t.id === action.toast.id ? { ...t, ...action.toast } : t,
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
case "DISMISS_TOAST": {
|
||||
const { toastId } = action
|
||||
case 'DISMISS_TOAST': {
|
||||
const { toastId } = action;
|
||||
|
||||
// ! Side effects ! - This could be extracted into a dismissToast() action,
|
||||
// but I'll keep it here for simplicity
|
||||
if (toastId) {
|
||||
addToRemoveQueue(toastId)
|
||||
addToRemoveQueue(toastId);
|
||||
} else {
|
||||
state.toasts.forEach((toast) => {
|
||||
addToRemoveQueue(toast.id)
|
||||
})
|
||||
addToRemoveQueue(toast.id);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -109,84 +106,86 @@ export const reducer = (state: State, action: Action): State => {
|
||||
...t,
|
||||
open: false,
|
||||
}
|
||||
: t
|
||||
: t,
|
||||
),
|
||||
}
|
||||
};
|
||||
}
|
||||
case "REMOVE_TOAST":
|
||||
case 'REMOVE_TOAST':
|
||||
if (action.toastId === undefined) {
|
||||
return {
|
||||
...state,
|
||||
toasts: [],
|
||||
}
|
||||
};
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.filter((t) => t.id !== action.toastId),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const listeners: Array<(state: State) => void> = []
|
||||
const listeners: Array<(state: State) => void> = [];
|
||||
|
||||
let memoryState: State = { toasts: [] }
|
||||
let memoryState: State = { toasts: [] };
|
||||
|
||||
function dispatch(action: Action) {
|
||||
memoryState = reducer(memoryState, action)
|
||||
memoryState = reducer(memoryState, action);
|
||||
listeners.forEach((listener) => {
|
||||
listener(memoryState)
|
||||
})
|
||||
listener(memoryState);
|
||||
});
|
||||
}
|
||||
|
||||
type Toast = Omit<ToasterToast, "id">
|
||||
type Toast = Omit<ToasterToast, 'id'>;
|
||||
|
||||
function toast({ ...props }: Toast) {
|
||||
const id = genId()
|
||||
const id = genId();
|
||||
|
||||
const update = (props: ToasterToast) =>
|
||||
dispatch({
|
||||
type: "UPDATE_TOAST",
|
||||
type: 'UPDATE_TOAST',
|
||||
toast: { ...props, id },
|
||||
})
|
||||
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
|
||||
});
|
||||
const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id });
|
||||
|
||||
dispatch({
|
||||
type: "ADD_TOAST",
|
||||
type: 'ADD_TOAST',
|
||||
toast: {
|
||||
...props,
|
||||
id,
|
||||
open: true,
|
||||
onOpenChange: (open) => {
|
||||
if (!open) dismiss()
|
||||
if (!open) {
|
||||
dismiss();
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
return {
|
||||
id: id,
|
||||
dismiss,
|
||||
update,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function useToast() {
|
||||
const [state, setState] = React.useState<State>(memoryState)
|
||||
const [state, setState] = React.useState<State>(memoryState);
|
||||
|
||||
React.useEffect(() => {
|
||||
listeners.push(setState)
|
||||
listeners.push(setState);
|
||||
return () => {
|
||||
const index = listeners.indexOf(setState)
|
||||
const index = listeners.indexOf(setState);
|
||||
if (index > -1) {
|
||||
listeners.splice(index, 1)
|
||||
listeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}, [state])
|
||||
};
|
||||
}, [state]);
|
||||
|
||||
return {
|
||||
...state,
|
||||
toast,
|
||||
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
|
||||
}
|
||||
dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }),
|
||||
};
|
||||
}
|
||||
|
||||
export { useToast, toast }
|
||||
export { useToast, toast };
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Api } from "./generated/Api";
|
||||
import qs from "qs";
|
||||
import { Api } from './generated/Api';
|
||||
import qs from 'qs';
|
||||
|
||||
const api = new Api({
|
||||
paramsSerializer: (params) => qs.stringify(params, { arrayFormat: "repeat" }),
|
||||
paramsSerializer: (params) => qs.stringify(params, { arrayFormat: 'repeat' }),
|
||||
});
|
||||
|
||||
export default api;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import api from "./api";
|
||||
export * from "./generated/data-contracts";
|
||||
export { queries } from "./queries";
|
||||
import api from './api';
|
||||
export * from './generated/data-contracts';
|
||||
export { queries } from './queries';
|
||||
export default api;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createQueryKeyStore } from "@lukemorales/query-key-factory";
|
||||
import { createQueryKeyStore } from '@lukemorales/query-key-factory';
|
||||
|
||||
import api from "./api";
|
||||
import api from './api';
|
||||
|
||||
type ListEventQuery = Parameters<typeof api.eventList>[1];
|
||||
type ListWorkflowRunsQuery = Parameters<typeof api.workflowRunList>[1];
|
||||
@@ -8,17 +8,17 @@ type ListWorkflowRunsQuery = Parameters<typeof api.workflowRunList>[1];
|
||||
export const queries = createQueryKeyStore({
|
||||
user: {
|
||||
current: {
|
||||
queryKey: ["user:get"],
|
||||
queryKey: ['user:get'],
|
||||
queryFn: async () => (await api.userGetCurrent()).data,
|
||||
},
|
||||
},
|
||||
workflows: {
|
||||
list: (tenant: string) => ({
|
||||
queryKey: ["workflow:list", tenant],
|
||||
queryKey: ['workflow:list', tenant],
|
||||
queryFn: async () => (await api.workflowList(tenant)).data,
|
||||
}),
|
||||
getVersion: (workflow: string, version?: string) => ({
|
||||
queryKey: ["workflow-version:get", workflow, version],
|
||||
queryKey: ['workflow-version:get', workflow, version],
|
||||
queryFn: async () =>
|
||||
(
|
||||
await api.workflowVersionGet(workflow, {
|
||||
@@ -27,7 +27,7 @@ export const queries = createQueryKeyStore({
|
||||
).data,
|
||||
}),
|
||||
getDefinition: (workflow: string, version?: string) => ({
|
||||
queryKey: ["workflow-version:get:definition", workflow, version],
|
||||
queryKey: ['workflow-version:get:definition', workflow, version],
|
||||
queryFn: async () =>
|
||||
(
|
||||
await api.workflowVersionGetDefinition(workflow, {
|
||||
@@ -38,35 +38,35 @@ export const queries = createQueryKeyStore({
|
||||
},
|
||||
workflowRuns: {
|
||||
list: (tenant: string, query: ListWorkflowRunsQuery) => ({
|
||||
queryKey: ["workflow-run:list", tenant, query],
|
||||
queryKey: ['workflow-run:list', tenant, query],
|
||||
queryFn: async () => (await api.workflowRunList(tenant, query)).data,
|
||||
}),
|
||||
get: (tenant: string, workflowRun: string) => ({
|
||||
queryKey: ["workflow-run:get", tenant, workflowRun],
|
||||
queryKey: ['workflow-run:get', tenant, workflowRun],
|
||||
queryFn: async () => (await api.workflowRunGet(tenant, workflowRun)).data,
|
||||
}),
|
||||
},
|
||||
events: {
|
||||
list: (tenant: string, query: ListEventQuery) => ({
|
||||
queryKey: ["event:list", tenant, query],
|
||||
queryKey: ['event:list', tenant, query],
|
||||
queryFn: async () => (await api.eventList(tenant, query)).data,
|
||||
}),
|
||||
listKeys: (tenant: string) => ({
|
||||
queryKey: ["event-keys:list", tenant],
|
||||
queryKey: ['event-keys:list', tenant],
|
||||
queryFn: async () => (await api.eventKeyList(tenant)).data,
|
||||
}),
|
||||
getData: (event: string) => ({
|
||||
queryKey: ["event-data:get", event],
|
||||
queryKey: ['event-data:get', event],
|
||||
queryFn: async () => (await api.eventDataGet(event)).data,
|
||||
}),
|
||||
},
|
||||
workers: {
|
||||
list: (tenant: string) => ({
|
||||
queryKey: ["worker:list", tenant],
|
||||
queryKey: ['worker:list', tenant],
|
||||
queryFn: async () => (await api.workerList(tenant)).data,
|
||||
}),
|
||||
get: (worker: string) => ({
|
||||
queryKey: ["worker:get", worker],
|
||||
queryKey: ['worker:get', worker],
|
||||
queryFn: async () => (await api.workerGet(worker)).data,
|
||||
}),
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { atom } from "jotai";
|
||||
import { Tenant } from "./api";
|
||||
import { atom } from 'jotai';
|
||||
import { Tenant } from './api';
|
||||
|
||||
const getInitialValue = <T>(key: string): T | undefined => {
|
||||
const item = localStorage.getItem(key);
|
||||
@@ -11,7 +11,7 @@ const getInitialValue = <T>(key: string): T | undefined => {
|
||||
return;
|
||||
};
|
||||
|
||||
const currTenantKey = "currTenant";
|
||||
const currTenantKey = 'currTenant';
|
||||
|
||||
const currTenantAtomInit = atom(getInitialValue<Tenant>(currTenantKey));
|
||||
|
||||
@@ -20,5 +20,5 @@ export const currTenantAtom = atom(
|
||||
(_get, set, newVal: Tenant) => {
|
||||
set(currTenantAtomInit, newVal);
|
||||
localStorage.setItem(currTenantKey, JSON.stringify(newVal));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { AxiosError } from "axios";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { APIErrors } from "./api";
|
||||
import { getFieldErrors } from "./utils";
|
||||
import { useToast } from '@/components/ui/use-toast';
|
||||
import { AxiosError } from 'axios';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { APIErrors } from './api';
|
||||
import { getFieldErrors } from './utils';
|
||||
|
||||
export function useApiError(props: {
|
||||
setFieldErrors?: Dispatch<SetStateAction<Record<string, string>>>;
|
||||
@@ -15,8 +15,8 @@ export function useApiError(props: {
|
||||
if (error.response?.status) {
|
||||
if (error.response?.status >= 500) {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "An internal error occurred.",
|
||||
title: 'Error',
|
||||
description: 'An internal error occurred.',
|
||||
duration: 5000,
|
||||
});
|
||||
|
||||
@@ -31,7 +31,9 @@ export function useApiError(props: {
|
||||
const fieldErrors = getFieldErrors(apiErrors);
|
||||
|
||||
if (Object.keys(fieldErrors).length != 0) {
|
||||
props.setFieldErrors && props.setFieldErrors(fieldErrors);
|
||||
if (props.setFieldErrors) {
|
||||
props.setFieldErrors(fieldErrors);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -40,8 +42,8 @@ export function useApiError(props: {
|
||||
|
||||
if (!apiErrors || !apiErrors.errors || apiErrors.errors.length === 0) {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "An internal error occurred.",
|
||||
title: 'Error',
|
||||
description: 'An internal error occurred.',
|
||||
duration: 5000,
|
||||
});
|
||||
|
||||
@@ -51,7 +53,7 @@ export function useApiError(props: {
|
||||
for (const error of apiErrors.errors) {
|
||||
if (error.description) {
|
||||
toast({
|
||||
title: "Error",
|
||||
title: 'Error',
|
||||
description: error.description,
|
||||
duration: 5000,
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useOutletContext } from "react-router-dom";
|
||||
import { Tenant, TenantMember, User } from "./api";
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import { Tenant, TenantMember, User } from './api';
|
||||
|
||||
export type TenantContextType = { tenant: Tenant };
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { APIErrors } from "./api/generated/data-contracts";
|
||||
import { type ClassValue, clsx } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import { APIErrors } from './api/generated/data-contracts';
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
@@ -24,7 +24,7 @@ export function getFieldErrors(apiErrors: APIErrors): Record<string, string> {
|
||||
|
||||
export function capitalize(s: string) {
|
||||
if (!s) {
|
||||
return "";
|
||||
return '';
|
||||
} else if (s.length == 0) {
|
||||
return s;
|
||||
} else if (s.length == 1) {
|
||||
@@ -36,18 +36,18 @@ export function capitalize(s: string) {
|
||||
|
||||
export function relativeDate(date?: string | number) {
|
||||
if (!date) {
|
||||
return "N/A";
|
||||
return 'N/A';
|
||||
}
|
||||
|
||||
const rtf = new Intl.RelativeTimeFormat("en", {
|
||||
localeMatcher: "best fit", // other values: "lookup"
|
||||
numeric: "auto", // other values: "auto"
|
||||
style: "long", // other values: "short" or "narrow"
|
||||
const rtf = new Intl.RelativeTimeFormat('en', {
|
||||
localeMatcher: 'best fit', // other values: "lookup"
|
||||
numeric: 'auto', // other values: "auto"
|
||||
style: 'long', // other values: "short" or "narrow"
|
||||
});
|
||||
|
||||
const time = timeFrom(date);
|
||||
if (!time) {
|
||||
return "N/A";
|
||||
return 'N/A';
|
||||
}
|
||||
|
||||
return rtf.format(-time.time, time.unitOfTime);
|
||||
@@ -56,7 +56,9 @@ export function relativeDate(date?: string | number) {
|
||||
function timeFrom(time: string | number, secondTime?: string | number) {
|
||||
// Get timestamps
|
||||
const unixTime = new Date(time).getTime();
|
||||
if (!unixTime) return;
|
||||
if (!unixTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
let now = new Date().getTime();
|
||||
|
||||
@@ -69,20 +71,20 @@ function timeFrom(time: string | number, secondTime?: string | number) {
|
||||
|
||||
// Setup return object
|
||||
const tfn: {
|
||||
when: "past" | "now" | "future";
|
||||
when: 'past' | 'now' | 'future';
|
||||
unitOfTime: Intl.RelativeTimeFormatUnit;
|
||||
time: number;
|
||||
} = {
|
||||
when: "now",
|
||||
unitOfTime: "seconds",
|
||||
when: 'now',
|
||||
unitOfTime: 'seconds',
|
||||
time: 0,
|
||||
};
|
||||
|
||||
// Check if time is in the past, present, or future
|
||||
if (difference > 0) {
|
||||
tfn.when = "future";
|
||||
tfn.when = 'future';
|
||||
} else if (difference < -1) {
|
||||
tfn.when = "past";
|
||||
tfn.when = 'past';
|
||||
}
|
||||
|
||||
// Convert difference to absolute
|
||||
@@ -91,27 +93,27 @@ function timeFrom(time: string | number, secondTime?: string | number) {
|
||||
// Calculate time unit
|
||||
if (difference / (60 * 60 * 24 * 365) > 1) {
|
||||
// Years
|
||||
tfn.unitOfTime = "years";
|
||||
tfn.unitOfTime = 'years';
|
||||
tfn.time = Math.floor(difference / (60 * 60 * 24 * 365));
|
||||
} else if (difference / (60 * 60 * 24 * 45) > 1) {
|
||||
// Months
|
||||
tfn.unitOfTime = "months";
|
||||
tfn.unitOfTime = 'months';
|
||||
tfn.time = Math.floor(difference / (60 * 60 * 24 * 45));
|
||||
} else if (difference / (60 * 60 * 24) > 1) {
|
||||
// Days
|
||||
tfn.unitOfTime = "days";
|
||||
tfn.unitOfTime = 'days';
|
||||
tfn.time = Math.floor(difference / (60 * 60 * 24));
|
||||
} else if (difference / (60 * 60) > 1) {
|
||||
// Hours
|
||||
tfn.unitOfTime = "hours";
|
||||
tfn.unitOfTime = 'hours';
|
||||
tfn.time = Math.floor(difference / (60 * 60));
|
||||
} else if (difference / 60 > 1) {
|
||||
// Minutes
|
||||
tfn.unitOfTime = "minutes";
|
||||
tfn.unitOfTime = 'minutes';
|
||||
tfn.time = Math.floor(difference / 60);
|
||||
} else {
|
||||
// Seconds
|
||||
tfn.unitOfTime = "seconds";
|
||||
tfn.unitOfTime = 'seconds';
|
||||
tfn.time = Math.floor(difference);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import ReactDOM from "react-dom/client";
|
||||
import "./index.css";
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import queryClient from "./query-client.tsx";
|
||||
import Router from "./router.tsx";
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import { QueryClientProvider } from '@tanstack/react-query';
|
||||
import queryClient from './query-client.tsx';
|
||||
import Router from './router.tsx';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Router />
|
||||
</QueryClientProvider>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
|
||||
const schema = z.object({
|
||||
email: z.string().email("Invalid email address"),
|
||||
password: z.string().min(8, "Password must be at least 8 characters long"),
|
||||
email: z.string().email('Invalid email address'),
|
||||
password: z.string().min(8, 'Password must be at least 8 characters long'),
|
||||
});
|
||||
|
||||
interface UserLoginFormProps {
|
||||
@@ -36,7 +36,7 @@ export function UserLoginForm({ className, ...props }: UserLoginFormProps) {
|
||||
errors.password?.message?.toString() || props.fieldErrors?.password;
|
||||
|
||||
return (
|
||||
<div className={cn("grid gap-6", className)}>
|
||||
<div className={cn('grid gap-6', className)}>
|
||||
<form
|
||||
onSubmit={handleSubmit((d) => {
|
||||
props.onSubmit(d);
|
||||
@@ -46,7 +46,7 @@ export function UserLoginForm({ className, ...props }: UserLoginFormProps) {
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input
|
||||
{...register("email")}
|
||||
{...register('email')}
|
||||
id="email"
|
||||
placeholder="name@example.com"
|
||||
type="email"
|
||||
@@ -62,7 +62,7 @@ export function UserLoginForm({ className, ...props }: UserLoginFormProps) {
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<Input
|
||||
{...register("password")}
|
||||
{...register('password')}
|
||||
id="password"
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { UserLoginForm } from "./components/user-login-form";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { buttonVariants } from "@/components/ui/button";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import api, { UserLoginRequest } from "@/lib/api";
|
||||
import { useState } from "react";
|
||||
import { useApiError } from "@/lib/hooks";
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { UserLoginForm } from './components/user-login-form';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { buttonVariants } from '@/components/ui/button';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import api, { UserLoginRequest } from '@/lib/api';
|
||||
import { useState } from 'react';
|
||||
import { useApiError } from '@/lib/hooks';
|
||||
|
||||
export default function Login() {
|
||||
const navigate = useNavigate();
|
||||
@@ -15,12 +15,12 @@ export default function Login() {
|
||||
});
|
||||
|
||||
const loginMutation = useMutation({
|
||||
mutationKey: ["user:update:login"],
|
||||
mutationKey: ['user:update:login'],
|
||||
mutationFn: async (data: UserLoginRequest) => {
|
||||
await api.userUpdateLogin(data);
|
||||
},
|
||||
onSuccess: () => {
|
||||
navigate("/");
|
||||
navigate('/');
|
||||
},
|
||||
onError: handleApiError,
|
||||
});
|
||||
@@ -31,8 +31,8 @@ export default function Login() {
|
||||
<Link
|
||||
to="/auth/register"
|
||||
className={cn(
|
||||
buttonVariants({ variant: "ghost" }),
|
||||
"absolute right-4 top-4 md:right-8 md:top-8"
|
||||
buttonVariants({ variant: 'ghost' }),
|
||||
'absolute right-4 top-4 md:right-8 md:top-8',
|
||||
)}
|
||||
>
|
||||
Register
|
||||
@@ -53,14 +53,14 @@ export default function Login() {
|
||||
fieldErrors={fieldErrors}
|
||||
/>
|
||||
<p className="px-8 text-center text-sm text-muted-foreground">
|
||||
By clicking continue, you agree to our{" "}
|
||||
By clicking continue, you agree to our{' '}
|
||||
<Link
|
||||
to="/terms"
|
||||
className="underline underline-offset-4 hover:text-primary"
|
||||
>
|
||||
Terms of Service
|
||||
</Link>{" "}
|
||||
and{" "}
|
||||
</Link>{' '}
|
||||
and{' '}
|
||||
<Link
|
||||
to="/privacy"
|
||||
className="underline underline-offset-4 hover:text-primary"
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string().min(3, "Name must be at least 3 characters long"),
|
||||
email: z.string().email("Invalid email address"),
|
||||
password: z.string().min(8, "Password must be at least 8 characters long"),
|
||||
name: z.string().min(3, 'Name must be at least 3 characters long'),
|
||||
email: z.string().email('Invalid email address'),
|
||||
password: z.string().min(8, 'Password must be at least 8 characters long'),
|
||||
});
|
||||
|
||||
type submitType = z.infer<typeof schema>;
|
||||
type SubmitType = z.infer<typeof schema>;
|
||||
|
||||
interface UserRegisterFormProps {
|
||||
className?: string;
|
||||
onSubmit: (opts: submitType) => void;
|
||||
onSubmit: (opts: SubmitType) => void;
|
||||
isLoading: boolean;
|
||||
fieldErrors?: Record<string, string>;
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export function UserRegisterForm({
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<submitType>({
|
||||
} = useForm<SubmitType>({
|
||||
resolver: zodResolver(schema),
|
||||
});
|
||||
|
||||
@@ -44,7 +44,7 @@ export function UserRegisterForm({
|
||||
errors.password?.message?.toString() || props.fieldErrors?.password;
|
||||
|
||||
return (
|
||||
<div className={cn("grid gap-6", className)}>
|
||||
<div className={cn('grid gap-6', className)}>
|
||||
<form
|
||||
onSubmit={handleSubmit((d) => {
|
||||
props.onSubmit(d);
|
||||
@@ -54,7 +54,7 @@ export function UserRegisterForm({
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="name">Name</Label>
|
||||
<Input
|
||||
{...register("name")}
|
||||
{...register('name')}
|
||||
id="name"
|
||||
placeholder="Boba Fett"
|
||||
type="name"
|
||||
@@ -69,7 +69,7 @@ export function UserRegisterForm({
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input
|
||||
{...register("email")}
|
||||
{...register('email')}
|
||||
id="email"
|
||||
placeholder="name@example.com"
|
||||
type="email"
|
||||
@@ -85,7 +85,7 @@ export function UserRegisterForm({
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<Input
|
||||
{...register("password")}
|
||||
{...register('password')}
|
||||
id="password"
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { UserRegisterForm } from "./components/user-register-form";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { buttonVariants } from "@/components/ui/button";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import api, { UserRegisterRequest } from "@/lib/api";
|
||||
import { useState } from "react";
|
||||
import { useApiError } from "@/lib/hooks";
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { UserRegisterForm } from './components/user-register-form';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { buttonVariants } from '@/components/ui/button';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import api, { UserRegisterRequest } from '@/lib/api';
|
||||
import { useState } from 'react';
|
||||
import { useApiError } from '@/lib/hooks';
|
||||
|
||||
export default function Login() {
|
||||
const navigate = useNavigate();
|
||||
@@ -15,12 +15,12 @@ export default function Login() {
|
||||
});
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationKey: ["user:create"],
|
||||
mutationKey: ['user:create'],
|
||||
mutationFn: async (data: UserRegisterRequest) => {
|
||||
await api.userCreate(data);
|
||||
},
|
||||
onSuccess: () => {
|
||||
navigate("/");
|
||||
navigate('/');
|
||||
},
|
||||
onError: handleApiError,
|
||||
});
|
||||
@@ -31,8 +31,8 @@ export default function Login() {
|
||||
<Link
|
||||
to="/auth/login"
|
||||
className={cn(
|
||||
buttonVariants({ variant: "ghost" }),
|
||||
"absolute right-4 top-4 md:right-8 md:top-8"
|
||||
buttonVariants({ variant: 'ghost' }),
|
||||
'absolute right-4 top-4 md:right-8 md:top-8',
|
||||
)}
|
||||
>
|
||||
Login
|
||||
@@ -53,14 +53,14 @@ export default function Login() {
|
||||
fieldErrors={fieldErrors}
|
||||
/>
|
||||
<p className="px-8 text-center text-sm text-muted-foreground">
|
||||
By clicking continue, you agree to our{" "}
|
||||
By clicking continue, you agree to our{' '}
|
||||
<Link
|
||||
to="/terms"
|
||||
className="underline underline-offset-4 hover:text-primary"
|
||||
>
|
||||
Terms of Service
|
||||
</Link>{" "}
|
||||
and{" "}
|
||||
</Link>{' '}
|
||||
and{' '}
|
||||
<Link
|
||||
to="/privacy"
|
||||
className="underline underline-offset-4 hover:text-primary"
|
||||
|
||||
@@ -3,16 +3,16 @@ import {
|
||||
Outlet,
|
||||
redirect,
|
||||
useLoaderData,
|
||||
} from "react-router-dom";
|
||||
import api from "@/lib/api";
|
||||
import queryClient from "@/query-client";
|
||||
import { useContextFromParent } from "@/lib/outlet";
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
} from 'react-router-dom';
|
||||
import api from '@/lib/api';
|
||||
import queryClient from '@/query-client';
|
||||
import { useContextFromParent } from '@/lib/outlet';
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
|
||||
const authMiddleware = async (currentUrl: string) => {
|
||||
try {
|
||||
const user = await queryClient.fetchQuery({
|
||||
queryKey: ["user:get:current"],
|
||||
queryKey: ['user:get:current'],
|
||||
queryFn: async () => {
|
||||
const res = await api.userGetCurrent();
|
||||
|
||||
@@ -20,8 +20,8 @@ const authMiddleware = async (currentUrl: string) => {
|
||||
},
|
||||
});
|
||||
|
||||
if (!user.emailVerified && !currentUrl.includes("/verify-email")) {
|
||||
throw redirect("/verify-email");
|
||||
if (!user.emailVerified && !currentUrl.includes('/verify-email')) {
|
||||
throw redirect('/verify-email');
|
||||
}
|
||||
|
||||
return user;
|
||||
@@ -29,10 +29,10 @@ const authMiddleware = async (currentUrl: string) => {
|
||||
if (error instanceof Response) {
|
||||
throw error;
|
||||
} else if (
|
||||
!currentUrl.includes("/auth/login") &&
|
||||
!currentUrl.includes("/auth/register")
|
||||
!currentUrl.includes('/auth/login') &&
|
||||
!currentUrl.includes('/auth/register')
|
||||
) {
|
||||
throw redirect("/auth/login");
|
||||
throw redirect('/auth/login');
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -43,7 +43,7 @@ const membershipsPopulator = async () => {
|
||||
const memberships = res.data;
|
||||
|
||||
if (memberships.rows?.length === 0) {
|
||||
throw redirect("/onboarding/create-tenant");
|
||||
throw redirect('/onboarding/create-tenant');
|
||||
}
|
||||
|
||||
return res.data.rows;
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { DataTableColumnHeader } from "../../../../components/molecules/data-table/data-table-column-header";
|
||||
import { columns as workflowRunsColumns } from "../../workflow-runs/components/workflow-runs-columns";
|
||||
import { Event, queries } from "@/lib/api";
|
||||
import { relativeDate } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { DataTableColumnHeader } from '../../../../components/molecules/data-table/data-table-column-header';
|
||||
import { columns as workflowRunsColumns } from '../../workflow-runs/components/workflow-runs-columns';
|
||||
import { Event, queries } from '@/lib/api';
|
||||
import { relativeDate } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { useMemo, useState } from "react";
|
||||
import { currTenantAtom } from "@/lib/atoms";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useAtom } from "jotai";
|
||||
import invariant from "tiny-invariant";
|
||||
import { DataTable } from "@/components/molecules/data-table/data-table";
|
||||
} from '@/components/ui/popover';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { currTenantAtom } from '@/lib/atoms';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useAtom } from 'jotai';
|
||||
import invariant from 'tiny-invariant';
|
||||
import { DataTable } from '@/components/molecules/data-table/data-table';
|
||||
|
||||
export const columns = ({
|
||||
onRowClick,
|
||||
@@ -25,12 +25,12 @@ export const columns = ({
|
||||
}): ColumnDef<Event>[] => {
|
||||
return [
|
||||
{
|
||||
id: "select",
|
||||
id: 'select',
|
||||
header: ({ table }) => (
|
||||
<Checkbox
|
||||
checked={
|
||||
table.getIsAllPageRowsSelected() ||
|
||||
(table.getIsSomePageRowsSelected() && "indeterminate")
|
||||
(table.getIsSomePageRowsSelected() && 'indeterminate')
|
||||
}
|
||||
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
|
||||
aria-label="Select all"
|
||||
@@ -49,7 +49,7 @@ export const columns = ({
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "key",
|
||||
accessorKey: 'key',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Event" />
|
||||
),
|
||||
@@ -62,7 +62,7 @@ export const columns = ({
|
||||
onRowClick?.(row.original);
|
||||
}}
|
||||
>
|
||||
{row.getValue("key")}
|
||||
{row.getValue('key')}
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
@@ -70,7 +70,7 @@ export const columns = ({
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "Seen at",
|
||||
accessorKey: 'Seen at',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Seen at" />
|
||||
),
|
||||
@@ -79,7 +79,7 @@ export const columns = ({
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "Workflow Runs",
|
||||
accessorKey: 'Workflow Runs',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Workflow Runs" />
|
||||
),
|
||||
@@ -104,7 +104,7 @@ function WorkflowRunSummary({ event }: { event: Event }) {
|
||||
invariant(tenant);
|
||||
|
||||
const [hoverCardOpen, setPopoverOpen] = useState<
|
||||
"failed" | "succeeded" | "running"
|
||||
'failed' | 'succeeded' | 'running'
|
||||
>();
|
||||
|
||||
const numFailed = event.workflowRunSummary?.failed || 0;
|
||||
@@ -126,14 +126,14 @@ function WorkflowRunSummary({ event }: { event: Event }) {
|
||||
return (
|
||||
listWorkflowRunsQuery.data?.rows?.filter((run) => {
|
||||
if (hoverCardOpen) {
|
||||
if (hoverCardOpen == "failed") {
|
||||
return run.status == "FAILED";
|
||||
if (hoverCardOpen == 'failed') {
|
||||
return run.status == 'FAILED';
|
||||
}
|
||||
if (hoverCardOpen == "succeeded") {
|
||||
return run.status == "SUCCEEDED";
|
||||
if (hoverCardOpen == 'succeeded') {
|
||||
return run.status == 'SUCCEEDED';
|
||||
}
|
||||
if (hoverCardOpen == "running") {
|
||||
return run.status == "RUNNING" || run.status == "PENDING";
|
||||
if (hoverCardOpen == 'running') {
|
||||
return run.status == 'RUNNING' || run.status == 'PENDING';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ function WorkflowRunSummary({ event }: { event: Event }) {
|
||||
pageCount={0}
|
||||
columnVisibility={{
|
||||
select: false,
|
||||
"Triggered by": false,
|
||||
'Triggered by': false,
|
||||
actions: false,
|
||||
}}
|
||||
isLoading={listWorkflowRunsQuery.isLoading}
|
||||
@@ -163,7 +163,7 @@ function WorkflowRunSummary({ event }: { event: Event }) {
|
||||
<div className="flex flex-row gap-2 items-center justify-start">
|
||||
{numFailed > 0 && (
|
||||
<Popover
|
||||
open={hoverCardOpen == "failed"}
|
||||
open={hoverCardOpen == 'failed'}
|
||||
// open={true}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
@@ -175,7 +175,7 @@ function WorkflowRunSummary({ event }: { event: Event }) {
|
||||
<Badge
|
||||
variant="failed"
|
||||
className="cursor-pointer"
|
||||
onClick={() => setPopoverOpen("failed")}
|
||||
onClick={() => setPopoverOpen('failed')}
|
||||
>
|
||||
{numFailed} Failed
|
||||
</Badge>
|
||||
@@ -190,7 +190,7 @@ function WorkflowRunSummary({ event }: { event: Event }) {
|
||||
)}
|
||||
{numSucceeded > 0 && (
|
||||
<Popover
|
||||
open={hoverCardOpen == "succeeded"}
|
||||
open={hoverCardOpen == 'succeeded'}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
setPopoverOpen(undefined);
|
||||
@@ -201,7 +201,7 @@ function WorkflowRunSummary({ event }: { event: Event }) {
|
||||
<Badge
|
||||
variant="successful"
|
||||
className="cursor-pointer"
|
||||
onClick={() => setPopoverOpen("succeeded")}
|
||||
onClick={() => setPopoverOpen('succeeded')}
|
||||
>
|
||||
{numSucceeded} Succeeded
|
||||
</Badge>
|
||||
@@ -216,7 +216,7 @@ function WorkflowRunSummary({ event }: { event: Event }) {
|
||||
)}
|
||||
{numRunning > 0 && (
|
||||
<Popover
|
||||
open={hoverCardOpen == "running"}
|
||||
open={hoverCardOpen == 'running'}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
setPopoverOpen(undefined);
|
||||
@@ -227,7 +227,7 @@ function WorkflowRunSummary({ event }: { event: Event }) {
|
||||
<Badge
|
||||
variant="inProgress"
|
||||
className="cursor-pointer"
|
||||
onClick={() => setPopoverOpen("running")}
|
||||
onClick={() => setPopoverOpen('running')}
|
||||
>
|
||||
{numRunning} Running
|
||||
</Badge>
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
import { DataTable } from "../../../components/molecules/data-table/data-table";
|
||||
import { columns } from "./components/event-columns";
|
||||
import { columns as workflowRunsColumns } from "../workflow-runs/components/workflow-runs-columns";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { DataTable } from '../../../components/molecules/data-table/data-table';
|
||||
import { columns } from './components/event-columns';
|
||||
import { columns as workflowRunsColumns } from '../workflow-runs/components/workflow-runs-columns';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
ColumnFiltersState,
|
||||
PaginationState,
|
||||
RowSelectionState,
|
||||
SortingState,
|
||||
} from "@tanstack/react-table";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
} from '@tanstack/react-table';
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import api, {
|
||||
Event,
|
||||
EventOrderByDirection,
|
||||
EventOrderByField,
|
||||
ReplayEventRequest,
|
||||
queries,
|
||||
} from "@/lib/api";
|
||||
import invariant from "tiny-invariant";
|
||||
import { useAtom } from "jotai";
|
||||
import { currTenantAtom } from "@/lib/atoms";
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
import { FilterOption } from "@/components/molecules/data-table/data-table-toolbar";
|
||||
} from '@/lib/api';
|
||||
import invariant from 'tiny-invariant';
|
||||
import { useAtom } from 'jotai';
|
||||
import { currTenantAtom } from '@/lib/atoms';
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
import { FilterOption } from '@/components/molecules/data-table/data-table-toolbar';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { relativeDate } from "@/lib/utils";
|
||||
import { Code } from "@/components/ui/code";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import { Button } from "@/components/ui/button";
|
||||
} from '@/components/ui/dialog';
|
||||
import { relativeDate } from '@/lib/utils';
|
||||
import { Code } from '@/components/ui/code';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
ArrowPathIcon,
|
||||
ArrowPathRoundedSquareIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { useApiError } from "@/lib/hooks";
|
||||
} from '@heroicons/react/24/outline';
|
||||
import { useApiError } from '@/lib/hooks';
|
||||
|
||||
export default function Events() {
|
||||
return (
|
||||
@@ -65,14 +65,14 @@ function EventsTable() {
|
||||
useEffect(() => {
|
||||
if (
|
||||
selectedEvent &&
|
||||
(!searchParams.get("eventId") ||
|
||||
searchParams.get("eventId") !== selectedEvent.metadata.id)
|
||||
(!searchParams.get('eventId') ||
|
||||
searchParams.get('eventId') !== selectedEvent.metadata.id)
|
||||
) {
|
||||
setSearchParams({ eventId: selectedEvent.metadata.id });
|
||||
} else if (
|
||||
!selectedEvent &&
|
||||
searchParams.get("eventId") &&
|
||||
searchParams.get("eventId") !== ""
|
||||
searchParams.get('eventId') &&
|
||||
searchParams.get('eventId') !== ''
|
||||
) {
|
||||
setSearchParams({});
|
||||
}
|
||||
@@ -103,14 +103,14 @@ function EventsTable() {
|
||||
}
|
||||
|
||||
switch (sorting[0]?.id) {
|
||||
case "Seen at":
|
||||
case 'Seen at':
|
||||
default:
|
||||
return EventOrderByField.CreatedAt;
|
||||
}
|
||||
}, [sorting]);
|
||||
|
||||
const keys = useMemo(() => {
|
||||
const filter = columnFilters.find((filter) => filter.id === "key");
|
||||
const filter = columnFilters.find((filter) => filter.id === 'key');
|
||||
|
||||
if (!filter) {
|
||||
return;
|
||||
@@ -138,7 +138,7 @@ function EventsTable() {
|
||||
});
|
||||
|
||||
const replayEventsMutation = useMutation({
|
||||
mutationKey: ["event:update:replay", tenant.metadata.id],
|
||||
mutationKey: ['event:update:replay', tenant.metadata.id],
|
||||
mutationFn: async (data: ReplayEventRequest) => {
|
||||
await api.eventUpdateReplay(tenant.metadata.id, data);
|
||||
},
|
||||
@@ -186,8 +186,9 @@ function EventsTable() {
|
||||
|
||||
const actions = [
|
||||
<Button
|
||||
key="replay"
|
||||
disabled={Object.keys(rowSelection).length === 0}
|
||||
variant={Object.keys(rowSelection).length === 0 ? "outline" : "default"}
|
||||
variant={Object.keys(rowSelection).length === 0 ? 'outline' : 'default'}
|
||||
size="sm"
|
||||
className="h-8 px-2 lg:px-3 gap-2"
|
||||
onClick={() => {
|
||||
@@ -200,16 +201,17 @@ function EventsTable() {
|
||||
Replay
|
||||
</Button>,
|
||||
<Button
|
||||
key="refresh"
|
||||
className="h-8 px-2 lg:px-3"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
listEventsQuery.refetch();
|
||||
setRotate(!rotate);
|
||||
}}
|
||||
variant={"outline"}
|
||||
variant={'outline'}
|
||||
>
|
||||
<ArrowPathIcon
|
||||
className={`h-4 w-4 transition-transform ${rotate ? "rotate-180" : ""}`}
|
||||
className={`h-4 w-4 transition-transform ${rotate ? 'rotate-180' : ''}`}
|
||||
/>
|
||||
</Button>,
|
||||
];
|
||||
@@ -231,8 +233,8 @@ function EventsTable() {
|
||||
data={listEventsQuery.data?.rows || []}
|
||||
filters={[
|
||||
{
|
||||
columnId: "key",
|
||||
title: "Key",
|
||||
columnId: 'key',
|
||||
title: 'Key',
|
||||
options: eventKeyFilters,
|
||||
},
|
||||
]}
|
||||
@@ -320,7 +322,7 @@ function EventWorkflowRunsList({ event }: { event: Event }) {
|
||||
filters={[]}
|
||||
pageCount={listWorkflowRunsQuery.data?.pagination?.num_pages || 0}
|
||||
columnVisibility={{
|
||||
"Triggered by": false,
|
||||
'Triggered by': false,
|
||||
}}
|
||||
isLoading={listWorkflowRunsQuery.isLoading}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import BrushChart from "@/components/molecules/brush-chart/brush-chart";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import ParentSize from "@visx/responsive/lib/components/ParentSize";
|
||||
import BrushChart from '@/components/molecules/brush-chart/brush-chart';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import ParentSize from '@visx/responsive/lib/components/ParentSize';
|
||||
|
||||
export default function EventMetrics() {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { cn } from '@/lib/utils';
|
||||
import {
|
||||
AdjustmentsHorizontalIcon,
|
||||
BuildingOffice2Icon,
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
ServerStackIcon,
|
||||
Squares2X2Icon,
|
||||
UserCircleIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
} from '@heroicons/react/24/outline';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -18,9 +18,9 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import hatchet from "@/assets/hatchet_logo.png";
|
||||
import invariant from "tiny-invariant";
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import hatchet from '@/assets/hatchet_logo.png';
|
||||
import invariant from 'tiny-invariant';
|
||||
|
||||
import {
|
||||
Command,
|
||||
@@ -28,27 +28,27 @@ import {
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
} from "@/components/ui/command";
|
||||
} from '@/components/ui/command';
|
||||
|
||||
import { Link, Outlet, useNavigate, useOutletContext } from "react-router-dom";
|
||||
import api, { TenantMember, User } from "@/lib/api";
|
||||
import { useApiError } from "@/lib/hooks";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { CaretSortIcon, PlusCircledIcon } from "@radix-ui/react-icons";
|
||||
import { Link, Outlet, useNavigate, useOutletContext } from 'react-router-dom';
|
||||
import api, { TenantMember, User } from '@/lib/api';
|
||||
import { useApiError } from '@/lib/hooks';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { CaretSortIcon, PlusCircledIcon } from '@radix-ui/react-icons';
|
||||
import {
|
||||
PopoverTrigger,
|
||||
Popover,
|
||||
PopoverContent,
|
||||
} from "@radix-ui/react-popover";
|
||||
import React, { useEffect } from "react";
|
||||
} from '@radix-ui/react-popover';
|
||||
import React, { useEffect } from 'react';
|
||||
import {
|
||||
MembershipsContextType,
|
||||
UserContextType,
|
||||
useContextFromParent,
|
||||
} from "@/lib/outlet";
|
||||
import { useAtom } from "jotai";
|
||||
import { currTenantAtom } from "@/lib/atoms";
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
} from '@/lib/outlet';
|
||||
import { useAtom } from 'jotai';
|
||||
import { currTenantAtom } from '@/lib/atoms';
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
|
||||
function Main() {
|
||||
const { user, memberships } = useOutletContext<
|
||||
@@ -96,7 +96,7 @@ interface SidebarProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
|
||||
function Sidebar({ className, memberships }: SidebarProps) {
|
||||
return (
|
||||
<div className={cn("h-full border-r max-w-xs", className)}>
|
||||
<div className={cn('h-full border-r max-w-xs', className)}>
|
||||
<div className="flex flex-col justify-between items-start space-y-4 px-4 py-4 h-full">
|
||||
<div className="grow">
|
||||
<div className="py-2">
|
||||
@@ -158,12 +158,12 @@ function MainNav({ user }: MainNavProps) {
|
||||
const { handleApiError } = useApiError({});
|
||||
|
||||
const logoutMutation = useMutation({
|
||||
mutationKey: ["user:update:logout"],
|
||||
mutationKey: ['user:update:logout'],
|
||||
mutationFn: async () => {
|
||||
await api.userUpdateLogout();
|
||||
},
|
||||
onSuccess: () => {
|
||||
navigate("/auth/login");
|
||||
navigate('/auth/login');
|
||||
},
|
||||
onError: handleApiError,
|
||||
});
|
||||
@@ -242,7 +242,7 @@ function TenantSwitcher({ className, memberships }: TenantSwitcherProps) {
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
aria-label="Select a team"
|
||||
className={cn("w-full justify-between", className)}
|
||||
className={cn('w-full justify-between', className)}
|
||||
>
|
||||
<BuildingOffice2Icon className="mr-2 h-4 w-4" />
|
||||
{currTenant.name}
|
||||
@@ -268,10 +268,10 @@ function TenantSwitcher({ className, memberships }: TenantSwitcherProps) {
|
||||
{membership.tenant?.name}
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
"ml-auto h-4 w-4",
|
||||
'ml-auto h-4 w-4',
|
||||
currTenant.slug === membership.tenant?.slug
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
? 'opacity-100'
|
||||
: 'opacity-0',
|
||||
)}
|
||||
/>
|
||||
</CommandItem>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { DataTableColumnHeader } from "@/components/molecules/data-table/data-table-column-header";
|
||||
import { StepRun } from "@/lib/api";
|
||||
import { relativeDate } from "@/lib/utils";
|
||||
import { Link } from "react-router-dom";
|
||||
import { RunStatus } from "@/pages/main/workflow-runs/components/run-statuses";
|
||||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { DataTableColumnHeader } from '@/components/molecules/data-table/data-table-column-header';
|
||||
import { StepRun } from '@/lib/api';
|
||||
import { relativeDate } from '@/lib/utils';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { RunStatus } from '@/pages/main/workflow-runs/components/run-statuses';
|
||||
|
||||
export const columns: ColumnDef<StepRun>[] = [
|
||||
{
|
||||
accessorKey: "action",
|
||||
accessorKey: 'action',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Action" />
|
||||
),
|
||||
@@ -22,13 +22,13 @@ export const columns: ColumnDef<StepRun>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "id",
|
||||
accessorKey: 'id',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Step Id" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<Link to={"/workflow-runs/" + row.original.jobRun?.workflowRunId}>
|
||||
<Link to={'/workflow-runs/' + row.original.jobRun?.workflowRunId}>
|
||||
<div className="pl-0 cursor-pointer hover:underline min-w-fit whitespace-nowrap">
|
||||
{row.original.step?.readableId}
|
||||
</div>
|
||||
@@ -39,7 +39,7 @@ export const columns: ColumnDef<StepRun>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
accessorKey: 'status',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Status" />
|
||||
),
|
||||
@@ -48,7 +48,7 @@ export const columns: ColumnDef<StepRun>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "Started at",
|
||||
accessorKey: 'Started at',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Started at" />
|
||||
),
|
||||
@@ -59,14 +59,14 @@ export const columns: ColumnDef<StepRun>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "Finished at",
|
||||
accessorKey: 'Finished at',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Finished at" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const finishedAt = row.original.finishedAt
|
||||
? relativeDate(row.original.finishedAt)
|
||||
: "N/A";
|
||||
: 'N/A';
|
||||
|
||||
return <div>{finishedAt}</div>;
|
||||
},
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { queries } from "@/lib/api";
|
||||
import { currTenantAtom } from "@/lib/atoms";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useAtom } from "jotai";
|
||||
import { useParams } from "react-router-dom";
|
||||
import invariant from "tiny-invariant";
|
||||
import { relativeDate } from "@/lib/utils";
|
||||
import { ServerStackIcon } from "@heroicons/react/24/outline";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { DataTable } from "@/components/molecules/data-table/data-table";
|
||||
import { columns } from "./components/step-runs-columns";
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { queries } from '@/lib/api';
|
||||
import { currTenantAtom } from '@/lib/atoms';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useAtom } from 'jotai';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import invariant from 'tiny-invariant';
|
||||
import { relativeDate } from '@/lib/utils';
|
||||
import { ServerStackIcon } from '@heroicons/react/24/outline';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { DataTable } from '@/components/molecules/data-table/data-table';
|
||||
import { columns } from './components/step-runs-columns';
|
||||
|
||||
export default function ExpandedWorkflowRun() {
|
||||
const [tenant] = useAtom(currTenantAtom);
|
||||
@@ -62,7 +62,11 @@ export default function ExpandedWorkflowRun() {
|
||||
</h3>
|
||||
<div className="flex-wrap flex flex-row gap-4">
|
||||
{worker.actions?.map((action) => {
|
||||
return <Button variant="outline">{action}</Button>;
|
||||
return (
|
||||
<Button variant="outline" key={action}>
|
||||
{action}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { queries } from "@/lib/api";
|
||||
import invariant from "tiny-invariant";
|
||||
import { useAtom } from "jotai";
|
||||
import { currTenantAtom } from "@/lib/atoms";
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
import { relativeDate } from "@/lib/utils";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { queries } from '@/lib/api';
|
||||
import invariant from 'tiny-invariant';
|
||||
import { useAtom } from 'jotai';
|
||||
import { currTenantAtom } from '@/lib/atoms';
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
import { relativeDate } from '@/lib/utils';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
export default function Workers() {
|
||||
const [tenant] = useAtom(currTenantAtom);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { DataTableColumnHeader } from "@/components/molecules/data-table/data-table-column-header";
|
||||
import { JobRun, StepRun } from "@/lib/api";
|
||||
import { relativeDate } from "@/lib/utils";
|
||||
import { RunStatus } from "../../components/run-statuses";
|
||||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { DataTableColumnHeader } from '@/components/molecules/data-table/data-table-column-header';
|
||||
import { JobRun, StepRun } from '@/lib/api';
|
||||
import { relativeDate } from '@/lib/utils';
|
||||
import { RunStatus } from '../../components/run-statuses';
|
||||
|
||||
type JobRunRow = {
|
||||
kind: "job";
|
||||
kind: 'job';
|
||||
} & JobRun;
|
||||
|
||||
type StepRunRow = {
|
||||
kind: "step";
|
||||
kind: 'step';
|
||||
onClick?: () => void;
|
||||
} & StepRun;
|
||||
|
||||
@@ -20,10 +20,10 @@ export type JobRunColumns = (JobRunRow | StepRunRow) & {
|
||||
|
||||
export const columns: ColumnDef<JobRunColumns>[] = [
|
||||
{
|
||||
accessorKey: "id",
|
||||
accessorKey: 'id',
|
||||
header: () => <></>,
|
||||
cell: ({ row }) => {
|
||||
if (row.original.kind === "job") {
|
||||
if (row.original.kind === 'job') {
|
||||
return <></>;
|
||||
}
|
||||
return (
|
||||
@@ -36,14 +36,14 @@ export const columns: ColumnDef<JobRunColumns>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
accessorKey: 'status',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Status" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
let reason;
|
||||
|
||||
if (row.original.kind == "step") {
|
||||
if (row.original.kind == 'step') {
|
||||
reason = row.original.cancelledReason;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ export const columns: ColumnDef<JobRunColumns>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "Started at",
|
||||
accessorKey: 'Started at',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Started at" />
|
||||
),
|
||||
@@ -64,14 +64,14 @@ export const columns: ColumnDef<JobRunColumns>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "Finished at",
|
||||
accessorKey: 'Finished at',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Finished at" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const finishedAt = row.original.finishedAt
|
||||
? relativeDate(row.original.finishedAt)
|
||||
: "N/A";
|
||||
: 'N/A';
|
||||
|
||||
return <div>{finishedAt}</div>;
|
||||
},
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { JobRun, StepRun, StepRunStatus, queries, Event } from "@/lib/api";
|
||||
import CronPrettifier from "cronstrue";
|
||||
import { currTenantAtom } from "@/lib/atoms";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useAtom } from "jotai";
|
||||
import { Link, useParams } from "react-router-dom";
|
||||
import invariant from "tiny-invariant";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { relativeDate } from "@/lib/utils";
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { JobRun, StepRun, StepRunStatus, queries, Event } from '@/lib/api';
|
||||
import CronPrettifier from 'cronstrue';
|
||||
import { currTenantAtom } from '@/lib/atoms';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useAtom } from 'jotai';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import invariant from 'tiny-invariant';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { relativeDate } from '@/lib/utils';
|
||||
import {
|
||||
AdjustmentsHorizontalIcon,
|
||||
BoltIcon,
|
||||
Square3Stack3DIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { DataTable } from "@/components/molecules/data-table/data-table";
|
||||
import { JobRunColumns, columns } from "./components/job-runs-columns";
|
||||
import { TableCell, TableRow } from "@/components/ui/table";
|
||||
import { RunStatus } from "../components/run-statuses";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { useState } from "react";
|
||||
import { Code } from "@/components/ui/code";
|
||||
} from '@heroicons/react/24/outline';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { DataTable } from '@/components/molecules/data-table/data-table';
|
||||
import { JobRunColumns, columns } from './components/job-runs-columns';
|
||||
import { TableCell, TableRow } from '@/components/ui/table';
|
||||
import { RunStatus } from '../components/run-statuses';
|
||||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { useState } from 'react';
|
||||
import { Code } from '@/components/ui/code';
|
||||
|
||||
export default function ExpandedWorkflowRun() {
|
||||
const [expandedStepRuns, setExpandedStepRuns] = useState<string[]>([]);
|
||||
@@ -55,7 +55,7 @@ export default function ExpandedWorkflowRun() {
|
||||
<h2 className="text-2xl font-bold leading-tight text-foreground">
|
||||
{run?.metadata.id}
|
||||
</h2>
|
||||
<Badge className="text-sm mt-1" variant={"secondary"}>
|
||||
<Badge className="text-sm mt-1" variant={'secondary'}>
|
||||
{/* {workflow.versions && workflow.versions[0].version} */}
|
||||
{run.status}
|
||||
</Badge>
|
||||
@@ -106,7 +106,7 @@ export default function ExpandedWorkflowRun() {
|
||||
?.map((jobRun): JobRunColumns[] => {
|
||||
return [
|
||||
{
|
||||
kind: "job",
|
||||
kind: 'job',
|
||||
isExpandable: false,
|
||||
getRow: () => {
|
||||
return getJobRunRow({ jobRun, columns });
|
||||
@@ -117,7 +117,7 @@ export default function ExpandedWorkflowRun() {
|
||||
?.map((stepRun): JobRunColumns[] => {
|
||||
const res: JobRunColumns[] = [
|
||||
{
|
||||
kind: "step",
|
||||
kind: 'step',
|
||||
isExpandable: true,
|
||||
onClick: () => {
|
||||
if (
|
||||
@@ -125,8 +125,8 @@ export default function ExpandedWorkflowRun() {
|
||||
) {
|
||||
setExpandedStepRuns(
|
||||
expandedStepRuns.filter(
|
||||
(id) => id != stepRun.metadata.id
|
||||
)
|
||||
(id) => id != stepRun.metadata.id,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
setExpandedStepRuns([
|
||||
@@ -141,7 +141,7 @@ export default function ExpandedWorkflowRun() {
|
||||
|
||||
if (expandedStepRuns.includes(stepRun.metadata.id)) {
|
||||
res.push({
|
||||
kind: "step",
|
||||
kind: 'step',
|
||||
isExpandable: false,
|
||||
|
||||
getRow: () => {
|
||||
@@ -212,7 +212,7 @@ function getExpandedStepRunRow({
|
||||
}
|
||||
|
||||
function StepInputSection({ stepRun }: { stepRun: StepRun }) {
|
||||
const input = stepRun.input || "{}";
|
||||
const input = stepRun.input || '{}';
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -227,7 +227,7 @@ function StepInputSection({ stepRun }: { stepRun: StepRun }) {
|
||||
}
|
||||
|
||||
function StepOutputSection({ stepRun }: { stepRun: StepRun }) {
|
||||
const output = stepRun.output || "{}";
|
||||
const output = stepRun.output || '{}';
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -242,14 +242,14 @@ function StepOutputSection({ stepRun }: { stepRun: StepRun }) {
|
||||
}
|
||||
|
||||
function StepStatusSection({ stepRun }: { stepRun: StepRun }) {
|
||||
let statusText = "Unknown";
|
||||
let statusText = 'Unknown';
|
||||
|
||||
switch (stepRun.status) {
|
||||
case StepRunStatus.RUNNING:
|
||||
statusText = "This step is currently running";
|
||||
statusText = 'This step is currently running';
|
||||
break;
|
||||
case StepRunStatus.FAILED:
|
||||
statusText = "This step failed";
|
||||
statusText = 'This step failed';
|
||||
|
||||
if (stepRun.error) {
|
||||
statusText = `This step failed with error ${stepRun.error}`;
|
||||
@@ -257,16 +257,17 @@ function StepStatusSection({ stepRun }: { stepRun: StepRun }) {
|
||||
|
||||
break;
|
||||
case StepRunStatus.CANCELLED:
|
||||
statusText = "This step was cancelled";
|
||||
statusText = 'This step was cancelled';
|
||||
|
||||
switch (stepRun.cancelledReason) {
|
||||
case "TIMED_OUT":
|
||||
case 'TIMED_OUT':
|
||||
statusText = `This step was cancelled because it exceeded its timeout of ${
|
||||
stepRun.step?.timeout || "60s"
|
||||
stepRun.step?.timeout || '60s'
|
||||
}`;
|
||||
break;
|
||||
case "PREVIOUS_STEP_TIMED_OUT":
|
||||
statusText = `This step was cancelled because the previous step timed out`;
|
||||
case 'PREVIOUS_STEP_TIMED_OUT':
|
||||
statusText =
|
||||
'This step was cancelled because the previous step timed out';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -274,10 +275,10 @@ function StepStatusSection({ stepRun }: { stepRun: StepRun }) {
|
||||
|
||||
break;
|
||||
case StepRunStatus.SUCCEEDED:
|
||||
statusText = "This step succeeded";
|
||||
statusText = 'This step succeeded';
|
||||
break;
|
||||
case StepRunStatus.PENDING:
|
||||
statusText = "This step is pending";
|
||||
statusText = 'This step is pending';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -300,7 +301,7 @@ function StepConfigurationSection({ stepRun }: { stepRun: StepRun }) {
|
||||
Configuration
|
||||
</h3>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Timeout: {stepRun.step?.timeout || "60s"}
|
||||
Timeout: {stepRun.step?.timeout || '60s'}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -343,7 +344,7 @@ function EventDataSection({ event }: { event: Event }) {
|
||||
|
||||
function TriggeringCronSection({ cron }: { cron: string }) {
|
||||
const prettyInterval = `Runs ${CronPrettifier.toString(
|
||||
cron
|
||||
cron,
|
||||
).toLowerCase()} UTC`;
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { JobRunStatus, StepRunStatus, WorkflowRunStatus } from "@/lib/api";
|
||||
import { capitalize } from "@/lib/utils";
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { JobRunStatus, StepRunStatus, WorkflowRunStatus } from '@/lib/api';
|
||||
import { capitalize } from '@/lib/utils';
|
||||
|
||||
type RunStatus = `${StepRunStatus | WorkflowRunStatus | JobRunStatus}`;
|
||||
type RunStatusType = `${StepRunStatus | WorkflowRunStatus | JobRunStatus}`;
|
||||
|
||||
export function RunStatus({
|
||||
status,
|
||||
reason,
|
||||
}: {
|
||||
status: RunStatus;
|
||||
status: RunStatusType;
|
||||
reason?: string;
|
||||
}) {
|
||||
let variant: "inProgress" | "successful" | "failed" = "inProgress";
|
||||
let text = "Running";
|
||||
let variant: 'inProgress' | 'successful' | 'failed' = 'inProgress';
|
||||
let text = 'Running';
|
||||
|
||||
switch (status) {
|
||||
case "SUCCEEDED":
|
||||
variant = "successful";
|
||||
text = "Succeeded";
|
||||
case 'SUCCEEDED':
|
||||
variant = 'successful';
|
||||
text = 'Succeeded';
|
||||
break;
|
||||
case "FAILED":
|
||||
case "CANCELLED":
|
||||
variant = "failed";
|
||||
text = "Cancelled";
|
||||
case 'FAILED':
|
||||
case 'CANCELLED':
|
||||
variant = 'failed';
|
||||
text = 'Cancelled';
|
||||
|
||||
switch (reason) {
|
||||
case "TIMED_OUT":
|
||||
text = "Timed out";
|
||||
case 'TIMED_OUT':
|
||||
text = 'Timed out';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { DataTableColumnHeader } from "../../../../components/molecules/data-table/data-table-column-header";
|
||||
import { WorkflowRun } from "@/lib/api";
|
||||
import { relativeDate } from "@/lib/utils";
|
||||
import { Link } from "react-router-dom";
|
||||
import { RunStatus } from "./run-statuses";
|
||||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { DataTableColumnHeader } from '../../../../components/molecules/data-table/data-table-column-header';
|
||||
import { WorkflowRun } from '@/lib/api';
|
||||
import { relativeDate } from '@/lib/utils';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { RunStatus } from './run-statuses';
|
||||
|
||||
export const columns: ColumnDef<WorkflowRun>[] = [
|
||||
{
|
||||
id: "select",
|
||||
id: 'select',
|
||||
header: ({ table }) => (
|
||||
<Checkbox
|
||||
checked={
|
||||
table.getIsAllPageRowsSelected() ||
|
||||
(table.getIsSomePageRowsSelected() && "indeterminate")
|
||||
(table.getIsSomePageRowsSelected() && 'indeterminate')
|
||||
}
|
||||
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
|
||||
aria-label="Select all"
|
||||
@@ -32,12 +32,12 @@ export const columns: ColumnDef<WorkflowRun>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "id",
|
||||
accessorKey: 'id',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Run Id" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<Link to={"/workflow-runs/" + row.original.metadata.id}>
|
||||
<Link to={'/workflow-runs/' + row.original.metadata.id}>
|
||||
<div className="cursor-pointer hover:underline min-w-fit whitespace-nowrap">
|
||||
{row.original.metadata.id}
|
||||
</div>
|
||||
@@ -47,7 +47,7 @@ export const columns: ColumnDef<WorkflowRun>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
accessorKey: 'status',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Status" />
|
||||
),
|
||||
@@ -56,13 +56,13 @@ export const columns: ColumnDef<WorkflowRun>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "Workflow",
|
||||
accessorKey: 'Workflow',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Workflow" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const workflowName =
|
||||
row.original.workflowVersion?.workflow?.name || "N/A";
|
||||
row.original.workflowVersion?.workflow?.name || 'N/A';
|
||||
|
||||
return <div className="min-w-fit whitespace-nowrap">{workflowName}</div>;
|
||||
},
|
||||
@@ -70,12 +70,12 @@ export const columns: ColumnDef<WorkflowRun>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "Triggered by",
|
||||
accessorKey: 'Triggered by',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Triggered by" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const eventKey = row.original.triggeredBy?.event?.key || "N/A";
|
||||
const eventKey = row.original.triggeredBy?.event?.key || 'N/A';
|
||||
|
||||
return <div>{eventKey}</div>;
|
||||
},
|
||||
@@ -83,7 +83,7 @@ export const columns: ColumnDef<WorkflowRun>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "Started at",
|
||||
accessorKey: 'Started at',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader
|
||||
column={column}
|
||||
@@ -102,7 +102,7 @@ export const columns: ColumnDef<WorkflowRun>[] = [
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "Finished at",
|
||||
accessorKey: 'Finished at',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader
|
||||
column={column}
|
||||
@@ -113,7 +113,7 @@ export const columns: ColumnDef<WorkflowRun>[] = [
|
||||
cell: ({ row }) => {
|
||||
const finishedAt = row.original.finishedAt
|
||||
? relativeDate(row.original.finishedAt)
|
||||
: "N/A";
|
||||
: 'N/A';
|
||||
|
||||
return <div className="whitespace-nowrap">{finishedAt}</div>;
|
||||
},
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { DataTable } from "../../../components/molecules/data-table/data-table";
|
||||
import { columns } from "./components/workflow-runs-columns";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { useMemo, useState } from "react";
|
||||
import { DataTable } from '../../../components/molecules/data-table/data-table';
|
||||
import { columns } from './components/workflow-runs-columns';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { useMemo, useState } from 'react';
|
||||
import {
|
||||
ColumnFiltersState,
|
||||
PaginationState,
|
||||
SortingState,
|
||||
} from "@tanstack/react-table";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import invariant from "tiny-invariant";
|
||||
import { useAtom } from "jotai";
|
||||
import { currTenantAtom } from "@/lib/atoms";
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
import { queries } from "@/lib/api";
|
||||
} from '@tanstack/react-table';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import invariant from 'tiny-invariant';
|
||||
import { useAtom } from 'jotai';
|
||||
import { currTenantAtom } from '@/lib/atoms';
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
import { queries } from '@/lib/api';
|
||||
|
||||
export default function WorkflowRuns() {
|
||||
return (
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { DataTable } from "@/components/molecules/data-table/data-table";
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import api, { Workflow, queries } from "@/lib/api";
|
||||
import { currTenantAtom } from "@/lib/atoms";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { isAxiosError } from "axios";
|
||||
import { useAtom } from "jotai";
|
||||
import { DataTable } from '@/components/molecules/data-table/data-table';
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import api, { Workflow, queries } from '@/lib/api';
|
||||
import { currTenantAtom } from '@/lib/atoms';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { isAxiosError } from 'axios';
|
||||
import { useAtom } from 'jotai';
|
||||
import {
|
||||
LoaderFunctionArgs,
|
||||
redirect,
|
||||
useLoaderData,
|
||||
useParams,
|
||||
} from "react-router-dom";
|
||||
import invariant from "tiny-invariant";
|
||||
import { columns } from "../../workflow-runs/components/workflow-runs-columns";
|
||||
import { WorkflowTags } from "../components/workflow-tags";
|
||||
import { Code } from "@/components/ui/code";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { relativeDate } from "@/lib/utils";
|
||||
import { Square3Stack3DIcon } from "@heroicons/react/24/outline";
|
||||
} from 'react-router-dom';
|
||||
import invariant from 'tiny-invariant';
|
||||
import { columns } from '../../workflow-runs/components/workflow-runs-columns';
|
||||
import { WorkflowTags } from '../components/workflow-tags';
|
||||
import { Code } from '@/components/ui/code';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { relativeDate } from '@/lib/utils';
|
||||
import { Square3Stack3DIcon } from '@heroicons/react/24/outline';
|
||||
|
||||
export async function loader({
|
||||
params,
|
||||
@@ -37,7 +37,8 @@ export async function loader({
|
||||
throw error;
|
||||
} else if (isAxiosError(error)) {
|
||||
// TODO: handle error better
|
||||
throw redirect("/unauthorized");
|
||||
redirect('/unauthorized');
|
||||
throw new Error('unauthorized');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,9 +73,9 @@ export default function ExpandedWorkflow() {
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center mt-4">
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Updated{" "}
|
||||
Updated{' '}
|
||||
{relativeDate(
|
||||
workflow.versions && workflow.versions[0].metadata.updatedAt
|
||||
workflow.versions && workflow.versions[0].metadata.updatedAt,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Workflow } from "@/lib/api";
|
||||
import { cn, relativeDate } from "@/lib/utils";
|
||||
import { ChevronRightIcon } from "@heroicons/react/24/outline";
|
||||
import { Link } from "react-router-dom";
|
||||
import { WorkflowTags } from "./workflow-tags";
|
||||
import { Workflow } from '@/lib/api';
|
||||
import { cn, relativeDate } from '@/lib/utils';
|
||||
import { ChevronRightIcon } from '@heroicons/react/24/outline';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { WorkflowTags } from './workflow-tags';
|
||||
|
||||
const statuses = {
|
||||
offline: "text-gray-500 bg-gray-100/10",
|
||||
online: "text-green-400 bg-green-400/10",
|
||||
error: "text-rose-400 bg-rose-400/10",
|
||||
offline: 'text-gray-500 bg-gray-100/10',
|
||||
online: 'text-green-400 bg-green-400/10',
|
||||
error: 'text-rose-400 bg-rose-400/10',
|
||||
};
|
||||
|
||||
interface WorkflowListProps {
|
||||
@@ -25,7 +25,7 @@ export default function WorkflowList({ workflows }: WorkflowListProps) {
|
||||
<div className="min-w-0 flex-auto">
|
||||
<div className="flex items-center gap-x-3">
|
||||
<div
|
||||
className={cn(statuses["online"], "flex-none rounded-full p-1")}
|
||||
className={cn(statuses.online, 'flex-none rounded-full p-1')}
|
||||
>
|
||||
<div className="h-2 w-2 rounded-full bg-current" />
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WorkflowTag } from "@/lib/api";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { WorkflowTag } from '@/lib/api';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export function WorkflowTags({ tags }: { tags: WorkflowTag[] }) {
|
||||
return tags?.map((tag) => {
|
||||
@@ -8,7 +8,7 @@ export function WorkflowTags({ tags }: { tags: WorkflowTag[] }) {
|
||||
key={tag.name}
|
||||
className={cn(
|
||||
`text-[${tag.color}] bg-[${tag.color}]/10 ring-[${tag.color}]/30`,
|
||||
"flex-none rounded-full py-1 px-2 text-xs font-medium ring-1 ring-inset"
|
||||
'flex-none rounded-full py-1 px-2 text-xs font-medium ring-1 ring-inset',
|
||||
)}
|
||||
>
|
||||
{tag.name}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import WorkflowList from "./components/workflow-list";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { queries } from "@/lib/api";
|
||||
import invariant from "tiny-invariant";
|
||||
import { useAtom } from "jotai";
|
||||
import { currTenantAtom } from "@/lib/atoms";
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import WorkflowList from './components/workflow-list';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { queries } from '@/lib/api';
|
||||
import invariant from 'tiny-invariant';
|
||||
import { useAtom } from 'jotai';
|
||||
import { currTenantAtom } from '@/lib/atoms';
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
|
||||
export default function Workflows() {
|
||||
const [tenant] = useAtom(currTenantAtom);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Icons } from "@/components/ui/icons";
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Icons } from '@/components/ui/icons';
|
||||
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string().min(4).max(32),
|
||||
@@ -42,21 +42,21 @@ export function TenantCreateForm({
|
||||
useEffect(() => {
|
||||
const subscription = watch((value, { name }) => {
|
||||
switch (name) {
|
||||
case "name":
|
||||
case 'name':
|
||||
if (!isSlugSuffixed) {
|
||||
const slug = value.name
|
||||
?.toLowerCase()
|
||||
.replace(/[^a-z0-9-]/g, "-")
|
||||
.replace(/-+/g, "-")
|
||||
.replace(/^-|-$/g, "");
|
||||
.replace(/[^a-z0-9-]/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^-|-$/g, '');
|
||||
|
||||
if (slug) {
|
||||
setValue("slug", slug);
|
||||
setValue('slug', slug);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case "slug":
|
||||
case 'slug':
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -70,7 +70,7 @@ export function TenantCreateForm({
|
||||
const slugError = errors.slug?.message?.toString() || props.fieldErrors?.slug;
|
||||
|
||||
return (
|
||||
<div className={cn("grid gap-6", className)}>
|
||||
<div className={cn('grid gap-6', className)}>
|
||||
<form
|
||||
onSubmit={handleSubmit((d) => {
|
||||
props.onSubmit(d);
|
||||
@@ -83,7 +83,7 @@ export function TenantCreateForm({
|
||||
A display name for your tenant.
|
||||
</div>
|
||||
<Input
|
||||
{...register("name")}
|
||||
{...register('name')}
|
||||
id="name"
|
||||
placeholder="My Awesome Tenant"
|
||||
type="name"
|
||||
@@ -95,10 +95,10 @@ export function TenantCreateForm({
|
||||
// add a random suffix to the slug if it's not modified
|
||||
if (!isSlugSuffixed) {
|
||||
const newSlug =
|
||||
getValues("slug") +
|
||||
"-" +
|
||||
getValues('slug') +
|
||||
'-' +
|
||||
Math.random().toString(36).substr(2, 5);
|
||||
setValue("slug", newSlug);
|
||||
setValue('slug', newSlug);
|
||||
setIsSlugSuffixed(true);
|
||||
}
|
||||
}}
|
||||
@@ -113,7 +113,7 @@ export function TenantCreateForm({
|
||||
A URI-friendly identifier for your tenant.
|
||||
</div>
|
||||
<Input
|
||||
{...register("slug")}
|
||||
{...register('slug')}
|
||||
id="slug"
|
||||
placeholder="my-awesome-tenant-123456"
|
||||
type="name"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import api, { CreateTenantRequest } from "@/lib/api";
|
||||
import { useApiError } from "@/lib/hooks";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { TenantCreateForm } from "./components/tenant-create-form";
|
||||
import api, { CreateTenantRequest } from '@/lib/api';
|
||||
import { useApiError } from '@/lib/hooks';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { TenantCreateForm } from './components/tenant-create-form';
|
||||
|
||||
export default function CreateTenant() {
|
||||
const navigate = useNavigate();
|
||||
@@ -13,12 +13,12 @@ export default function CreateTenant() {
|
||||
});
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationKey: ["user:update:login"],
|
||||
mutationKey: ['user:update:login'],
|
||||
mutationFn: async (data: CreateTenantRequest) => {
|
||||
await api.tenantCreate(data);
|
||||
},
|
||||
onSuccess: () => {
|
||||
navigate("/");
|
||||
navigate('/');
|
||||
},
|
||||
onError: handleApiError,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ThemeProvider } from "@/components/theme-provider";
|
||||
import { Toaster } from "@/components/ui/toaster";
|
||||
import { Outlet } from "react-router-dom";
|
||||
import { ThemeProvider } from '@/components/theme-provider';
|
||||
import { Toaster } from '@/components/ui/toaster';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
function Root() {
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
import { QueryClient } from '@tanstack/react-query';
|
||||
|
||||
const queryClient: QueryClient = new QueryClient({});
|
||||
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
import React from "react";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import React from 'react';
|
||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: "/",
|
||||
path: '/',
|
||||
lazy: async () =>
|
||||
import("./pages/root.tsx").then((res) => {
|
||||
import('./pages/root.tsx').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
}),
|
||||
children: [
|
||||
{
|
||||
path: "/auth/login",
|
||||
path: '/auth/login',
|
||||
lazy: async () =>
|
||||
import("./pages/auth/login").then((res) => {
|
||||
import('./pages/auth/login').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "/auth/register",
|
||||
path: '/auth/register',
|
||||
lazy: async () =>
|
||||
import("./pages/auth/register").then((res) => {
|
||||
import('./pages/auth/register').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "/",
|
||||
path: '/',
|
||||
lazy: async () =>
|
||||
import("./pages/main/auth").then((res) => {
|
||||
import('./pages/main/auth').then((res) => {
|
||||
return {
|
||||
loader: res.loader,
|
||||
Component: res.default,
|
||||
@@ -40,54 +40,54 @@ const routes = [
|
||||
}),
|
||||
children: [
|
||||
{
|
||||
path: "/onboarding/create-tenant",
|
||||
path: '/onboarding/create-tenant',
|
||||
lazy: async () =>
|
||||
import("./pages/onboarding/create-tenant").then((res) => {
|
||||
import('./pages/onboarding/create-tenant').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "/",
|
||||
path: '/',
|
||||
lazy: async () =>
|
||||
import("./pages/main").then((res) => {
|
||||
import('./pages/main').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
}),
|
||||
children: [
|
||||
{
|
||||
path: "/events",
|
||||
path: '/events',
|
||||
lazy: async () =>
|
||||
import("./pages/main/events").then((res) => {
|
||||
import('./pages/main/events').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "/events/metrics",
|
||||
path: '/events/metrics',
|
||||
lazy: async () =>
|
||||
import("./pages/main/events/metrics").then((res) => {
|
||||
import('./pages/main/events/metrics').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "/workflows",
|
||||
path: '/workflows',
|
||||
lazy: async () =>
|
||||
import("./pages/main/workflows").then((res) => {
|
||||
import('./pages/main/workflows').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "/workflows/:workflow",
|
||||
path: '/workflows/:workflow',
|
||||
lazy: async () =>
|
||||
import("./pages/main/workflows/$workflow").then((res) => {
|
||||
import('./pages/main/workflows/$workflow').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
loader: res.loader,
|
||||
@@ -95,36 +95,36 @@ const routes = [
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "/workflow-runs",
|
||||
path: '/workflow-runs',
|
||||
lazy: async () =>
|
||||
import("./pages/main/workflow-runs").then((res) => {
|
||||
import('./pages/main/workflow-runs').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "/workflow-runs/:run",
|
||||
path: '/workflow-runs/:run',
|
||||
lazy: async () =>
|
||||
import("./pages/main/workflow-runs/$run").then((res) => {
|
||||
import('./pages/main/workflow-runs/$run').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "/workers",
|
||||
path: '/workers',
|
||||
lazy: async () =>
|
||||
import("./pages/main/workers").then((res) => {
|
||||
import('./pages/main/workers').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "/workers/:worker",
|
||||
path: '/workers/:worker',
|
||||
lazy: async () =>
|
||||
import("./pages/main/workers/$worker").then((res) => {
|
||||
import('./pages/main/workers/$worker').then((res) => {
|
||||
return {
|
||||
Component: res.default,
|
||||
};
|
||||
@@ -138,7 +138,7 @@ const routes = [
|
||||
},
|
||||
];
|
||||
|
||||
const router = createBrowserRouter(routes, { basename: "/" });
|
||||
const router = createBrowserRouter(routes, { basename: '/' });
|
||||
|
||||
const Router: React.FC = () => {
|
||||
return <RouterProvider router={router} />;
|
||||
|
||||
@@ -2,31 +2,39 @@
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"lib": [
|
||||
"ES2020",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
},
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
"include": [
|
||||
"vite.config.ts",
|
||||
"postcss.config.js",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import path from "path";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import { defineConfig } from "vite";
|
||||
import path from 'path';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user