mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-06 16:04:23 +00:00
Add git api calls on frontend
This commit is contained in:
@@ -1,22 +1,28 @@
|
||||
import React from 'react';
|
||||
import { Tree } from '@geist-ui/core';
|
||||
import { File, Folder } from '@geist-ui/icons';
|
||||
import { Tree, Button, Tooltip, Spacer, ButtonGroup } from '@geist-ui/core';
|
||||
import { File, Folder, GitPullRequest, GitCommit, Plus, Trash } from '@geist-ui/icons';
|
||||
|
||||
const FileTree = ({
|
||||
files = [],
|
||||
onFileSelect = () => {},
|
||||
selectedFile = null
|
||||
selectedFile = null,
|
||||
gitEnabled = false,
|
||||
gitAutoCommit = false,
|
||||
onPull = () => {},
|
||||
onCommitAndPush = () => {},
|
||||
onCreateFile = () => {},
|
||||
onDeleteFile = () => {}
|
||||
}) => {
|
||||
if (files.length === 0) {
|
||||
return <div>No files to display</div>;
|
||||
}
|
||||
|
||||
const handleSelect = (filePath) => {
|
||||
onFileSelect(filePath);
|
||||
onFileSelect(filePath);
|
||||
};
|
||||
|
||||
const renderLabel = (node) => {
|
||||
const path = getFilePath(node);
|
||||
const path = node.extra;
|
||||
return (
|
||||
<span style={{ color: path === selectedFile ? '#0070f3' : 'inherit' }}>
|
||||
{node.name}
|
||||
@@ -27,12 +33,63 @@ const FileTree = ({
|
||||
const renderIcon = ({ type }) => type === 'directory' ? <Folder /> : <File />;
|
||||
|
||||
return (
|
||||
<Tree
|
||||
value={files}
|
||||
onClick={handleSelect}
|
||||
renderIcon={renderIcon}
|
||||
renderLabel={renderLabel}
|
||||
/>
|
||||
<div>
|
||||
<ButtonGroup className='file-tree-buttons'>
|
||||
<Tooltip text="Create new file" type="dark">
|
||||
<Button
|
||||
icon={<Plus />}
|
||||
auto
|
||||
scale={2/3}
|
||||
onClick={onCreateFile}
|
||||
px={0.6}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Spacer w={0.5} />
|
||||
<Tooltip text={selectedFile ? "Delete current file" : "No file selected"} type="dark">
|
||||
<Button
|
||||
icon={<Trash />}
|
||||
auto
|
||||
scale={2/3}
|
||||
onClick={onDeleteFile}
|
||||
disabled={!selectedFile}
|
||||
type="error"
|
||||
px={0.6}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Spacer w={0.5} />
|
||||
<Tooltip text={gitEnabled ? "Pull changes from remote" : "Git is not enabled"} type="dark">
|
||||
<Button
|
||||
icon={<GitPullRequest />}
|
||||
auto
|
||||
scale={2/3}
|
||||
onClick={onPull}
|
||||
disabled={!gitEnabled}
|
||||
px={0.6}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Spacer w={0.5} />
|
||||
<Tooltip text={
|
||||
!gitEnabled ? "Git is not enabled" :
|
||||
gitAutoCommit ? "Auto-commit is enabled" :
|
||||
"Commit and push changes"
|
||||
} type="dark">
|
||||
<Button
|
||||
icon={<GitCommit />}
|
||||
auto
|
||||
scale={2/3}
|
||||
onClick={onCommitAndPush}
|
||||
disabled={!gitEnabled || gitAutoCommit}
|
||||
px={0.6}
|
||||
/>
|
||||
</Tooltip>
|
||||
</ButtonGroup>
|
||||
<Tree
|
||||
value={files}
|
||||
onClick={handleSelect}
|
||||
renderIcon={renderIcon}
|
||||
renderLabel={renderLabel}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Grid, Breadcrumbs, Tabs, Dot, useTheme } from '@geist-ui/core';
|
||||
import { Grid, Breadcrumbs, Tabs, Dot, useTheme, useToasts, Modal, Input, Button } from '@geist-ui/core';
|
||||
import { Code, Eye } from '@geist-ui/icons';
|
||||
import Editor from './Editor';
|
||||
import FileTree from './FileTree';
|
||||
import MarkdownPreview from './MarkdownPreview';
|
||||
import { commitAndPush, saveFileContent, deleteFile } from '../services/api';
|
||||
|
||||
const MainContent = ({
|
||||
content,
|
||||
@@ -14,9 +15,71 @@ const MainContent = ({
|
||||
onFileSelect,
|
||||
onContentChange,
|
||||
onSave,
|
||||
settings,
|
||||
pullLatestChanges,
|
||||
}) => {
|
||||
const [activeTab, setActiveTab] = useState('source');
|
||||
const { type: themeType } = useTheme();
|
||||
const { setToast } = useToasts();
|
||||
const [newFileModalVisible, setNewFileModalVisible] = useState(false);
|
||||
const [newFileName, setNewFileName] = useState('');
|
||||
|
||||
const handlePull = async () => {
|
||||
try {
|
||||
await pullLatestChanges();
|
||||
setToast({ text: 'Successfully pulled latest changes', type: 'success' });
|
||||
} catch (error) {
|
||||
setToast({ text: 'Failed to pull changes: ' + error.message, type: 'error' });
|
||||
}
|
||||
};
|
||||
|
||||
const handleCommitAndPush = async () => {
|
||||
try {
|
||||
const message = prompt('Enter commit message:');
|
||||
if (message) {
|
||||
await commitAndPush(message);
|
||||
setToast({ text: 'Changes committed and pushed successfully', type: 'success' });
|
||||
await pullLatestChanges(); // Pull changes after successful push
|
||||
}
|
||||
} catch (error) {
|
||||
setToast({ text: 'Failed to commit and push changes: ' + error.message, type: 'error' });
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateFile = () => {
|
||||
setNewFileModalVisible(true);
|
||||
};
|
||||
|
||||
const handleNewFileSubmit = async () => {
|
||||
if (newFileName) {
|
||||
try {
|
||||
await saveFileContent(newFileName, '');
|
||||
setToast({ text: 'New file created successfully', type: 'success' });
|
||||
await pullLatestChanges(); // Refresh file list
|
||||
onFileSelect(newFileName); // Select the new file
|
||||
} catch (error) {
|
||||
setToast({ text: 'Failed to create new file: ' + error.message, type: 'error' });
|
||||
}
|
||||
}
|
||||
setNewFileModalVisible(false);
|
||||
setNewFileName('');
|
||||
};
|
||||
|
||||
const handleDeleteFile = async () => {
|
||||
if (selectedFile) {
|
||||
const confirmDelete = window.confirm(`Are you sure you want to delete "${selectedFile}"?`);
|
||||
if (confirmDelete) {
|
||||
try {
|
||||
await deleteFile(selectedFile);
|
||||
setToast({ text: 'File deleted successfully', type: 'success' });
|
||||
await pullLatestChanges(); // Refresh file list
|
||||
onFileSelect(null); // Deselect the file
|
||||
} catch (error) {
|
||||
setToast({ text: 'Failed to delete file: ' + error.message, type: 'error' });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const renderBreadcrumbs = () => {
|
||||
if (!selectedFile) return null;
|
||||
@@ -34,41 +97,60 @@ const MainContent = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid.Container gap={1} height="calc(100vh - 64px)">
|
||||
<Grid xs={24} sm={6} md={5} lg={4} height="100%" className="sidebar">
|
||||
{error ? (
|
||||
<div className="error">{error}</div>
|
||||
) : (
|
||||
<FileTree
|
||||
files={files}
|
||||
onFileSelect={onFileSelect}
|
||||
selectedFile={selectedFile}
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid xs={24} sm={18} md={19} lg={20} height="100%" className="main-content">
|
||||
<div className="content-header">
|
||||
{renderBreadcrumbs()}
|
||||
<Tabs value={activeTab} onChange={setActiveTab}>
|
||||
<Tabs.Item label={<Code />} value="source" />
|
||||
<Tabs.Item label={<Eye />} value="preview" />
|
||||
</Tabs>
|
||||
</div>
|
||||
<div className="content-body">
|
||||
{activeTab === 'source' ? (
|
||||
<Editor
|
||||
content={content}
|
||||
onChange={onContentChange}
|
||||
onSave={onSave}
|
||||
filePath={selectedFile}
|
||||
themeType={themeType}
|
||||
<>
|
||||
<Grid.Container gap={1} height="calc(100vh - 64px)">
|
||||
<Grid xs={24} sm={6} md={5} lg={4} height="100%" className="sidebar">
|
||||
<div className="file-tree-container">
|
||||
<FileTree
|
||||
files={files}
|
||||
onFileSelect={onFileSelect}
|
||||
selectedFile={selectedFile}
|
||||
gitEnabled={settings.gitEnabled}
|
||||
gitAutoCommit={settings.gitAutoCommit}
|
||||
onPull={handlePull}
|
||||
onCommitAndPush={handleCommitAndPush}
|
||||
onCreateFile={handleCreateFile}
|
||||
onDeleteFile={handleDeleteFile}
|
||||
/>
|
||||
) : (
|
||||
<MarkdownPreview content={content} />
|
||||
)}
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid xs={24} sm={18} md={19} lg={20} height="100%" className="main-content">
|
||||
<div className="content-header">
|
||||
{renderBreadcrumbs()}
|
||||
<Tabs value={activeTab} onChange={setActiveTab}>
|
||||
<Tabs.Item label={<Code />} value="source" />
|
||||
<Tabs.Item label={<Eye />} value="preview" />
|
||||
</Tabs>
|
||||
</div>
|
||||
<div className="content-body">
|
||||
{activeTab === 'source' ? (
|
||||
<Editor
|
||||
content={content}
|
||||
onChange={onContentChange}
|
||||
onSave={onSave}
|
||||
filePath={selectedFile}
|
||||
themeType={themeType}
|
||||
/>
|
||||
) : (
|
||||
<MarkdownPreview content={content} />
|
||||
)}
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
<Modal visible={newFileModalVisible} onClose={() => setNewFileModalVisible(false)}>
|
||||
<Modal.Title>Create New File</Modal.Title>
|
||||
<Modal.Content>
|
||||
<Input
|
||||
width="100%"
|
||||
placeholder="Enter file name"
|
||||
value={newFileName}
|
||||
onChange={(e) => setNewFileName(e.target.value)}
|
||||
/>
|
||||
</Modal.Content>
|
||||
<Modal.Action passive onClick={() => setNewFileModalVisible(false)}>Cancel</Modal.Action>
|
||||
<Modal.Action onClick={handleNewFileSubmit}>Create</Modal.Action>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user