Added memory editing functionality

This commit is contained in:
2024-11-24 18:00:27 +01:00
parent 2c820f6ead
commit b6c1a95abd
15 changed files with 688 additions and 53 deletions

View File

@@ -0,0 +1,124 @@
import { BaseEntryEditor } from './BaseEntryEditor';
const CreateForm = ({ formData, setFormData }) => (
<>
<div>
<label className="block text-sm font-medium text-gray-700">Script</label>
<textarea
value={formData.script || ''}
onChange={e => setFormData({...formData, script: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={4}
/>
</div>
</>
);
const EditForm = ({ formData, setFormData }) => (
<>
<CreateForm formData={formData} setFormData={setFormData} />
<div>
<label className="block text-sm font-medium text-gray-700">Standard Output</label>
<textarea
value={formData.stdout || ''}
onChange={e => setFormData({...formData, stdout: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={4}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Standard Error</label>
<textarea
value={formData.stderr || ''}
onChange={e => setFormData({...formData, stderr: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={4}
/>
</div>
<div>
<div className="flex items-center mb-2">
<input
type="checkbox"
checked={formData.exit_code !== null}
onChange={e => setFormData({
...formData,
exit_code: e.target.checked ? 0 : null
})}
className="rounded border-gray-300"
/>
<label className="ml-2 text-sm font-medium text-gray-700">Exit Code</label>
</div>
<input
type="number"
value={formData.exit_code ?? ''}
onChange={e => setFormData({...formData, exit_code: e.target.value ? Number(e.target.value) : null})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm disabled:bg-gray-100"
disabled={formData.exit_code === null}
/>
</div>
<div>
<div className="flex items-center mb-2">
<input
type="checkbox"
checked={formData.pid !== null}
onChange={e => setFormData({
...formData,
pid: e.target.checked ? 0 : null
})}
className="rounded border-gray-300"
/>
<label className="ml-2 text-sm font-medium text-gray-700">Process ID</label>
</div>
<input
type="number"
value={formData.pid ?? ''}
onChange={e => setFormData({...formData, pid: e.target.value ? Number(e.target.value) : null})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm disabled:bg-gray-100"
disabled={formData.pid === null}
/>
</div>
</>
);
const ViewMode = ({ formData }) => (
<>
<div>
<span className="text-sm font-medium text-gray-700">Script:</span>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-2 rounded">{formData.script || ''}</pre>
</div>
{formData.pid !== null && (
<div>
<span className="text-sm font-medium text-gray-700">Process ID:</span>
<span className="ml-2 text-sm text-gray-900">{formData.pid}</span>
</div>
)}
<div>
<span className="text-sm font-medium text-gray-700">Standard Output:</span>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-2 rounded">{formData.stdout || ''}</pre>
</div>
<div>
<span className="text-sm font-medium text-gray-700">Standard Error:</span>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-2 rounded">{formData.stderr || ''}</pre>
</div>
{formData.exit_code !== null && (
<div>
<span className="text-sm font-medium text-gray-700">Exit Code:</span>
<span className="ml-2 text-sm text-gray-900">{formData.exit_code}</span>
</div>
)}
</>
);
export const BackgroundEntryEditor = (props) => (
<BaseEntryEditor {...props}>
{({ formData, setFormData, isEditing, isNew }) => {
if (isNew) {
return <CreateForm formData={formData} setFormData={setFormData} />;
}
if (isEditing) {
return <EditForm formData={formData} setFormData={setFormData} />;
}
return <ViewMode formData={formData} />;
}}
</BaseEntryEditor>
);

View File

@@ -1,8 +1,30 @@
import React, { useState } from 'react';
import { BackgroundEntryEditor } from './BackgroundEntryEditor';
import { ParseErrorEntryEditor } from './ParseErrorEntryEditor';
import { ReadEntryEditor } from './ReadEntryEditor';
import { ReasoningEntryEditor } from './ReasoningEntryEditor';
import { RepeatEntryEditor } from './RepeatEntryEditor';
import { SingleEntryEditor } from './SingleEntryEditor';
import { WriteEntryEditor } from './WriteEntryEditor';
const EntryTypes = {
SINGLE: 'single'
BACKGROUND: 'background',
PARSE_ERROR: 'parse_error',
READ_STDIN: 'read_stdin',
REASONING: 'reasoning',
REPEAT: 'repeat',
SINGLE: 'single',
WRITE: 'write'
};
const EntryEditors = {
[EntryTypes.BACKGROUND]: BackgroundEntryEditor,
[EntryTypes.PARSE_ERROR]: ParseErrorEntryEditor,
[EntryTypes.READ_STDIN]: ReadEntryEditor,
[EntryTypes.REASONING]: ReasoningEntryEditor,
[EntryTypes.REPEAT]: RepeatEntryEditor,
[EntryTypes.SINGLE]: SingleEntryEditor,
[EntryTypes.WRITE]: WriteEntryEditor
};
export const MemoryEditor = ({
@@ -14,33 +36,74 @@ export const MemoryEditor = ({
onUpdateEntry
}) => {
const [showCreateDialog, setShowCreateDialog] = useState(false);
const [selectedType, setSelectedType] = useState(EntryTypes.SINGLE);
const handleCreate = (_id, entry) => {
onCreateEntry(entry);
setShowCreateDialog(false);
};
const renderCreateDialog = () => {
const generateId = () => {
const now = new Date();
const id = now.getFullYear() +
String(now.getMonth() + 1).padStart(2, '0') +
String(now.getDate()).padStart(2, '0') + '_' +
String(now.getHours()).padStart(2, '0') +
String(now.getMinutes()).padStart(2, '0') +
String(now.getSeconds()).padStart(2, '0') + '_' +
String(now.getMilliseconds()).padStart(3, '0');
return now.getFullYear() +
String(now.getMonth() + 1).padStart(2, '0') +
String(now.getDate()).padStart(2, '0') + '_' +
String(now.getHours()).padStart(2, '0') +
String(now.getMinutes()).padStart(2, '0') +
String(now.getSeconds()).padStart(2, '0') + '_' +
String(now.getMilliseconds()).padStart(3, '0');
};
const entry = {
type: EntryTypes.SINGLE,
id: id,
script: '',
timeout: null,
limit: null,
executed: false
const getInitialEntry = (type) => {
const baseEntry = {
type: type,
id: generateId()
};
switch (type) {
case EntryTypes.BACKGROUND:
case EntryTypes.REPEAT:
case EntryTypes.SINGLE:
return {
...baseEntry,
script: '',
timeout: null,
limit: null
};
case EntryTypes.PARSE_ERROR:
return {
...baseEntry,
content: '',
error: ''
};
case EntryTypes.READ_STDIN:
return {
...baseEntry,
content: '',
read: false
};
case EntryTypes.REASONING:
return {
...baseEntry,
content: ''
};
case EntryTypes.WRITE:
return {
...baseEntry,
content: '',
written: false
};
default:
return baseEntry;
}
};
const renderCreateDialog = () => {
const EditorComponent = EntryEditors[selectedType];
const entry = getInitialEntry(selectedType);
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center">
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-[100]">
<div className="bg-white p-4 rounded-lg max-w-2xl w-full m-4">
<div className="flex justify-between items-center mb-4">
<h2 className="text-lg font-medium">Create New Entry</h2>
@@ -51,10 +114,23 @@ export const MemoryEditor = ({
</button>
</div>
<SingleEntryEditor
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700">Entry Type</label>
<select
value={selectedType}
onChange={(e) => setSelectedType(e.target.value)}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
>
{Object.entries(EntryTypes).map(([key, value]) => (
<option key={value} value={value}>
{key.toLowerCase().replace('_', ' ')}
</option>
))}
</select>
</div>
<EditorComponent
entry={entry}
isNew={true}
isEditing={true}
onSave={handleCreate}
onCancel={() => setShowCreateDialog(false)}
/>
@@ -63,6 +139,25 @@ export const MemoryEditor = ({
);
};
const renderEntry = (entry) => {
const EditorComponent = EntryEditors[entry.type];
if (!EditorComponent) {
console.warn(`Unknown entry type: ${entry.type}`);
return null;
}
return (
<EditorComponent
key={entry.id}
entry={entry}
onSave={onSaveEntry}
onDelete={onDeleteEntry}
onReset={onResetEntry}
onUpdate={onUpdateEntry}
/>
);
};
return (
<div className="p-4">
<div className="flex justify-end mb-4">
@@ -75,17 +170,7 @@ export const MemoryEditor = ({
</div>
<div className="space-y-4">
{entries.map(entry => (
<SingleEntryEditor
key={entry.id}
entry={entry}
isEditing={true}
onSave={onSaveEntry}
onDelete={onDeleteEntry}
onReset={onResetEntry}
onUpdate={onUpdateEntry}
/>
))}
{entries.map(renderEntry)}
</div>
{showCreateDialog && renderCreateDialog()}

View File

@@ -0,0 +1,53 @@
import { BaseEntryEditor } from './BaseEntryEditor';
const CreateForm = ({ formData, setFormData }) => (
<>
<div>
<label className="block text-sm font-medium text-gray-700">Content</label>
<textarea
value={formData.content || ''}
onChange={e => setFormData({...formData, content: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={4}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Error</label>
<textarea
value={formData.error || ''}
onChange={e => setFormData({...formData, error: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={4}
/>
</div>
</>
);
const EditForm = CreateForm;
const ViewMode = ({ formData }) => (
<>
<div>
<span className="text-sm font-medium text-gray-700">Content:</span>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-2 rounded">{formData.content || ''}</pre>
</div>
<div>
<span className="text-sm font-medium text-red-700">Error:</span>
<pre className="mt-1 text-sm text-red-900 bg-red-50 p-2 rounded">{formData.error || ''}</pre>
</div>
</>
);
export const ParseErrorEntryEditor = (props) => (
<BaseEntryEditor {...props}>
{({ formData, setFormData, isEditing, isNew }) => {
if (isNew) {
return <CreateForm formData={formData} setFormData={setFormData} />;
}
if (isEditing) {
return <EditForm formData={formData} setFormData={setFormData} />;
}
return <ViewMode formData={formData} />;
}}
</BaseEntryEditor>
);

View File

@@ -0,0 +1,54 @@
import { BaseEntryEditor } from './BaseEntryEditor';
const CreateForm = ({ formData, setFormData }) => (
<>
<div>
<label className="block text-sm font-medium text-gray-700">Content</label>
<textarea
value={formData.content || ''}
onChange={e => setFormData({...formData, content: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={4}
/>
</div>
<div className="flex items-center">
<input
type="checkbox"
checked={formData.read || false}
onChange={e => setFormData({...formData, read: e.target.checked})}
className="rounded border-gray-300"
/>
<span className="ml-2 text-sm text-gray-700">Read</span>
</div>
</>
);
const EditForm = CreateForm;
const ViewMode = ({ formData }) => (
<>
<div>
<span className="text-sm font-medium text-gray-700">Content:</span>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-2 rounded">{formData.content || ''}</pre>
</div>
<div>
<span className="text-sm text-gray-700">
{formData.read ? '✓ Read' : '✗ Not Read'}
</span>
</div>
</>
);
export const ReadEntryEditor = (props) => (
<BaseEntryEditor {...props}>
{({ formData, setFormData, isEditing, isNew }) => {
if (isNew) {
return <CreateForm formData={formData} setFormData={setFormData} />;
}
if (isEditing) {
return <EditForm formData={formData} setFormData={setFormData} />;
}
return <ViewMode formData={formData} />;
}}
</BaseEntryEditor>
);

View File

@@ -0,0 +1,40 @@
import { BaseEntryEditor } from './BaseEntryEditor';
const CreateForm = ({ formData, setFormData }) => (
<>
<div>
<label className="block text-sm font-medium text-gray-700">Content</label>
<textarea
value={formData.content || ''}
onChange={e => setFormData({...formData, content: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={6}
/>
</div>
</>
);
const EditForm = CreateForm;
const ViewMode = ({ formData }) => (
<>
<div>
<span className="text-sm font-medium text-gray-700">Reasoning:</span>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-2 rounded whitespace-pre-wrap">{formData.content || ''}</pre>
</div>
</>
);
export const ReasoningEntryEditor = (props) => (
<BaseEntryEditor {...props}>
{({ formData, setFormData, isEditing, isNew }) => {
if (isNew) {
return <CreateForm formData={formData} setFormData={setFormData} />;
}
if (isEditing) {
return <EditForm formData={formData} setFormData={setFormData} />;
}
return <ViewMode formData={formData} />;
}}
</BaseEntryEditor>
);

View File

@@ -0,0 +1,164 @@
import { BaseEntryEditor } from './BaseEntryEditor';
const CreateForm = ({ formData, setFormData }) => (
<>
<div>
<label className="block text-sm font-medium text-gray-700">Script</label>
<textarea
value={formData.script || ''}
onChange={e => setFormData({...formData, script: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={4}
/>
</div>
<div>
<div className="flex items-center mb-2">
<input
type="checkbox"
checked={formData.timeout !== null}
onChange={e => setFormData({
...formData,
timeout: e.target.checked ? 1 : null
})}
className="rounded border-gray-300"
/>
<label className="ml-2 text-sm font-medium text-gray-700">Custom Timeout (seconds)</label>
</div>
<input
type="number"
value={formData.timeout || ''}
onChange={e => setFormData({...formData, timeout: e.target.value ? Number(e.target.value) : null})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm disabled:bg-gray-100"
step="0.1"
disabled={formData.timeout === null}
/>
</div>
<div>
<div className="flex items-center mb-2">
<input
type="checkbox"
checked={formData.limit !== null}
onChange={e => setFormData({
...formData,
limit: e.target.checked ? 1024 : null
})}
className="rounded border-gray-300"
/>
<label className="ml-2 text-sm font-medium text-gray-700">Custom Memory Limit (bytes)</label>
</div>
<input
type="number"
value={formData.limit || ''}
onChange={e => setFormData({...formData, limit: e.target.value ? Number(e.target.value) : null})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm disabled:bg-gray-100"
disabled={formData.limit === null}
/>
</div>
</>
);
const EditForm = ({ formData, setFormData }) => (
<>
<CreateForm formData={formData} setFormData={setFormData} />
<div>
<label className="block text-sm font-medium text-gray-700">Standard Output</label>
<textarea
value={formData.stdout || ''}
onChange={e => setFormData({...formData, stdout: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={4}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Standard Error</label>
<textarea
value={formData.stderr || ''}
onChange={e => setFormData({...formData, stderr: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={4}
/>
</div>
<div>
<div className="flex items-center mb-2">
<input
type="checkbox"
checked={formData.exit_code !== null}
onChange={e => setFormData({
...formData,
exit_code: e.target.checked ? 0 : null
})}
className="rounded border-gray-300"
/>
<label className="ml-2 text-sm font-medium text-gray-700">Exit Code</label>
</div>
<input
type="number"
value={formData.exit_code ?? ''}
onChange={e => setFormData({...formData, exit_code: e.target.value ? Number(e.target.value) : null})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm disabled:bg-gray-100"
disabled={formData.exit_code === null}
/>
</div>
<div>
<label className="flex items-center">
<input
type="checkbox"
checked={formData.timed_out || false}
onChange={e => setFormData({...formData, timed_out: e.target.checked})}
className="rounded border-gray-300"
/>
<span className="ml-2 text-sm text-gray-700">Timed Out</span>
</label>
</div>
</>
);
const ViewMode = ({ formData }) => (
<>
<div>
<span className="text-sm font-medium text-gray-700">Script:</span>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-2 rounded">{formData.script || ''}</pre>
</div>
<div>
<span className="text-sm font-medium text-gray-700">Timeout:</span>
<span className="ml-2 text-sm text-gray-900">{formData.timeout || 'None'}</span>
</div>
<div>
<span className="text-sm font-medium text-gray-700">Memory Limit:</span>
<span className="ml-2 text-sm text-gray-900">{formData.limit || 'None'}</span>
</div>
<div>
<span className="text-sm font-medium text-gray-700">Standard Output:</span>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-2 rounded">{formData.stdout || ''}</pre>
</div>
<div>
<span className="text-sm font-medium text-gray-700">Standard Error:</span>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-2 rounded">{formData.stderr || ''}</pre>
</div>
{formData.exit_code !== null && (
<div>
<span className="text-sm font-medium text-gray-700">Exit Code:</span>
<span className="ml-2 text-sm text-gray-900">{formData.exit_code}</span>
</div>
)}
<div>
<span className="text-sm text-gray-700">
{formData.timed_out ? '⚠ Timed Out' : '✓ Within Timeout'}
</span>
</div>
</>
);
export const RepeatEntryEditor = (props) => (
<BaseEntryEditor {...props}>
{({ formData, setFormData, isEditing, isNew }) => {
if (isNew) {
return <CreateForm formData={formData} setFormData={setFormData} />;
}
if (isEditing) {
return <EditForm formData={formData} setFormData={setFormData} />;
}
return <ViewMode formData={formData} />;
}}
</BaseEntryEditor>
);

View File

@@ -12,22 +12,46 @@ const CreateForm = ({ formData, setFormData }) => (
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Timeout (seconds)</label>
<div className="flex items-center mb-2">
<input
type="checkbox"
checked={formData.timeout !== null}
onChange={e => setFormData({
...formData,
timeout: e.target.checked ? 1 : null
})}
className="rounded border-gray-300"
/>
<label className="ml-2 text-sm font-medium text-gray-700">Custom Timeout (seconds)</label>
</div>
<input
type="number"
value={formData.timeout || ''}
onChange={e => setFormData({...formData, timeout: e.target.value ? Number(e.target.value) : null})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm disabled:bg-gray-100"
step="0.1"
disabled={formData.timeout === null}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Memory Limit (bytes)</label>
<div className="flex items-center mb-2">
<input
type="checkbox"
checked={formData.limit !== null}
onChange={e => setFormData({
...formData,
limit: e.target.checked ? 1024 : null
})}
className="rounded border-gray-300"
/>
<label className="ml-2 text-sm font-medium text-gray-700">Custom Memory Limit (bytes)</label>
</div>
<input
type="number"
type="number"
value={formData.limit || ''}
onChange={e => setFormData({...formData, limit: e.target.value ? Number(e.target.value) : null})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm disabled:bg-gray-100"
disabled={formData.limit === null}
/>
</div>
</>
@@ -55,12 +79,24 @@ const EditForm = ({ formData, setFormData }) => (
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Exit Code</label>
<div className="flex items-center mb-2">
<input
type="checkbox"
checked={formData.exit_code !== null}
onChange={e => setFormData({
...formData,
exit_code: e.target.checked ? 0 : null
})}
className="rounded border-gray-300"
/>
<label className="ml-2 text-sm font-medium text-gray-700">Exit Code</label>
</div>
<input
type="number"
value={formData.exit_code ?? ''}
onChange={e => setFormData({...formData, exit_code: e.target.value ? Number(e.target.value) : null})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm disabled:bg-gray-100"
disabled={formData.exit_code === null}
/>
</div>
<div className="flex space-x-4">
@@ -108,10 +144,12 @@ const ViewMode = ({ formData }) => (
<span className="text-sm font-medium text-gray-700">Standard Error:</span>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-2 rounded">{formData.stderr || ''}</pre>
</div>
<div>
<span className="text-sm font-medium text-gray-700">Exit Code:</span>
<span className="ml-2 text-sm text-gray-900">{formData.exit_code ?? 'None'}</span>
</div>
{formData.exit_code !== null && (
<div>
<span className="text-sm font-medium text-gray-700">Exit Code:</span>
<span className="ml-2 text-sm text-gray-900">{formData.exit_code}</span>
</div>
)}
<div className="flex space-x-4">
<span className="text-sm text-gray-700">
{formData.executed ? '✓ Executed' : '✗ Not Executed'}
@@ -135,4 +173,4 @@ export const SingleEntryEditor = (props) => (
return <ViewMode formData={formData} />;
}}
</BaseEntryEditor>
);
);

View File

@@ -0,0 +1,54 @@
import { BaseEntryEditor } from './BaseEntryEditor';
const CreateForm = ({ formData, setFormData }) => (
<>
<div>
<label className="block text-sm font-medium text-gray-700">Content</label>
<textarea
value={formData.content || ''}
onChange={e => setFormData({...formData, content: e.target.value})}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
rows={6}
/>
</div>
<div className="flex items-center">
<input
type="checkbox"
checked={formData.written || false}
onChange={e => setFormData({...formData, written: e.target.checked})}
className="rounded border-gray-300"
/>
<span className="ml-2 text-sm text-gray-700">Written</span>
</div>
</>
);
const EditForm = CreateForm;
const ViewMode = ({ formData }) => (
<>
<div>
<span className="text-sm font-medium text-gray-700">Content:</span>
<pre className="mt-1 text-sm text-gray-900 bg-gray-50 p-2 rounded whitespace-pre-wrap">{formData.content || ''}</pre>
</div>
<div>
<span className="text-sm text-gray-700">
{formData.written ? '✓ Written' : '✗ Not Written'}
</span>
</div>
</>
);
export const WriteEntryEditor = (props) => (
<BaseEntryEditor {...props}>
{({ formData, setFormData, isEditing, isNew }) => {
if (isNew) {
return <CreateForm formData={formData} setFormData={setFormData} />;
}
if (isEditing) {
return <EditForm formData={formData} setFormData={setFormData} />;
}
return <ViewMode formData={formData} />;
}}
</BaseEntryEditor>
);