adding gitea service
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useState, useRef } from 'preact/hooks';
|
||||
import { useState } from 'preact/hooks';
|
||||
import { MindforgeApiService } from '../services/MindforgeApiService';
|
||||
import { FileTreeComponent } from './FileTreeComponent';
|
||||
import { Button } from './Button';
|
||||
import * as diff from 'diff';
|
||||
import { marked } from 'marked';
|
||||
@@ -13,62 +14,66 @@ function utf8ToBase64(str: string): string {
|
||||
|
||||
type CheckTypeEnum = 'language' | 'content' | 'both';
|
||||
|
||||
export function VerificadorComponent() {
|
||||
const [text, setText] = useState('');
|
||||
const [fileName, setFileName] = useState('manual_input.md');
|
||||
const [checkType, setCheckType] = useState<CheckTypeEnum>('language');
|
||||
interface FileResult {
|
||||
path: string;
|
||||
fileName: string;
|
||||
originalContent: string;
|
||||
languageResult: string | null;
|
||||
contentResult: string | null;
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
export function VerificadorComponent() {
|
||||
const [selectedPaths, setSelectedPaths] = useState<string[]>([]);
|
||||
const [checkType, setCheckType] = useState<CheckTypeEnum>('language');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const [languageResult, setLanguageResult] = useState<string | null>(null);
|
||||
const [contentResult, setContentResult] = useState<string | null>(null);
|
||||
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleFileUpload = (e: Event) => {
|
||||
const target = e.target as HTMLInputElement;
|
||||
if (target.files && target.files.length > 0) {
|
||||
const file = target.files[0];
|
||||
setFileName(file.name);
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
if (event.target?.result) {
|
||||
setText(event.target.result as string);
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
};
|
||||
const [results, setResults] = useState<FileResult[]>([]);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!text.trim()) {
|
||||
setError('Por favor, insira algum texto ou faça upload de um arquivo.');
|
||||
if (selectedPaths.length === 0) {
|
||||
setError('Selecione pelo menos um arquivo do repositório.');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
setLanguageResult(null);
|
||||
setContentResult(null);
|
||||
|
||||
const base64Content = utf8ToBase64(text);
|
||||
setResults([]);
|
||||
|
||||
try {
|
||||
if (checkType === 'both') {
|
||||
const [langRes, contRes] = await Promise.all([
|
||||
MindforgeApiService.checkFile({ fileContent: base64Content, fileName, checkType: 'language' }),
|
||||
MindforgeApiService.checkFile({ fileContent: base64Content, fileName, checkType: 'content' })
|
||||
]);
|
||||
setLanguageResult(langRes.result);
|
||||
setContentResult(contRes.result);
|
||||
} else {
|
||||
const res = await MindforgeApiService.checkFile({ fileContent: base64Content, fileName, checkType });
|
||||
if (checkType === 'language') setLanguageResult(res.result);
|
||||
else setContentResult(res.result);
|
||||
}
|
||||
const fileResults = await Promise.all(
|
||||
selectedPaths.map(async (path): Promise<FileResult> => {
|
||||
const fileName = path.split('/').pop() ?? path;
|
||||
try {
|
||||
const { content } = await MindforgeApiService.getFileContent(path);
|
||||
const base64Content = utf8ToBase64(content);
|
||||
|
||||
let languageResult: string | null = null;
|
||||
let contentResult: string | null = null;
|
||||
|
||||
if (checkType === 'both') {
|
||||
const [langRes, contRes] = await Promise.all([
|
||||
MindforgeApiService.checkFile({ fileContent: base64Content, fileName, checkType: 'language' }),
|
||||
MindforgeApiService.checkFile({ fileContent: base64Content, fileName, checkType: 'content' }),
|
||||
]);
|
||||
languageResult = langRes.result;
|
||||
contentResult = contRes.result;
|
||||
} else {
|
||||
const res = await MindforgeApiService.checkFile({ fileContent: base64Content, fileName, checkType });
|
||||
if (checkType === 'language') languageResult = res.result;
|
||||
else contentResult = res.result;
|
||||
}
|
||||
|
||||
return { path, fileName, originalContent: content, languageResult, contentResult, error: null };
|
||||
} catch (err: any) {
|
||||
return { path, fileName, originalContent: '', languageResult: null, contentResult: null, error: err.message };
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
setResults(fileResults);
|
||||
} catch (err: any) {
|
||||
setError(err.message || 'Ocorreu um erro ao processar sua requisição.');
|
||||
setError(err.message || 'Ocorreu um erro ao processar os arquivos.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -93,34 +98,17 @@ export function VerificadorComponent() {
|
||||
return (
|
||||
<div className="verificador-container">
|
||||
<h2 className="title" style={{ fontSize: '2.5rem' }}>Verificador de Arquivos</h2>
|
||||
<p className="subtitle">Faça o upload do seu arquivo Markdown para validação de linguagem ou conteúdo.</p>
|
||||
<p className="subtitle">Selecione os arquivos do repositório para validação de linguagem ou conteúdo.</p>
|
||||
|
||||
<div className="verificador-form">
|
||||
<div className="input-group">
|
||||
<label>Texto (Markdown)</label>
|
||||
<textarea
|
||||
className="text-area"
|
||||
value={text}
|
||||
onInput={(e) => setText((e.target as HTMLTextAreaElement).value)}
|
||||
placeholder="Cole seu texto aqui ou faça upload de um arquivo..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="file-input-wrapper">
|
||||
<input
|
||||
type="file"
|
||||
accept=".md,.txt"
|
||||
ref={fileInputRef}
|
||||
onChange={handleFileUpload}
|
||||
className="file-input"
|
||||
id="verificador-file"
|
||||
/>
|
||||
<label htmlFor="verificador-file" className="file-input-label">
|
||||
📁 Escolher Arquivo
|
||||
</label>
|
||||
<span style={{ fontSize: '0.9rem', color: 'rgba(255,255,255,0.6)' }}>
|
||||
{fileName !== 'manual_input.md' ? fileName : 'Nenhum arquivo selecionado'}
|
||||
</span>
|
||||
<label>Arquivos do Repositório</label>
|
||||
<FileTreeComponent selectedPaths={selectedPaths} onSelectionChange={setSelectedPaths} />
|
||||
{selectedPaths.length > 0 && (
|
||||
<div style={{ fontSize: '0.85rem', color: 'rgba(255,255,255,0.5)', marginTop: '0.4rem' }}>
|
||||
{selectedPaths.length} arquivo{selectedPaths.length !== 1 ? 's' : ''} selecionado{selectedPaths.length !== 1 ? 's' : ''}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="input-group">
|
||||
@@ -150,46 +138,55 @@ export function VerificadorComponent() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Render Results */}
|
||||
{!loading && (languageResult || contentResult) && (
|
||||
{!loading && results.length > 0 && (
|
||||
<div className="response-section">
|
||||
{checkType === 'language' && languageResult && (
|
||||
<div className="side-pane">
|
||||
<div className="pane-title">Resultado - Linguagem (Diff)</div>
|
||||
<div className="response-content">
|
||||
{renderDiff(text, languageResult)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{results.map((fileResult) => (
|
||||
<div key={fileResult.path} className="file-result-block">
|
||||
<div className="file-result-title">{fileResult.fileName}</div>
|
||||
|
||||
{checkType === 'content' && contentResult && (
|
||||
<div className="side-pane">
|
||||
<div className="pane-title">Resultado - Conteúdo</div>
|
||||
<div
|
||||
className="response-content markdown-body"
|
||||
dangerouslySetInnerHTML={{ __html: marked.parse(contentResult) as string }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{fileResult.error && (
|
||||
<div style={{ color: '#ff7b72', padding: '0.5rem' }}>{fileResult.error}</div>
|
||||
)}
|
||||
|
||||
{checkType === 'both' && languageResult && contentResult && (
|
||||
<div className="side-by-side">
|
||||
<div className="side-pane">
|
||||
<div className="pane-title">Linguagem (Diff)</div>
|
||||
<div className="response-content" style={{ minHeight: '300px' }}>
|
||||
{renderDiff(text, languageResult)}
|
||||
{!fileResult.error && checkType === 'language' && fileResult.languageResult && (
|
||||
<div className="side-pane">
|
||||
<div className="pane-title">Linguagem (Diff)</div>
|
||||
<div className="response-content">
|
||||
{renderDiff(fileResult.originalContent, fileResult.languageResult)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="side-pane">
|
||||
<div className="pane-title">Conteúdo</div>
|
||||
<div
|
||||
className="response-content markdown-body"
|
||||
style={{ minHeight: '300px' }}
|
||||
dangerouslySetInnerHTML={{ __html: marked.parse(contentResult) as string }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!fileResult.error && checkType === 'content' && fileResult.contentResult && (
|
||||
<div className="side-pane">
|
||||
<div className="pane-title">Conteúdo</div>
|
||||
<div
|
||||
className="response-content markdown-body"
|
||||
dangerouslySetInnerHTML={{ __html: marked.parse(fileResult.contentResult) as string }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!fileResult.error && checkType === 'both' && fileResult.languageResult && fileResult.contentResult && (
|
||||
<div className="side-by-side">
|
||||
<div className="side-pane">
|
||||
<div className="pane-title">Linguagem (Diff)</div>
|
||||
<div className="response-content" style={{ minHeight: '200px' }}>
|
||||
{renderDiff(fileResult.originalContent, fileResult.languageResult)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="side-pane">
|
||||
<div className="pane-title">Conteúdo</div>
|
||||
<div
|
||||
className="response-content markdown-body"
|
||||
style={{ minHeight: '200px' }}
|
||||
dangerouslySetInnerHTML={{ __html: marked.parse(fileResult.contentResult) as string }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user