mirror of
https://github.com/formbricks/formbricks.git
synced 2026-02-05 06:10:34 -06:00
Check for unsaved changes in Survey Editor before changing pages (#409)
* fix: remove environmentsNavbar on survey editor * objects deep comparision utility function * feat: confirm on window reload or close * feat: confirm save on back * feat: custom alert dialog * remove radixui alert dialog * replaced shadcn alert with new custom alert dialog * fix: save button varient to darkCTA * fix: moved beforeunload logic to surveymenubar * fix: remove deepequal function * installed lodash * fix: survey not comparing on change * fix: isqual import
This commit is contained in:
@@ -211,6 +211,8 @@ export default function EnvironmentsNavbar({ environmentId, session }: Environme
|
||||
return <ErrorComponent />;
|
||||
}
|
||||
|
||||
if (pathname?.includes("/edit")) return null;
|
||||
|
||||
return (
|
||||
<nav className="top-0 z-10 w-full border-b border-slate-200 bg-white">
|
||||
{environment?.type === "development" && (
|
||||
|
||||
@@ -37,6 +37,7 @@ export default function SurveyEditor({ environmentId, surveyId }: SurveyEditorPr
|
||||
}
|
||||
}, [survey]);
|
||||
|
||||
|
||||
if (isLoadingSurvey || isLoadingProduct || !localSurvey) {
|
||||
return <LoadingSpinner />;
|
||||
}
|
||||
@@ -50,6 +51,7 @@ export default function SurveyEditor({ environmentId, surveyId }: SurveyEditorPr
|
||||
<SurveyMenuBar
|
||||
setLocalSurvey={setLocalSurvey}
|
||||
localSurvey={localSurvey}
|
||||
survey={survey}
|
||||
environmentId={environmentId}
|
||||
activeId={activeView}
|
||||
setActiveId={setActiveView}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import AlertDialog from "@/components/shared/AlertDialog";
|
||||
import DeleteDialog from "@/components/shared/DeleteDialog";
|
||||
import SurveyStatusDropdown from "@/components/shared/SurveyStatusDropdown";
|
||||
import { useProduct } from "@/lib/products/products";
|
||||
@@ -11,9 +12,11 @@ import { ArrowLeftIcon, Cog8ToothIcon, ExclamationTriangleIcon } from "@heroicon
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
interface SurveyMenuBarProps {
|
||||
localSurvey: Survey;
|
||||
survey: Survey;
|
||||
setLocalSurvey: (survey: Survey) => void;
|
||||
environmentId: string;
|
||||
activeId: "questions" | "settings";
|
||||
@@ -22,6 +25,7 @@ interface SurveyMenuBarProps {
|
||||
|
||||
export default function SurveyMenuBar({
|
||||
localSurvey,
|
||||
survey,
|
||||
environmentId,
|
||||
setLocalSurvey,
|
||||
activeId,
|
||||
@@ -31,6 +35,7 @@ export default function SurveyMenuBar({
|
||||
const { triggerSurveyMutate, isMutatingSurvey } = useSurveyMutation(environmentId, localSurvey.id);
|
||||
const [audiencePrompt, setAudiencePrompt] = useState(true);
|
||||
const [isDeleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
const [isConfirmDialogOpen, setConfirmDialogOpen] = useState(false);
|
||||
const { product } = useProduct(environmentId);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -39,6 +44,21 @@ export default function SurveyMenuBar({
|
||||
}
|
||||
}, [activeId, audiencePrompt]);
|
||||
|
||||
useEffect(() => {
|
||||
const warningText = "You have unsaved changes - are you sure you wish to leave this page?";
|
||||
const handleWindowClose = (e: BeforeUnloadEvent) => {
|
||||
if(!isEqual(localSurvey, survey)){
|
||||
e.preventDefault();
|
||||
return e.returnValue = warningText
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("beforeunload", handleWindowClose);
|
||||
return () => {
|
||||
window.removeEventListener("beforeunload", handleWindowClose);
|
||||
};
|
||||
}, [localSurvey, survey]);
|
||||
|
||||
// write a function which updates the local survey status
|
||||
const updateLocalSurveyStatus = (status: Survey["status"]) => {
|
||||
const updatedSurvey = { ...localSurvey, status };
|
||||
@@ -58,6 +78,8 @@ export default function SurveyMenuBar({
|
||||
const handleBack = () => {
|
||||
if (localSurvey.createdAt === localSurvey.updatedAt && localSurvey.status === "draft") {
|
||||
setDeleteDialogOpen(true);
|
||||
} else if (!isEqual(localSurvey, survey)) {
|
||||
setConfirmDialogOpen(true);
|
||||
} else {
|
||||
router.back();
|
||||
}
|
||||
@@ -165,6 +187,18 @@ export default function SurveyMenuBar({
|
||||
useSaveInsteadOfCancel={true}
|
||||
onSave={() => saveSurveyAction(true)}
|
||||
/>
|
||||
<AlertDialog
|
||||
confirmWhat="Survey changes"
|
||||
open={isConfirmDialogOpen}
|
||||
setOpen={setConfirmDialogOpen}
|
||||
onDiscard={() => {
|
||||
setConfirmDialogOpen(false);
|
||||
router.back();
|
||||
}}
|
||||
text="You have unsaved changes in your survey. Would you like to save them before leaving?"
|
||||
useSaveInsteadOfCancel={true}
|
||||
onSave={() => saveSurveyAction(true)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,150 +1,45 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
||||
import Modal from "@/components/shared/Modal";
|
||||
import { Button } from "@formbricks/ui";
|
||||
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
|
||||
const AlertDialog: React.ComponentType<AlertDialogPrimitive.AlertDialogContentProps> =
|
||||
AlertDialogPrimitive.Root;
|
||||
|
||||
const AlertDialogTrigger: React.ComponentType<AlertDialogPrimitive.AlertDialogTriggerProps> =
|
||||
AlertDialogPrimitive.Trigger;
|
||||
|
||||
const AlertDialogPortal = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: AlertDialogPrimitive.AlertDialogPortalProps) => (
|
||||
<AlertDialogPrimitive.Portal className={cn(className)} {...props}>
|
||||
<div className="fixed inset-0 z-50 flex items-end justify-center sm:items-center">{children}</div>
|
||||
</AlertDialogPrimitive.Portal>
|
||||
);
|
||||
AlertDialogPortal.displayName = AlertDialogPrimitive.Portal.displayName;
|
||||
|
||||
const AlertDialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Overlay
|
||||
className={cn(
|
||||
"animate-in fade-in fixed inset-0 z-50 bg-black/50 backdrop-blur-sm transition-opacity",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
));
|
||||
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
|
||||
|
||||
const AlertDialogContent: React.ComponentType<AlertDialogPrimitive.AlertDialogContentProps> =
|
||||
React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPortal>
|
||||
<AlertDialogOverlay />
|
||||
<AlertDialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"animate-in fade-in-90 slide-in-from-bottom-10 sm:zoom-in-90 sm:slide-in-from-bottom-0 fixed z-50 grid w-full max-w-lg scale-100 gap-4 bg-white p-6 opacity-100 sm:rounded-lg md:w-full",
|
||||
"dark:bg-slate-900",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</AlertDialogPortal>
|
||||
));
|
||||
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
|
||||
|
||||
interface AlertDialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
dangerouslySetInnerHTML?: {
|
||||
__html: string;
|
||||
};
|
||||
interface AlertDialogProps {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
confirmWhat: string;
|
||||
onDiscard: () => void;
|
||||
text?: string;
|
||||
useSaveInsteadOfCancel?: boolean;
|
||||
onSave?: () => void;
|
||||
}
|
||||
|
||||
const AlertDialogHeader = ({ className, ...props }: AlertDialogHeaderProps) => (
|
||||
<div className={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...props} />
|
||||
);
|
||||
AlertDialogHeader.displayName = "AlertDialogHeader";
|
||||
|
||||
interface AlertDialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
dangerouslySetInnerHTML?: {
|
||||
__html: string;
|
||||
};
|
||||
export default function AlertDialog({
|
||||
open,
|
||||
setOpen,
|
||||
confirmWhat,
|
||||
onDiscard,
|
||||
text,
|
||||
useSaveInsteadOfCancel = false,
|
||||
onSave,
|
||||
}: AlertDialogProps) {
|
||||
return (
|
||||
<Modal open={open} setOpen={setOpen} title={`Confirm ${confirmWhat}`}>
|
||||
<p>{text || "Are you sure? This action cannot be undone."}</p>
|
||||
<div className="my-4 space-x-2 text-right">
|
||||
<Button variant="warn" onClick={onDiscard}>
|
||||
Discard
|
||||
</Button>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
onClick={() => {
|
||||
if (useSaveInsteadOfCancel && onSave) {
|
||||
onSave();
|
||||
}
|
||||
setOpen(false);
|
||||
}}>
|
||||
{useSaveInsteadOfCancel ? "Save" : "Cancel"}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const AlertDialogFooter = ({ className, ...props }: AlertDialogFooterProps) => (
|
||||
<div
|
||||
className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
AlertDialogFooter.displayName = "AlertDialogFooter";
|
||||
|
||||
const AlertDialogTitle: React.ComponentType<AlertDialogPrimitive.AlertDialogTitleProps> = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold text-slate-900", "dark:text-slate-50", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
|
||||
|
||||
const AlertDialogDescription: React.ComponentType<AlertDialogPrimitive.AlertDialogDescriptionProps> =
|
||||
React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-slate-500", "dark:text-slate-400", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
|
||||
|
||||
const AlertDialogAction: React.ComponentType<AlertDialogPrimitive.AlertDialogActionProps> = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Action
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-10 items-center justify-center rounded-md bg-slate-900 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-slate-700 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
|
||||
|
||||
const AlertDialogCancel: React.ComponentType<AlertDialogPrimitive.AlertDialogCancelProps> = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Cancel
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"mt-2 inline-flex h-10 items-center justify-center rounded-md border border-slate-200 bg-transparent px-4 py-2 text-sm font-semibold text-slate-900 transition-colors hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:text-slate-100 dark:hover:bg-slate-700 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900 sm:mt-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
|
||||
|
||||
export {
|
||||
AlertDialog,
|
||||
AlertDialogTrigger,
|
||||
AlertDialogContent,
|
||||
AlertDialogHeader,
|
||||
AlertDialogFooter,
|
||||
AlertDialogTitle,
|
||||
AlertDialogDescription,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
};
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"@heroicons/react": "^2.0.18",
|
||||
"@json2csv/node": "^7.0.1",
|
||||
"@paralleldrive/cuid2": "^2.2.0",
|
||||
"@radix-ui/react-alert-dialog": "^1.0.3",
|
||||
"@radix-ui/react-collapsible": "^1.0.2",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.4",
|
||||
"@types/node": "20.2.3",
|
||||
@@ -31,6 +30,7 @@
|
||||
"eslint": "8.41.0",
|
||||
"eslint-config-next": "^13.4.3",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.221.0",
|
||||
"markdown-it": "^13.0.1",
|
||||
"next": "13.4.3",
|
||||
@@ -60,6 +60,7 @@
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"@types/lodash": "^4.14.195",
|
||||
"@types/markdown-it": "^12.2.3",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint-config-formbricks": "workspace:*",
|
||||
|
||||
71
pnpm-lock.yaml
generated
71
pnpm-lock.yaml
generated
@@ -220,9 +220,6 @@ importers:
|
||||
'@paralleldrive/cuid2':
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0
|
||||
'@radix-ui/react-alert-dialog':
|
||||
specifier: ^1.0.3
|
||||
version: 1.0.3(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-collapsible':
|
||||
specifier: ^1.0.2
|
||||
version: 1.0.2(react-dom@18.2.0)(react@18.2.0)
|
||||
@@ -259,6 +256,9 @@ importers:
|
||||
jsonwebtoken:
|
||||
specifier: ^9.0.0
|
||||
version: 9.0.0
|
||||
lodash:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
lucide-react:
|
||||
specifier: ^0.221.0
|
||||
version: 0.221.0(react@18.2.0)
|
||||
@@ -341,6 +341,9 @@ importers:
|
||||
'@types/bcryptjs':
|
||||
specifier: ^2.4.2
|
||||
version: 2.4.2
|
||||
'@types/lodash':
|
||||
specifier: ^4.14.195
|
||||
version: 4.14.195
|
||||
'@types/markdown-it':
|
||||
specifier: ^12.2.3
|
||||
version: 12.2.3
|
||||
@@ -496,7 +499,7 @@ importers:
|
||||
version: 8.8.0(eslint@8.41.0)
|
||||
eslint-config-turbo:
|
||||
specifier: latest
|
||||
version: 1.8.8(eslint@8.41.0)
|
||||
version: 1.10.3(eslint@8.41.0)
|
||||
eslint-plugin-react:
|
||||
specifier: 7.32.2
|
||||
version: 7.32.2(eslint@8.41.0)
|
||||
@@ -4438,25 +4441,6 @@ packages:
|
||||
'@babel/runtime': 7.21.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-alert-dialog@1.0.3(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-QXFy7+bhGi0u+paF2QbJeSCHZs4gLMJIPm6sajUamyW0fro6g1CaSGc5zmc4QmK2NlSGUrq8m+UsUqJYtzvXow==}
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.21.0
|
||||
'@radix-ui/primitive': 1.0.0
|
||||
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.0(react@18.2.0)
|
||||
'@radix-ui/react-dialog': 1.0.3(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-primitive': 1.0.2(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-slot': 1.0.1(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-arrow@1.0.2(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-fqYwhhI9IarZ0ll2cUSfKuXHlJK0qE4AfnRrPBbRwEH/4mGQn04/QFGomLi8TXWIdv9WJk//KgGm+aDxVIr1wA==}
|
||||
peerDependencies:
|
||||
@@ -4622,33 +4606,6 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-dialog@1.0.3(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-owNhq36kNPqC2/a+zJRioPg6HHnTn5B/sh/NjTY8r4W9g1L5VJlrzZIVcBr7R9Mg8iLjVmh6MGgMlfoVf/WO/A==}
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.21.0
|
||||
'@radix-ui/primitive': 1.0.0
|
||||
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.0(react@18.2.0)
|
||||
'@radix-ui/react-dismissable-layer': 1.0.3(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-focus-guards': 1.0.0(react@18.2.0)
|
||||
'@radix-ui/react-focus-scope': 1.0.2(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-id': 1.0.0(react@18.2.0)
|
||||
'@radix-ui/react-portal': 1.0.2(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-presence': 1.0.0(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-primitive': 1.0.2(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-slot': 1.0.1(react@18.2.0)
|
||||
'@radix-ui/react-use-controllable-state': 1.0.0(react@18.2.0)
|
||||
aria-hidden: 1.2.3
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
react-remove-scroll: 2.5.5(@types/react@18.2.7)(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-direction@1.0.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==}
|
||||
peerDependencies:
|
||||
@@ -5950,6 +5907,10 @@ packages:
|
||||
resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==}
|
||||
dev: true
|
||||
|
||||
/@types/lodash@4.14.195:
|
||||
resolution: {integrity: sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==}
|
||||
dev: true
|
||||
|
||||
/@types/markdown-it@12.2.3:
|
||||
resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==}
|
||||
dependencies:
|
||||
@@ -10350,13 +10311,13 @@ packages:
|
||||
eslint: 8.41.0
|
||||
dev: false
|
||||
|
||||
/eslint-config-turbo@1.8.8(eslint@8.41.0):
|
||||
resolution: {integrity: sha512-+yT22sHOT5iC1sbBXfLIdXfbZuiv9bAyOXsxTxFCWelTeFFnANqmuKB3x274CFvf7WRuZ/vYP/VMjzU9xnFnxA==}
|
||||
/eslint-config-turbo@1.10.3(eslint@8.41.0):
|
||||
resolution: {integrity: sha512-ggzPfTJfMsMS383oZ4zfTP1zQvyMyiigOQJRUnLt1nqII6SKkTzdKZdwmXRDHU24KFwUfEFtT6c8vnm2VhL0uQ==}
|
||||
peerDependencies:
|
||||
eslint: '>6.6.0'
|
||||
dependencies:
|
||||
eslint: 8.41.0
|
||||
eslint-plugin-turbo: 1.8.8(eslint@8.41.0)
|
||||
eslint-plugin-turbo: 1.10.3(eslint@8.41.0)
|
||||
dev: false
|
||||
|
||||
/eslint-import-resolver-node@0.3.6:
|
||||
@@ -10575,8 +10536,8 @@ packages:
|
||||
string.prototype.matchall: 4.0.8
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-turbo@1.8.8(eslint@8.41.0):
|
||||
resolution: {integrity: sha512-zqyTIvveOY4YU5jviDWw9GXHd4RiKmfEgwsjBrV/a965w0PpDwJgEUoSMB/C/dU310Sv9mF3DSdEjxjJLaw6rA==}
|
||||
/eslint-plugin-turbo@1.10.3(eslint@8.41.0):
|
||||
resolution: {integrity: sha512-g3Mnnk7el1FqxHfqbE/MayLvCsYjA/vKmAnUj66kV4AlM7p/EZqdt42NMcMSKtDVEm0w+utQkkzWG2Xsa0Pd/g==}
|
||||
peerDependencies:
|
||||
eslint: '>6.6.0'
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user