mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Configure structured data output for agent forms #10866 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
209 lines
7.1 KiB
TypeScript
209 lines
7.1 KiB
TypeScript
import type * as Monaco from 'monaco-editor';
|
|
import { useEffect, useState } from 'react';
|
|
import type { JSONSchema } from '../types/jsonSchema.ts';
|
|
|
|
export interface MonacoEditorOptions {
|
|
minimap?: { enabled: boolean };
|
|
fontSize?: number;
|
|
fontFamily?: string;
|
|
lineNumbers?: 'on' | 'off';
|
|
roundedSelection?: boolean;
|
|
scrollBeyondLastLine?: boolean;
|
|
readOnly?: boolean;
|
|
automaticLayout?: boolean;
|
|
formatOnPaste?: boolean;
|
|
formatOnType?: boolean;
|
|
tabSize?: number;
|
|
insertSpaces?: boolean;
|
|
detectIndentation?: boolean;
|
|
folding?: boolean;
|
|
foldingStrategy?: 'auto' | 'indentation';
|
|
renderLineHighlight?: 'all' | 'line' | 'none' | 'gutter';
|
|
matchBrackets?: 'always' | 'near' | 'never';
|
|
autoClosingBrackets?:
|
|
| 'always'
|
|
| 'languageDefined'
|
|
| 'beforeWhitespace'
|
|
| 'never';
|
|
autoClosingQuotes?:
|
|
| 'always'
|
|
| 'languageDefined'
|
|
| 'beforeWhitespace'
|
|
| 'never';
|
|
guides?: {
|
|
bracketPairs?: boolean;
|
|
indentation?: boolean;
|
|
};
|
|
}
|
|
|
|
export const defaultEditorOptions: MonacoEditorOptions = {
|
|
minimap: { enabled: false },
|
|
fontSize: 14,
|
|
fontFamily: "var(--font-sans), 'SF Mono', Monaco, Menlo, Consolas, monospace",
|
|
lineNumbers: 'on',
|
|
roundedSelection: false,
|
|
scrollBeyondLastLine: false,
|
|
readOnly: false,
|
|
automaticLayout: true,
|
|
formatOnPaste: true,
|
|
formatOnType: true,
|
|
tabSize: 2,
|
|
insertSpaces: true,
|
|
detectIndentation: true,
|
|
folding: true,
|
|
foldingStrategy: 'indentation',
|
|
renderLineHighlight: 'all',
|
|
matchBrackets: 'always',
|
|
autoClosingBrackets: 'always',
|
|
autoClosingQuotes: 'always',
|
|
guides: {
|
|
bracketPairs: true,
|
|
indentation: true,
|
|
},
|
|
};
|
|
|
|
export function useMonacoTheme() {
|
|
const [isDarkMode, setIsDarkMode] = useState(false);
|
|
|
|
// Check for dark mode by examining CSS variables
|
|
useEffect(() => {
|
|
const checkDarkMode = () => {
|
|
// Get the current background color value
|
|
const backgroundColor = getComputedStyle(document.documentElement)
|
|
.getPropertyValue('--background')
|
|
.trim();
|
|
|
|
// If the background color HSL has a low lightness value, it's likely dark mode
|
|
const isDark =
|
|
backgroundColor.includes('222.2') ||
|
|
backgroundColor.includes('84% 4.9%');
|
|
|
|
setIsDarkMode(isDark);
|
|
};
|
|
|
|
// Check initially
|
|
checkDarkMode();
|
|
|
|
// Set up a mutation observer to detect theme changes
|
|
const observer = new MutationObserver(checkDarkMode);
|
|
observer.observe(document.documentElement, {
|
|
attributes: true,
|
|
attributeFilter: ['class', 'style'],
|
|
});
|
|
|
|
return () => observer.disconnect();
|
|
}, []);
|
|
|
|
const defineMonacoThemes = (monaco: typeof Monaco) => {
|
|
// Define custom light theme that matches app colors
|
|
monaco.editor.defineTheme('appLightTheme', {
|
|
base: 'vs',
|
|
inherit: true,
|
|
rules: [
|
|
// JSON syntax highlighting based on utils.ts type colors
|
|
{ token: 'string', foreground: '3B82F6' }, // text-blue-500
|
|
{ token: 'number', foreground: 'A855F7' }, // text-purple-500
|
|
{ token: 'keyword', foreground: '3B82F6' }, // text-blue-500
|
|
{ token: 'delimiter', foreground: '0F172A' }, // text-slate-900
|
|
{ token: 'keyword.json', foreground: 'A855F7' }, // text-purple-500
|
|
{ token: 'string.key.json', foreground: '2563EB' }, // text-blue-600
|
|
{ token: 'string.value.json', foreground: '3B82F6' }, // text-blue-500
|
|
{ token: 'boolean', foreground: '22C55E' }, // text-green-500
|
|
{ token: 'null', foreground: '64748B' }, // text-gray-500
|
|
],
|
|
colors: {
|
|
// Light theme colors (using hex values instead of CSS variables)
|
|
'editor.background': '#f8fafc', // --background
|
|
'editor.foreground': '#0f172a', // --foreground
|
|
'editorCursor.foreground': '#0f172a', // --foreground
|
|
'editor.lineHighlightBackground': '#f1f5f9', // --muted
|
|
'editorLineNumber.foreground': '#64748b', // --muted-foreground
|
|
'editor.selectionBackground': '#e2e8f0', // --accent
|
|
'editor.inactiveSelectionBackground': '#e2e8f0', // --accent
|
|
'editorIndentGuide.background': '#e2e8f0', // --border
|
|
'editor.findMatchBackground': '#cbd5e1', // --accent
|
|
'editor.findMatchHighlightBackground': '#cbd5e133', // --accent with opacity
|
|
},
|
|
});
|
|
|
|
// Define custom dark theme that matches app colors
|
|
monaco.editor.defineTheme('appDarkTheme', {
|
|
base: 'vs-dark',
|
|
inherit: true,
|
|
rules: [
|
|
// JSON syntax highlighting based on utils.ts type colors
|
|
{ token: 'string', foreground: '3B82F6' }, // text-blue-500
|
|
{ token: 'number', foreground: 'A855F7' }, // text-purple-500
|
|
{ token: 'keyword', foreground: '3B82F6' }, // text-blue-500
|
|
{ token: 'delimiter', foreground: 'F8FAFC' }, // text-slate-50
|
|
{ token: 'keyword.json', foreground: 'A855F7' }, // text-purple-500
|
|
{ token: 'string.key.json', foreground: '60A5FA' }, // text-blue-400
|
|
{ token: 'string.value.json', foreground: '3B82F6' }, // text-blue-500
|
|
{ token: 'boolean', foreground: '22C55E' }, // text-green-500
|
|
{ token: 'null', foreground: '94A3B8' }, // text-gray-400
|
|
],
|
|
colors: {
|
|
// Dark theme colors (using hex values instead of CSS variables)
|
|
'editor.background': '#0f172a', // --background
|
|
'editor.foreground': '#f8fafc', // --foreground
|
|
'editorCursor.foreground': '#f8fafc', // --foreground
|
|
'editor.lineHighlightBackground': '#1e293b', // --muted
|
|
'editorLineNumber.foreground': '#64748b', // --muted-foreground
|
|
'editor.selectionBackground': '#334155', // --accent
|
|
'editor.inactiveSelectionBackground': '#334155', // --accent
|
|
'editorIndentGuide.background': '#1e293b', // --border
|
|
'editor.findMatchBackground': '#475569', // --accent
|
|
'editor.findMatchHighlightBackground': '#47556933', // --accent with opacity
|
|
},
|
|
});
|
|
};
|
|
|
|
// Helper to configure JSON language validation
|
|
const configureJsonDefaults = (
|
|
monaco: typeof Monaco,
|
|
schema?: JSONSchema,
|
|
) => {
|
|
// Create a new diagnostics options object
|
|
const diagnosticsOptions: Monaco.languages.json.DiagnosticsOptions = {
|
|
validate: true,
|
|
allowComments: false,
|
|
schemaValidation: 'error',
|
|
enableSchemaRequest: true,
|
|
schemas: schema
|
|
? [
|
|
{
|
|
uri:
|
|
typeof schema === 'object' && schema.$id
|
|
? schema.$id
|
|
: 'https://jsonjoy-builder/schema',
|
|
fileMatch: ['*'],
|
|
schema,
|
|
},
|
|
]
|
|
: [
|
|
{
|
|
uri: 'http://json-schema.org/draft-07/schema',
|
|
fileMatch: ['*'],
|
|
schema: {
|
|
$schema: 'http://json-schema.org/draft-07/schema',
|
|
type: 'object',
|
|
additionalProperties: true,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
monaco.languages.json.jsonDefaults.setDiagnosticsOptions(
|
|
diagnosticsOptions,
|
|
);
|
|
};
|
|
|
|
return {
|
|
isDarkMode,
|
|
currentTheme: isDarkMode ? 'appDarkTheme' : 'appLightTheme',
|
|
defineMonacoThemes,
|
|
configureJsonDefaults,
|
|
defaultEditorOptions,
|
|
};
|
|
}
|