mirror of
https://github.com/whyour/qinglong.git
synced 2025-05-22 22:36:06 +08:00
脚本管理增加强制打开文件操作
This commit is contained in:
parent
cf94ecfb11
commit
576408de01
|
@ -186,7 +186,7 @@
|
|||
"秒后重试": "Retry after seconds",
|
||||
"在您的设备上打开两步验证应用程序以查看您的身份验证代码并验证您的身份。": "Open the two-factor authentication application on your device to view your authentication code and verify your identity.",
|
||||
"请选择脚本文件": "Please select a script file",
|
||||
"当前文件不支持预览": "The current file does not support preview",
|
||||
"当前文件不支持预览": "Current file type is not supported for preview",
|
||||
"清空日志": "Clear Logs",
|
||||
"设置": "Settings",
|
||||
"退出": "Exit",
|
||||
|
@ -501,5 +501,9 @@
|
|||
"常规定时": "Normal Timing",
|
||||
"手动运行": "Manual Run",
|
||||
"开机运行": "Boot Run",
|
||||
"时区": "Timezone"
|
||||
"时区": "Timezone",
|
||||
"强制打开": "Force Open",
|
||||
"强制打开可能会导致编辑器显示异常": "Force opening may cause display issues in the editor",
|
||||
"确认离开": "Confirm Leave",
|
||||
"当前文件未保存,确认离开吗": "Current file is not saved, are you sure to leave?"
|
||||
}
|
||||
|
|
|
@ -501,6 +501,10 @@
|
|||
"常规定时": "常规定时",
|
||||
"手动运行": "手动运行",
|
||||
"开机运行": "开机运行",
|
||||
"时区": "时区"
|
||||
"时区": "时区",
|
||||
"强制打开": "强制打开",
|
||||
"强制打开可能会导致编辑器显示异常": "强制打开可能会导致编辑器显示异常",
|
||||
"确认离开": "确认离开",
|
||||
"当前文件未保存,确认离开吗": "当前文件未保存,确认离开吗"
|
||||
}
|
||||
|
|
@ -202,9 +202,6 @@ const CronDetailModal = ({
|
|||
.catch((e) => reject(e));
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -232,9 +229,6 @@ const CronDetailModal = ({
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -259,9 +253,6 @@ const CronDetailModal = ({
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -298,9 +289,6 @@ const CronDetailModal = ({
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -337,9 +325,6 @@ const CronDetailModal = ({
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
PushpinOutlined,
|
||||
SettingOutlined,
|
||||
StopOutlined,
|
||||
UnorderedListOutlined
|
||||
UnorderedListOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { history, useOutletContext } from '@umijs/max';
|
||||
|
@ -36,7 +36,7 @@ import {
|
|||
TablePaginationConfig,
|
||||
Tabs,
|
||||
Tag,
|
||||
Typography
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { ColumnProps } from 'antd/lib/table';
|
||||
import { FilterValue, SorterResult } from 'antd/lib/table/interface';
|
||||
|
@ -453,9 +453,6 @@ const Crontab = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -488,9 +485,6 @@ const Crontab = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -524,9 +518,6 @@ const Crontab = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -569,9 +560,6 @@ const Crontab = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -614,9 +602,6 @@ const Crontab = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -738,9 +723,6 @@ const Crontab = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -766,9 +748,6 @@ const Crontab = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ const ViewManageModal = ({
|
|||
title: intl.get('名称'),
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
render: (v) => (v === '全部任务' ? intl.get('全部任务') : v)
|
||||
render: (v) => (v === '全部任务' ? intl.get('全部任务') : v),
|
||||
},
|
||||
{
|
||||
title: intl.get('类型'),
|
||||
|
@ -162,9 +162,6 @@ const ViewManageModal = ({
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -315,9 +315,6 @@ const Dependence = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -342,9 +339,6 @@ const Dependence = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -367,9 +361,6 @@ const Dependence = () => {
|
|||
getDependencies();
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -419,9 +410,6 @@ const Dependence = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -439,9 +427,6 @@ const Dependence = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
12
src/pages/env/index.tsx
vendored
12
src/pages/env/index.tsx
vendored
|
@ -292,9 +292,6 @@ const Env = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -337,9 +334,6 @@ const Env = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -456,9 +450,6 @@ const Env = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -484,9 +475,6 @@ const Env = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -175,9 +175,6 @@ const Log = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--background-color);
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
background: var(--card-background);
|
||||
padding: 24px;
|
||||
border-radius: 12px;
|
||||
max-width: 360px;
|
||||
width: 100%;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.iconWrapper {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 50%;
|
||||
background: var(--background-color);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 32px;
|
||||
color: var(--text-color-secondary);
|
||||
}
|
||||
|
||||
.message {
|
||||
font-size: 16px;
|
||||
color: var(--text-color);
|
||||
margin-bottom: 16px;
|
||||
font-weight: 500;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.actionArea {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button {
|
||||
min-width: 140px;
|
||||
height: 36px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.warning {
|
||||
font-size: 13px;
|
||||
color: var(--text-color-secondary);
|
||||
line-height: 1.5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.warningIcon {
|
||||
font-size: 14px;
|
||||
color: #faad14;
|
||||
}
|
41
src/pages/script/components/UnsupportedFilePreview/index.tsx
Normal file
41
src/pages/script/components/UnsupportedFilePreview/index.tsx
Normal file
|
@ -0,0 +1,41 @@
|
|||
import React from 'react';
|
||||
import { Button, Space } from 'antd';
|
||||
import { FileUnknownOutlined, WarningOutlined } from '@ant-design/icons';
|
||||
import intl from 'react-intl-universal';
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface UnsupportedFilePreviewProps {
|
||||
onForceOpen: () => void;
|
||||
}
|
||||
|
||||
const UnsupportedFilePreview: React.FC<UnsupportedFilePreviewProps> = ({
|
||||
onForceOpen,
|
||||
}) => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.iconWrapper}>
|
||||
<FileUnknownOutlined className={styles.icon} />
|
||||
</div>
|
||||
<div className={styles.message}>
|
||||
{intl.get('当前文件不支持预览')}
|
||||
</div>
|
||||
<Space direction="vertical" size={8} className={styles.actionArea}>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={onForceOpen}
|
||||
className={styles.button}
|
||||
>
|
||||
{intl.get('强制打开')}
|
||||
</Button>
|
||||
<div className={styles.warning}>
|
||||
<WarningOutlined className={styles.warningIcon} />
|
||||
{intl.get('强制打开可能会导致编辑器显示异常')}
|
||||
</div>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UnsupportedFilePreview;
|
|
@ -43,6 +43,7 @@ import EditModal from './editModal';
|
|||
import EditScriptNameModal from './editNameModal';
|
||||
import styles from './index.module.less';
|
||||
import RenameModal from './renameModal';
|
||||
import UnsupportedFilePreview from './components/UnsupportedFilePreview';
|
||||
const { Text } = Typography;
|
||||
|
||||
const Script = () => {
|
||||
|
@ -63,6 +64,7 @@ const Script = () => {
|
|||
useState(false);
|
||||
const [currentNode, setCurrentNode] = useState<any>();
|
||||
const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
|
||||
const [showMonaco, setShowMonaco] = useState(true);
|
||||
|
||||
const handleIsEditing = (filename: string, value: boolean) => {
|
||||
setIsEditing(value && canPreviewInMonaco(filename));
|
||||
|
@ -82,7 +84,7 @@ const Script = () => {
|
|||
.finally(() => needLoading && setLoading(false));
|
||||
};
|
||||
|
||||
const getDetail = (node: any) => {
|
||||
const getDetail = (node: any, options: any = {}) => {
|
||||
request
|
||||
.get(
|
||||
`${config.apiPrefix}scripts/detail?file=${encodeURIComponent(
|
||||
|
@ -92,6 +94,9 @@ const Script = () => {
|
|||
.then(({ code, data }) => {
|
||||
if (code === 200) {
|
||||
setValue(data);
|
||||
if (options.callback) {
|
||||
options.callback();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -126,7 +131,7 @@ const Script = () => {
|
|||
if (item) {
|
||||
obj.node = item;
|
||||
setExpandedKeys([p as string]);
|
||||
onTreeSelect([vkey], obj);
|
||||
onSelect([vkey], obj);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -141,18 +146,27 @@ const Script = () => {
|
|||
|
||||
if (node.type === 'directory') {
|
||||
setValue(intl.get('请选择脚本文件'));
|
||||
setShowMonaco(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canPreviewInMonaco(node.title)) {
|
||||
setValue(intl.get('当前文件不支持预览'));
|
||||
setShowMonaco(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setShowMonaco(true);
|
||||
const newMode = getEditorMode(value);
|
||||
setMode(isPhone && newMode === 'typescript' ? 'javascript' : newMode);
|
||||
setValue(intl.get('加载中...'));
|
||||
getDetail(node);
|
||||
|
||||
getDetail(node, {
|
||||
callback: () => {
|
||||
if (isEditing) {
|
||||
setIsEditing(true);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const onTreeSelect = useCallback(
|
||||
|
@ -161,20 +175,20 @@ const Script = () => {
|
|||
if (node.key === select && isEditing) {
|
||||
return;
|
||||
}
|
||||
const content = editorRef.current
|
||||
|
||||
const currentContent = editorRef.current
|
||||
? editorRef.current.getValue().replace(/\r\n/g, '\n')
|
||||
: value;
|
||||
if (content !== value) {
|
||||
const originalContent = value.replace(/\r\n/g, '\n');
|
||||
|
||||
if (currentContent !== originalContent && isEditing) {
|
||||
Modal.confirm({
|
||||
title: `确认离开`,
|
||||
content: <>{intl.get('当前修改未保存,确定离开吗')}</>,
|
||||
title: intl.get('确认离开'),
|
||||
content: <>{intl.get('当前文件未保存,确认离开吗')}</>,
|
||||
onOk() {
|
||||
onSelect(keys[0], e.node);
|
||||
handleIsEditing(e.node.title, false);
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
} else {
|
||||
handleIsEditing(e.node.title, false);
|
||||
|
@ -268,9 +282,6 @@ const Script = () => {
|
|||
.catch((e) => reject(e));
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -320,9 +331,6 @@ const Script = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -493,7 +501,7 @@ const Script = () => {
|
|||
label: intl.get('编辑'),
|
||||
key: 'edit',
|
||||
icon: <EditOutlined />,
|
||||
disabled: !currentNode || !canPreviewInMonaco(currentNode?.title),
|
||||
disabled: !currentNode,
|
||||
},
|
||||
{
|
||||
label: intl.get('重命名'),
|
||||
|
@ -514,6 +522,20 @@ const Script = () => {
|
|||
},
|
||||
};
|
||||
|
||||
const handleForceOpen = () => {
|
||||
if (!currentNode) return;
|
||||
|
||||
setMode('plaintext');
|
||||
setValue(intl.get('加载中...'));
|
||||
setShowMonaco(true);
|
||||
|
||||
getDetail(currentNode, {
|
||||
callback: () => {
|
||||
setIsEditing(true);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
className="ql-container-wrapper log-wrapper"
|
||||
|
@ -575,9 +597,7 @@ const Script = () => {
|
|||
</Tooltip>,
|
||||
<Tooltip title={intl.get('编辑')}>
|
||||
<Button
|
||||
disabled={
|
||||
!currentNode || !canPreviewInMonaco(currentNode?.title)
|
||||
}
|
||||
disabled={!currentNode}
|
||||
type="primary"
|
||||
onClick={editFile}
|
||||
icon={<EditOutlined />}
|
||||
|
@ -666,21 +686,28 @@ const Script = () => {
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Editor
|
||||
language={mode}
|
||||
value={value}
|
||||
theme={theme}
|
||||
options={{
|
||||
readOnly: !isEditing,
|
||||
fontSize: 12,
|
||||
lineNumbersMinChars: 3,
|
||||
glyphMargin: false,
|
||||
accessibilitySupport: 'off',
|
||||
}}
|
||||
onMount={(editor) => {
|
||||
editorRef.current = editor;
|
||||
}}
|
||||
/>
|
||||
{showMonaco ? (
|
||||
<Editor
|
||||
language={mode}
|
||||
value={value}
|
||||
theme={theme}
|
||||
options={{
|
||||
readOnly: !isEditing,
|
||||
fontSize: 12,
|
||||
lineNumbersMinChars: 3,
|
||||
glyphMargin: false,
|
||||
accessibilitySupport: 'off',
|
||||
}}
|
||||
onMount={(editor) => {
|
||||
editorRef.current = editor;
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<UnsupportedFilePreview
|
||||
filename={currentNode?.title || ''}
|
||||
onForceOpen={handleForceOpen}
|
||||
/>
|
||||
)}
|
||||
</SplitPane>
|
||||
)}
|
||||
{isPhone && (
|
||||
|
|
|
@ -181,9 +181,6 @@ const Setting = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -213,9 +210,6 @@ const Setting = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -266,9 +266,6 @@ const Subscription = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -302,9 +299,6 @@ const Subscription = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -370,9 +364,6 @@ const Subscription = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -415,9 +406,6 @@ const Subscription = () => {
|
|||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,168 @@
|
|||
import * as monaco from 'monaco-editor';
|
||||
|
||||
interface FileTypeConfig {
|
||||
extensions?: string[]; // 文件扩展名
|
||||
filenames?: string[]; // 完整文件名
|
||||
patterns?: RegExp[]; // 文件名正则匹配
|
||||
startsWith?: string[]; // 文件名前缀匹配
|
||||
endsWith?: string[]; // 文件名后缀匹配
|
||||
}
|
||||
|
||||
// 文件类型分类配置(只包含特殊文件类型)
|
||||
const fileTypeConfigs: Record<string, FileTypeConfig> = {
|
||||
// 前端特殊文件
|
||||
frontend: {
|
||||
extensions: [
|
||||
'.json5', // JSON5
|
||||
'.vue', // Vue
|
||||
'.svelte', // Svelte
|
||||
'.astro', // Astro
|
||||
'.wxss', // 微信小程序样式
|
||||
'.pcss', // PostCSS
|
||||
'.acss', // 支付宝小程序样式
|
||||
],
|
||||
patterns: [
|
||||
/\.env\.(local|development|production|test)$/,
|
||||
/\.module\.(css|less|scss|sass)$/,
|
||||
/\.d\.ts$/,
|
||||
/\.config\.(js|ts|json)$/,
|
||||
],
|
||||
},
|
||||
|
||||
// 小程序相关
|
||||
miniprogram: {
|
||||
extensions: [
|
||||
'.wxml', // 微信小程序
|
||||
'.wxs', // 微信小程序
|
||||
'.axml', // 支付宝小程序
|
||||
'.sjs', // 支付宝小程序
|
||||
'.swan', // 百度小程序
|
||||
'.ttml', // 字节跳动小程序
|
||||
'.ttss', // 字节跳动小程序
|
||||
'.wxl', // 微信小程序语言包
|
||||
'.qml', // QQ小程序
|
||||
'.qss', // QQ小程序
|
||||
'.ksml', // 快手小程序
|
||||
'.kss', // 快手小程序
|
||||
],
|
||||
},
|
||||
|
||||
// 开发工具相关
|
||||
devtools: {
|
||||
extensions: [
|
||||
'.prisma', // Prisma
|
||||
'.mdx', // MDX
|
||||
'.swagger', // Swagger
|
||||
'.openapi', // OpenAPI
|
||||
],
|
||||
},
|
||||
|
||||
// 锁文件
|
||||
lock: {
|
||||
filenames: [
|
||||
'yarn.lock',
|
||||
'pnpm-lock.yaml',
|
||||
'package-lock.json',
|
||||
'composer.lock',
|
||||
'Gemfile.lock',
|
||||
'poetry.lock',
|
||||
'Cargo.lock',
|
||||
],
|
||||
},
|
||||
|
||||
// 无后缀配置文件
|
||||
noExtension: {
|
||||
filenames: [
|
||||
'.dockerignore',
|
||||
'.gitignore',
|
||||
'.npmignore',
|
||||
'.browserslistrc',
|
||||
'.czrc',
|
||||
'.huskyrc',
|
||||
'.lintstagedrc',
|
||||
'.nvmrc',
|
||||
'.gcloudignore',
|
||||
'.htaccess',
|
||||
],
|
||||
patterns: [
|
||||
/^\.env\./,
|
||||
],
|
||||
},
|
||||
|
||||
// CI/CD 配置
|
||||
cicd: {
|
||||
patterns: [
|
||||
/^\.github\/workflows\/.*\.yml$/,
|
||||
/^\.gitlab\/.*\.yml$/,
|
||||
/^\.circleci\/.*\.yml$/,
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查文件是否可以在 Monaco 编辑器中预览
|
||||
* @param fileName 文件名
|
||||
* @returns boolean
|
||||
*/
|
||||
export function canPreviewInMonaco(fileName: string): boolean {
|
||||
if (!fileName) return false;
|
||||
|
||||
// 获取 Monaco 支持的语言
|
||||
const supportedLanguages = monaco.languages.getLanguages();
|
||||
const ext = fileName.slice(fileName.lastIndexOf('.')).toLowerCase();
|
||||
return supportedLanguages.some((lang) => lang.extensions?.includes(ext));
|
||||
const lowercaseFileName = fileName.toLowerCase();
|
||||
|
||||
// 检查 Monaco 原生支持
|
||||
if (supportedLanguages.some((lang) =>
|
||||
lang.extensions?.includes(ext) ||
|
||||
(lang.filenames?.includes(lowercaseFileName))
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查额外支持的文件类型
|
||||
return Object.values(fileTypeConfigs).some(config => {
|
||||
return (
|
||||
(config.extensions?.includes(ext)) ||
|
||||
(config.filenames?.includes(lowercaseFileName)) ||
|
||||
(config.patterns?.some(pattern => pattern.test(lowercaseFileName))) ||
|
||||
(config.startsWith?.some(prefix => lowercaseFileName.startsWith(prefix))) ||
|
||||
(config.endsWith?.some(suffix => lowercaseFileName.endsWith(suffix)))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类型分类
|
||||
* @param fileName 文件名
|
||||
* @returns string 文件类型分类名称
|
||||
*/
|
||||
export function getFileCategory(fileName: string): string {
|
||||
if (!fileName) return 'unknown';
|
||||
|
||||
const lowercaseFileName = fileName.toLowerCase();
|
||||
const ext = fileName.slice(fileName.lastIndexOf('.')).toLowerCase();
|
||||
|
||||
for (const [category, config] of Object.entries(fileTypeConfigs)) {
|
||||
if (
|
||||
(config.extensions?.includes(ext)) ||
|
||||
(config.filenames?.includes(lowercaseFileName)) ||
|
||||
(config.patterns?.some(pattern => pattern.test(lowercaseFileName))) ||
|
||||
(config.startsWith?.some(prefix => lowercaseFileName.startsWith(prefix))) ||
|
||||
(config.endsWith?.some(suffix => lowercaseFileName.endsWith(suffix)))
|
||||
) {
|
||||
return category;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查 Monaco 原生支持
|
||||
const supportedLanguages = monaco.languages.getLanguages();
|
||||
if (supportedLanguages.some((lang) =>
|
||||
lang.extensions?.includes(ext) ||
|
||||
(lang.filenames?.includes(lowercaseFileName))
|
||||
)) {
|
||||
return 'monaco-native';
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user