diff --git a/Dockerfile b/Dockerfile index 97861ca9..5b568f46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # Build Burrito UI -FROM docker.io/library/node:20.9.0@sha256:5f21943fe97b24ae1740da6d7b9c56ac43fe3495acb47c1b232b0a352b02a25c AS builder-ui +FROM docker.io/library/node:20.11.1@sha256:f3299f16246c71ab8b304d6745bb4059fa9283e8d025972e28436a9f9b36ed24 AS builder-ui WORKDIR /workspace # Copy the node modules manifests diff --git a/ui/.gitignore b/ui/.gitignore index 438657a9..2bceaf0f 100644 --- a/ui/.gitignore +++ b/ui/.gitignore @@ -1,5 +1,4 @@ # Logs -logs *.log npm-debug.log* yarn-debug.log* diff --git a/ui/package.json b/ui/package.json index 3950a3f0..0bc132a2 100644 --- a/ui/package.json +++ b/ui/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "@floating-ui/react": "^0.26.9", "@tanstack/react-query": "^5.8.3", "@tanstack/react-table": "^8.10.7", "axios": "^1.5.1", @@ -22,16 +23,16 @@ "devDependencies": { "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", + "@typescript-eslint/eslint-plugin": "^7.0.1", + "@typescript-eslint/parser": "^7.0.1", "@vitejs/plugin-react-swc": "^3.3.2", "autoprefixer": "^10.4.16", - "eslint": "^8.45.0", + "eslint": "^8.56.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", "postcss": "^8.4.31", "tailwindcss": "^3.3.3", - "typescript": "^5.0.2", + "typescript": "^5.3.3", "vite": "^5.0.11" } } diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 0a540e7b..b71a0c27 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -8,9 +8,10 @@ import { import ThemeProvider from "@/contexts/ThemeContext"; import Layout from "@/layout/Layout"; -import Layers from "@/pages/layers/Layers"; -import Pulls from "@/pages/pulls/Pulls"; -import Login from "@/pages/login/Login"; +import Layers from "@/pages/Layers"; +import Pulls from "@/pages/Pulls"; +import Logs from "@/pages/Logs"; +import Login from "@/pages/Login"; const queryClient = new QueryClient(); const router = createBrowserRouter([ @@ -30,6 +31,10 @@ const router = createBrowserRouter([ path: "pulls", element: , }, + { + path: "logs/:layerId?/:runId?", + element: , + }, ], }, { diff --git a/ui/src/assets/icons/ArrowResizeDiagonalIcon.tsx b/ui/src/assets/icons/ArrowResizeDiagonalIcon.tsx new file mode 100644 index 00000000..be6097b8 --- /dev/null +++ b/ui/src/assets/icons/ArrowResizeDiagonalIcon.tsx @@ -0,0 +1,9 @@ +import { SVGProps } from "react"; + +const ArrowResizeDiagonalIcon = (props: SVGProps) => ( + + + +); + +export default ArrowResizeDiagonalIcon; diff --git a/ui/src/assets/icons/CopyIcon.tsx b/ui/src/assets/icons/CopyIcon.tsx new file mode 100644 index 00000000..9875f8bb --- /dev/null +++ b/ui/src/assets/icons/CopyIcon.tsx @@ -0,0 +1,9 @@ +import { SVGProps } from "react"; + +const CopyIcon = (props: SVGProps) => ( + + + +); + +export default CopyIcon; diff --git a/ui/src/assets/icons/DownloadAltIcon.tsx b/ui/src/assets/icons/DownloadAltIcon.tsx new file mode 100644 index 00000000..5fd7403f --- /dev/null +++ b/ui/src/assets/icons/DownloadAltIcon.tsx @@ -0,0 +1,9 @@ +import { SVGProps } from "react"; + +const DownloadAltIcon = (props: SVGProps) => ( + + + +); + +export default DownloadAltIcon; diff --git a/ui/src/assets/icons/EyeIcon.tsx b/ui/src/assets/icons/EyeIcon.tsx new file mode 100644 index 00000000..ec5e5939 --- /dev/null +++ b/ui/src/assets/icons/EyeIcon.tsx @@ -0,0 +1,9 @@ +import { SVGProps } from "react"; + +const EyeIcon = (props: SVGProps) => ( + + + +); + +export default EyeIcon; diff --git a/ui/src/assets/icons/TimesIcon.tsx b/ui/src/assets/icons/TimesIcon.tsx new file mode 100644 index 00000000..60f7079a --- /dev/null +++ b/ui/src/assets/icons/TimesIcon.tsx @@ -0,0 +1,9 @@ +import { SVGProps } from "react"; + +const TimesIcon = (props: SVGProps) => ( + + + +); + +export default TimesIcon; diff --git a/ui/src/assets/icons/WindowIcon.tsx b/ui/src/assets/icons/WindowIcon.tsx new file mode 100644 index 00000000..6ed2926e --- /dev/null +++ b/ui/src/assets/icons/WindowIcon.tsx @@ -0,0 +1,9 @@ +import { SVGProps } from "react"; + +const WindowIcon = (props: SVGProps) => ( + + + +); + +export default WindowIcon; diff --git a/ui/src/clients/layers/types.ts b/ui/src/clients/layers/types.ts index 0bac984d..477fd913 100644 --- a/ui/src/clients/layers/types.ts +++ b/ui/src/clients/layers/types.ts @@ -3,15 +3,26 @@ export type Layers = { }; export type Layer = { + id: string; namespace: string; name: string; state: LayerState; repository: string; branch: string; path: string; + runCount: number; + lastRunAt: string; + latestRuns: Run[]; lastResult: string; isRunning: boolean; isPR: boolean; }; export type LayerState = "success" | "warning" | "error" | "disabled"; + +export type Run = { + id: string; + commit: string; + date: string; + action: string; +}; diff --git a/ui/src/clients/logs/client.ts b/ui/src/clients/logs/client.ts new file mode 100644 index 00000000..cec81961 --- /dev/null +++ b/ui/src/clients/logs/client.ts @@ -0,0 +1,10 @@ +import axios from "axios"; + +import { Logs } from "@/clients/logs/types.ts"; + +export const fetchLogs = async (runId: string, attemptId: number | null) => { + const response = await axios.get( + `${import.meta.env.VITE_API_BASE_URL}/logs/${runId}/${attemptId}` + ); + return response.data; +}; diff --git a/ui/src/clients/logs/types.ts b/ui/src/clients/logs/types.ts new file mode 100644 index 00000000..39647f3d --- /dev/null +++ b/ui/src/clients/logs/types.ts @@ -0,0 +1,3 @@ +export type Logs = { + results: string[]; +}; diff --git a/ui/src/clients/reactQueryConfig.ts b/ui/src/clients/reactQueryConfig.ts index f72c6c43..747c9039 100644 --- a/ui/src/clients/reactQueryConfig.ts +++ b/ui/src/clients/reactQueryConfig.ts @@ -1,4 +1,6 @@ export const reactQueryKeys = { layers: ["layers"], repositories: ["repositories"], + attempts: (runId: string) => ["run", runId, "attempts"], + logs: (runId: string, attemptId: number | null) => ["logs", runId, attemptId], }; diff --git a/ui/src/clients/runs/client.ts b/ui/src/clients/runs/client.ts new file mode 100644 index 00000000..f7ffdfbd --- /dev/null +++ b/ui/src/clients/runs/client.ts @@ -0,0 +1,10 @@ +import axios from "axios"; + +import { Attempts } from "@/clients/runs/types.ts"; + +export const fetchAttempts = async (runId: string) => { + const response = await axios.get( + `${import.meta.env.VITE_API_BASE_URL}/run/${runId}/attempts` + ); + return response.data; +}; diff --git a/ui/src/clients/runs/types.ts b/ui/src/clients/runs/types.ts new file mode 100644 index 00000000..286bc322 --- /dev/null +++ b/ui/src/clients/runs/types.ts @@ -0,0 +1,3 @@ +export type Attempts = { + count: number; +}; diff --git a/ui/src/components/buttons/AttemptButton.tsx b/ui/src/components/buttons/AttemptButton.tsx new file mode 100644 index 00000000..be36f8ac --- /dev/null +++ b/ui/src/components/buttons/AttemptButton.tsx @@ -0,0 +1,72 @@ +import React from "react"; +import { twMerge } from "tailwind-merge"; + +import TimesIcon from "@/assets/icons/TimesIcon"; + +export interface AttemptButtonProps { + className?: string; + variant?: "light" | "dark"; + attempt: number; + isActive?: boolean; + onClick?: () => void; + onClose?: () => void; +} + +const AttemptButton: React.FC = ({ + className, + variant = "light", + attempt, + isActive, + onClick, + onClose, +}) => { + const styles = { + base: { + light: `bg-primary-300 + text-nuances-black + fill-primary-600`, + + dark: `bg-nuances-300 + text-nuances-400 + fill-nuances-400`, + }, + + isActive: { + light: `bg-primary-500 + text-nuances-black + fill-primary-600`, + + dark: `bg-nuances-black + text-nuances-white + fill-nuances-50`, + }, + }; + + const handleClose = (e: React.MouseEvent) => { + e.stopPropagation(); + onClose && onClose(); + }; + + return ( + + ); +}; + +export default AttemptButton; diff --git a/ui/src/components/buttons/LogsButton.tsx b/ui/src/components/buttons/LogsButton.tsx new file mode 100644 index 00000000..38844f21 --- /dev/null +++ b/ui/src/components/buttons/LogsButton.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import { twMerge } from "tailwind-merge"; + +import WindowIcon from "@/assets/icons/WindowIcon"; + +export interface LogsButtonProps + extends React.HTMLAttributes { + className?: string; + variant?: "light" | "dark"; +} + +const LogsButton = React.forwardRef( + ({ className, variant = "light", ...props }, ref) => { + return ( + + ); + } +); + +export default LogsButton; diff --git a/ui/src/components/buttons/OpenInLogsButton.tsx b/ui/src/components/buttons/OpenInLogsButton.tsx new file mode 100644 index 00000000..94f9f829 --- /dev/null +++ b/ui/src/components/buttons/OpenInLogsButton.tsx @@ -0,0 +1,29 @@ +import React from "react"; + +import Button from "@/components/core/Button"; +import ArrowResizeDiagonalIcon from "@/assets/icons/ArrowResizeDiagonalIcon"; + +export interface OpenInLogsButtonProps { + className?: string; + variant?: "primary" | "secondary" | "tertiary"; + onClick?: () => void; +} + +const OpenInLogsButton: React.FC = ({ + className, + variant = "primary", + onClick, +}) => { + return ( + + ); +}; + +export default OpenInLogsButton; diff --git a/ui/src/components/buttons/SocialButton.tsx b/ui/src/components/buttons/SocialButton.tsx index 964b481f..588ea52a 100644 --- a/ui/src/components/buttons/SocialButton.tsx +++ b/ui/src/components/buttons/SocialButton.tsx @@ -1,6 +1,6 @@ import React from "react"; -import Button from "@/components/buttons/Button"; +import Button from "@/components/core/Button"; import GithubIcon from "@/assets/icons/GithubIcon"; import GitlabIcon from "@/assets/icons/GitlabIcon"; diff --git a/ui/src/components/cards/Card.tsx b/ui/src/components/cards/Card.tsx index f9bf5486..4f3b5de6 100644 --- a/ui/src/components/cards/Card.tsx +++ b/ui/src/components/cards/Card.tsx @@ -2,8 +2,9 @@ import React from "react"; import { twMerge } from "tailwind-merge"; import { Tooltip } from "react-tooltip"; -import Tag from "@/components/tags/Tag"; -import SyncIcon from "@/assets/icons/SyncIcon"; +import Running from "@/components/widgets/Running"; +import Tag from "@/components/widgets/Tag"; +import ModalLogsTerminal from "@/components/tools/ModalLogsTerminal"; import CodeBranchIcon from "@/assets/icons/CodeBranchIcon"; import ChiliLight from "@/assets/illustrations/ChiliLight"; import ChiliDark from "@/assets/illustrations/ChiliDark"; @@ -19,6 +20,7 @@ export interface CardProps { const Card: React.FC = ({ className, variant = "light", + layer, layer: { name, namespace, @@ -31,6 +33,22 @@ const Card: React.FC = ({ isPR, }, }) => { + const styles = { + base: { + light: `bg-nuances-white + shadow-light`, + + dark: `bg-nuances-400 + shadow-dark`, + }, + + isRunning: { + light: `outline-blue-400`, + + dark: `outline-blue-500`, + }, + }; + const getTag = () => { return (
@@ -62,14 +80,8 @@ const Card: React.FC = ({ rounded-2xl p-6 gap-4 - ${variant === "light" ? "bg-nuances-white" : "bg-nuances-400"} - ${variant === "light" ? "shadow-light" : "shadow-dark"} - ${ - isRunning && - `outline outline-4 ${ - variant === "light" ? "outline-blue-400" : "outline-blue-500" - }` - }`, + ${styles.base[variant]}`, + isRunning && `outline outline-4 ${styles.isRunning[variant]}`, className )} > @@ -79,7 +91,7 @@ const Card: React.FC = ({ items-center justify-between self-stretch - gap-3 + gap-4 `} > = ({ {name} {isRunning ? ( -
- Running - -
+ ) : isPR ? ( = ({ ))}
+ {layer.latestRuns.length > 0 && ( + + )} void; + handleActive?: (layer: Layer, run: string) => void; + layer: Layer; +} + +const RunCard: React.FC = ({ + className, + variant = "light", + isActive, + onClick, + handleActive, + layer, + layer: { name, namespace, runCount, latestRuns, isRunning }, +}) => { + const [isExpanded, setIsExpanded] = useState(false); + + const handleActiveRun = ( + event: React.MouseEvent, + layer: Layer, + run: string + ) => { + event.stopPropagation(); + handleActive && handleActive(layer, run); + }; + + const handleExpand = (event: React.MouseEvent) => { + event.stopPropagation(); + setIsExpanded(!isExpanded); + }; + + const styles = { + base: { + light: `bg-primary-100 + text-nuances-black + outline-primary-500 + hover:bg-nuances-white`, + + dark: `bg-nuances-black + text-nuances-50 + outline-nuances-50 + hover:bg-nuances-400`, + }, + + isActive: { + light: `bg-nuances-white + shadow-light`, + + dark: `bg-nuances-400 + shadow-dark`, + }, + + isRunning: { + light: `outline-blue-400`, + + dark: `outline-blue-500`, + }, + }; + + return ( +
+
+
+ {name} + {isRunning && } +
+ {namespace} +
+
+ + Runs + + {runCount} + +
+
+
+ {latestRuns.map((run, index) => ( + handleActiveRun(event, layer, run.id)} + > + {run.commit} - {run.date} - {run.action} + + ))} +
+
+
+ ); +}; + +export default RunCard; diff --git a/ui/src/components/misc/Box.tsx b/ui/src/components/core/Box.tsx similarity index 100% rename from ui/src/components/misc/Box.tsx rename to ui/src/components/core/Box.tsx diff --git a/ui/src/components/buttons/Button.tsx b/ui/src/components/core/Button.tsx similarity index 100% rename from ui/src/components/buttons/Button.tsx rename to ui/src/components/core/Button.tsx diff --git a/ui/src/components/checkboxes/Checkbox.tsx b/ui/src/components/core/Checkbox.tsx similarity index 100% rename from ui/src/components/checkboxes/Checkbox.tsx rename to ui/src/components/core/Checkbox.tsx diff --git a/ui/src/components/inputs/Dropdown.tsx b/ui/src/components/core/Dropdown.tsx similarity index 95% rename from ui/src/components/inputs/Dropdown.tsx rename to ui/src/components/core/Dropdown.tsx index d32e2c33..8a16a64d 100644 --- a/ui/src/components/inputs/Dropdown.tsx +++ b/ui/src/components/core/Dropdown.tsx @@ -1,7 +1,7 @@ import React, { useState, useRef } from "react"; import { twMerge } from "tailwind-merge"; -import Box from "@/components/misc/Box"; +import Box from "@/components/core/Box"; import AngleDownIcon from "@/assets/icons/AngleDownIcon"; @@ -73,7 +73,8 @@ const Dropdown: React.FC = ({ text-nuances-200 fill-nuances-200 hover:outline-0 - focus:outline-0`, + focus:outline-0 + cursor-default`, }; return ( @@ -99,9 +100,9 @@ const Dropdown: React.FC = ({ focus:outline focus:outline-2 ${styles.base[variant]}`, + className, filled && styles.filled[variant], - disabled && styles.disabled, - className + disabled && styles.disabled )} tabIndex={0} onMouseDown={handleClick} @@ -111,7 +112,6 @@ const Dropdown: React.FC = ({ > {label} - {open && ( void; +} + +const AttemptsDropdown: React.FC = ({ + variant, + runId, + select, + onChange, +}) => { + const attemptsQuery = useQuery({ + queryKey: reactQueryKeys.attempts(runId), + queryFn: () => fetchAttempts(runId), + }); + + const handleChange = ( + e: React.ChangeEvent, + index: number + ) => { + if (e.target.checked) { + onChange([...select, index]); + } else { + onChange(select.filter((i) => i !== index)); + } + }; + + return ( + + Attempts +
+
+ {attemptsQuery.isLoading && Loading...} + {attemptsQuery.isError && An error occurred.} + {attemptsQuery.isSuccess && + (attemptsQuery.data.count !== 0 ? ( + Array.from(Array(attemptsQuery.data.count)).map((_, index) => ( + handleChange(e, index)} + /> + )) + ) : ( + No attempts found. + ))} +
+
+ ); +}; + +export default AttemptsDropdown; diff --git a/ui/src/components/dropdowns/DateDropdown.tsx b/ui/src/components/dropdowns/DateDropdown.tsx new file mode 100644 index 00000000..3fdbcb70 --- /dev/null +++ b/ui/src/components/dropdowns/DateDropdown.tsx @@ -0,0 +1,66 @@ +import React from "react"; + +import Box from "@/components/core/Box"; +import Checkbox from "@/components/core/Checkbox"; + +export interface DateDropdownProps { + variant?: "light" | "dark"; + filter: "ascending" | "descending" | null; + onChange: (filter: "ascending" | "descending" | null) => void; +} + +const DateDropdown: React.FC = ({ + variant, + filter, + onChange, +}) => { + const handleChange = ( + e: React.ChangeEvent, + state: "ascending" | "descending" | null + ) => { + if (e.target.checked) { + onChange(state); + } else { + onChange(null); + } + }; + + return ( + + Date +
+
+ handleChange(e, "descending")} + /> + handleChange(e, "ascending")} + /> +
+
+ ); +}; + +export default DateDropdown; diff --git a/ui/src/pages/layers/components/RepositoriesDropdown.tsx b/ui/src/components/dropdowns/RepositoriesDropdown.tsx similarity index 86% rename from ui/src/pages/layers/components/RepositoriesDropdown.tsx rename to ui/src/components/dropdowns/RepositoriesDropdown.tsx index 8c26a985..32c88c11 100644 --- a/ui/src/pages/layers/components/RepositoriesDropdown.tsx +++ b/ui/src/components/dropdowns/RepositoriesDropdown.tsx @@ -4,9 +4,9 @@ import { useQuery } from "@tanstack/react-query"; import { fetchRepositories } from "@/clients/repositories/client"; import { reactQueryKeys } from "@/clients/reactQueryConfig"; -import Box from "@/components/misc/Box"; -import Input from "@/components/inputs/Input"; -import Checkbox from "@/components/checkboxes/Checkbox"; +import Box from "@/components/core/Box"; +import Input from "@/components/core/Input"; +import Checkbox from "@/components/core/Checkbox"; export interface RepositoriesDropdownProps { variant?: "light" | "dark"; @@ -50,18 +50,16 @@ const RepositoriesDropdown: React.FC = ({ return ( - - Repositories - + Repositories
= ({ return ( - - State - + State
= ({ className, variant }) => { +const CardLoader: React.FC = ({ + className, + variant = "light", +}) => { const styles = { light: `bg-[linear-gradient(270deg,_#D8EBFF_0%,_#ECF5FF_100%)] shadow-light`, @@ -17,7 +20,7 @@ const CardLoader: React.FC = ({ className, variant }) => { return (
= ({ + className, + variant = "light", +}) => { + const style = { + light: `bg-[linear-gradient(270deg,_#D8EBFF_0%,_#ECF5FF_100%)] + shadow-light`, + dark: `bg-[linear-gradient(270deg,_#252525_0%,_rgba(68,_67,_67,_0.24)_100%)] + shadow-dark`, + }; + + return ( +
+ ); +}; + +export default RunCardLoader; diff --git a/ui/src/components/loaders/TableLoader.tsx b/ui/src/components/loaders/TableLoader.tsx index dc9b99b4..a83091af 100644 --- a/ui/src/components/loaders/TableLoader.tsx +++ b/ui/src/components/loaders/TableLoader.tsx @@ -3,10 +3,13 @@ import { twMerge } from "tailwind-merge"; export interface TableLoaderProps { className?: string; - variant: "light" | "dark"; + variant?: "light" | "dark"; } -const TableLoader: React.FC = ({ className, variant }) => { +const TableLoader: React.FC = ({ + className, + variant = "light", +}) => { const styles = { light: `bg-[linear-gradient(270deg,_#D8EBFF_0%,_#ECF5FF_100%)]`, dark: `bg-[linear-gradient(270deg,_#252525_0%,_rgba(68,_67,_67,_0.24)_100%)]`, diff --git a/ui/src/components/misc/ThemeToggle.tsx b/ui/src/components/misc/ThemeToggle.tsx index b48fca61..92832b6a 100644 --- a/ui/src/components/misc/ThemeToggle.tsx +++ b/ui/src/components/misc/ThemeToggle.tsx @@ -3,8 +3,8 @@ import { twMerge } from "tailwind-merge"; import { ThemeContext } from "@/contexts/ThemeContext"; -import Box from "@/components/misc/Box"; -import Toggle from "@/components/buttons/Toggle"; +import Box from "@/components/core/Box"; +import Toggle from "@/components/core/Toggle"; export interface ThemeToggleProps { className?: string; diff --git a/ui/src/components/navigation/NavigationBar.tsx b/ui/src/components/navigation/NavigationBar.tsx index 335b41e9..975e0a94 100644 --- a/ui/src/components/navigation/NavigationBar.tsx +++ b/ui/src/components/navigation/NavigationBar.tsx @@ -6,6 +6,7 @@ import ProfilePicture from "@/components/misc/ProfilePicture"; import Burrito from "@/assets/illustrations/Burrito"; import LayerGroupIcon from "@/assets/icons/LayerGroupIcon"; import CodeBranchIcon from "@/assets/icons/CodeBranchIcon"; +import WindowIcon from "@/assets/icons/WindowIcon"; export interface NavigationBarProps { className?: string; @@ -58,6 +59,14 @@ export const NavigationBar: React.FC = ({ > + + isActive ? "fill-inherit" : "fill-primary-600" + } + to="/logs" + > + +
diff --git a/ui/src/components/navigation/NavigationLink.tsx b/ui/src/components/navigation/NavigationLink.tsx new file mode 100644 index 00000000..523b6e30 --- /dev/null +++ b/ui/src/components/navigation/NavigationLink.tsx @@ -0,0 +1,69 @@ +import React from "react"; +import { twMerge } from "tailwind-merge"; + +import { Link, LinkProps } from "react-router-dom"; + +export interface NavigationLinkProps { + className?: string; + to: LinkProps["to"]; + children: React.ReactNode; + disabled?: boolean; +} + +const NavigationLink: React.FC = ({ + className, + to, + children, + disabled, +}) => { + return !disabled ? ( + +
+ {children} +
+ + ) : ( +
+ {children} +
+ ); +}; + +export default NavigationLink; diff --git a/ui/src/components/tables/Table.tsx b/ui/src/components/tables/Table.tsx index 56ed9424..decc0e69 100644 --- a/ui/src/components/tables/Table.tsx +++ b/ui/src/components/tables/Table.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; import { twMerge } from "tailwind-merge"; import { createColumnHelper, @@ -8,12 +8,13 @@ import { } from "@tanstack/react-table"; import { Tooltip } from "react-tooltip"; -import Tag from "@/components/tags/Tag"; import TableLoader from "@/components/loaders/TableLoader"; +import ModalLogsTerminal from "@/components/tools/ModalLogsTerminal"; +import Running from "@/components/widgets/Running"; +import Tag from "@/components/widgets/Tag"; import ChiliLight from "@/assets/illustrations/ChiliLight"; import ChiliDark from "@/assets/illustrations/ChiliDark"; import CodeBranchIcon from "@/assets/icons/CodeBranchIcon"; -import SyncIcon from "@/assets/icons/SyncIcon"; import { Layer, LayerState } from "@/clients/layers/types"; @@ -31,6 +32,7 @@ const Table: React.FC = ({ data, }) => { const columnHelper = createColumnHelper(); + const [hoveredRow, setHoveredRow] = useState(null); const columns = [ columnHelper.accessor("isPR", { @@ -61,7 +63,33 @@ const Table: React.FC = ({ cell: (result) => (
{result.getValue()} - {result.row.original.isRunning && ( + {result.row.original === hoveredRow && + result.row.original.latestRuns.length > 0 ? ( +
+ +
+ ) : result.row.original.isRunning ? (
= ({ pointer-events-none ${ variant === "light" - ? "bg-[linear-gradient(270deg,_#FFF_56.84%,_rgba(255,_255,_255,_0.00)_100%)]" - : "bg-[linear-gradient(270deg,_#000_56.84%,_rgba(0,_0,_0,_0.00)_100%)]" + ? "bg-[linear-gradient(270deg,_#FFF_58.7%,_rgba(255,_255,_255,_0.00)_100%)]" + : "bg-[linear-gradient(270deg,_#000_58.7%,_rgba(0,_0,_0,_0.00)_100%)]" } `} > -
- Running - -
+
- )} + ) : null}
), }), @@ -283,6 +304,8 @@ const Table: React.FC = ({ -outline-offset-4 ${styles.row.running[variant]}` )} + onMouseEnter={() => setHoveredRow(row.original)} + onMouseLeave={() => setHoveredRow(null)} > {row.getVisibleCells().map((cell, index) => ( = ({ + className, + variant = "light", + layer: { namespace, name }, + run, +}) => { + const styles = { + light: `bg-nuances-50 + text-nuances-black + fill-nuances-black + border-primary-500`, + dark: `bg-nuances-400 + text-nuances-50 + fill-nuances-50 + border-nuances-black`, + }; + + const [selectedAttempts, setSelectedAttempts] = useState([]); + const [activeAttempt, setActiveAttempt] = useState(null); + /* TODO: The states above should eventually be moved to search params. + An unresolved bug in the useSearchParams hook is causing rerenders which + triggers the useEffect and resets the selectedAttempts and activeAttempt states. */ + const [displayLogsCopiedTooltip, setDisplayLogsCopiedTooltip] = + useState(false); + + const attemptsQuery = useQuery({ + queryKey: reactQueryKeys.attempts(run), + queryFn: () => fetchAttempts(run), + }); + + const logsQuery = useQuery({ + queryKey: reactQueryKeys.logs(run, activeAttempt), + queryFn: () => fetchLogs(run, activeAttempt), + enabled: activeAttempt !== null && !attemptsQuery.isFetching, + }); + + useEffect(() => { + setActiveAttempt(null); + setSelectedAttempts([]); + + if (attemptsQuery.data && attemptsQuery.data.count > 0) { + setActiveAttempt(attemptsQuery.data.count - 1); + setSelectedAttempts([attemptsQuery.data.count - 1]); + } + }, [attemptsQuery.data]); + + const handleCopy = () => { + if (logsQuery.isSuccess) { + navigator.clipboard.writeText(logsQuery.data.results.join("")); // TODO: check if this works properly + setDisplayLogsCopiedTooltip(true); + } + }; + + const handleClose = (attempt: number) => { + setSelectedAttempts(selectedAttempts.filter((a) => a !== attempt)); + setActiveAttempt(activeAttempt === attempt ? null : activeAttempt); + }; + + return ( +
+ {/* TODO: add overflow-auto to the div below, need to make proper floating dropdowns before */} +
+
+ {name} + {namespace} + 0} + variant={variant} + > + + +
+
+ logsQuery.refetch()} + /> +
setDisplayLogsCopiedTooltip(false)} + > + +
+ +
+
+
+
+ {selectedAttempts + .sort((a, b) => b - a) + .map((attempt) => ( + setActiveAttempt(attempt)} + onClose={() => handleClose(attempt)} + /> + ))} +
+
+ + + {activeAttempt !== null && + logsQuery.isSuccess && + logsQuery.data.results.map((log, i) => ( + + + + + ))} + +
+ {i + 1} + {log}
+
+ +
+ ); +}; + +export default LogsTerminal; diff --git a/ui/src/components/tools/ModalLogsTerminal.tsx b/ui/src/components/tools/ModalLogsTerminal.tsx new file mode 100644 index 00000000..b06f8d28 --- /dev/null +++ b/ui/src/components/tools/ModalLogsTerminal.tsx @@ -0,0 +1,91 @@ +import React, { useState } from "react"; +import { + useFloating, + useDismiss, + useRole, + useClick, + useInteractions, + FloatingFocusManager, + FloatingOverlay, + FloatingPortal, +} from "@floating-ui/react"; +import { useNavigate } from "react-router-dom"; + +import LogsButton from "@/components/buttons/LogsButton"; +import LogsTerminal from "@/components/tools/LogsTerminal"; +import OpenInLogsButton from "@/components/buttons/OpenInLogsButton"; + +import { Layer } from "@/clients/layers/types"; + +export interface ModalLogsTerminalProps { + variant?: "light" | "dark"; + layer: Layer; +} + +const ModalLogsTerminal: React.FC = ({ + variant = "light", + layer, +}) => { + const [isOpen, setIsOpen] = useState(false); + + const { refs, context } = useFloating({ + open: isOpen, + onOpenChange: setIsOpen, + }); + + const click = useClick(context); + const role = useRole(context); + const dismiss = useDismiss(context, { outsidePressEvent: "mousedown" }); + + const { getReferenceProps, getFloatingProps } = useInteractions([ + click, + role, + dismiss, + ]); + + const navigate = useNavigate(); + + const handleOpenInLogs = () => { + navigate(`/logs/${layer.id}/${layer.latestRuns[0].id}`); + }; + + return ( + <> + + + {isOpen && ( + + +
+ + +
+
+
+ )} +
+ + ); +}; + +export default ModalLogsTerminal; diff --git a/ui/src/components/widgets/Running.tsx b/ui/src/components/widgets/Running.tsx new file mode 100644 index 00000000..8816f00e --- /dev/null +++ b/ui/src/components/widgets/Running.tsx @@ -0,0 +1,14 @@ +import React from "react"; + +import SyncIcon from "@/assets/icons/SyncIcon"; + +const Running: React.FC = () => { + return ( +
+ Running + +
+ ); +}; + +export default Running; diff --git a/ui/src/components/tags/Tag.tsx b/ui/src/components/widgets/Tag.tsx similarity index 89% rename from ui/src/components/tags/Tag.tsx rename to ui/src/components/widgets/Tag.tsx index 514a61e7..7924cbc5 100644 --- a/ui/src/components/tags/Tag.tsx +++ b/ui/src/components/widgets/Tag.tsx @@ -9,13 +9,13 @@ export interface TagProps { const Tag: React.FC = ({ variant }) => { const styles = { success: `bg-status-success-default - text-nuances-black`, + text-nuances-black`, warning: `bg-status-warning-default - text-nuances-black`, + text-nuances-black`, error: `bg-status-error-default - text-nuances-white`, + text-nuances-white`, disabled: `bg-nuances-50 - text-nuances-200`, + text-nuances-200`, }; const getContent = () => { diff --git a/ui/src/layout/Layout.tsx b/ui/src/layout/Layout.tsx index 135f387f..f4a0bf82 100644 --- a/ui/src/layout/Layout.tsx +++ b/ui/src/layout/Layout.tsx @@ -12,7 +12,7 @@ const Layout: React.FC = () => { className={` flex ${theme === "light" ? "bg-primary-100" : "bg-nuances-black"} - `} + `} > diff --git a/ui/src/pages/layers/Layers.tsx b/ui/src/pages/Layers.tsx similarity index 77% rename from ui/src/pages/layers/Layers.tsx rename to ui/src/pages/Layers.tsx index dddc71e1..4dc23916 100644 --- a/ui/src/pages/layers/Layers.tsx +++ b/ui/src/pages/Layers.tsx @@ -7,16 +7,16 @@ import { reactQueryKeys } from "@/clients/reactQueryConfig"; import { ThemeContext } from "@/contexts/ThemeContext"; -import Button from "@/components/buttons/Button"; -import Input from "@/components/inputs/Input"; -import Dropdown from "@/components/inputs/Dropdown"; -import Toggle from "@/components/buttons/Toggle"; +import Button from "@/components/core/Button"; +import Input from "@/components/core/Input"; +import Dropdown from "@/components/core/Dropdown"; +import Toggle from "@/components/core/Toggle"; import NavigationButton from "@/components/navigation/NavigationButton"; import Card from "@/components/cards/Card"; import Table from "@/components/tables/Table"; -import StateDropdown from "@/pages/layers/components/StateDropdown"; -import RepositoriesDropdown from "@/pages/layers/components/RepositoriesDropdown"; +import StateDropdown from "@/components/dropdowns/StateDropdown"; +import RepositoriesDropdown from "@/components/dropdowns/RepositoriesDropdown"; import { LayerState } from "@/clients/layers/types"; @@ -108,8 +108,6 @@ const Layers: React.FC = () => {
{ { `} > {view === "grid" ? ( -
+
{layersQuery.isLoading ? ( Array.from({ length: 100 }).map((_, index) => ( )) ) : layersQuery.isError ? ( - An error has occurred + + An error has occurred. + ) : layersQuery.isSuccess ? ( - layersQuery.data.results.map((layer, index) => ( - - )) + layersQuery.data.results.length > 0 ? ( + layersQuery.data.results.map((layer, index) => ( + + )) + ) : ( + + No layers found + + ) ) : ( <> )} @@ -258,9 +282,37 @@ const Layers: React.FC = () => { {layersQuery.isLoading ? ( ) : layersQuery.isError ? ( - An error has occurred + + An error has occurred. + ) : layersQuery.isSuccess ? ( -
+ layersQuery.data.results.length > 0 ? ( +
+ ) : ( +
+ + No layers found + +
+ ) ) : ( <> )} diff --git a/ui/src/pages/login/Login.tsx b/ui/src/pages/Login.tsx similarity index 98% rename from ui/src/pages/login/Login.tsx rename to ui/src/pages/Login.tsx index fd83b800..7d9e2bfa 100644 --- a/ui/src/pages/login/Login.tsx +++ b/ui/src/pages/Login.tsx @@ -3,8 +3,8 @@ import { useNavigate } from "react-router-dom"; import { ThemeContext } from "@/contexts/ThemeContext"; -import Input from "@/components/inputs/Input"; -import Button from "@/components/buttons/Button"; +import Input from "@/components/core/Input"; +import Button from "@/components/core/Button"; import SocialButton from "@/components/buttons/SocialButton"; import Burrito from "@/assets/illustrations/Burrito"; diff --git a/ui/src/pages/Logs.tsx b/ui/src/pages/Logs.tsx new file mode 100644 index 00000000..761f6dc4 --- /dev/null +++ b/ui/src/pages/Logs.tsx @@ -0,0 +1,335 @@ +import React, { useContext, useCallback, useMemo } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { useParams, useSearchParams, useNavigate } from "react-router-dom"; + +import { fetchLayers } from "@/clients/layers/client"; +import { reactQueryKeys } from "@/clients/reactQueryConfig"; + +import { ThemeContext } from "@/contexts/ThemeContext"; + +import Button from "@/components/core/Button"; +import Input from "@/components/core/Input"; +import Dropdown from "@/components/core/Dropdown"; +import RepositoriesDropdown from "@/components/dropdowns/RepositoriesDropdown"; +import DateDropdown from "@/components/dropdowns/DateDropdown"; +import Toggle from "@/components/core/Toggle"; +import RunCardLoader from "@/components/loaders/RunCardLoader"; +import RunCard from "@/components/cards/RunCard"; +import LogsTerminal from "@/components/tools/LogsTerminal"; + +import SearchIcon from "@/assets/icons/SearchIcon"; + +import { Layer } from "@/clients/layers/types"; + +const Logs: React.FC = () => { + const { theme } = useContext(ThemeContext); + const { layerId, runId } = useParams(); + const [searchParams, setSerchParams] = useSearchParams(); + const navigate = useNavigate(); + + const search = useMemo( + () => searchParams.get("search") || "", + [searchParams] + ); + + const setSearch = useCallback( + (search: string) => { + searchParams.set("search", search); + setSerchParams(searchParams); + }, + [searchParams, setSerchParams] + ); + + const repositoryFilter = useMemo(() => { + const param = searchParams.get("repositories"); + return param ? param.split(",") : []; + }, [searchParams]); + + const setRepositoryFilter = useCallback( + (repositoryFilter: string[]) => { + searchParams.set("repositories", repositoryFilter.join(",")); + setSerchParams(searchParams); + }, + [searchParams, setSerchParams] + ); + + const dateFilter = useMemo<"ascending" | "descending" | null>(() => { + const param = searchParams.get("date"); + return param === "ascending" + ? "ascending" + : param === "descending" + ? "descending" + : null; + }, [searchParams]); + + const setDateFilter = useCallback( + (dateFilter: "ascending" | "descending" | null) => { + searchParams.set("date", dateFilter || ""); + setSerchParams(searchParams); + }, + [searchParams, setSerchParams] + ); + + const hidePRFilter = useMemo( + () => searchParams.get("hidepr") !== "false", + [searchParams] + ); + + const setHidePRFilter = useCallback( + (hidePRFilter: boolean) => { + searchParams.set("hidepr", hidePRFilter.toString()); + setSerchParams(searchParams); + }, + [searchParams, setSerchParams] + ); + + const layersQuery = useQuery({ + queryKey: reactQueryKeys.layers, + queryFn: fetchLayers, + select: (data) => ({ + ...data, + results: data.results + .filter((layer) => + layer.name.toLowerCase().includes(search.toLowerCase()) + ) + .filter( + (layer) => + repositoryFilter.length === 0 || + repositoryFilter.includes(layer.repository) + ) + .filter((layer) => !hidePRFilter || !layer.isPR) + .sort((a, b) => + dateFilter === "ascending" + ? new Date(a.lastRunAt).getTime() - new Date(b.lastRunAt).getTime() + : dateFilter === "descending" + ? new Date(b.lastRunAt).getTime() - new Date(a.lastRunAt).getTime() + : 0 + ), + }), + }); + + const handleActive = (layer: Layer, run?: string) => { + navigate({ + pathname: `/logs/${layer.id}${ + run + ? `/${run}` + : layer.latestRuns.length > 0 + ? `/${layer.latestRuns[0].id}` + : "" + }`, + search: searchParams.toString(), + }); + }; + + return ( +
+
+
+

+ Logs +

+ +
+ } + value={search} + onChange={(e) => setSearch(e.target.value)} + /> +
+
+ + {` + ${ + layersQuery.isSuccess ? layersQuery.data.results.length : 0 + } layers + `} + + + + Filter by + +
+ + + + + + +
+ setHidePRFilter(!hidePRFilter)} + label="Hide Pull Requests" + /> +
+
+
+
+
+ {layersQuery.isLoading ? ( + Array.from({ length: 100 }).map((_, index) => ( + + )) + ) : layersQuery.isError ? ( + + An error has occurred + + ) : layersQuery.isSuccess ? ( + layersQuery.data.results.length > 0 ? ( + layersQuery.data.results.map((layer, index) => ( + handleActive(layer)} + handleActive={handleActive} + layer={layer} + /> + )) + ) : ( + + No layers found + + ) + ) : ( + <> + )} +
+ {layersQuery.isSuccess && + layersQuery.data.results.length > 0 && + (layerId && + layersQuery.data.results.some((layer) => layer.id === layerId) ? ( + runId ? ( + ((activeLayerObject) => + activeLayerObject && ( + + ))( + layersQuery.data.results.find((layer) => layer.id === layerId) + ) + ) : ( +
+ + There is no run for this layer... + +
+ ) + ) : ( +
+ + Select a layer... + +
+ ))} +
+
+ ); +}; + +export default Logs; diff --git a/ui/src/pages/pulls/Pulls.tsx b/ui/src/pages/Pulls.tsx similarity index 92% rename from ui/src/pages/pulls/Pulls.tsx rename to ui/src/pages/Pulls.tsx index b6f2637a..06534bbe 100644 --- a/ui/src/pages/pulls/Pulls.tsx +++ b/ui/src/pages/Pulls.tsx @@ -2,7 +2,7 @@ import React, { useContext } from "react"; import { ThemeContext } from "@/contexts/ThemeContext"; -import TrafficCone from "./temp/TrafficCone"; +import TrafficCone from "@/components/temp/TrafficCone"; const Pulls: React.FC = () => { const { theme } = useContext(ThemeContext); diff --git a/ui/tailwind.config.js b/ui/tailwind.config.js index 231c8aa2..d3b2a9f6 100644 --- a/ui/tailwind.config.js +++ b/ui/tailwind.config.js @@ -49,7 +49,7 @@ export default { light: "#FFFBDC", }, }, - overlay: "#00000040", + overlay: "#00000080", }, boxShadow: { light: "0px 0px 32px 0px rgba(121, 140, 140, 0.16)", diff --git a/ui/yarn.lock b/ui/yarn.lock index 0d5df841..6f1a51cc 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -181,18 +181,34 @@ "@floating-ui/core" "^1.0.0" "@floating-ui/utils" "^0.2.0" +"@floating-ui/react-dom@^2.0.8": + version "2.0.8" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.8.tgz#afc24f9756d1b433e1fe0d047c24bd4d9cefaa5d" + integrity sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw== + dependencies: + "@floating-ui/dom" "^1.6.1" + +"@floating-ui/react@^0.26.9": + version "0.26.9" + resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.9.tgz#bbccbefa0e60c8b7f4c0387ba0fc0607bb65f2cc" + integrity sha512-p86wynZJVEkEq2BBjY/8p2g3biQ6TlgT4o/3KgFKyTWoJLU1GZ8wpctwRqtkEl2tseYA+kw7dBAIDFcednfI5w== + dependencies: + "@floating-ui/react-dom" "^2.0.8" + "@floating-ui/utils" "^0.2.1" + tabbable "^6.0.1" + "@floating-ui/utils@^0.2.0", "@floating-ui/utils@^0.2.1": version "0.2.1" resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2" integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q== "@humanwhocodes/config-array@^0.11.13": - version "0.11.13" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" - integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== dependencies: - "@humanwhocodes/object-schema" "^2.0.1" - debug "^4.1.1" + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" minimatch "^3.0.5" "@humanwhocodes/module-importer@^1.0.1": @@ -200,10 +216,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" - integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" + integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== "@isaacs/cliui@^8.0.2": version "8.0.2" @@ -345,79 +361,79 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz#9ffdf9ed133a7464f4ae187eb9e1294413fab235" integrity sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg== -"@swc/core-darwin-arm64@1.3.102": - version "1.3.102" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.102.tgz#2bbd90a8751e6eee981f857ec3f0b6233208da37" - integrity sha512-CJDxA5Wd2cUMULj3bjx4GEoiYyyiyL8oIOu4Nhrs9X+tlg8DnkCm4nI57RJGP8Mf6BaXPIJkHX8yjcefK2RlDA== - -"@swc/core-darwin-x64@1.3.102": - version "1.3.102" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.102.tgz#df16d51f45771d3c9cca8554b28a3190cdb075cf" - integrity sha512-X5akDkHwk6oAer49oER0qZMjNMkLH3IOZaV1m98uXIasAGyjo5WH1MKPeMLY1sY6V6TrufzwiSwD4ds571ytcg== - -"@swc/core-linux-arm-gnueabihf@1.3.102": - version "1.3.102" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.102.tgz#eb71697590c56ea261fa9a4b198c45304c7ece39" - integrity sha512-kJH3XtZP9YQdjq/wYVBeFuiVQl4HaC4WwRrIxAHwe2OyvrwUI43dpW3LpxSggBnxXcVCXYWf36sTnv8S75o2Gw== - -"@swc/core-linux-arm64-gnu@1.3.102": - version "1.3.102" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.102.tgz#75d72d5253d56723fa7054e1a8f313bf3d17b1a2" - integrity sha512-flQP2WDyCgO24WmKA1wjjTx+xfCmavUete2Kp6yrM+631IHLGnr17eu7rYJ/d4EnDBId/ytMyrnWbTVkaVrpbQ== - -"@swc/core-linux-arm64-musl@1.3.102": - version "1.3.102" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.102.tgz#7db86022fec57c1e06c573d45cef5e911bcc420e" - integrity sha512-bQEQSnC44DyoIGLw1+fNXKVGoCHi7eJOHr8BdH0y1ooy9ArskMjwobBFae3GX4T1AfnrTaejyr0FvLYIb0Zkog== - -"@swc/core-linux-x64-gnu@1.3.102": - version "1.3.102" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.102.tgz#298a25aa854924bedc7e4b69da52da19f84fc7a8" - integrity sha512-dFvnhpI478svQSxqISMt00MKTDS0e4YtIr+ioZDG/uJ/q+RpcNy3QI2KMm05Fsc8Y0d4krVtvCKWgfUMsJZXAg== - -"@swc/core-linux-x64-musl@1.3.102": - version "1.3.102" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.102.tgz#1bcd911aaa88b96f3bb665b0fd84ef4d21adf886" - integrity sha512-+a0M3CvjeIRNA/jTCzWEDh2V+mhKGvLreHOL7J97oULZy5yg4gf7h8lQX9J8t9QLbf6fsk+0F8bVH1Ie/PbXjA== - -"@swc/core-win32-arm64-msvc@1.3.102": - version "1.3.102" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.102.tgz#59084786364d03fa4a120bdd589a557a00caedeb" - integrity sha512-w76JWLjkZNOfkB25nqdWUNCbt0zJ41CnWrJPZ+LxEai3zAnb2YtgB/cCIrwxDebRuMgE9EJXRj7gDDaTEAMOOQ== - -"@swc/core-win32-ia32-msvc@1.3.102": - version "1.3.102" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.102.tgz#27954889d940a63796d58ff7753f5f27ed381a1f" - integrity sha512-vlDb09HiGqKwz+2cxDS9T5/461ipUQBplvuhW+cCbzzGuPq8lll2xeyZU0N1E4Sz3MVdSPx1tJREuRvlQjrwNg== - -"@swc/core-win32-x64-msvc@1.3.102": - version "1.3.102" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.102.tgz#477da542e6b01b3eb64476ec9a78f497a9b87807" - integrity sha512-E/jfSD7sShllxBwwgDPeXp1UxvIqehj/ShSUqq1pjR/IDRXngcRSXKJK92mJkNFY7suH6BcCWwzrxZgkO7sWmw== - -"@swc/core@^1.3.96": - version "1.3.102" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.102.tgz#870874bcf1d78cd7bb1bc66b31bf2b1a87c1a667" - integrity sha512-OAjNLY/f6QWKSDzaM3bk31A+OYHu6cPa9P/rFIx8X5d24tHXUpRiiq6/PYI6SQRjUPlB72GjsjoEU8F+ALadHg== - dependencies: - "@swc/counter" "^0.1.1" +"@swc/core-darwin-arm64@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.2.tgz#3b5677c5b9c5a7a91d953b96cd603c94064e2835" + integrity sha512-1uSdAn1MRK5C1m/TvLZ2RDvr0zLvochgrZ2xL+lRzugLlCTlSA+Q4TWtrZaOz+vnnFVliCpw7c7qu0JouhgQIw== + +"@swc/core-darwin-x64@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.4.2.tgz#bbc8bbf420389b12541151255a50f319cc17ef96" + integrity sha512-TYD28+dCQKeuxxcy7gLJUCFLqrwDZnHtC2z7cdeGfZpbI2mbfppfTf2wUPzqZk3gEC96zHd4Yr37V3Tvzar+lQ== + +"@swc/core-linux-arm-gnueabihf@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.2.tgz#aa9a18f130820717df08c9dd882043fc47e8d35a" + integrity sha512-Eyqipf7ZPGj0vplKHo8JUOoU1un2sg5PjJMpEesX0k+6HKE2T8pdyeyXODN0YTFqzndSa/J43EEPXm+rHAsLFQ== + +"@swc/core-linux-arm64-gnu@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.2.tgz#5ef1de0ca7cc3a034aa3a1c3c1794b78e6ca207e" + integrity sha512-wZn02DH8VYPv3FC0ub4my52Rttsus/rFw+UUfzdb3tHMHXB66LqN+rR0ssIOZrH6K+VLN6qpTw9VizjyoH0BxA== + +"@swc/core-linux-arm64-musl@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.2.tgz#5dfd2a8c0483770a307de0ccb6019a082ff0d902" + integrity sha512-3G0D5z9hUj9bXNcwmA1eGiFTwe5rWkuL3DsoviTj73TKLpk7u64ND0XjEfO0huVv4vVu9H1jodrKb7nvln/dlw== + +"@swc/core-linux-x64-gnu@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.2.tgz#314aa76b7c1208e315e3156ab57b7188fb605bc2" + integrity sha512-LFxn9U8cjmYHw3jrdPNqPAkBGglKE3tCZ8rA7hYyp0BFxuo7L2ZcEnPm4RFpmSCCsExFH+LEJWuMGgWERoktvg== + +"@swc/core-linux-x64-musl@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.2.tgz#b2b226657f6a8d48f561cb3dbe2d414cfbafe467" + integrity sha512-dp0fAmreeVVYTUcb4u9njTPrYzKnbIH0EhH2qvC9GOYNNREUu2GezSIDgonjOXkHiTCvopG4xU7y56XtXj4VrQ== + +"@swc/core-win32-arm64-msvc@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.2.tgz#582f79fa328ce0f426ab8313b3d881e7315fab2f" + integrity sha512-HlVIiLMQkzthAdqMslQhDkoXJ5+AOLUSTV6fm6shFKZKqc/9cJvr4S8UveNERL9zUficA36yM3bbfo36McwnvQ== + +"@swc/core-win32-ia32-msvc@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.2.tgz#15c8289e1c18857f79b9b888100ab1f871bf58f6" + integrity sha512-WCF8faPGjCl4oIgugkp+kL9nl3nUATlzKXCEGFowMEmVVCFM0GsqlmGdPp1pjZoWc9tpYanoXQDnp5IvlDSLhA== + +"@swc/core-win32-x64-msvc@1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.2.tgz#c999ca7b68124d058b40a1431cdd6f56779670d5" + integrity sha512-oV71rwiSpA5xre2C5570BhCsg1HF97SNLsZ/12xv7zayGzqr3yvFALFJN8tHKpqUdCB4FGPjoP3JFdV3i+1wUw== + +"@swc/core@^1.3.107": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.4.2.tgz#310b0d5e93e47ca72f54150c8f9efcb434c39b17" + integrity sha512-vWgY07R/eqj1/a0vsRKLI9o9klGZfpLNOVEnrv4nrccxBgYPjcf22IWwAoaBJ+wpA7Q4fVjCUM8lP0m01dpxcg== + dependencies: + "@swc/counter" "^0.1.2" "@swc/types" "^0.1.5" optionalDependencies: - "@swc/core-darwin-arm64" "1.3.102" - "@swc/core-darwin-x64" "1.3.102" - "@swc/core-linux-arm-gnueabihf" "1.3.102" - "@swc/core-linux-arm64-gnu" "1.3.102" - "@swc/core-linux-arm64-musl" "1.3.102" - "@swc/core-linux-x64-gnu" "1.3.102" - "@swc/core-linux-x64-musl" "1.3.102" - "@swc/core-win32-arm64-msvc" "1.3.102" - "@swc/core-win32-ia32-msvc" "1.3.102" - "@swc/core-win32-x64-msvc" "1.3.102" - -"@swc/counter@^0.1.1": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.2.tgz#bf06d0770e47c6f1102270b744e17b934586985e" - integrity sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw== + "@swc/core-darwin-arm64" "1.4.2" + "@swc/core-darwin-x64" "1.4.2" + "@swc/core-linux-arm-gnueabihf" "1.4.2" + "@swc/core-linux-arm64-gnu" "1.4.2" + "@swc/core-linux-arm64-musl" "1.4.2" + "@swc/core-linux-x64-gnu" "1.4.2" + "@swc/core-linux-x64-musl" "1.4.2" + "@swc/core-win32-arm64-msvc" "1.4.2" + "@swc/core-win32-ia32-msvc" "1.4.2" + "@swc/core-win32-x64-msvc" "1.4.2" + +"@swc/counter@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== "@swc/types@^0.1.5": version "0.1.5" @@ -485,20 +501,20 @@ integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A== "@types/semver@^7.5.0": - version "7.5.6" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" - integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== + version "7.5.7" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.7.tgz#326f5fdda70d13580777bcaa1bc6fa772a5aef0e" + integrity sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg== -"@typescript-eslint/eslint-plugin@^6.0.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.17.0.tgz#dfc38f790704ba8a54a1277c51efdb489f6ecf9f" - integrity sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ== +"@typescript-eslint/eslint-plugin@^7.0.1": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.2.tgz#c13a34057be425167cc4a765158c46fdf2fd981d" + integrity sha512-/XtVZJtbaphtdrWjr+CJclaCVGPtOdBpFEnvtNf/jRV0IiEemRrL0qABex/nEt8isYcnFacm3nPHYQwL+Wb7qg== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.17.0" - "@typescript-eslint/type-utils" "6.17.0" - "@typescript-eslint/utils" "6.17.0" - "@typescript-eslint/visitor-keys" "6.17.0" + "@typescript-eslint/scope-manager" "7.0.2" + "@typescript-eslint/type-utils" "7.0.2" + "@typescript-eslint/utils" "7.0.2" + "@typescript-eslint/visitor-keys" "7.0.2" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -506,47 +522,47 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^6.0.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.17.0.tgz#8cd7a0599888ca6056082225b2fdf9a635bf32a1" - integrity sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A== +"@typescript-eslint/parser@^7.0.1": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.0.2.tgz#95c31233d343db1ca1df8df7811b5b87ca7b1a68" + integrity sha512-GdwfDglCxSmU+QTS9vhz2Sop46ebNCXpPPvsByK7hu0rFGRHL+AusKQJ7SoN+LbLh6APFpQwHKmDSwN35Z700Q== dependencies: - "@typescript-eslint/scope-manager" "6.17.0" - "@typescript-eslint/types" "6.17.0" - "@typescript-eslint/typescript-estree" "6.17.0" - "@typescript-eslint/visitor-keys" "6.17.0" + "@typescript-eslint/scope-manager" "7.0.2" + "@typescript-eslint/types" "7.0.2" + "@typescript-eslint/typescript-estree" "7.0.2" + "@typescript-eslint/visitor-keys" "7.0.2" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz#70e6c1334d0d76562dfa61aed9009c140a7601b4" - integrity sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA== +"@typescript-eslint/scope-manager@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz#6ec4cc03752758ddd1fdaae6fbd0ed9a2ca4fe63" + integrity sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g== dependencies: - "@typescript-eslint/types" "6.17.0" - "@typescript-eslint/visitor-keys" "6.17.0" + "@typescript-eslint/types" "7.0.2" + "@typescript-eslint/visitor-keys" "7.0.2" -"@typescript-eslint/type-utils@6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.17.0.tgz#5febad3f523e393006614cbda28b826925b728d5" - integrity sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg== +"@typescript-eslint/type-utils@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.0.2.tgz#a7fc0adff0c202562721357e7478207d380a757b" + integrity sha512-IKKDcFsKAYlk8Rs4wiFfEwJTQlHcdn8CLwLaxwd6zb8HNiMcQIFX9sWax2k4Cjj7l7mGS5N1zl7RCHOVwHq2VQ== dependencies: - "@typescript-eslint/typescript-estree" "6.17.0" - "@typescript-eslint/utils" "6.17.0" + "@typescript-eslint/typescript-estree" "7.0.2" + "@typescript-eslint/utils" "7.0.2" debug "^4.3.4" ts-api-utils "^1.0.1" -"@typescript-eslint/types@6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.17.0.tgz#844a92eb7c527110bf9a7d177e3f22bd5a2f40cb" - integrity sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A== +"@typescript-eslint/types@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.0.2.tgz#b6edd108648028194eb213887d8d43ab5750351c" + integrity sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA== -"@typescript-eslint/typescript-estree@6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz#b913d19886c52d8dc3db856903a36c6c64fd62aa" - integrity sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg== +"@typescript-eslint/typescript-estree@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz#3c6dc8a3b9799f4ef7eca0d224ded01974e4cb39" + integrity sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw== dependencies: - "@typescript-eslint/types" "6.17.0" - "@typescript-eslint/visitor-keys" "6.17.0" + "@typescript-eslint/types" "7.0.2" + "@typescript-eslint/visitor-keys" "7.0.2" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -554,25 +570,25 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.17.0.tgz#f2b16d4c9984474656c420438cdede7eccd4079e" - integrity sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ== +"@typescript-eslint/utils@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.0.2.tgz#8756123054cd934c8ba7db6a6cffbc654b10b5c4" + integrity sha512-PZPIONBIB/X684bhT1XlrkjNZJIEevwkKDsdwfiu1WeqBxYEEdIgVDgm8/bbKHVu+6YOpeRqcfImTdImx/4Bsw== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.17.0" - "@typescript-eslint/types" "6.17.0" - "@typescript-eslint/typescript-estree" "6.17.0" + "@typescript-eslint/scope-manager" "7.0.2" + "@typescript-eslint/types" "7.0.2" + "@typescript-eslint/typescript-estree" "7.0.2" semver "^7.5.4" -"@typescript-eslint/visitor-keys@6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz#3ed043709c39b43ec1e58694f329e0b0430c26b6" - integrity sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg== +"@typescript-eslint/visitor-keys@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz#2899b716053ad7094962beb895d11396fc12afc7" + integrity sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ== dependencies: - "@typescript-eslint/types" "6.17.0" + "@typescript-eslint/types" "7.0.2" eslint-visitor-keys "^3.4.1" "@ungap/structured-clone@^1.2.0": @@ -581,11 +597,11 @@ integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== "@vitejs/plugin-react-swc@^3.3.2": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.5.0.tgz#1fadff5148003e8091168c431e44c850f9a39e74" - integrity sha512-1PrOvAaDpqlCV+Up8RkAh9qaiUjoDUcjtttyhXDKw53XA6Ve16SOp6cCOpRs8Dj8DqUQs6eTW5YkLcLJjrXAig== + version "3.6.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.6.0.tgz#dc9cd1363baf3780f3ad3e0a12a46a3ffe0c7526" + integrity sha512-XFRbsGgpGxGzEV5i5+vRiro1bwcIaZDIdBRP16qwm+jP68ue/S8FJTBEgOeojtVDYrbSua3XFp71kC8VJE6v+g== dependencies: - "@swc/core" "^1.3.96" + "@swc/core" "^1.3.107" acorn-jsx@^5.3.2: version "5.3.2" @@ -816,7 +832,7 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: +debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -863,9 +879,9 @@ eastasianwidth@^0.2.0: integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== electron-to-chromium@^1.4.668: - version "1.4.677" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.677.tgz#49ee77713516740bdde32ac2d1443c444f0dafe7" - integrity sha512-erDa3CaDzwJOpyvfKhOiJjBVNnMM0qxHq47RheVVwsSQrgBA9ZSGV9kdaOfZDPXcHzhG7lBxhj6A7KvfLJBd6Q== + version "1.4.678" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.678.tgz#80d43226a793cf4a689722f9cbdf5d69da32beb0" + integrity sha512-NbdGC2p0O5Q5iVhLEsNBSfytaw7wbEFJlIvaF71wi6QDtLAph5/rVogjyOpf/QggJIt8hNK3KdwNJnc2bzckbw== emoji-regex@^8.0.0: version "8.0.0" @@ -939,7 +955,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.45.0: +eslint@^8.56.0: version "8.56.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15" integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== @@ -1081,9 +1097,9 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.2.9: - version "3.2.9" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" - integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== follow-redirects@^1.15.4: version "1.15.5" @@ -1201,9 +1217,9 @@ hasown@^2.0.0: function-bind "^1.1.2" ignore@^5.2.0, ignore@^5.2.4: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" - integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== import-fresh@^3.2.1: version "3.3.0" @@ -1758,9 +1774,9 @@ scheduler@^0.23.0: loose-envify "^1.1.0" semver@^7.5.4: - version "7.5.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + version "7.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== dependencies: lru-cache "^6.0.0" @@ -1853,6 +1869,11 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +tabbable@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97" + integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== + tailwind-merge@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-2.2.1.tgz#3f10f296a2dba1d88769de8244fafd95c3324aeb" @@ -1915,9 +1936,9 @@ to-regex-range@^5.0.1: is-number "^7.0.0" ts-api-utils@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" - integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== + version "1.2.1" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.2.1.tgz#f716c7e027494629485b21c0df6180f4d08f5e8b" + integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA== ts-interface-checker@^0.1.9: version "0.1.13" @@ -1936,7 +1957,7 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -typescript@^5.0.2: +typescript@^5.3.3: version "5.3.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==