diff --git a/frontend/README.md b/frontend/README.md index ff064cb..6feb62c 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,91 +1,39 @@ -# Helm dashboard V2 +# Helm dashboard React -Welcome to our new project, upgrading helm dashbord, we call it, Helm Dashboard version... 2! 🤩 - -Helm dashboard V2 is an open source effort to modernize the helm-dashboard. -Our goals are to create a version which is more: - -1. Maintable +Welcome to the frontend of the helm dashboard. +We care most about keeping the project: +1. Maintainable 2. Extendable 3. Contributor friendly -## What is helm? - -First thing first, if you are new here please check out these resources to see what helm is all about -[Video](https://www.youtube.com/watch?v=fy8SHvNZGeE) -[Article](https://kruschecompany.com/helm-kubernetes/) - -# Legacy dashboard vs dashboard V2 - -The legacy dashboard found [here](https://github.com/komodorio/helm-dashboard/tree/main/pkg/dashboard/static) is a static webapp and was written vanilla css, jquery, javascript and html. If you inspect the code abit you may notice that its relitvly hard to extend and maintain such a project. - -Our goal with dashboard V2 is to improve the ability to maintain and extend our dashboard app. To achive this we are using a more modern frontend stack. +# The FE Stack - Vite, as our build tool. -- React will be used to make this project more inviting for developers to contribute too. +- React, as our UI library. - TypeScript and ESLint will keep the project safe, please keep them clean. -- Tailwind will be used for styling. -- React-Query will be used to fetch data from the backend. +- Tailwind for styling. +- React-Query for fetching data from the backend. - Storybook is utilized to develop a component library. Please follow through the file structure to understand how things are structured and should be used. # Contribution guide -## Running legacy dashboard - -The legacy dashboard is great for refrence and checking that you have implemented the UI correctly. - -1. Install [helm](https://helm.sh/docs/intro/install/) and [kubectl](https://kubernetes.io/docs/tasks/tools/). -2. `git clone https://github.com/komodorio/helm-dashboard.git`. -3. `go build -o bin/dashboard .` -4. `bin/dashboard` - -The UI should now be running on http://localhost:8080/ -If you're having issues with that please follow the main README in the main folder. -If you still having troubles please contact us on our [Slack community channel](https://join.slack.com/t/komodorkommunity/shared_invite/zt-1lz4cme86-2zIKTRtTFnzL_UNxaUS9yw) - ## Setting up your development environment -1. First you should fork this repositroy. +1. First you should fork this repository. 2. Clone your new repository using `git clone `. -3. Make sure to checkout branch `helm-dashboard-v2`. - - `git fetch` - - `git checkout helm-dashboard-v2` -## Running dashboard V2 +## Running helm dashboard 1. Make sure you cloned the project correctly. This is explained in this [stage](https://github.com/komodorio/helm-dashboard/blob/helm-dashboard-v2/dashboard/README.md#setting-up-your-development-environment). -2. go to `helm-dashboard-v2/dashboard` in your local project. -3. inorder to install dependncies and start the development server +2. run the backend server. This is also explained in the above link. +2. go to `frontend` in your local project. +3. in order to install dependencies and start the development server - `npm i` - `npm run dev` 4. with the default integration the dashboard should run on http://localhost:5173/ -## Setting up a local cluster with ease - -1. Install [Docker](https://docs.docker.com/engine/install/ubuntu/) -2. Install [Minikube](https://minikube.sigs.k8s.io/docs/start/) -3. Start your cluster `minikube start` - -You should now be able to follow the [Helm tutorial](https://helm.sh/docs/intro/quickstart/) and interact with Helm normally. - -## Choosing a task - -If you are completely new to the project its recommended to look for tasks labled: `good first issue`. -These tasks should be simple enough for a begginer or for someone looking to learn the code base. - -You are also free to reachout to us on [Slack](https://join.slack.com/t/komodorkommunity/shared_invite/zt-1lz4cme86-2zIKTRtTFnzL_UNxaUS9yw), we can help you find a task that suits your perfectly. - -## Opening a pull request - -Inorder to open a pull request with your changes. \ - -1. make sure you are synced with `helm-dashboard-v2` and that all conflicts are resolved. \ -2. commit your changes and push to your fork. \ -3. then navigate to https://github.com/komodorio/helm-dashboard and open a pull request. Make sure you are merging from your branch to `helm-dashboard-v2`. \ -4. you should now tag a main developer (@chad11111 - for example) and get your pull request reviewed. # Component library diff --git a/frontend/src/API/apiService.ts b/frontend/src/API/apiService.ts index 4f5af9e..2343d3d 100644 --- a/frontend/src/API/apiService.ts +++ b/frontend/src/API/apiService.ts @@ -116,7 +116,9 @@ class ApiService { }): Promise => { if (!release) return null; - const data = await this.fetchWithDefaults( + const data = await this.fetchWithDefaults< + Promise + >( `/api/helm/releases/${release.namespace}/${release.name}/resources?health=true` ); return data; @@ -129,14 +131,21 @@ class ApiService { if (!params.namespace || !params.chart) return []; - const data = await this.fetchWithDefaults( + const data = await this.fetchWithDefaults( `/api/helm/releases/${params.namespace}/${params.chart}/history` ); return data; }; - getValues = async ({ queryKey }: any) => { + getValues = async ({ + queryKey, + }: { + queryKey: [ + string, + { namespace: string; chart: { name: string }; version: number } + ]; + }) => { const [, params] = queryKey; const { namespace, chart, version } = params; diff --git a/frontend/src/API/interfaces.ts b/frontend/src/API/interfaces.ts index fea99b4..8f2f3a2 100644 --- a/frontend/src/API/interfaces.ts +++ b/frontend/src/API/interfaces.ts @@ -26,7 +26,7 @@ export interface Scanner { export interface ScanResult { scannerType: string; - result: any; + result: string; } export interface ScannersList { diff --git a/frontend/src/API/releases.ts b/frontend/src/API/releases.ts index b010d4f..9160ec7 100644 --- a/frontend/src/API/releases.ts +++ b/frontend/src/API/releases.ts @@ -16,16 +16,43 @@ export function useGetInstalledReleases( ) { return useQuery( ["installedReleases", context], - () => - apiService.fetchWithDefaults("/api/helm/releases", { - headers: { - "X-Kubecontext": context, - }, - }), + () => apiService.fetchWithDefaults("/api/helm/releases"), options ); } +export interface ReleaseManifest { + apiVersion: string; + kind: string; + metadata: { + name: string; + namespace: string; + labels: Record; + }; + spec: { + replicas: number; + selector: Record; + template: { + metadata: { + labels: Record; + }; + spec: { + containers: { + name: string; + image: string; + ports: { + containerPort: number; + }[]; + env: { + name: string; + value: string; + }[]; + }[]; + }; + }; + }; +} + export function useGetReleaseManifest({ namespace, chartName, @@ -33,12 +60,12 @@ export function useGetReleaseManifest({ }: { namespace: string; chartName: string; - options?: UseQueryOptions; + options?: UseQueryOptions; }) { - return useQuery( + return useQuery( ["manifest", namespace, chartName], () => - apiService.fetchWithDefaults( + apiService.fetchWithDefaults( `/api/helm/releases/${namespace}/${chartName}/manifests` ), options @@ -219,12 +246,12 @@ export function useChartReleaseValues({ userDefinedValue?: string; revision?: number; version?: string; - options?: UseQueryOptions; + options?: UseQueryOptions; }) { - return useQuery( + return useQuery( ["values", namespace, release, userDefinedValue, version], () => - apiService.fetchWithDefaults( + apiService.fetchWithDefaults( `/api/helm/releases/${namespace}/${release}/values?${"userDefined=true"}${ revision ? `&revision=${revision}` : "" }`, @@ -253,7 +280,7 @@ export const useVersionData = ({ namespace: string; releaseName: string; isInstallRepoChart?: boolean; - options?: UseQueryOptions; + options?: UseQueryOptions; }) => { return useQuery( [ @@ -287,7 +314,7 @@ export const useVersionData = ({ return data; }, - + // @ts-ignore options ); }; @@ -311,12 +338,12 @@ export interface StructuredResources { export interface Metadata { name: string; namespace: string; - creationTimestamp: any; - labels: any; + creationTimestamp: Date; + labels: string[]; } export interface Spec { - [key: string]: any; + [key: string]: string; } export interface Status { @@ -326,8 +353,8 @@ export interface Status { export interface Condition { type: string; status: string; - lastProbeTime: any; - lastTransitionTime: any; + lastProbeTime: Date; + lastTransitionTime: Date; reason: string; message: string; } diff --git a/frontend/src/API/repositories.ts b/frontend/src/API/repositories.ts index 020962b..c06fd5f 100644 --- a/frontend/src/API/repositories.ts +++ b/frontend/src/API/repositories.ts @@ -56,10 +56,10 @@ export function useChartRepoValues({ version: string; chart: string; }) { - return useQuery( + return useQuery( ["helm", "repositories", "values", chart, version], () => - apiService.fetchWithDefaults( + apiService.fetchWithDefaults( `/api/helm/repositories/values?chart=${chart}&version=${version}`, { headers: { "Content-Type": "text/plain; charset=utf-8" }, diff --git a/frontend/src/API/shared.ts b/frontend/src/API/shared.ts index 71410a3..3c5ee85 100644 --- a/frontend/src/API/shared.ts +++ b/frontend/src/API/shared.ts @@ -40,7 +40,7 @@ export const useDiffData = ({ selectedRepo: string; versionsError: string; currentVerManifest: string; - selectedVerData: any; + selectedVerData: { [key: string]: string }; chart: string; }) => { return useQuery( diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 3014067..d70a708 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -55,7 +55,7 @@ export default function App() { } /> }> - }> + }> } /> ({ + const { data: statusData } = useQuery({ queryKey: ["resourceStatus", release], queryFn: () => apiService.getResourceStatus({ release }), }); @@ -61,10 +59,9 @@ export default function InstalledPackageCard({ const handleOnClick = () => { const { name, namespace } = release; - navigate( - `/${selectedCluster}/${namespace}/${name}/installed/revision/${release.revision}`, - { state: release } - ); + navigate(`/${namespace}/${name}/installed/revision/${release.revision}`, { + state: release, + }); }; const statusColor = getStatusColor(release.status as DeploymentStatus); diff --git a/frontend/src/components/LinkWithSearchParams.tsx b/frontend/src/components/LinkWithSearchParams.tsx index 4291e07..be94730 100644 --- a/frontend/src/components/LinkWithSearchParams.tsx +++ b/frontend/src/components/LinkWithSearchParams.tsx @@ -1,4 +1,5 @@ -import { NavLink, useLocation } from "react-router-dom"; +import { NavLink, useLocation, useParams } from "react-router-dom"; +import { useAppContext } from "../context/AppContext"; const LinkWithSearchParams = ({ to, @@ -11,14 +12,22 @@ const LinkWithSearchParams = ({ children: React.ReactNode; }) => { const { search } = useLocation(); - const params = new URLSearchParams(search); + const { context } = useParams(); + const {clusterMode} = useAppContext(); + const params = new URLSearchParams(search); // For state we don't want to keep while navigating props.exclude?.forEach((key) => { params.delete(key); }); - return ; + let prefixedUrl = to; + + if (!clusterMode) { + prefixedUrl = `/${context}${to}`; + } + + return ; }; export default LinkWithSearchParams; diff --git a/frontend/src/components/modal/AddRepositoryModal.tsx b/frontend/src/components/modal/AddRepositoryModal.tsx index 8714a49..c7ba9c6 100644 --- a/frontend/src/components/modal/AddRepositoryModal.tsx +++ b/frontend/src/components/modal/AddRepositoryModal.tsx @@ -5,7 +5,7 @@ import useAlertError from "../../hooks/useAlertError"; import useCustomSearchParams from "../../hooks/useCustomSearchParams"; import { useAppContext } from "../../context/AppContext"; import { useQueryClient } from "@tanstack/react-query"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; import apiService from "../../API/apiService"; interface FormKeys { @@ -27,7 +27,6 @@ function AddRepositoryModal({ isOpen, onClose }: AddRepositoryModalProps) { const { searchParamsObject } = useCustomSearchParams(); const { repo_url, repo_name } = searchParamsObject; const { setSelectedRepo } = useAppContext(); - const { context } = useParams(); const navigate = useNavigate(); const queryClient = useQueryClient(); @@ -45,10 +44,11 @@ function AddRepositoryModal({ isOpen, onClose }: AddRepositoryModalProps) { setIsLoading(true); - apiService.fetchWithDefaults("/api/helm/repositories", { - method: "POST", - body, - }) + apiService + .fetchWithDefaults("/api/helm/repositories", { + method: "POST", + body, + }) .then(() => { setIsLoading(false); onClose(); @@ -57,7 +57,7 @@ function AddRepositoryModal({ isOpen, onClose }: AddRepositoryModalProps) { queryKey: ["helm", "repositories"], }); setSelectedRepo(formData.name || ""); - navigate(`/${context}/repository/${formData.name}`, { + navigate(`/repository/${formData.name}`, { replace: true, }); }) diff --git a/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx b/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx index 504bc7e..ce34868 100644 --- a/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx +++ b/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx @@ -1,5 +1,4 @@ import { useParams } from "react-router-dom"; -import useAlertError from "../../../hooks/useAlertError"; import { useMemo, useState } from "react"; import { useChartReleaseValues, @@ -19,6 +18,7 @@ import { useChartRepoValues } from "../../../API/repositories"; import { useDiffData } from "../../../API/shared"; import { InstallChartModalProps } from "../../../data/types"; import { DefinedValues } from "./DefinedValues"; +import apiService from "../../../API/apiService"; export const InstallReleaseChartModal = ({ isOpen, @@ -30,7 +30,6 @@ export const InstallReleaseChartModal = ({ latestRevision, }: InstallChartModalProps) => { const navigate = useNavigateWithSearchParams(); - const { setShowErrorModal } = useAlertError(); const [userValues, setUserValues] = useState(); const [installError, setInstallError] = useState(""); @@ -150,35 +149,23 @@ export const InstallReleaseChartModal = ({ formData.append("version", selectedVersion || ""); formData.append("values", userValues || releaseValues || ""); // if userValues is empty, we use the release values - const res = await fetch( - // Todo: Change to BASE_URL from env + const data = await apiService.fetchWithDefaults( `/api/helm/releases/${ namespace ? namespace : "default" }${`/${releaseName}`}`, { method: "post", body: formData, - headers: { - "X-Kubecontext": selectedCluster as string, - }, } ); - - if (!res.ok) { - setShowErrorModal({ - title: "Failed to upgrade the chart", - msg: String(await res.text()), - }); - } - - return res.json(); + return data; }, { onSuccess: async (response) => { onClose(); setSelectedVersionData({ version: "", urls: [] }); //cleanup navigate( - `/${selectedCluster}/${ + `/${ namespace ? namespace : "default" }/${releaseName}/installed/revision/${response.version}` ); diff --git a/frontend/src/components/modal/InstallChartModal/InstallRepoChartModal.tsx b/frontend/src/components/modal/InstallChartModal/InstallRepoChartModal.tsx index e1ef4e6..2ce913f 100644 --- a/frontend/src/components/modal/InstallChartModal/InstallRepoChartModal.tsx +++ b/frontend/src/components/modal/InstallChartModal/InstallRepoChartModal.tsx @@ -1,5 +1,4 @@ import { useParams } from "react-router-dom"; -import useAlertError from "../../../hooks/useAlertError"; import { useMemo, useState } from "react"; import { useGetVersions, useVersionData } from "../../../API/releases"; import Modal, { ModalButtonStyle } from "../Modal"; @@ -13,6 +12,7 @@ import { isNewerVersion, isNoneEmptyArray } from "../../../utils"; import { useDiffData } from "../../../API/shared"; import { InstallChartModalProps } from "../../../data/types"; import { DefinedValues } from "./DefinedValues"; +import apiService from "../../../API/apiService"; export const InstallRepoChartModal = ({ isOpen, @@ -22,7 +22,6 @@ export const InstallRepoChartModal = ({ latestVersion, }: InstallChartModalProps) => { const navigate = useNavigateWithSearchParams(); - const { setShowErrorModal } = useAlertError(); const [userValues, setUserValues] = useState(""); const [installError, setInstallError] = useState(""); @@ -130,32 +129,20 @@ export const InstallRepoChartModal = ({ formData.append("version", selectedVersion || ""); formData.append("values", userValues); formData.append("name", releaseName || ""); - const res = await fetch( - // Todo: Change to BASE_URL from env + const data = await apiService.fetchWithDefaults( `/api/helm/releases/${namespace ? namespace : "default"}`, { method: "post", body: formData, - headers: { - "X-Kubecontext": selectedCluster as string, - }, } ); - - if (!res.ok) { - setShowErrorModal({ - title: "Failed to install the chart", - msg: String(await res.text()), - }); - } - - return res.json(); + return data; }, { onSuccess: async (response) => { onClose(); navigate( - `/${selectedCluster}/${response.namespace}/${response.name}/installed/revision/1` + `/${response.namespace}/${response.name}/installed/revision/1` ); }, onError: (error) => { diff --git a/frontend/src/components/repository/RepositoryViewer.tsx b/frontend/src/components/repository/RepositoryViewer.tsx index 03ddff6..71586b9 100644 --- a/frontend/src/components/repository/RepositoryViewer.tsx +++ b/frontend/src/components/repository/RepositoryViewer.tsx @@ -6,7 +6,7 @@ import apiService from "../../API/apiService"; import Spinner from "../Spinner"; import { useUpdateRepo } from "../../API/repositories"; import { useEffect, useMemo, useState } from "react"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; import { useAppContext } from "../../context/AppContext"; type RepositoryViewerProps = { @@ -16,7 +16,6 @@ type RepositoryViewerProps = { function RepositoryViewer({ repository }: RepositoryViewerProps) { const [searchValue, setSearchValue] = useState(""); const [isRemoveLoading, setIsRemove] = useState(false); - const { context } = useParams(); const { setSelectedRepo, selectedRepo } = useAppContext(); const queryClient = useQueryClient(); @@ -54,7 +53,7 @@ function RepositoryViewer({ repository }: RepositoryViewerProps) { method: "DELETE", } ); - navigate(`/${context}/repository`, { replace: true }); + navigate("/repository", { replace: true }); setSelectedRepo(""); queryClient.invalidateQueries({ queryKey: ["helm", "repositories"], diff --git a/frontend/src/components/revision/RevisionDetails.tsx b/frontend/src/components/revision/RevisionDetails.tsx index 824f128..f249133 100644 --- a/frontend/src/components/revision/RevisionDetails.tsx +++ b/frontend/src/components/revision/RevisionDetails.tsx @@ -23,7 +23,7 @@ import { import RevisionDiff from "./RevisionDiff"; import RevisionResource from "./RevisionResource"; import Tabs from "../Tabs"; -import { useMutation } from "@tanstack/react-query"; +import { type UseQueryResult, useMutation } from "@tanstack/react-query"; import Modal, { ModalButtonStyle } from "../modal/Modal"; import Spinner from "../Spinner"; import useAlertError from "../../hooks/useAlertError"; @@ -125,10 +125,10 @@ export default function RevisionDetails({ ns: namespace, name: chart, }); - } catch (error: any) { + } catch (error: unknown) { setShowErrorModal({ title: "Test failed to run", - msg: error.message, + msg: (error as Error).message, }); } setShowTestResults(true); @@ -207,7 +207,7 @@ export default function RevisionDetails({ { navigate( - `/${context}/repository?add_repo=true&repo_url=${latestVerData[0].urls[0]}&repo_name=${latestVerData[0].repository}` + `/repository?add_repo=true&repo_url=${latestVerData[0].urls[0]}&repo_name=${latestVerData[0].repository}` ); }} className="underline text-sm cursor-pointer text-blue-600" @@ -320,7 +320,7 @@ const Rollback = ({ release: Release; installedRevision: ReleaseRevision; }) => { - const { chart, namespace, revision, context } = useParams(); + const { chart, namespace, revision } = useParams(); const navigate = useNavigateWithSearchParams(); const [showRollbackDiff, setShowRollbackDiff] = useState(false); @@ -330,9 +330,7 @@ const Rollback = ({ useRollbackRelease({ onSuccess: () => { navigate( - `/${context}/${namespace}/${chart}/installed/revision/${ - revisionInt + 1 - }` + `/${namespace}/${chart}/installed/revision/${revisionInt + 1}` ); window.location.reload(); }, @@ -398,7 +396,11 @@ const Rollback = ({ ); }; - const RollbackModalContent = ({ dataResponse }: { dataResponse: any }) => { + const RollbackModalContent = ({ + dataResponse, + }: { + dataResponse: UseQueryResult; + }) => { const { data, isLoading, diff --git a/frontend/src/components/revision/RevisionsList.tsx b/frontend/src/components/revision/RevisionsList.tsx index c90b927..a0c9bfe 100644 --- a/frontend/src/components/revision/RevisionsList.tsx +++ b/frontend/src/components/revision/RevisionsList.tsx @@ -18,10 +18,11 @@ export default function RevisionsList({ selectedRevision, }: RevisionsListProps) { const navigate = useNavigateWithSearchParams(); - const { context, namespace, chart } = useParams(); + const { namespace, chart } = useParams(); + const changeRelease = (newRevision: number) => { navigate( - `/${context}/${namespace}/${chart}/installed/revision/${newRevision}` + `/${namespace}/${chart}/installed/revision/${newRevision}` ); }; diff --git a/frontend/src/hooks/useNavigateWithSearchParams.ts b/frontend/src/hooks/useNavigateWithSearchParams.ts index 597040a..32b624e 100644 --- a/frontend/src/hooks/useNavigateWithSearchParams.ts +++ b/frontend/src/hooks/useNavigateWithSearchParams.ts @@ -1,10 +1,27 @@ -import { useLocation, useNavigate } from "react-router-dom"; +import { + type NavigateOptions, + useLocation, + useNavigate, + useParams, +} from "react-router-dom"; +import { useAppContext } from "../context/AppContext"; const useNavigateWithSearchParams = () => { const navigate = useNavigate(); + const { clusterMode } = useAppContext(); + const { context } = useParams(); + const { search } = useLocation(); - const navigateWithSearchParams = (url: string, ...restArgs: any[]) => { - navigate(url + search, ...restArgs); + const navigateWithSearchParams = ( + url: string, + ...restArgs: NavigateOptions[] + ) => { + let prefixedUrl = url; + + if (!clusterMode) { + prefixedUrl = `/${context}${url}`; + } + navigate(`${prefixedUrl}${search}`, ...restArgs); }; return navigateWithSearchParams; diff --git a/frontend/src/layout/Header.tsx b/frontend/src/layout/Header.tsx index e95ba5d..cc0d50d 100644 --- a/frontend/src/layout/Header.tsx +++ b/frontend/src/layout/Header.tsx @@ -1,4 +1,4 @@ -import { useLocation, useParams } from "react-router-dom"; +import { useLocation } from "react-router-dom"; import LogoHeader from "../assets/logo-header.svg"; import DropDown from "../components/common/DropDown"; import WatcherIcon from "../assets/k8s-watcher.svg"; @@ -22,7 +22,7 @@ export default function Header() { setClusterMode(data.ClusterMode); }, }); - const { context } = useParams(); + const location = useLocation(); const openSupportChat = () => { @@ -58,7 +58,7 @@ export default function Header() { return (
- + helm dashboard logo
  • @@ -79,7 +79,7 @@ export default function Header() {
  • { - navigate(`/${context}/repository/${selectedRepository.name}`, { + navigate(`/repository/${selectedRepository.name}`, { replace: true, }); }; @@ -28,7 +28,7 @@ function RepositoryPage() { useEffect(() => { if (selectedRepo && !repoFromParams) { - navigate(`/${context}/repository/${selectedRepo}`, { + navigate(`/repository/${selectedRepo}`, { replace: true, }); } diff --git a/frontend/yarn.lock b/frontend/yarn.lock index d4d05dc..72c14bb 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1461,10 +1461,10 @@ resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz" integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== -"@esbuild/darwin-arm64@0.17.19": +"@esbuild/darwin-x64@0.17.19": version "0.17.19" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz" - integrity sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg== + resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz" + integrity sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" @@ -5621,6 +5621,10 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== function-bind@^1.1.1: version "1.1.1"