feat: add resources
This commit is contained in:
parent
cc76842582
commit
25def8c245
@ -1,6 +1,6 @@
|
|||||||
import { createTheme, Shadows, ThemeOptions } from '@mui/material/styles';
|
import { createTheme, Shadows, ThemeOptions } from '@mui/material/styles';
|
||||||
import { useTheme as useMuiTheme, Theme } from '@mui/material/styles';
|
import { useTheme as useMuiTheme, Theme } from '@mui/material/styles';
|
||||||
import { amber } from '@mui/material/colors';
|
import { amber, red } from '@mui/material/colors';
|
||||||
const generateShadows = (color: string): Shadows => {
|
const generateShadows = (color: string): Shadows => {
|
||||||
return [
|
return [
|
||||||
'none',
|
'none',
|
||||||
@ -56,6 +56,9 @@ export const themeOptions: ThemeOptions = {
|
|||||||
default: '#ffffff', // 设置默认背景颜色
|
default: '#ffffff', // 设置默认背景颜色
|
||||||
// paper: '#f5f5f5', // 设置纸张背景颜色
|
// paper: '#f5f5f5', // 设置纸张背景颜色
|
||||||
},
|
},
|
||||||
|
error: {
|
||||||
|
main: red[500],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
shadows: generateShadows('rgba(255, 193, 7, 0.2)'),
|
shadows: generateShadows('rgba(255, 193, 7, 0.2)'),
|
||||||
typography: {
|
typography: {
|
||||||
@ -103,6 +106,24 @@ export const themeOptions: ThemeOptions = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
MuiSelect: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'& .MuiOutlinedInput-notchedOutline': {
|
||||||
|
borderColor: amber[300],
|
||||||
|
},
|
||||||
|
'&:hover .MuiOutlinedInput-notchedOutline': {
|
||||||
|
borderColor: amber[500],
|
||||||
|
},
|
||||||
|
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
|
||||||
|
borderColor: amber[500],
|
||||||
|
},
|
||||||
|
'& .MuiSelect-icon': {
|
||||||
|
color: amber[500], // Set arrow icon color to primary
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
MuiCard: {
|
MuiCard: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
root: {
|
root: {
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="/system/lib/app.js"></script>
|
<!-- <script src="/system/lib/app.js"></script> -->
|
||||||
|
<script src="https://kevisual.xiongxiao.me/system/lib/app.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -3,10 +3,15 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
"basename": "/root/resources",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build"
|
"build": "vite build",
|
||||||
|
"pub": "envision deploy ./dist -k resources -v 0.0.1 -u -o root"
|
||||||
},
|
},
|
||||||
|
"files": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -17,7 +22,7 @@
|
|||||||
"@kevisual/center-components": "workspace:*",
|
"@kevisual/center-components": "workspace:*",
|
||||||
"@kevisual/router": "^0.0.9",
|
"@kevisual/router": "^0.0.9",
|
||||||
"@kevisual/store": "^0.0.2",
|
"@kevisual/store": "^0.0.2",
|
||||||
"@mui/material": "^6.4.7",
|
"@mui/material": "^6.4.8",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@vitejs/plugin-basic-ssl": "^2.0.0",
|
"@vitejs/plugin-basic-ssl": "^2.0.0",
|
||||||
@ -25,10 +30,11 @@
|
|||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"lucide-react": "^0.482.0",
|
"lucide-react": "^0.482.0",
|
||||||
"nanoid": "^5.1.3",
|
"nanoid": "^5.1.4",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^6.1.1",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
|
"react-datepicker": "^8.2.1",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^14.3.8",
|
||||||
"react-toastify": "^11.0.5",
|
"react-toastify": "^11.0.5",
|
||||||
@ -37,4 +43,4 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@kevisual/types": "^0.0.6"
|
"@kevisual/types": "^0.0.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
6
packages/resources/public/config.js
Normal file
6
packages/resources/public/config.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export const config = {
|
||||||
|
api: () => location.origin,
|
||||||
|
apps: {
|
||||||
|
login: '/user/login',
|
||||||
|
},
|
||||||
|
};
|
@ -7,6 +7,8 @@
|
|||||||
}
|
}
|
||||||
:root {
|
:root {
|
||||||
--scrollbar-color: #ffbf00;
|
--scrollbar-color: #ffbf00;
|
||||||
|
--primary-color: #ffc107;
|
||||||
|
--secondary-color: #ffa000;
|
||||||
}
|
}
|
||||||
#root {
|
#root {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -26,3 +28,39 @@
|
|||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: var(--scrollbar-color) #fff;
|
scrollbar-color: var(--scrollbar-color) #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scrollbar::-webkit-scrollbar {
|
||||||
|
height: 4px;
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar::-webkit-scrollbar-thumb {
|
||||||
|
background-color: var(--scrollbar-color);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar::-webkit-scrollbar-track {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-select-outlined.ant-select-multiple .ant-select-selection-item {
|
||||||
|
background: var(--secondary-color);
|
||||||
|
color: white;
|
||||||
|
svg {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-select-selection-item {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
.ant-select {
|
||||||
|
.ant-select-arrow {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-picker-input {
|
||||||
|
.ant-picker-suffix,
|
||||||
|
.ant-picker-clear {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,50 +1,4 @@
|
|||||||
import { page, app } from './app.ts';
|
import { bootstrap } from './pages/Bootstrap';
|
||||||
import { basename } from './modules/basename.ts';
|
|
||||||
import './pages/main.tsx';
|
|
||||||
|
|
||||||
export const render = ({ renderRoot }) => {
|
bootstrap('#ai-root');
|
||||||
renderRoot.innerHTML = `
|
|
||||||
<h1>Hello, World!</h1>
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
console.log('basename', basename, page, app);
|
|
||||||
|
|
||||||
if (page) {
|
|
||||||
page.addPage('/', 'home');
|
|
||||||
page.subscribe('home', () => {
|
|
||||||
render({
|
|
||||||
renderRoot: document.getElementById('ai-root'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
page.addPage('', 'index');
|
|
||||||
page.subscribe('index', () => {
|
|
||||||
const root = document.getElementById('ai-root') as HTMLElement;
|
|
||||||
root.innerHTML = `
|
|
||||||
<h1>Hello, World!</h1>
|
|
||||||
`;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app) {
|
|
||||||
app
|
|
||||||
.route({
|
|
||||||
path: 'app-template',
|
|
||||||
key: 'render',
|
|
||||||
})
|
|
||||||
.define(async (ctx) => {
|
|
||||||
let { renderRoot } = ctx.query;
|
|
||||||
if (!renderRoot) {
|
|
||||||
ctx.throw(404, 'renderRoot is required');
|
|
||||||
}
|
|
||||||
if (typeof renderRoot === 'string') {
|
|
||||||
renderRoot = document.querySelector(renderRoot);
|
|
||||||
}
|
|
||||||
if (!renderRoot) {
|
|
||||||
ctx.throw(404, 'renderRoot not found');
|
|
||||||
}
|
|
||||||
render({
|
|
||||||
renderRoot,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.addTo(app);
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,15 @@
|
|||||||
|
import { toastLogin } from '@/pages/message/ToastLogin';
|
||||||
import { QueryClient } from '@kevisual/query';
|
import { QueryClient } from '@kevisual/query';
|
||||||
|
|
||||||
export const query = new QueryClient();
|
export const query = new QueryClient();
|
||||||
|
|
||||||
|
query.afterResponse = async (response) => {
|
||||||
|
if (response.code === 401) {
|
||||||
|
toastLogin();
|
||||||
|
return {
|
||||||
|
...response,
|
||||||
|
noMsg: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
@ -5,10 +5,47 @@ import { Left } from './layout/Left';
|
|||||||
import { Main } from './main/index';
|
import { Main } from './main/index';
|
||||||
import { ToastContainer } from 'react-toastify';
|
import { ToastContainer } from 'react-toastify';
|
||||||
import { useSettingsStore } from './store/settings';
|
import { useSettingsStore } from './store/settings';
|
||||||
import { CircularProgress } from '@mui/material';
|
import { CircularProgress, useTheme } from '@mui/material';
|
||||||
import { useResourceStore } from './store/resource';
|
import { useResourceStore } from './store/resource';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import 'dayjs/locale/zh-cn';
|
||||||
|
|
||||||
export const App = () => {
|
import zhCN from 'antd/locale/zh_CN';
|
||||||
|
import ConfigProvider from 'antd/es/config-provider';
|
||||||
|
|
||||||
|
dayjs.locale('zh-cn');
|
||||||
|
export const AntdConfigProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const primaryColor = theme.palette.primary.main;
|
||||||
|
const secondaryColor = theme.palette.secondary.main;
|
||||||
|
return (
|
||||||
|
<ConfigProvider
|
||||||
|
locale={zhCN}
|
||||||
|
theme={{
|
||||||
|
token: {
|
||||||
|
colorPrimary: primaryColor,
|
||||||
|
colorPrimaryHover: secondaryColor,
|
||||||
|
colorPrimaryActive: primaryColor,
|
||||||
|
borderRadius: 4,
|
||||||
|
colorBorder: primaryColor,
|
||||||
|
// colorText: primaryColor,
|
||||||
|
colorIcon: primaryColor,
|
||||||
|
colorIconHover: secondaryColor,
|
||||||
|
colorInfoHover: secondaryColor,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
DatePicker: {
|
||||||
|
colorPrimary: primaryColor,
|
||||||
|
colorPrimaryHover: secondaryColor,
|
||||||
|
colorPrimaryActive: primaryColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}>
|
||||||
|
{children}
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export const InitProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
const { init, mounted, settings } = useSettingsStore();
|
const { init, mounted, settings } = useSettingsStore();
|
||||||
const { setPrefix, init: initResource } = useResourceStore();
|
const { setPrefix, init: initResource } = useResourceStore();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -16,24 +53,46 @@ export const App = () => {
|
|||||||
initResource();
|
initResource();
|
||||||
}, []);
|
}, []);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (settings.prefix && mounted) {
|
if (settings.prefix && mounted === 'success') {
|
||||||
setPrefix(settings.prefix);
|
setPrefix(settings.prefix);
|
||||||
}
|
}
|
||||||
}, [mounted, settings.prefix]);
|
}, [mounted, settings.prefix]);
|
||||||
if (!mounted) {
|
|
||||||
|
const handleRetry = () => {
|
||||||
|
init();
|
||||||
|
initResource();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mounted === 'loading') {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
|
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
} else if (mounted === 'error') {
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', height: '100vh', color: 'red' }}>
|
||||||
|
<h2>出现问题</h2>
|
||||||
|
<p>加载设置时遇到错误。请重试。</p>
|
||||||
|
<button onClick={handleRetry} style={{ marginTop: '20px', padding: '10px 20px', backgroundColor: '#f44336', color: '#fff', border: 'none', borderRadius: '4px', cursor: 'pointer' }}>
|
||||||
|
重试
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
return <>{children}</>;
|
||||||
|
};
|
||||||
|
export const App = () => {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<Left>
|
<AntdConfigProvider>
|
||||||
<Main />
|
<InitProvider>
|
||||||
</Left>
|
<Left>
|
||||||
<ToastContainer />
|
<Main />
|
||||||
|
</Left>
|
||||||
|
</InitProvider>
|
||||||
|
<ToastContainer />
|
||||||
|
</AntdConfigProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
61
packages/resources/src/pages/Bootstrap.tsx
Normal file
61
packages/resources/src/pages/Bootstrap.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
import { App } from './App';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export class ReactRenderer {
|
||||||
|
component: any;
|
||||||
|
element: HTMLElement;
|
||||||
|
ref: React.RefObject<any>;
|
||||||
|
props: any;
|
||||||
|
root: any;
|
||||||
|
constructor(component: any, { props, className }: any) {
|
||||||
|
this.component = component;
|
||||||
|
const el = document.createElement('div');
|
||||||
|
this.element = el;
|
||||||
|
this.ref = React.createRef();
|
||||||
|
this.props = {
|
||||||
|
...props,
|
||||||
|
ref: this.ref,
|
||||||
|
};
|
||||||
|
el.className = className;
|
||||||
|
this.root = createRoot(this.element);
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProps(props: any) {
|
||||||
|
this.props = {
|
||||||
|
...this.props,
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
this.root.render(React.createElement(this.component, this.props));
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.root.unmount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReactRenderer;
|
||||||
|
|
||||||
|
export const bootstrap = (el: HTMLElement | string) => {
|
||||||
|
// createRoot(document.getElementById('ai-root')!).render(<App />);
|
||||||
|
const root = typeof el === 'string' ? document.querySelector(el) : el;
|
||||||
|
if (root) {
|
||||||
|
const renderer = new ReactRenderer(App, {
|
||||||
|
props: {},
|
||||||
|
className: 'resources-root w-full h-full',
|
||||||
|
});
|
||||||
|
if (window.context) {
|
||||||
|
window.context.resourcesApp = renderer;
|
||||||
|
} else {
|
||||||
|
window.context = {
|
||||||
|
resourcesApp: renderer,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
root.appendChild(renderer.element);
|
||||||
|
}
|
||||||
|
};
|
@ -90,3 +90,83 @@ export const getIcon = (name: string) => {
|
|||||||
return <File />;
|
return <File />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件类型,文件大类
|
||||||
|
* @param name 文件名
|
||||||
|
* @returns 文件类型
|
||||||
|
*/
|
||||||
|
export const getFileType = (name?: string) => {
|
||||||
|
if (!name) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const extension = getExtension(name);
|
||||||
|
switch (extension) {
|
||||||
|
case 'pdf':
|
||||||
|
return 'pdf';
|
||||||
|
case 'jpg':
|
||||||
|
case 'jpeg':
|
||||||
|
case 'gif':
|
||||||
|
case 'png':
|
||||||
|
return 'image';
|
||||||
|
case 'mp3':
|
||||||
|
case 'wav':
|
||||||
|
case 'ogg':
|
||||||
|
case 'm4a':
|
||||||
|
case 'aac':
|
||||||
|
case 'flac':
|
||||||
|
case 'wma':
|
||||||
|
return 'audio';
|
||||||
|
case 'mp4':
|
||||||
|
return 'video';
|
||||||
|
case 'doc':
|
||||||
|
case 'docx':
|
||||||
|
return 'word';
|
||||||
|
case 'ppt':
|
||||||
|
case 'pptx':
|
||||||
|
return 'ppt';
|
||||||
|
case 'xls':
|
||||||
|
case 'xlsx':
|
||||||
|
return 'excel';
|
||||||
|
case 'zip':
|
||||||
|
case 'rar':
|
||||||
|
case '7z':
|
||||||
|
case 'tar':
|
||||||
|
case 'gz':
|
||||||
|
case 'bz2':
|
||||||
|
return 'zip';
|
||||||
|
case 'txt':
|
||||||
|
case 'md':
|
||||||
|
case 'csv':
|
||||||
|
case 'json':
|
||||||
|
case 'xml':
|
||||||
|
case 'yaml':
|
||||||
|
case 'yml':
|
||||||
|
case 'toml':
|
||||||
|
case 'ini':
|
||||||
|
case 'conf':
|
||||||
|
case 'cfg':
|
||||||
|
case 'config':
|
||||||
|
case 'props':
|
||||||
|
case 'properties':
|
||||||
|
case 'log':
|
||||||
|
case 'sh':
|
||||||
|
case 'bash':
|
||||||
|
case 'zsh':
|
||||||
|
case 'fish':
|
||||||
|
case 'bat':
|
||||||
|
case 'cmd':
|
||||||
|
return 'text';
|
||||||
|
case 'html':
|
||||||
|
case 'htm':
|
||||||
|
return 'html';
|
||||||
|
case 'css':
|
||||||
|
case 'js':
|
||||||
|
case 'ts':
|
||||||
|
case 'jsx':
|
||||||
|
case 'tsx':
|
||||||
|
return 'code';
|
||||||
|
default:
|
||||||
|
return 'other';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -1,16 +1,60 @@
|
|||||||
import { useResourceStore } from '@/pages/store/resource';
|
import { useResourceStore } from '@/pages/store/resource';
|
||||||
import { useResourceFileStore } from '@/pages/store/resource-file';
|
import { useResourceFileStore } from '@/pages/store/resource-file';
|
||||||
import { Drawer } from '@mui/material';
|
import { Box, Divider, Drawer, Tab, Tabs } from '@mui/material';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
import { QuickValues, QuickTabs } from './QuickTabs';
|
||||||
|
|
||||||
export const FileDrawer = () => {
|
export const FileDrawer = () => {
|
||||||
const { prefix } = useResourceStore();
|
const { prefix } = useResourceStore();
|
||||||
const { resource, openDrawer, setOpenDrawer } = useResourceFileStore();
|
const { resource, openDrawer, setOpenDrawer } = useResourceFileStore();
|
||||||
|
const [tab, setTab] = useState<string>(QuickValues[0]);
|
||||||
|
const quickCom = useMemo(() => {
|
||||||
|
return QuickTabs.find((item) => item.value === tab)?.component;
|
||||||
|
}, [tab]);
|
||||||
return (
|
return (
|
||||||
<Drawer open={openDrawer} onClose={() => setOpenDrawer(false)} anchor='right' {...(!openDrawer && { inert: true })}>
|
<>
|
||||||
<div className='p-4 w-[600px]'>
|
<Drawer
|
||||||
<h2 className='text-2xl font-bold'>{resource?.name ? resource.name.replace(prefix, '') : resource?.prefix?.replace(prefix, '')}</h2>
|
// aria-label={'文件详情'}
|
||||||
<pre className='flex flex-col gap-2'>{JSON.stringify(resource, null, 2)}</pre>
|
open={openDrawer}
|
||||||
</div>
|
onClose={() => {
|
||||||
</Drawer>
|
// document.getElementById('focus-safe-element')?.focus();
|
||||||
|
const activeElement = document.activeElement as HTMLElement;
|
||||||
|
if (activeElement) {
|
||||||
|
activeElement.blur();
|
||||||
|
}
|
||||||
|
setOpenDrawer(false);
|
||||||
|
}}
|
||||||
|
ModalProps={{
|
||||||
|
keepMounted: true,
|
||||||
|
}}
|
||||||
|
anchor='right'
|
||||||
|
style={{
|
||||||
|
zIndex: 1000,
|
||||||
|
}}>
|
||||||
|
<div className='p-4 w-[400px] max-w-[90%] overflow-hidden h-full sm:w-[600px]'>
|
||||||
|
<div style={{ height: '140px' }}>
|
||||||
|
<h2 className='text-2xl font-bold truncate py-2 pb-6 '>
|
||||||
|
{resource?.name ? resource.name.replace(prefix, '') : resource?.prefix?.replace(prefix, '')}
|
||||||
|
</h2>
|
||||||
|
<Divider />
|
||||||
|
<Box sx={{ borderBottom: 1, mt: 2, borderColor: 'divider' }}>
|
||||||
|
<Tabs value={tab} onChange={(_, value) => setTab(value)}>
|
||||||
|
{QuickTabs.map((item) => (
|
||||||
|
<Tab key={item.value} label={item.label} value={item.value} icon={item.icon} iconPosition='start' />
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
<Box className='' sx={{ p: 2, height: 'calc(100% - 140px)', overflow: 'hidden' }}>
|
||||||
|
<div className='scrollbar' style={{ height: '100%', overflow: 'auto' }}>
|
||||||
|
{quickCom && quickCom()}
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
</Drawer>
|
||||||
|
<button id='focus-safe-element' style={{ display: 'none' }}>
|
||||||
|
Focus Safe Element
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
27
packages/resources/src/pages/file/draw/QuickTabs.tsx
Normal file
27
packages/resources/src/pages/file/draw/QuickTabs.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { MetaForm } from './modules/MetaForm';
|
||||||
|
import { ContentForm } from './modules/ContextForm';
|
||||||
|
import { Cpu, File, FileText, Rabbit } from 'lucide-react';
|
||||||
|
import { Quick } from './quick';
|
||||||
|
export const QuickTabs = [
|
||||||
|
{
|
||||||
|
label: 'Quick',
|
||||||
|
value: 'quick',
|
||||||
|
icon: <Rabbit />,
|
||||||
|
index: 99,
|
||||||
|
component: () => <Quick />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '元数据',
|
||||||
|
value: 'meta',
|
||||||
|
icon: <Cpu />,
|
||||||
|
component: () => <MetaForm />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '内容',
|
||||||
|
value: 'content',
|
||||||
|
icon: <FileText />,
|
||||||
|
component: () => <ContentForm />,
|
||||||
|
},
|
||||||
|
].sort((a, b) => (b?.index || 0) - (a?.index || 0));
|
||||||
|
|
||||||
|
export const QuickValues = QuickTabs.map((item) => item.value);
|
@ -0,0 +1,29 @@
|
|||||||
|
import { useResourceFileStore } from '@/pages/store/resource-file';
|
||||||
|
import { Box, Typography } from '@mui/material';
|
||||||
|
import prettyBytes from 'pretty-bytes';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
type ContentShowType = {
|
||||||
|
size: number;
|
||||||
|
lastModified: string;
|
||||||
|
etag: string;
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
export const ContentForm = () => {
|
||||||
|
const { resource } = useResourceFileStore();
|
||||||
|
const contentShow = resource as ContentShowType;
|
||||||
|
return (
|
||||||
|
<Box className='p-4 border rounded-md mt-2'>
|
||||||
|
{/* <Typography variant='h6'>{contentShow?.name || 'No Name Available'}</Typography> */}
|
||||||
|
<Typography variant='body1'>
|
||||||
|
<strong>Size:</strong> {contentShow?.size ? prettyBytes(contentShow?.size) : 'N/A'}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant='body1'>
|
||||||
|
<strong>Last Modified:</strong> {contentShow?.lastModified ? dayjs(contentShow?.lastModified).format('YYYY-MM-DD HH:mm:ss') : 'N/A'}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant='body1'>
|
||||||
|
<strong>ETag:</strong> {contentShow?.etag || 'N/A'}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,28 @@
|
|||||||
|
import ReactDatePicker from 'antd/es/date-picker';
|
||||||
|
import { useTheme } from '@mui/material';
|
||||||
|
import 'antd/es/date-picker/style/index';
|
||||||
|
interface DatePickerProps {
|
||||||
|
value?: Date | null;
|
||||||
|
onChange?: (date: Date | null) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DatePicker = ({ value, onChange }: DatePickerProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const primaryColor = theme.palette.primary.main;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ReactDatePicker
|
||||||
|
placement='topLeft'
|
||||||
|
placeholder='请选择日期'
|
||||||
|
value={value}
|
||||||
|
showNow={false}
|
||||||
|
// showTime={true}
|
||||||
|
onChange={(date) => onChange?.(date)} //
|
||||||
|
style={{
|
||||||
|
color: primaryColor,
|
||||||
|
}}
|
||||||
|
popupStyle={{ zIndex: 2000 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
39
packages/resources/src/pages/file/draw/modules/DialogKey.tsx
Normal file
39
packages/resources/src/pages/file/draw/modules/DialogKey.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { Button, Dialog, DialogContent, DialogTitle, FormControlLabel, TextField } from '@mui/material';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useMetaStore } from './MetaForm';
|
||||||
|
export const DialogKey = ({ onAdd }: { onAdd: (key: string) => void }) => {
|
||||||
|
const { openPropertyModal, setOpenPropertyModal } = useMetaStore();
|
||||||
|
const [key, setKey] = useState('');
|
||||||
|
return (
|
||||||
|
<Dialog open={openPropertyModal} onClose={() => setOpenPropertyModal(false)}>
|
||||||
|
<DialogTitle>添加元数据key</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<div className='flex flex-col items-center gap-3 px-4 pb-4'>
|
||||||
|
<FormControlLabel
|
||||||
|
label='key'
|
||||||
|
labelPlacement='top'
|
||||||
|
control={<TextField variant='outlined' size='small' name={key} value={key} onChange={(e) => setKey(e.target.value)} />}
|
||||||
|
sx={{
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
'& .MuiFormControlLabel-label': {
|
||||||
|
textAlign: 'left',
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant='contained'
|
||||||
|
color='primary'
|
||||||
|
style={{ color: 'white' }}
|
||||||
|
onClick={() => {
|
||||||
|
onAdd(key);
|
||||||
|
setKey('');
|
||||||
|
setOpenPropertyModal(false);
|
||||||
|
}}>
|
||||||
|
添加
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
368
packages/resources/src/pages/file/draw/modules/MetaForm.tsx
Normal file
368
packages/resources/src/pages/file/draw/modules/MetaForm.tsx
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
import { useResourceFileStore } from '@/pages/store/resource-file';
|
||||||
|
import { FormControlLabel, Box, TextField, Button, IconButton, ButtonGroup, Tooltip, Select, MenuItem, Typography, FormGroup } from '@mui/material';
|
||||||
|
import { Info, Plus, Save, Share, Shuffle, Trash } from 'lucide-react';
|
||||||
|
import { useState, useEffect, useMemo } from 'react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import { create } from 'zustand';
|
||||||
|
import { uniq } from 'lodash-es';
|
||||||
|
import { DatePicker } from './DatePicker';
|
||||||
|
import { SelectPicker } from './SelectPicker';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { DialogKey } from './DialogKey';
|
||||||
|
|
||||||
|
export const setShareKeysOperate = (value: 'public' | 'protected' | 'private') => {
|
||||||
|
const keys = ['password', 'usernames', 'expiration-time'];
|
||||||
|
const deleteKeys = keys.map((item) => {
|
||||||
|
return {
|
||||||
|
key: item,
|
||||||
|
operate: 'delete',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (value === 'protected') {
|
||||||
|
return deleteKeys.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
operate: 'add',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return deleteKeys;
|
||||||
|
};
|
||||||
|
export const keysTips = [
|
||||||
|
{
|
||||||
|
key: 'share',
|
||||||
|
tips: `共享设置
|
||||||
|
1. 设置公共可以直接访问
|
||||||
|
2. 设置受保护需要登录后访问
|
||||||
|
3. 设置私有只有自己可以访问。\n
|
||||||
|
受保护可以设置密码,设置访问的用户名。切换共享状态后,需要重新设置密码和用户名。`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'content-type',
|
||||||
|
tips: `内容类型,设置文件的内容类型。默认不要修改。`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'app-source',
|
||||||
|
tips: `应用来源,上传方式。默认不要修改。`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'cache-control',
|
||||||
|
tips: `缓存控制,设置文件的缓存控制。默认不要修改。`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'password',
|
||||||
|
tips: `密码,设置文件的密码。不设置默认是所有人都可以访问。`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'usernames',
|
||||||
|
tips: `用户名,设置文件的用户名。不设置默认是所有人都可以访问。`,
|
||||||
|
parse: (value: string) => {
|
||||||
|
if (!value) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return value.split(',');
|
||||||
|
},
|
||||||
|
stringify: (value: string[]) => {
|
||||||
|
if (!value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return value.join(',');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'expiration-time',
|
||||||
|
tips: `过期时间,设置文件的过期时间。不设置默认是永久。`,
|
||||||
|
parse: (value: Date) => {
|
||||||
|
if (!value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return dayjs(value);
|
||||||
|
},
|
||||||
|
stringify: (value?: dayjs.Dayjs) => {
|
||||||
|
if (!value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return value.toISOString();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export class KeyParse {
|
||||||
|
static parse(metadata: Record<string, any>) {
|
||||||
|
const keys = Object.keys(metadata);
|
||||||
|
const newMetadata = {};
|
||||||
|
keys.forEach((key) => {
|
||||||
|
const tip = keysTips.find((item) => item.key === key);
|
||||||
|
if (tip && tip.parse) {
|
||||||
|
newMetadata[key] = tip.parse(metadata[key]);
|
||||||
|
} else {
|
||||||
|
newMetadata[key] = metadata[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return newMetadata;
|
||||||
|
}
|
||||||
|
static stringify(metadata: Record<string, any>) {
|
||||||
|
const keys = Object.keys(metadata);
|
||||||
|
const newMetadata = {};
|
||||||
|
keys.forEach((key) => {
|
||||||
|
const tip = keysTips.find((item) => item.key === key);
|
||||||
|
if (tip && tip.stringify) {
|
||||||
|
newMetadata[key] = tip.stringify(metadata[key]);
|
||||||
|
} else {
|
||||||
|
newMetadata[key] = metadata[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return newMetadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const useMetaOperate = ({
|
||||||
|
onSave,
|
||||||
|
metaStore,
|
||||||
|
handleFormDataChange,
|
||||||
|
}: {
|
||||||
|
onSave: () => void;
|
||||||
|
metaStore: MetaStore;
|
||||||
|
handleFormDataChange: (key: string, value: string | Date | null | string[]) => void;
|
||||||
|
}) => {
|
||||||
|
const { keys, setKeys, openPropertyModal, setOpenPropertyModal } = metaStore;
|
||||||
|
const hasShare = keys.includes('share');
|
||||||
|
const hasPassword = keys.includes('password');
|
||||||
|
const addMeta = (key: string) => {
|
||||||
|
setKeys(uniq([...keys, key]));
|
||||||
|
};
|
||||||
|
const defaultBtnList = [
|
||||||
|
{
|
||||||
|
icon: <Save />,
|
||||||
|
key: 'save',
|
||||||
|
tooltip: '保存元数据, 修改后需要手动保存',
|
||||||
|
onClick: () => onSave(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Plus />,
|
||||||
|
key: 'add',
|
||||||
|
tooltip: '添加元数据',
|
||||||
|
onClick: () => setOpenPropertyModal(true),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
if (!hasShare) {
|
||||||
|
defaultBtnList.push({
|
||||||
|
icon: <Share />,
|
||||||
|
key: 'share',
|
||||||
|
tooltip: '开启共享',
|
||||||
|
onClick: () => addMeta('share'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (hasShare && hasPassword) {
|
||||||
|
defaultBtnList.push({
|
||||||
|
icon: <Shuffle />,
|
||||||
|
key: 'password',
|
||||||
|
tooltip: '随机生成密码',
|
||||||
|
onClick: () => {
|
||||||
|
const password = Math.random().toString(36).substring(2, 8);
|
||||||
|
handleFormDataChange('password', password);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return defaultBtnList;
|
||||||
|
};
|
||||||
|
type MetaStore = {
|
||||||
|
keys: string[];
|
||||||
|
setKeys: (keys: string[]) => void;
|
||||||
|
openPropertyModal: boolean;
|
||||||
|
setOpenPropertyModal: (openPropertyModal: boolean) => void;
|
||||||
|
};
|
||||||
|
export const useMetaStore = create<MetaStore>((set) => ({
|
||||||
|
keys: [],
|
||||||
|
setKeys: (keys) => set({ keys }),
|
||||||
|
openPropertyModal: false,
|
||||||
|
setOpenPropertyModal: (openPropertyModal) => set({ openPropertyModal }),
|
||||||
|
}));
|
||||||
|
export const MetaForm = () => {
|
||||||
|
const { resource, updateMeta } = useResourceFileStore();
|
||||||
|
const [formData, setFormData] = useState<any>({});
|
||||||
|
const metaStore = useMetaStore();
|
||||||
|
const { keys, setKeys } = metaStore;
|
||||||
|
useEffect(() => {
|
||||||
|
// setFormData(resource?.metaData || {});
|
||||||
|
setFormData(KeyParse.parse(resource?.metaData || {}));
|
||||||
|
}, [resource]);
|
||||||
|
useEffect(() => {
|
||||||
|
setKeys(Object.keys(resource?.metaData || {}));
|
||||||
|
}, [resource]);
|
||||||
|
if (!keys.length) {
|
||||||
|
return <div className='text-center text-gray-500'>没有元数据</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleFormDataChange = (key: string, value: string | Date | null | string[]) => {
|
||||||
|
// setFormData({ ...formData, [key]: value });
|
||||||
|
const _formData = { ...formData };
|
||||||
|
if (key === 'share') {
|
||||||
|
const shareKeysOperate = setShareKeysOperate(value as 'public' | 'protected' | 'private');
|
||||||
|
shareKeysOperate.forEach((item) => {
|
||||||
|
if (item.operate === 'add') {
|
||||||
|
_formData[item.key] = '';
|
||||||
|
} else if (item.operate === 'delete') {
|
||||||
|
delete _formData[item.key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_formData.share = value;
|
||||||
|
setFormData(_formData);
|
||||||
|
const newKeys = keys
|
||||||
|
.map((item) => {
|
||||||
|
const operate = shareKeysOperate.find((item2) => item2.key === item);
|
||||||
|
if (operate && operate.operate === 'delete') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
.filter((item) => item !== null);
|
||||||
|
const addKeys = shareKeysOperate.filter((item) => item.operate === 'add').map((item) => item.key);
|
||||||
|
const _newKeys = uniq([...newKeys, ...addKeys]);
|
||||||
|
setKeys(_newKeys);
|
||||||
|
console.log(_newKeys);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
_formData[key] = value;
|
||||||
|
}
|
||||||
|
setFormData(_formData);
|
||||||
|
};
|
||||||
|
const deleteMeta = (key: string) => {
|
||||||
|
setKeys(keys.filter((item) => item !== key));
|
||||||
|
delete formData[key];
|
||||||
|
setFormData({ ...formData });
|
||||||
|
};
|
||||||
|
const onSave = () => {
|
||||||
|
const newMetadata = KeyParse.stringify(formData);
|
||||||
|
updateMeta(newMetadata);
|
||||||
|
};
|
||||||
|
const addMetaKey = (key: string) => {
|
||||||
|
if (keys.includes(key)) {
|
||||||
|
toast.error('元数据key已存在');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
formData[key] = '';
|
||||||
|
setKeys([...keys, key]);
|
||||||
|
setFormData({ ...formData });
|
||||||
|
};
|
||||||
|
const btnList = useMetaOperate({ onSave, metaStore, handleFormDataChange });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='relative w-full h-full'>
|
||||||
|
<Box className='sticky top-0 z-10 pointer-events-none'>
|
||||||
|
<div className='flex justify-end mr-20'>
|
||||||
|
<div className=' pointer-events-auto'>
|
||||||
|
<ButtonGroup className='bg-white' variant='contained' sx={{ color: 'white' }}>
|
||||||
|
{btnList.map((item) => {
|
||||||
|
const icon = (
|
||||||
|
<IconButton color='secondary' onClick={item.onClick}>
|
||||||
|
{item.icon}
|
||||||
|
</IconButton>
|
||||||
|
);
|
||||||
|
if (item.tooltip) {
|
||||||
|
return (
|
||||||
|
<Tooltip key={item.key} title={item.tooltip} placement='top' arrow>
|
||||||
|
{icon}
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <>{icon}</>;
|
||||||
|
})}
|
||||||
|
</ButtonGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
<FormGroup>
|
||||||
|
{keys.map((key) => {
|
||||||
|
let control: React.ReactNode | null = null;
|
||||||
|
if (key === 'share') {
|
||||||
|
control = <KeyShareSelect name={key} value={formData[key] || ''} onChange={(value) => handleFormDataChange(key, value)} />;
|
||||||
|
} else if (key === 'expiration-time') {
|
||||||
|
control = <DatePicker value={formData[key]} onChange={(date) => handleFormDataChange(key, date)} />;
|
||||||
|
} else if (key === 'usernames') {
|
||||||
|
control = <SelectPicker value={formData[key] || []} onChange={(value) => handleFormDataChange(key, value)} />;
|
||||||
|
} else {
|
||||||
|
control = <KeyTextField name={key} value={formData[key] || ''} onChange={(value) => handleFormDataChange(key, value)} />;
|
||||||
|
}
|
||||||
|
const Label = () => {
|
||||||
|
const tip = keysTips.find((item) => item.key === key);
|
||||||
|
return (
|
||||||
|
<div className='flex justify-between items-center gap-2'>
|
||||||
|
<div className='flex items-center gap-2'>
|
||||||
|
<Typography variant='caption' color='primary'>
|
||||||
|
{key}
|
||||||
|
</Typography>
|
||||||
|
{tip && (
|
||||||
|
<Tooltip title={tip?.tips} placement='top' arrow>
|
||||||
|
<Info size={12} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<IconButton color='error' onClick={() => deleteMeta(key)}>
|
||||||
|
<Trash />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div key={key} className='flex flex-col gap-2'>
|
||||||
|
<FormControlLabel
|
||||||
|
key={key}
|
||||||
|
label={<Label />}
|
||||||
|
labelPlacement='top'
|
||||||
|
control={control}
|
||||||
|
sx={{
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
'& .MuiFormControlLabel-label': {
|
||||||
|
textAlign: 'left',
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</FormGroup>
|
||||||
|
<DialogKey onAdd={addMetaKey} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const KeyTextField = ({ name, value, onChange }: { name: string; value: string; onChange?: (value: string) => void }) => {
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
variant='outlined'
|
||||||
|
size='small'
|
||||||
|
name={name}
|
||||||
|
defaultValue={value}
|
||||||
|
// value={formData[key] || ''}
|
||||||
|
onChange={(e) => onChange?.(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
marginBottom: '16px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const KeyShareSelect = ({ name, value, onChange }: { name: string; value: string; onChange?: (value: string) => void }) => {
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
variant='outlined'
|
||||||
|
size='small'
|
||||||
|
name={name}
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => onChange?.(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
marginBottom: '16px',
|
||||||
|
}}>
|
||||||
|
<MenuItem value='public' title='公开'>
|
||||||
|
公开
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value='protected' title='受保护'>
|
||||||
|
受保护
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value='private' title='私有'>
|
||||||
|
私有
|
||||||
|
</MenuItem>
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,18 @@
|
|||||||
|
import { styled } from '@mui/material';
|
||||||
|
import Select from 'antd/es/select';
|
||||||
|
import 'antd/es/select/style/index';
|
||||||
|
|
||||||
|
interface SelectPickerProps {
|
||||||
|
value: string[];
|
||||||
|
onChange: (value: string[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SelectPickerCom = ({ value, onChange }: SelectPickerProps) => {
|
||||||
|
return <Select style={{ width: '100%' }} showSearch={false} mode='tags' value={value} onChange={onChange} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SelectPicker = styled(SelectPickerCom)({
|
||||||
|
'& .ant-select-selector': {
|
||||||
|
color: 'var(--primary-color)',
|
||||||
|
},
|
||||||
|
});
|
11
packages/resources/src/pages/file/draw/quick/QuickLink.tsx
Normal file
11
packages/resources/src/pages/file/draw/quick/QuickLink.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* 链接生成,markdown超链接, 多选项。
|
||||||
|
* 1. markdown
|
||||||
|
* 2. HTML image
|
||||||
|
* 3. URL https url
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const QuickLink = () => {
|
||||||
|
const url = 'https://ab.c.com/a/b/c.jpg';
|
||||||
|
return <div>QuickLink</div>;
|
||||||
|
};
|
131
packages/resources/src/pages/file/draw/quick/QuickPreview.tsx
Normal file
131
packages/resources/src/pages/file/draw/quick/QuickPreview.tsx
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import { useResourceFileStore } from '@/pages/store/resource-file';
|
||||||
|
import { useSettingsStore } from '@/pages/store/settings';
|
||||||
|
import { Button, Tooltip, useTheme } from '@mui/material';
|
||||||
|
import { useShallow } from 'zustand/shallow';
|
||||||
|
import { Accordion, AccordionSummary, AccordionDetails } from '@mui/material';
|
||||||
|
import { ChevronDown } from 'lucide-react';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { getFileType } from '../../FileIcon';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
type AccordionItem = {
|
||||||
|
title?: string;
|
||||||
|
key?: string;
|
||||||
|
url?: string;
|
||||||
|
content?: any;
|
||||||
|
clickCopy?: boolean;
|
||||||
|
};
|
||||||
|
export const QuickPreview = () => {
|
||||||
|
const { resource } = useResourceFileStore(
|
||||||
|
useShallow((state) => ({
|
||||||
|
resource: state.resource,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
const { settings, baseUrl } = useSettingsStore(
|
||||||
|
useShallow((state) => ({
|
||||||
|
settings: state.settings,
|
||||||
|
baseUrl: state.baseUrl,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
const fileType = useMemo(() => getFileType(resource?.name), [resource]);
|
||||||
|
const accordionList = useMemo(() => {
|
||||||
|
const username = settings?.username;
|
||||||
|
if (!username) {
|
||||||
|
toast.error('请先登录');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const _url = new URL(`${baseUrl}/api/s1/share/${username}/${resource?.name}`);
|
||||||
|
const meta = resource?.metaData ?? {};
|
||||||
|
if (meta.password) {
|
||||||
|
_url.searchParams.set('p', meta.password);
|
||||||
|
}
|
||||||
|
const url = _url.toString();
|
||||||
|
let accordionList: AccordionItem[] = [];
|
||||||
|
const encodeUrl = encodeURIComponent(url);
|
||||||
|
const previewUrl = `${baseUrl}/app/preview?fileUrl=${encodeUrl}&fileType=${fileType}`;
|
||||||
|
accordionList.push({
|
||||||
|
title: '文件预览',
|
||||||
|
key: 'preview-file',
|
||||||
|
url: previewUrl,
|
||||||
|
content: (
|
||||||
|
<div className=''>
|
||||||
|
<div className='text-sm break-words'>{previewUrl}</div>
|
||||||
|
<Button variant='contained' color='primary' style={{ color: 'white' }} onClick={() => window.open(previewUrl, '_blank')}>
|
||||||
|
点击查看
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fileType === 'image') {
|
||||||
|
accordionList.push({
|
||||||
|
title: '预览图片',
|
||||||
|
key: 'preview-image',
|
||||||
|
url: url,
|
||||||
|
content: <img className='w-full h-full border-2 border-gray-300 rounded-md' src={url} alt={resource?.name} />,
|
||||||
|
});
|
||||||
|
accordionList.push({
|
||||||
|
title: 'markdown链接',
|
||||||
|
key: 'markdown-link',
|
||||||
|
url: url,
|
||||||
|
clickCopy: true,
|
||||||
|
content: ``,
|
||||||
|
});
|
||||||
|
accordionList.push({
|
||||||
|
title: 'HTML图片',
|
||||||
|
key: 'html-image',
|
||||||
|
url: url,
|
||||||
|
clickCopy: true,
|
||||||
|
content: `<img style="width: 100%;height: 100%;" src="${url}" alt="${resource?.name}" />`,
|
||||||
|
});
|
||||||
|
accordionList.push({
|
||||||
|
title: 'HTML超链接',
|
||||||
|
key: 'html-link',
|
||||||
|
url: url,
|
||||||
|
clickCopy: true,
|
||||||
|
content: `<a href="${url}">${resource?.name}</a>`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const downloadUrl = new URL(url);
|
||||||
|
downloadUrl.searchParams.set('download', 'true');
|
||||||
|
accordionList.push({
|
||||||
|
title: '下载地址',
|
||||||
|
key: 'download-url',
|
||||||
|
url: downloadUrl.toString(),
|
||||||
|
content: (
|
||||||
|
<div className=''>
|
||||||
|
<div className='text-sm break-words'>{downloadUrl.toString()}</div>
|
||||||
|
<Button variant='contained' color='primary' style={{ color: 'white' }} onClick={() => window.open(downloadUrl.toString(), '_blank')}>
|
||||||
|
点击下载
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
return accordionList;
|
||||||
|
}, [resource, baseUrl, settings]);
|
||||||
|
const theme = useTheme();
|
||||||
|
return (
|
||||||
|
<div className='p-4'>
|
||||||
|
{accordionList.map((item) => (
|
||||||
|
<Accordion key={item.key}>
|
||||||
|
<AccordionSummary expandIcon={<ChevronDown color={theme.palette.text.secondary} />}>{item.title}</AccordionSummary>
|
||||||
|
<AccordionDetails>
|
||||||
|
<div
|
||||||
|
className={clsx('text-sm whitespace-pre-wrap w-full overflow-ellipsis overflow-hidden', {
|
||||||
|
'cursor-copy': item.clickCopy, // cursor-copy的有吗
|
||||||
|
})}
|
||||||
|
onClick={() => {
|
||||||
|
if (item.clickCopy) {
|
||||||
|
navigator.clipboard.writeText(item.content);
|
||||||
|
toast.success('复制成功');
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{item.content}
|
||||||
|
</div>
|
||||||
|
</AccordionDetails>
|
||||||
|
</Accordion>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
41
packages/resources/src/pages/file/draw/quick/index.tsx
Normal file
41
packages/resources/src/pages/file/draw/quick/index.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { useResourceFileStore } from '@/pages/store/resource-file';
|
||||||
|
import { useShallow } from 'zustand/shallow';
|
||||||
|
import { QuickPreview } from './QuickPreview';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { getFileType } from '../../FileIcon';
|
||||||
|
|
||||||
|
const QuickModules = [
|
||||||
|
{
|
||||||
|
key: 'link',
|
||||||
|
type: 'link',
|
||||||
|
categroy: ['image', 'video', 'audio'],
|
||||||
|
tooltips: `链接生成,markdown超链接`,
|
||||||
|
component: () => <QuickPreview />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'preview',
|
||||||
|
type: 'all',
|
||||||
|
tooltips: `预览页面内容`,
|
||||||
|
component: () => <QuickPreview />,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const Quick = () => {
|
||||||
|
const { resource } = useResourceFileStore(
|
||||||
|
useShallow((state) => ({
|
||||||
|
resource: state.resource,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
const quickModule = useMemo(() => {
|
||||||
|
const fileType = getFileType(resource?.name);
|
||||||
|
const allCanUseModule = QuickModules.filter((item) => item.type === 'all');
|
||||||
|
if (!fileType) {
|
||||||
|
return allCanUseModule;
|
||||||
|
}
|
||||||
|
return QuickModules.filter((item) => item.type === fileType);
|
||||||
|
}, [resource]);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<QuickPreview />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -11,14 +11,35 @@ export const FileTable = () => {
|
|||||||
const { list, prefix, download, onOpenPrefix, deleteFile } = useResourceStore();
|
const { list, prefix, download, onOpenPrefix, deleteFile } = useResourceStore();
|
||||||
const { setOpenDrawer, setPrefix } = useResourceFileStore();
|
const { setOpenDrawer, setPrefix } = useResourceFileStore();
|
||||||
return (
|
return (
|
||||||
<TableContainer component={Paper}>
|
<TableContainer
|
||||||
<Table sx={{ minWidth: 650 }} aria-label='simple table'>
|
className='scrollbar'
|
||||||
|
sx={{
|
||||||
|
'&': {
|
||||||
|
// scrollbarWidth: 'none',
|
||||||
|
// scrollbarColor: '#888 #fff',
|
||||||
|
},
|
||||||
|
'&::-webkit-scrollbar': {
|
||||||
|
width: '4px !important',
|
||||||
|
height: '4px !important',
|
||||||
|
background: '#fff',
|
||||||
|
},
|
||||||
|
'&::-webkit-scrollbar-thumb': {
|
||||||
|
background: '#888',
|
||||||
|
borderRadius: '2px',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
component={Paper}>
|
||||||
|
<Table
|
||||||
|
sx={{
|
||||||
|
minWidth: 650,
|
||||||
|
}}
|
||||||
|
aria-label='simple table'>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>Name</TableCell>
|
<TableCell>Name</TableCell>
|
||||||
<TableCell sx={{ maxWidth: 100 }}>Size</TableCell>
|
<TableCell sx={{ minWidth: 100 }}>Size</TableCell>
|
||||||
<TableCell sx={{ maxWidth: 100 }}>Last Modified</TableCell>
|
<TableCell sx={{ minWidth: 180 }}>Last Modified</TableCell>
|
||||||
<TableCell sx={{ maxWidth: 100 }}>Actions</TableCell>
|
<TableCell sx={{ minWidth: 110 }}>Actions</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { createRoot } from 'react-dom/client';
|
import { bootstrap } from './Bootstrap';
|
||||||
import { App } from './App.tsx';
|
|
||||||
|
|
||||||
createRoot(document.getElementById('ai-root')!).render(<App />);
|
bootstrap('#ai-root');
|
||||||
|
@ -4,8 +4,11 @@ import { toast } from 'react-toastify';
|
|||||||
const LoginMessage = () => {
|
const LoginMessage = () => {
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
const currentUrl = window.location.href;
|
const currentUrl = window.location.href;
|
||||||
|
console.log(currentUrl);
|
||||||
const redirect = encodeURIComponent(currentUrl);
|
const redirect = encodeURIComponent(currentUrl);
|
||||||
window.location.href = '/user/login?redirect=' + redirect;
|
console.log('redirect', redirect);
|
||||||
|
const newUrl = location.origin + '/user/login/?redirect=' + redirect;
|
||||||
|
window.open(newUrl, '_self');
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -40,7 +40,6 @@ export const Settings = () => {
|
|||||||
}, [settings]);
|
}, [settings]);
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
let { name, value } = e.target;
|
let { name, value } = e.target;
|
||||||
console.log(name, value, e.target);
|
|
||||||
name = name.toLowerCase();
|
name = name.toLowerCase();
|
||||||
setConfig({ ...config, [name]: value });
|
setConfig({ ...config, [name]: value });
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { Resource } from './resource';
|
import { Resource } from './resource';
|
||||||
import { query } from '@/modules/query';
|
import { query } from '@/modules/query';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
interface ResourceFileStore {
|
interface ResourceFileStore {
|
||||||
resource: Resource | null;
|
resource: Resource | null;
|
||||||
@ -10,6 +11,7 @@ interface ResourceFileStore {
|
|||||||
prefix: string;
|
prefix: string;
|
||||||
setPrefix: (prefix: string, replace?: string) => void;
|
setPrefix: (prefix: string, replace?: string) => void;
|
||||||
getStatFile: () => Promise<any>;
|
getStatFile: () => Promise<any>;
|
||||||
|
updateMeta: (metadata: any) => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useResourceFileStore = create<ResourceFileStore>((set, get) => ({
|
export const useResourceFileStore = create<ResourceFileStore>((set, get) => ({
|
||||||
@ -32,4 +34,21 @@ export const useResourceFileStore = create<ResourceFileStore>((set, get) => ({
|
|||||||
set({ resource: { ...res.data, name: prefix } });
|
set({ resource: { ...res.data, name: prefix } });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
updateMeta: async (metadata: any) => {
|
||||||
|
const { resource, getStatFile } = get();
|
||||||
|
const res = await query.post({
|
||||||
|
path: 'file',
|
||||||
|
key: 'update-metadata',
|
||||||
|
data: {
|
||||||
|
prefix: resource?.name,
|
||||||
|
metadata: metadata,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (res.code === 200) {
|
||||||
|
// set({ resource: { ...res.data, name: resource?.name } });
|
||||||
|
getStatFile();
|
||||||
|
} else {
|
||||||
|
toast.error(res.message || '更新元数据失败');
|
||||||
|
}
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -2,6 +2,7 @@ import { create } from 'zustand';
|
|||||||
import { query } from '@/modules/query';
|
import { query } from '@/modules/query';
|
||||||
import { sortBy } from 'lodash-es';
|
import { sortBy } from 'lodash-es';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import { useSettingsStore } from './settings';
|
||||||
|
|
||||||
export type Resource = {
|
export type Resource = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -67,9 +68,16 @@ export const useResourceStore = create<ResourceStore>((set, get) => ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
download: (resource: Resource) => {
|
download: (resource: Resource) => {
|
||||||
const { prefix } = get();
|
const { baseUrl, settings } = useSettingsStore.getState();
|
||||||
const url = `${prefix}/${resource.name}`;
|
const username = settings?.username;
|
||||||
window.open(url, '_blank');
|
const _url = new URL(`${baseUrl}/api/s1/share/${username}/${resource?.name}`);
|
||||||
|
_url.searchParams.set('download', 'true');
|
||||||
|
const downloadUrl = _url.toString();
|
||||||
|
console.log('downloadUrl', downloadUrl);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = downloadUrl;
|
||||||
|
a.download = resource.name;
|
||||||
|
a.click();
|
||||||
},
|
},
|
||||||
listType: 'table',
|
listType: 'table',
|
||||||
setListType: (listType: 'table' | 'card') => {
|
setListType: (listType: 'table' | 'card') => {
|
||||||
|
@ -12,16 +12,18 @@ interface SettingsStore {
|
|||||||
settings: Settings;
|
settings: Settings;
|
||||||
setSettings: (settings: Settings) => void;
|
setSettings: (settings: Settings) => void;
|
||||||
querySettings: () => Promise<void>;
|
querySettings: () => Promise<void>;
|
||||||
mounted: boolean;
|
mounted: 'loading' | 'error' | 'success';
|
||||||
setMounted: (mounted: boolean) => void;
|
setMounted: (mounted: 'loading' | 'error' | 'success') => void;
|
||||||
init: () => Promise<void>;
|
init: () => Promise<void>;
|
||||||
updateSettings: (settings: Settings) => void;
|
updateSettings: (settings: Settings) => void;
|
||||||
|
baseUrl: string;
|
||||||
|
setBaseUrl: (baseUrl: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useSettingsStore = create<SettingsStore>((set, get) => ({
|
export const useSettingsStore = create<SettingsStore>((set, get) => ({
|
||||||
settings: {},
|
settings: {},
|
||||||
setSettings: (settings) => set({ settings }),
|
setSettings: (settings) => set({ settings }),
|
||||||
mounted: false,
|
mounted: 'loading',
|
||||||
setMounted: (mounted) => set({ mounted }),
|
setMounted: (mounted) => set({ mounted }),
|
||||||
querySettings: async () => {
|
querySettings: async () => {
|
||||||
const settings = get().settings;
|
const settings = get().settings;
|
||||||
@ -29,37 +31,48 @@ export const useSettingsStore = create<SettingsStore>((set, get) => ({
|
|||||||
path: 'config',
|
path: 'config',
|
||||||
key: 'getUploadConfig',
|
key: 'getUploadConfig',
|
||||||
});
|
});
|
||||||
console.log(res);
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const config = res.data;
|
const config = res.data;
|
||||||
localStorage.setItem('upload-config', JSON.stringify(config));
|
localStorage.setItem('upload-config', JSON.stringify(config));
|
||||||
set({ settings: config });
|
set({ settings: config });
|
||||||
if (JSON.stringify(settings) !== JSON.stringify(config)) {
|
if (JSON.stringify(settings) !== JSON.stringify(config)) {
|
||||||
set({ mounted: false });
|
set({ mounted: 'success' });
|
||||||
set({ mounted: true });
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
toast.error(res.message || '获取配置失败');
|
!res.noMsg && toast.error(res.message || '获取配置失败');
|
||||||
|
set({ mounted: 'error' });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateSettings: async (settings) => {
|
updateSettings: async (settings) => {
|
||||||
console.log('setinng', settings);
|
const res = await query.post({
|
||||||
// const res = await query.post({
|
path: 'config',
|
||||||
// path: 'config',
|
key: 'updateUploadConfig',
|
||||||
// key: 'updateUploadConfig',
|
data: {
|
||||||
// data: settings,
|
key: settings.key,
|
||||||
// });
|
version: settings.version,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (res.code === 200) {
|
||||||
|
toast.success('更新配置成功');
|
||||||
|
get().querySettings();
|
||||||
|
} else {
|
||||||
|
toast.error(res.message || '更新配置失败');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
init: async () => {
|
init: async () => {
|
||||||
const cacheConfig = localStorage.getItem('upload-config');
|
const cacheConfig = localStorage.getItem('upload-config');
|
||||||
if (cacheConfig) {
|
if (cacheConfig) {
|
||||||
try {
|
try {
|
||||||
set({ settings: JSON.parse(cacheConfig), mounted: true });
|
set({ settings: JSON.parse(cacheConfig), mounted: 'success' });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error('配置文件损坏');
|
toast.error('配置文件损坏');
|
||||||
localStorage.removeItem('upload-config');
|
localStorage.removeItem('upload-config');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
get().querySettings();
|
get().querySettings();
|
||||||
|
const baseUrl = location.origin;
|
||||||
|
set({ baseUrl });
|
||||||
},
|
},
|
||||||
|
baseUrl: '',
|
||||||
|
setBaseUrl: (baseUrl) => set({ baseUrl }),
|
||||||
}));
|
}));
|
||||||
|
@ -3,7 +3,7 @@ import { useDropzone } from 'react-dropzone';
|
|||||||
import { uploadFiles } from './utils/upload';
|
import { uploadFiles } from './utils/upload';
|
||||||
import { FileText, CloudUpload as UploadIcon } from 'lucide-react';
|
import { FileText, CloudUpload as UploadIcon } from 'lucide-react';
|
||||||
import { uploadFileChunked } from './utils/upload-chunk';
|
import { uploadFileChunked } from './utils/upload-chunk';
|
||||||
export const UploadButton = (props: { prefix?: string; onUpload?: (res: any) => void }) => {
|
export const UploadButton = (props: { prefix?: string; onUpload?: (res: any) => void; hasDirectory?: boolean; uploadDirectory?: boolean }) => {
|
||||||
const onDrop = async (acceptedFiles) => {
|
const onDrop = async (acceptedFiles) => {
|
||||||
console.log(acceptedFiles);
|
console.log(acceptedFiles);
|
||||||
if (acceptedFiles.length > 1) {
|
if (acceptedFiles.length > 1) {
|
||||||
@ -27,11 +27,18 @@ export const UploadButton = (props: { prefix?: string; onUpload?: (res: any) =>
|
|||||||
}}>
|
}}>
|
||||||
<UploadIcon />
|
<UploadIcon />
|
||||||
</Button>
|
</Button>
|
||||||
<input type='file' style={{ display: 'none' }} {...getInputProps()} />
|
<input
|
||||||
|
type='file'
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
{...getInputProps()}
|
||||||
|
// @ts-ignore
|
||||||
|
webkitdirectory={props.uploadDirectory ? 'true' : undefined}
|
||||||
|
mozdirectory={props.uploadDirectory ? 'true' : undefined}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export const Upload = () => {
|
export const Upload = ({ uploadDirectory = false }: { uploadDirectory?: boolean }) => {
|
||||||
const onDrop = async (acceptedFiles) => {
|
const onDrop = async (acceptedFiles) => {
|
||||||
console.log(acceptedFiles);
|
console.log(acceptedFiles);
|
||||||
if (acceptedFiles.length > 1) {
|
if (acceptedFiles.length > 1) {
|
||||||
@ -87,7 +94,14 @@ export const Upload = () => {
|
|||||||
}}>
|
}}>
|
||||||
<UploadIcon style={{ width: '48px', height: '48px', color: theme.palette.secondary.main }} />
|
<UploadIcon style={{ width: '48px', height: '48px', color: theme.palette.secondary.main }} />
|
||||||
<label style={{ cursor: 'pointer' }}>
|
<label style={{ cursor: 'pointer' }}>
|
||||||
<input type='file' style={{ display: 'none' }} {...getInputProps()} />
|
<input
|
||||||
|
type='file'
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
{...getInputProps()}
|
||||||
|
// @ts-ignore
|
||||||
|
webkitdirectory={uploadDirectory ? 'true' : undefined}
|
||||||
|
mozdirectory={uploadDirectory ? 'true' : undefined}
|
||||||
|
/>
|
||||||
<Box sx={{ color: theme.palette.secondary.main, '&:hover': { color: theme.palette.primary.main } }}>Click to upload or drag and drop</Box>
|
<Box sx={{ color: theme.palette.secondary.main, '&:hover': { color: theme.palette.primary.main } }}>Click to upload or drag and drop</Box>
|
||||||
</label>
|
</label>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -14,12 +14,25 @@ export const uploadFiles = async (files: File[], opts: ConvertOpts) => {
|
|||||||
const { directory } = opts;
|
const { directory } = opts;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
const webkitRelativePath = files[0]?.webkitRelativePath;
|
||||||
|
const keepDirectory = webkitRelativePath !== '';
|
||||||
|
const root = keepDirectory ? webkitRelativePath.split('/')[0] : '';
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
formData.append('file', files[i], files[i].name);
|
const file = files[i];
|
||||||
|
if (keepDirectory) {
|
||||||
|
// relativePath 去除第一级
|
||||||
|
const webkitRelativePath = file.webkitRelativePath.replace(root + '/', '');
|
||||||
|
formData.append('file', file, webkitRelativePath); // 保留文件夹路径
|
||||||
|
} else {
|
||||||
|
formData.append('file', files[i], files[i].name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (directory) {
|
if (directory) {
|
||||||
formData.append('directory', directory);
|
formData.append('directory', directory);
|
||||||
}
|
}
|
||||||
|
console.log('formData', formData, files);
|
||||||
|
resolve(null);
|
||||||
|
return;
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
if (!token) {
|
if (!token) {
|
||||||
toastLogin();
|
toastLogin();
|
||||||
|
@ -15,6 +15,7 @@ if (true) {
|
|||||||
target: 'https://kevisual.silkyai.cn',
|
target: 'https://kevisual.silkyai.cn',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
ws: true,
|
ws: true,
|
||||||
|
cookieDomainRewrite: 'localhost',
|
||||||
rewrite: (path) => path.replace(/^\/api/, '/api'),
|
rewrite: (path) => path.replace(/^\/api/, '/api'),
|
||||||
},
|
},
|
||||||
'/api/router': {
|
'/api/router': {
|
||||||
@ -27,6 +28,7 @@ if (true) {
|
|||||||
'/user/login': {
|
'/user/login': {
|
||||||
target: 'https://kevisual.silkyai.cn',
|
target: 'https://kevisual.silkyai.cn',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
|
cookieDomainRewrite: 'localhost',
|
||||||
rewrite: (path) => path.replace(/^\/user/, '/user'),
|
rewrite: (path) => path.replace(/^\/user/, '/user'),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -41,12 +43,27 @@ export default defineConfig({
|
|||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': path.resolve(__dirname, './src'),
|
'@': path.resolve(__dirname, './src'),
|
||||||
|
// 'react/jsx-dev-runtime': 'https://cdn.jsdelivr.net/npm/react/jsx-dev-runtime/+esm',
|
||||||
|
// 'react/jsx-runtime': 'https://cdn.jsdelivr.net/npm/react/jsx-runtime/+esm',
|
||||||
|
// 'react/jsx-runtime': path.resolve(__dirname, './node_modules/react/jsx-runtime'),
|
||||||
|
// 'react/jsx-dev-runtime': path.resolve(__dirname, './node_modules/react/jsx-dev-runtime'),
|
||||||
|
// 'react-dom/client': 'https://cdn.jsdelivr.net/npm/react-dom/client/+esm',
|
||||||
|
// react: 'https://cdn.jsdelivr.net/npm/react@19.0.0/+esm',
|
||||||
|
// 'react-dom': 'https://cdn.jsdelivr.net/npm/react-dom@19.0.0/+esm',
|
||||||
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
define: {
|
define: {
|
||||||
DEV_SERVER: JSON.stringify(process.env.NODE_ENV === 'development'),
|
DEV_SERVER: JSON.stringify(process.env.NODE_ENV === 'development'),
|
||||||
|
BASE_NAME: JSON.stringify('/root/resources/'),
|
||||||
|
},
|
||||||
|
base: './',
|
||||||
|
// base: isDev ? '/' : '/root/resources/',
|
||||||
|
build: {
|
||||||
|
rollupOptions: {
|
||||||
|
// external: ['react', 'react-dom'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
base: isDev ? '/' : '/root/resources/',
|
|
||||||
server: {
|
server: {
|
||||||
port: 6022,
|
port: 6022,
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
@ -59,6 +76,7 @@ export default defineConfig({
|
|||||||
target: 'http://localhost:4005',
|
target: 'http://localhost:4005',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
ws: true,
|
ws: true,
|
||||||
|
cookieDomainRewrite: 'localhost',
|
||||||
rewrite: (path) => path.replace(/^\/api/, '/api'),
|
rewrite: (path) => path.replace(/^\/api/, '/api'),
|
||||||
},
|
},
|
||||||
'/api/router': {
|
'/api/router': {
|
||||||
@ -68,12 +86,6 @@ export default defineConfig({
|
|||||||
rewriteWsOrigin: true,
|
rewriteWsOrigin: true,
|
||||||
rewrite: (path) => path.replace(/^\/api/, '/api'),
|
rewrite: (path) => path.replace(/^\/api/, '/api'),
|
||||||
},
|
},
|
||||||
'/api/s1/events': {
|
|
||||||
target: 'https://kevisual.silkyai.cn',
|
|
||||||
changeOrigin: true,
|
|
||||||
ws: true,
|
|
||||||
rewrite: (path) => path.replace(/^\/api/, '/api'),
|
|
||||||
},
|
|
||||||
...proxy,
|
...proxy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
256
pnpm-lock.yaml
generated
256
pnpm-lock.yaml
generated
@ -52,7 +52,7 @@ importers:
|
|||||||
version: 12.4.4(@types/react@19.0.10)(immer@10.1.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
version: 12.4.4(@types/react@19.0.10)(immer@10.1.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
antd:
|
antd:
|
||||||
specifier: ^5.24.3
|
specifier: ^5.24.3
|
||||||
version: 5.24.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
version: 5.24.3(date-fns@4.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
classnames:
|
classnames:
|
||||||
specifier: ^2.5.1
|
specifier: ^2.5.1
|
||||||
version: 2.5.1
|
version: 2.5.1
|
||||||
@ -227,8 +227,8 @@ importers:
|
|||||||
specifier: ^0.0.2
|
specifier: ^0.0.2
|
||||||
version: 0.0.2(rollup@4.34.7)
|
version: 0.0.2(rollup@4.34.7)
|
||||||
'@mui/material':
|
'@mui/material':
|
||||||
specifier: ^6.4.7
|
specifier: ^6.4.8
|
||||||
version: 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
version: 6.4.8(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
'@types/lodash-es':
|
'@types/lodash-es':
|
||||||
specifier: ^4.17.12
|
specifier: ^4.17.12
|
||||||
version: 4.17.12
|
version: 4.17.12
|
||||||
@ -251,8 +251,8 @@ importers:
|
|||||||
specifier: ^0.482.0
|
specifier: ^0.482.0
|
||||||
version: 0.482.0(react@19.0.0)
|
version: 0.482.0(react@19.0.0)
|
||||||
nanoid:
|
nanoid:
|
||||||
specifier: ^5.1.3
|
specifier: ^5.1.4
|
||||||
version: 5.1.3
|
version: 5.1.4
|
||||||
nprogress:
|
nprogress:
|
||||||
specifier: ^0.2.0
|
specifier: ^0.2.0
|
||||||
version: 0.2.0
|
version: 0.2.0
|
||||||
@ -262,6 +262,9 @@ importers:
|
|||||||
react:
|
react:
|
||||||
specifier: 19.0.0
|
specifier: 19.0.0
|
||||||
version: 19.0.0
|
version: 19.0.0
|
||||||
|
react-datepicker:
|
||||||
|
specifier: ^8.2.1
|
||||||
|
version: 8.2.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
react-dom:
|
react-dom:
|
||||||
specifier: 19.0.0
|
specifier: 19.0.0
|
||||||
version: 19.0.0(react@19.0.0)
|
version: 19.0.0(react@19.0.0)
|
||||||
@ -685,6 +688,27 @@ packages:
|
|||||||
resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==}
|
resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
|
'@floating-ui/core@1.6.9':
|
||||||
|
resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==}
|
||||||
|
|
||||||
|
'@floating-ui/dom@1.6.13':
|
||||||
|
resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==}
|
||||||
|
|
||||||
|
'@floating-ui/react-dom@2.1.2':
|
||||||
|
resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.8.0'
|
||||||
|
react-dom: '>=16.8.0'
|
||||||
|
|
||||||
|
'@floating-ui/react@0.27.5':
|
||||||
|
resolution: {integrity: sha512-BX3jKxo39Ba05pflcQmqPPwc0qdNsdNi/eweAFtoIdrJWNen2sVEWMEac3i6jU55Qfx+lOcdMNKYn2CtWmlnOQ==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=17.0.0'
|
||||||
|
react-dom: '>=17.0.0'
|
||||||
|
|
||||||
|
'@floating-ui/utils@0.2.9':
|
||||||
|
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
|
||||||
|
|
||||||
'@humanfs/core@0.19.1':
|
'@humanfs/core@0.19.1':
|
||||||
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
||||||
engines: {node: '>=18.18.0'}
|
engines: {node: '>=18.18.0'}
|
||||||
@ -777,6 +801,9 @@ packages:
|
|||||||
'@mui/core-downloads-tracker@6.4.7':
|
'@mui/core-downloads-tracker@6.4.7':
|
||||||
resolution: {integrity: sha512-XjJrKFNt9zAKvcnoIIBquXyFyhfrHYuttqMsoDS7lM7VwufYG4fAPw4kINjBFg++fqXM2BNAuWR9J7XVIuKIKg==}
|
resolution: {integrity: sha512-XjJrKFNt9zAKvcnoIIBquXyFyhfrHYuttqMsoDS7lM7VwufYG4fAPw4kINjBFg++fqXM2BNAuWR9J7XVIuKIKg==}
|
||||||
|
|
||||||
|
'@mui/core-downloads-tracker@6.4.8':
|
||||||
|
resolution: {integrity: sha512-vjP4+A1ybyCRhDZC7r5EPWu/gLseFZxaGyPdDl94vzVvk6Yj6gahdaqcjbhkaCrJjdZj90m3VioltWPAnWF/zw==}
|
||||||
|
|
||||||
'@mui/material@6.4.7':
|
'@mui/material@6.4.7':
|
||||||
resolution: {integrity: sha512-K65StXUeGAtFJ4ikvHKtmDCO5Ab7g0FZUu2J5VpoKD+O6Y3CjLYzRi+TMlI3kaL4CL158+FccMoOd/eaddmeRQ==}
|
resolution: {integrity: sha512-K65StXUeGAtFJ4ikvHKtmDCO5Ab7g0FZUu2J5VpoKD+O6Y3CjLYzRi+TMlI3kaL4CL158+FccMoOd/eaddmeRQ==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -797,6 +824,26 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@mui/material@6.4.8':
|
||||||
|
resolution: {integrity: sha512-5S9UTjKZZBd9GfbcYh/nYfD9cv6OXmj5Y7NgKYfk7JcSoshp8/pW5zP4wecRiroBSZX8wcrywSgogpVNO+5W0Q==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@emotion/react': ^11.5.0
|
||||||
|
'@emotion/styled': ^11.3.0
|
||||||
|
'@mui/material-pigment-css': ^6.4.8
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@emotion/react':
|
||||||
|
optional: true
|
||||||
|
'@emotion/styled':
|
||||||
|
optional: true
|
||||||
|
'@mui/material-pigment-css':
|
||||||
|
optional: true
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@mui/private-theming@6.4.6':
|
'@mui/private-theming@6.4.6':
|
||||||
resolution: {integrity: sha512-T5FxdPzCELuOrhpA2g4Pi6241HAxRwZudzAuL9vBvniuB5YU82HCmrARw32AuCiyTfWzbrYGGpZ4zyeqqp9RvQ==}
|
resolution: {integrity: sha512-T5FxdPzCELuOrhpA2g4Pi6241HAxRwZudzAuL9vBvniuB5YU82HCmrARw32AuCiyTfWzbrYGGpZ4zyeqqp9RvQ==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -807,6 +854,16 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@mui/private-theming@6.4.8':
|
||||||
|
resolution: {integrity: sha512-sWwQoNSn6elsPTAtSqCf+w5aaGoh7AASURNmpy+QTTD/zwJ0Jgwt0ZaaP6mXq2IcgHxYnYloM/+vJgHPMkRKTQ==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@mui/styled-engine@6.4.6':
|
'@mui/styled-engine@6.4.6':
|
||||||
resolution: {integrity: sha512-vSWYc9ZLX46be5gP+FCzWVn5rvDr4cXC5JBZwSIkYk9xbC7GeV+0kCvB8Q6XLFQJy+a62bbqtmdwS4Ghi9NBlQ==}
|
resolution: {integrity: sha512-vSWYc9ZLX46be5gP+FCzWVn5rvDr4cXC5JBZwSIkYk9xbC7GeV+0kCvB8Q6XLFQJy+a62bbqtmdwS4Ghi9NBlQ==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -820,6 +877,19 @@ packages:
|
|||||||
'@emotion/styled':
|
'@emotion/styled':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@mui/styled-engine@6.4.8':
|
||||||
|
resolution: {integrity: sha512-oyjx1b1FvUCI85ZMO4trrjNxGm90eLN3Ohy0AP/SqK5gWvRQg1677UjNf7t6iETOKAleHctJjuq0B3aXO2gtmw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@emotion/react': ^11.4.1
|
||||||
|
'@emotion/styled': ^11.3.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@emotion/react':
|
||||||
|
optional: true
|
||||||
|
'@emotion/styled':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@mui/system@6.4.7':
|
'@mui/system@6.4.7':
|
||||||
resolution: {integrity: sha512-7wwc4++Ak6tGIooEVA9AY7FhH2p9fvBMORT4vNLMAysH3Yus/9B9RYMbrn3ANgsOyvT3Z7nE+SP8/+3FimQmcg==}
|
resolution: {integrity: sha512-7wwc4++Ak6tGIooEVA9AY7FhH2p9fvBMORT4vNLMAysH3Yus/9B9RYMbrn3ANgsOyvT3Z7nE+SP8/+3FimQmcg==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -836,6 +906,22 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@mui/system@6.4.8':
|
||||||
|
resolution: {integrity: sha512-gV7iBHoqlsIenU2BP0wq14BefRoZcASZ/4LeyuQglayBl+DfLX5rEd3EYR3J409V2EZpR0NOM1LATAGlNk2cyA==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@emotion/react': ^11.5.0
|
||||||
|
'@emotion/styled': ^11.3.0
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@emotion/react':
|
||||||
|
optional: true
|
||||||
|
'@emotion/styled':
|
||||||
|
optional: true
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@mui/types@7.2.21':
|
'@mui/types@7.2.21':
|
||||||
resolution: {integrity: sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==}
|
resolution: {integrity: sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -844,6 +930,14 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@mui/types@7.2.24':
|
||||||
|
resolution: {integrity: sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@mui/utils@6.4.6':
|
'@mui/utils@6.4.6':
|
||||||
resolution: {integrity: sha512-43nZeE1pJF2anGafNydUcYFPtHwAqiBiauRtaMvurdrZI3YrUjHkAu43RBsxef7OFtJMXGiHFvq43kb7lig0sA==}
|
resolution: {integrity: sha512-43nZeE1pJF2anGafNydUcYFPtHwAqiBiauRtaMvurdrZI3YrUjHkAu43RBsxef7OFtJMXGiHFvq43kb7lig0sA==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -854,6 +948,16 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@mui/utils@6.4.8':
|
||||||
|
resolution: {integrity: sha512-C86gfiZ5BfZ51KqzqoHi1WuuM2QdSKoFhbkZeAfQRB+jCc4YNhhj11UXFVMMsqBgZ+Zy8IHNJW3M9Wj/LOwRXQ==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@ -1676,6 +1780,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==}
|
resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
date-fns@4.1.0:
|
||||||
|
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
||||||
|
|
||||||
dayjs@1.11.13:
|
dayjs@1.11.13:
|
||||||
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
||||||
|
|
||||||
@ -2189,6 +2296,11 @@ packages:
|
|||||||
engines: {node: ^18 || >=20}
|
engines: {node: ^18 || >=20}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
nanoid@5.1.4:
|
||||||
|
resolution: {integrity: sha512-GTFcMIDgR7tqji/LpSY8rtg464VnJl/j6ypoehYnuGb+Y8qZUdtKB8WVCXon0UEZgFDbuUxpIl//6FHLHgXSNA==}
|
||||||
|
engines: {node: ^18 || >=20}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
natural-compare@1.4.0:
|
natural-compare@1.4.0:
|
||||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||||
|
|
||||||
@ -2550,6 +2662,12 @@ packages:
|
|||||||
react: '>=16.9.0'
|
react: '>=16.9.0'
|
||||||
react-dom: '>=16.9.0'
|
react-dom: '>=16.9.0'
|
||||||
|
|
||||||
|
react-datepicker@8.2.1:
|
||||||
|
resolution: {integrity: sha512-1pyALWM9mTZ7DG7tfcApwBy2kkld9Kz/EI++LhPnoXJAASbvuq6fdsDfkoB3q1JrxF7vhghVmQ759H/rOwUNNw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc
|
||||||
|
react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc
|
||||||
|
|
||||||
react-dom@19.0.0:
|
react-dom@19.0.0:
|
||||||
resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==}
|
resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -2767,6 +2885,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
tabbable@6.2.0:
|
||||||
|
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
|
||||||
|
|
||||||
tailwind-merge@3.0.2:
|
tailwind-merge@3.0.2:
|
||||||
resolution: {integrity: sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw==}
|
resolution: {integrity: sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw==}
|
||||||
|
|
||||||
@ -3432,6 +3553,31 @@ snapshots:
|
|||||||
'@eslint/core': 0.12.0
|
'@eslint/core': 0.12.0
|
||||||
levn: 0.4.1
|
levn: 0.4.1
|
||||||
|
|
||||||
|
'@floating-ui/core@1.6.9':
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/utils': 0.2.9
|
||||||
|
|
||||||
|
'@floating-ui/dom@1.6.13':
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/core': 1.6.9
|
||||||
|
'@floating-ui/utils': 0.2.9
|
||||||
|
|
||||||
|
'@floating-ui/react-dom@2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/dom': 1.6.13
|
||||||
|
react: 19.0.0
|
||||||
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
|
|
||||||
|
'@floating-ui/react@0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
|
'@floating-ui/utils': 0.2.9
|
||||||
|
react: 19.0.0
|
||||||
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
|
tabbable: 6.2.0
|
||||||
|
|
||||||
|
'@floating-ui/utils@0.2.9': {}
|
||||||
|
|
||||||
'@humanfs/core@0.19.1': {}
|
'@humanfs/core@0.19.1': {}
|
||||||
|
|
||||||
'@humanfs/node@0.16.6':
|
'@humanfs/node@0.16.6':
|
||||||
@ -3479,7 +3625,7 @@ snapshots:
|
|||||||
'@emotion/css': 11.13.4
|
'@emotion/css': 11.13.4
|
||||||
crypto-js: 4.2.0
|
crypto-js: 4.2.0
|
||||||
eventemitter3: 5.0.1
|
eventemitter3: 5.0.1
|
||||||
nanoid: 5.1.3
|
nanoid: 5.1.4
|
||||||
rollup-plugin-dts: 6.1.1(rollup@4.34.7)(typescript@5.8.2)
|
rollup-plugin-dts: 6.1.1(rollup@4.34.7)(typescript@5.8.2)
|
||||||
scheduler: 0.23.2
|
scheduler: 0.23.2
|
||||||
zustand: 4.5.5(@types/react@19.0.10)(immer@10.1.1)(react@19.0.0)
|
zustand: 4.5.5(@types/react@19.0.10)(immer@10.1.1)(react@19.0.0)
|
||||||
@ -3548,6 +3694,8 @@ snapshots:
|
|||||||
|
|
||||||
'@mui/core-downloads-tracker@6.4.7': {}
|
'@mui/core-downloads-tracker@6.4.7': {}
|
||||||
|
|
||||||
|
'@mui/core-downloads-tracker@6.4.8': {}
|
||||||
|
|
||||||
'@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
'@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.0
|
'@babel/runtime': 7.26.0
|
||||||
@ -3569,6 +3717,27 @@ snapshots:
|
|||||||
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
|
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
|
||||||
'@types/react': 19.0.10
|
'@types/react': 19.0.10
|
||||||
|
|
||||||
|
'@mui/material@6.4.8(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.26.0
|
||||||
|
'@mui/core-downloads-tracker': 6.4.8
|
||||||
|
'@mui/system': 6.4.8(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
'@mui/types': 7.2.24(@types/react@19.0.10)
|
||||||
|
'@mui/utils': 6.4.8(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
'@popperjs/core': 2.11.8
|
||||||
|
'@types/react-transition-group': 4.4.12(@types/react@19.0.10)
|
||||||
|
clsx: 2.1.1
|
||||||
|
csstype: 3.1.3
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 19.0.0
|
||||||
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
|
react-is: 19.0.0
|
||||||
|
react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
|
optionalDependencies:
|
||||||
|
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
'@types/react': 19.0.10
|
||||||
|
|
||||||
'@mui/private-theming@6.4.6(@types/react@19.0.10)(react@19.0.0)':
|
'@mui/private-theming@6.4.6(@types/react@19.0.10)(react@19.0.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.0
|
'@babel/runtime': 7.26.0
|
||||||
@ -3578,6 +3747,15 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 19.0.10
|
'@types/react': 19.0.10
|
||||||
|
|
||||||
|
'@mui/private-theming@6.4.8(@types/react@19.0.10)(react@19.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.26.0
|
||||||
|
'@mui/utils': 6.4.8(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 19.0.0
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.0.10
|
||||||
|
|
||||||
'@mui/styled-engine@6.4.6(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)':
|
'@mui/styled-engine@6.4.6(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.0
|
'@babel/runtime': 7.26.0
|
||||||
@ -3591,6 +3769,19 @@ snapshots:
|
|||||||
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
|
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
|
||||||
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
|
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
|
||||||
|
'@mui/styled-engine@6.4.8(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.26.0
|
||||||
|
'@emotion/cache': 11.14.0
|
||||||
|
'@emotion/serialize': 1.3.3
|
||||||
|
'@emotion/sheet': 1.4.0
|
||||||
|
csstype: 3.1.3
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 19.0.0
|
||||||
|
optionalDependencies:
|
||||||
|
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
|
||||||
'@mui/system@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)':
|
'@mui/system@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.0
|
'@babel/runtime': 7.26.0
|
||||||
@ -3607,10 +3798,30 @@ snapshots:
|
|||||||
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
|
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
|
||||||
'@types/react': 19.0.10
|
'@types/react': 19.0.10
|
||||||
|
|
||||||
|
'@mui/system@6.4.8(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.26.0
|
||||||
|
'@mui/private-theming': 6.4.8(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
'@mui/styled-engine': 6.4.8(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)
|
||||||
|
'@mui/types': 7.2.24(@types/react@19.0.10)
|
||||||
|
'@mui/utils': 6.4.8(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
clsx: 2.1.1
|
||||||
|
csstype: 3.1.3
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 19.0.0
|
||||||
|
optionalDependencies:
|
||||||
|
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
|
||||||
|
'@types/react': 19.0.10
|
||||||
|
|
||||||
'@mui/types@7.2.21(@types/react@19.0.10)':
|
'@mui/types@7.2.21(@types/react@19.0.10)':
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 19.0.10
|
'@types/react': 19.0.10
|
||||||
|
|
||||||
|
'@mui/types@7.2.24(@types/react@19.0.10)':
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.0.10
|
||||||
|
|
||||||
'@mui/utils@6.4.6(@types/react@19.0.10)(react@19.0.0)':
|
'@mui/utils@6.4.6(@types/react@19.0.10)(react@19.0.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.0
|
'@babel/runtime': 7.26.0
|
||||||
@ -3623,6 +3834,18 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 19.0.10
|
'@types/react': 19.0.10
|
||||||
|
|
||||||
|
'@mui/utils@6.4.8(@types/react@19.0.10)(react@19.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.26.0
|
||||||
|
'@mui/types': 7.2.24(@types/react@19.0.10)
|
||||||
|
'@types/prop-types': 15.7.14
|
||||||
|
clsx: 2.1.1
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 19.0.0
|
||||||
|
react-is: 19.0.0
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.0.10
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nodelib/fs.stat': 2.0.5
|
'@nodelib/fs.stat': 2.0.5
|
||||||
@ -4187,7 +4410,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-convert: 2.0.1
|
color-convert: 2.0.1
|
||||||
|
|
||||||
antd@5.24.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
antd@5.24.3(date-fns@4.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ant-design/colors': 7.2.0
|
'@ant-design/colors': 7.2.0
|
||||||
'@ant-design/cssinjs': 1.23.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
'@ant-design/cssinjs': 1.23.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
@ -4219,7 +4442,7 @@ snapshots:
|
|||||||
rc-motion: 2.9.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
rc-motion: 2.9.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
rc-notification: 5.6.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
rc-notification: 5.6.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
rc-pagination: 5.1.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
rc-pagination: 5.1.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
rc-picker: 4.11.3(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
rc-picker: 4.11.3(date-fns@4.1.0)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
rc-progress: 4.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
rc-progress: 4.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
rc-rate: 2.13.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
rc-rate: 2.13.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
rc-resize-observer: 1.4.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
rc-resize-observer: 1.4.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
@ -4542,6 +4765,8 @@ snapshots:
|
|||||||
d3-transition: 3.0.1(d3-selection@3.0.0)
|
d3-transition: 3.0.1(d3-selection@3.0.0)
|
||||||
d3-zoom: 3.0.0
|
d3-zoom: 3.0.0
|
||||||
|
|
||||||
|
date-fns@4.1.0: {}
|
||||||
|
|
||||||
dayjs@1.11.13: {}
|
dayjs@1.11.13: {}
|
||||||
|
|
||||||
debug@4.3.7:
|
debug@4.3.7:
|
||||||
@ -5062,6 +5287,8 @@ snapshots:
|
|||||||
|
|
||||||
nanoid@5.1.3: {}
|
nanoid@5.1.3: {}
|
||||||
|
|
||||||
|
nanoid@5.1.4: {}
|
||||||
|
|
||||||
natural-compare@1.4.0: {}
|
natural-compare@1.4.0: {}
|
||||||
|
|
||||||
node-forge@1.3.1: {}
|
node-forge@1.3.1: {}
|
||||||
@ -5329,7 +5556,7 @@ snapshots:
|
|||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
react-dom: 19.0.0(react@19.0.0)
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
|
|
||||||
rc-picker@4.11.3(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
rc-picker@4.11.3(date-fns@4.1.0)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.0
|
'@babel/runtime': 7.26.0
|
||||||
'@rc-component/trigger': 2.2.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
'@rc-component/trigger': 2.2.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
@ -5340,6 +5567,7 @@ snapshots:
|
|||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
react-dom: 19.0.0(react@19.0.0)
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
|
date-fns: 4.1.0
|
||||||
dayjs: 1.11.13
|
dayjs: 1.11.13
|
||||||
|
|
||||||
rc-progress@4.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
rc-progress@4.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
||||||
@ -5505,6 +5733,14 @@ snapshots:
|
|||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
react-dom: 19.0.0(react@19.0.0)
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
|
|
||||||
|
react-datepicker@8.2.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/react': 0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
|
clsx: 2.1.1
|
||||||
|
date-fns: 4.1.0
|
||||||
|
react: 19.0.0
|
||||||
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
|
|
||||||
react-dom@19.0.0(react@19.0.0):
|
react-dom@19.0.0(react@19.0.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
@ -5737,6 +5973,8 @@ snapshots:
|
|||||||
|
|
||||||
supports-preserve-symlinks-flag@1.0.0: {}
|
supports-preserve-symlinks-flag@1.0.0: {}
|
||||||
|
|
||||||
|
tabbable@6.2.0: {}
|
||||||
|
|
||||||
tailwind-merge@3.0.2: {}
|
tailwind-merge@3.0.2: {}
|
||||||
|
|
||||||
tailwindcss-animate@1.0.7(tailwindcss@4.0.12):
|
tailwindcss-animate@1.0.7(tailwindcss@4.0.12):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user