重写ssh前端组件,通用化
This commit is contained in:
parent
b8412314a8
commit
7309d05bcb
@ -5,6 +5,16 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogTitle,
|
||||||
|
} from '@/components/ui/alert-dialog';
|
||||||
import { ChevronRight, Folder, File, Home, ArrowLeft, Plus, Trash2, RefreshCw, Link } from 'lucide-react';
|
import { ChevronRight, Folder, File, Home, ArrowLeft, Plus, Trash2, RefreshCw, Link } from 'lucide-react';
|
||||||
import { browseDirectory, createDirectory, removeFile, pathUtils, type RemoteFileInfo } from '@/services/fileService';
|
import { browseDirectory, createDirectory, removeFile, pathUtils, type RemoteFileInfo } from '@/services/fileService';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
@ -20,6 +30,8 @@ export const ServerFilePanel: React.FC<ServerFilePanelProps> = ({
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [showNewFolder, setShowNewFolder] = useState(false);
|
const [showNewFolder, setShowNewFolder] = useState(false);
|
||||||
const [newFolderName, setNewFolderName] = useState('');
|
const [newFolderName, setNewFolderName] = useState('');
|
||||||
|
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
|
||||||
|
const [pendingDeleteFile, setPendingDeleteFile] = useState<RemoteFileInfo | null>(null);
|
||||||
|
|
||||||
// 加载文件列表
|
// 加载文件列表
|
||||||
const loadFiles = async () => {
|
const loadFiles = async () => {
|
||||||
@ -81,24 +93,34 @@ export const ServerFilePanel: React.FC<ServerFilePanelProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除文件/目录
|
// 请求删除文件/目录(弹出确认框)
|
||||||
const handleDelete = async (file: RemoteFileInfo) => {
|
const handleDelete = (file: RemoteFileInfo) => {
|
||||||
const confirmed = window.confirm(
|
setPendingDeleteFile(file);
|
||||||
file.isDirectory
|
setDeleteConfirmOpen(true);
|
||||||
? `确定删除目录 "${file.name}" 及其所有内容吗?`
|
};
|
||||||
: `确定删除文件 "${file.name}" 吗?`
|
|
||||||
);
|
// 确认删除
|
||||||
if (!confirmed) return;
|
const handleConfirmDelete = async () => {
|
||||||
|
setDeleteConfirmOpen(false);
|
||||||
|
if (!pendingDeleteFile) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await removeFile(serverId, file.path, file.isDirectory);
|
await removeFile(serverId, pendingDeleteFile.path, pendingDeleteFile.isDirectory);
|
||||||
message.success('删除成功');
|
message.success('删除成功');
|
||||||
loadFiles();
|
loadFiles();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error(error.response?.data?.message || '删除失败');
|
message.error(error.response?.data?.message || '删除失败');
|
||||||
|
} finally {
|
||||||
|
setPendingDeleteFile(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 取消删除
|
||||||
|
const handleCancelDelete = () => {
|
||||||
|
setDeleteConfirmOpen(false);
|
||||||
|
setPendingDeleteFile(null);
|
||||||
|
};
|
||||||
|
|
||||||
// 面包屑导航
|
// 面包屑导航
|
||||||
const breadcrumbs = currentPath.split('/').filter(Boolean);
|
const breadcrumbs = currentPath.split('/').filter(Boolean);
|
||||||
|
|
||||||
@ -299,6 +321,36 @@ export const ServerFilePanel: React.FC<ServerFilePanelProps> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 删除确认对话框 */}
|
||||||
|
<AlertDialog open={deleteConfirmOpen} onOpenChange={setDeleteConfirmOpen}>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>确认删除</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
{pendingDeleteFile?.isDirectory ? (
|
||||||
|
<>
|
||||||
|
确定删除目录 <span className="font-semibold text-foreground">"{pendingDeleteFile.name}"</span> 及其所有内容吗?
|
||||||
|
<br />
|
||||||
|
<span className="text-red-600">此操作不可恢复!</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
确定删除文件 <span className="font-semibold text-foreground">"{pendingDeleteFile?.name}"</span> 吗?
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel onClick={handleCancelDelete}>
|
||||||
|
取消
|
||||||
|
</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={handleConfirmDelete} className="bg-red-600 hover:bg-red-700">
|
||||||
|
删除
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,8 +4,18 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Progress } from '@/components/ui/progress';
|
import { Progress } from '@/components/ui/progress';
|
||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogTitle,
|
||||||
|
} from '@/components/ui/alert-dialog';
|
||||||
import { Upload, X, File as FileIcon, CheckCircle, AlertCircle } from 'lucide-react';
|
import { Upload, X, File as FileIcon, CheckCircle, AlertCircle } from 'lucide-react';
|
||||||
import { submitAsyncUpload, getUploadTaskStatus, cancelUploadTask, pathUtils } from '@/services/fileService';
|
import { submitAsyncUpload, getUploadTaskStatus, cancelUploadTask, pathUtils, browseDirectory } from '@/services/fileService';
|
||||||
import type { UploadTaskStatus } from '@/services/fileService';
|
import type { UploadTaskStatus } from '@/services/fileService';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import type { UploadPanelProps } from './types';
|
import type { UploadPanelProps } from './types';
|
||||||
@ -27,6 +37,11 @@ export const UploadPanel: React.FC<UploadPanelProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [uploadFiles, setUploadFiles] = useState<UploadFileItem[]>([]);
|
const [uploadFiles, setUploadFiles] = useState<UploadFileItem[]>([]);
|
||||||
const [isDragging, setIsDragging] = useState(false);
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
|
const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
|
||||||
|
const [pendingOverwriteItem, setPendingOverwriteItem] = useState<UploadFileItem | null>(null);
|
||||||
|
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
|
||||||
|
const [pendingDeleteId, setPendingDeleteId] = useState<string | null>(null);
|
||||||
|
const [clearConfirmOpen, setClearConfirmOpen] = useState(false);
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
const pollIntervalsRef = useRef<Map<string, NodeJS.Timeout>>(new Map()); // 保存所有轮询定时器
|
const pollIntervalsRef = useRef<Map<string, NodeJS.Timeout>>(new Map()); // 保存所有轮询定时器
|
||||||
|
|
||||||
@ -61,22 +76,82 @@ export const UploadPanel: React.FC<UploadPanelProps> = ({
|
|||||||
setUploadFiles(prev => [...prev, ...newFiles]);
|
setUploadFiles(prev => [...prev, ...newFiles]);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 从列表移除文件
|
// 请求删除文件(弹出确认框)
|
||||||
const removeFile = (id: string) => {
|
const requestRemoveFile = (id: string) => {
|
||||||
|
const item = uploadFiles.find(f => f.id === id);
|
||||||
|
// 正在上传的需要确认
|
||||||
|
if (item?.status === 'uploading') {
|
||||||
|
setPendingDeleteId(id);
|
||||||
|
setDeleteConfirmOpen(true);
|
||||||
|
} else {
|
||||||
|
// 其他状态直接删除
|
||||||
|
doRemoveFile(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 实际执行删除文件或取消上传
|
||||||
|
const doRemoveFile = async (id: string) => {
|
||||||
|
const item = uploadFiles.find(f => f.id === id);
|
||||||
|
|
||||||
|
// 如果正在上传,先取消任务
|
||||||
|
if (item?.status === 'uploading' && item.taskId) {
|
||||||
|
try {
|
||||||
|
await cancelUploadTask(serverId, item.taskId);
|
||||||
|
message.success('上传已取消');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('取消上传失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 停止轮询
|
// 停止轮询
|
||||||
const interval = pollIntervalsRef.current.get(id);
|
const interval = pollIntervalsRef.current.get(id);
|
||||||
if (interval) {
|
if (interval) {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
pollIntervalsRef.current.delete(id);
|
pollIntervalsRef.current.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移除文件
|
// 移除文件
|
||||||
setUploadFiles(prev => prev.filter(f => f.id !== id));
|
setUploadFiles(prev => prev.filter(f => f.id !== id));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 确认删除
|
||||||
|
const handleConfirmDelete = async () => {
|
||||||
|
setDeleteConfirmOpen(false);
|
||||||
|
if (pendingDeleteId) {
|
||||||
|
await doRemoveFile(pendingDeleteId);
|
||||||
|
setPendingDeleteId(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消删除
|
||||||
|
const handleCancelDelete = () => {
|
||||||
|
setDeleteConfirmOpen(false);
|
||||||
|
setPendingDeleteId(null);
|
||||||
|
};
|
||||||
|
|
||||||
// 上传单个文件(异步上传+轮询)
|
// 上传单个文件(异步上传+轮询)
|
||||||
const uploadSingleFile = async (item: UploadFileItem) => {
|
const uploadSingleFile = async (item: UploadFileItem, overwrite: boolean = false, skipCheck: boolean = false) => {
|
||||||
const remotePath = pathUtils.join(currentPath, item.file.name);
|
const remotePath = pathUtils.join(currentPath, item.file.name);
|
||||||
|
|
||||||
|
// 如果不是覆盖模式且未跳过检查,先检查文件是否已存在
|
||||||
|
if (!overwrite && !skipCheck) {
|
||||||
|
try {
|
||||||
|
// 使用browseDirectory API检查文件是否存在
|
||||||
|
const files = await browseDirectory(serverId, currentPath);
|
||||||
|
const fileExists = files.some(f => f.name === item.file.name && !f.isDirectory);
|
||||||
|
|
||||||
|
if (fileExists) {
|
||||||
|
// 文件已存在,弹出确认对话框
|
||||||
|
setPendingOverwriteItem(item);
|
||||||
|
setConfirmDialogOpen(true);
|
||||||
|
return; // 暂停上传,等待用户决定
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('检查文件是否存在时出错:', error);
|
||||||
|
// 检查失败,继续上传
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. 提交异步上传任务
|
// 1. 提交异步上传任务
|
||||||
setUploadFiles(prev =>
|
setUploadFiles(prev =>
|
||||||
@ -87,7 +162,7 @@ export const UploadPanel: React.FC<UploadPanelProps> = ({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = await submitAsyncUpload(serverId, item.file, remotePath, false);
|
const result = await submitAsyncUpload(serverId, item.file, remotePath, overwrite);
|
||||||
const taskId = result.taskId;
|
const taskId = result.taskId;
|
||||||
|
|
||||||
// 2. 保存taskId
|
// 2. 保存taskId
|
||||||
@ -101,6 +176,8 @@ export const UploadPanel: React.FC<UploadPanelProps> = ({
|
|||||||
startPolling(item.id, taskId);
|
startPolling(item.id, taskId);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const errorMsg = error.response?.data?.message || '提交上传任务失败';
|
const errorMsg = error.response?.data?.message || '提交上传任务失败';
|
||||||
|
|
||||||
|
// 直接显示后端返回的错误信息
|
||||||
setUploadFiles(prev =>
|
setUploadFiles(prev =>
|
||||||
prev.map(f =>
|
prev.map(f =>
|
||||||
f.id === item.id
|
f.id === item.id
|
||||||
@ -112,6 +189,32 @@ export const UploadPanel: React.FC<UploadPanelProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理用户确认覆盖
|
||||||
|
const handleConfirmOverwrite = async () => {
|
||||||
|
setConfirmDialogOpen(false);
|
||||||
|
if (pendingOverwriteItem) {
|
||||||
|
// 以覆盖模式重新上传,跳过检查
|
||||||
|
await uploadSingleFile(pendingOverwriteItem, true, true);
|
||||||
|
setPendingOverwriteItem(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理用户取消覆盖
|
||||||
|
const handleCancelOverwrite = () => {
|
||||||
|
setConfirmDialogOpen(false);
|
||||||
|
if (pendingOverwriteItem) {
|
||||||
|
// 标记为错误状态
|
||||||
|
setUploadFiles(prev =>
|
||||||
|
prev.map(f =>
|
||||||
|
f.id === pendingOverwriteItem.id
|
||||||
|
? { ...f, status: 'error', errorMessage: '用户取消覆盖' }
|
||||||
|
: f
|
||||||
|
)
|
||||||
|
);
|
||||||
|
setPendingOverwriteItem(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 轮询查询上传状态
|
// 轮询查询上传状态
|
||||||
const startPolling = (fileId: string, taskId: string) => {
|
const startPolling = (fileId: string, taskId: string) => {
|
||||||
const pollInterval = setInterval(async () => {
|
const pollInterval = setInterval(async () => {
|
||||||
@ -143,6 +246,8 @@ export const UploadPanel: React.FC<UploadPanelProps> = ({
|
|||||||
clearInterval(pollInterval);
|
clearInterval(pollInterval);
|
||||||
pollIntervalsRef.current.delete(fileId);
|
pollIntervalsRef.current.delete(fileId);
|
||||||
const errorMsg = taskInfo.errorMessage || '上传失败';
|
const errorMsg = taskInfo.errorMessage || '上传失败';
|
||||||
|
|
||||||
|
// 直接显示后端返回的错误信息
|
||||||
setUploadFiles(prev =>
|
setUploadFiles(prev =>
|
||||||
prev.map(f =>
|
prev.map(f =>
|
||||||
f.id === fileId
|
f.id === fileId
|
||||||
@ -150,7 +255,7 @@ export const UploadPanel: React.FC<UploadPanelProps> = ({
|
|||||||
: f
|
: f
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
message.error(`${taskInfo.fileName}: ${errorMsg}`);
|
message.error(`上传失败: ${errorMsg}`);
|
||||||
} else if (taskInfo.status === 'CANCELLED') {
|
} else if (taskInfo.status === 'CANCELLED') {
|
||||||
clearInterval(pollInterval);
|
clearInterval(pollInterval);
|
||||||
pollIntervalsRef.current.delete(fileId);
|
pollIntervalsRef.current.delete(fileId);
|
||||||
@ -181,9 +286,21 @@ export const UploadPanel: React.FC<UploadPanelProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 清空列表
|
// 请求清空列表(弹出确认框)
|
||||||
const handleClearList = () => {
|
const handleClearList = () => {
|
||||||
|
setClearConfirmOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认清空列表
|
||||||
|
const handleConfirmClear = () => {
|
||||||
|
setClearConfirmOpen(false);
|
||||||
setUploadFiles([]);
|
setUploadFiles([]);
|
||||||
|
message.success('列表已清空');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消清空
|
||||||
|
const handleCancelClear = () => {
|
||||||
|
setClearConfirmOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 拖拽事件处理
|
// 拖拽事件处理
|
||||||
@ -311,16 +428,22 @@ export const UploadPanel: React.FC<UploadPanelProps> = ({
|
|||||||
{item.status === 'error' && (
|
{item.status === 'error' && (
|
||||||
<AlertCircle className="h-4 w-4 text-red-500" />
|
<AlertCircle className="h-4 w-4 text-red-500" />
|
||||||
)}
|
)}
|
||||||
{item.status === 'pending' && (
|
{/* 所有状态都显示X按钮 */}
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="h-6 w-6 p-0"
|
className="h-6 w-6 p-0"
|
||||||
onClick={() => removeFile(item.id)}
|
onClick={() => requestRemoveFile(item.id)}
|
||||||
|
title={
|
||||||
|
item.status === 'uploading'
|
||||||
|
? '取消上传'
|
||||||
|
: item.status === 'pending'
|
||||||
|
? '删除'
|
||||||
|
: '删除记录'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 mt-1">
|
<div className="flex items-center gap-2 mt-1">
|
||||||
@ -353,6 +476,66 @@ export const UploadPanel: React.FC<UploadPanelProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 覆盖确认对话框 */}
|
||||||
|
<AlertDialog open={confirmDialogOpen} onOpenChange={setConfirmDialogOpen}>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>文件已存在</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
文件 <span className="font-semibold text-foreground">{pendingOverwriteItem?.file.name}</span> 已存在,是否覆盖?
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel onClick={handleCancelOverwrite}>
|
||||||
|
取消
|
||||||
|
</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={handleConfirmOverwrite}>
|
||||||
|
覆盖
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
|
||||||
|
{/* 删除确认对话框 */}
|
||||||
|
<AlertDialog open={deleteConfirmOpen} onOpenChange={setDeleteConfirmOpen}>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>取消上传</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
确定要取消正在上传的文件吗?
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel onClick={handleCancelDelete}>
|
||||||
|
取消
|
||||||
|
</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={handleConfirmDelete}>
|
||||||
|
确定
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
|
||||||
|
{/* 清空列表确认对话框 */}
|
||||||
|
<AlertDialog open={clearConfirmOpen} onOpenChange={setClearConfirmOpen}>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>清空列表</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
确定要清空所有上传记录吗?此操作不可恢复。
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel onClick={handleCancelClear}>
|
||||||
|
取消
|
||||||
|
</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={handleConfirmClear}>
|
||||||
|
确定清空
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,9 +16,10 @@ const AlertDialogOverlay = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<AlertDialogPrimitive.Overlay
|
<AlertDialogPrimitive.Overlay
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
"fixed inset-0 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
style={{ zIndex: 1100 }}
|
||||||
{...props}
|
{...props}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
/>
|
/>
|
||||||
@ -34,9 +35,10 @@ const AlertDialogContent = React.forwardRef<
|
|||||||
<AlertDialogPrimitive.Content
|
<AlertDialogPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
"fixed left-[50%] top-[50%] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
style={{ zIndex: 1101 }}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</AlertDialogPortal>
|
</AlertDialogPortal>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user