refactor: migrate to directory-based stack structure

- Updated ComposeService to run docker commands from stack-specific directories, ensuring relative paths resolve correctly.
- Refactored FileSystemService to manage stacks as directories, including methods for creating, updating, and deleting stacks.
- Implemented automatic migration of existing flat-file stacks to the new directory structure on server startup.
- Adjusted API routes to use stack names instead of filenames, simplifying stack management.
- Modified frontend components to align with the new stack naming conventions and removed unnecessary file extensions.
This commit is contained in:
SaelixCode
2026-02-20 19:45:45 -05:00
parent 293f9cef26
commit 800d47845f
6 changed files with 321 additions and 119 deletions
+9 -9
View File
@@ -356,11 +356,12 @@ export default function EditorLayout() {
const handleCreateStack = async () => {
if (!newStackName.trim()) return;
const filename = newStackName.endsWith('.yml') ? newStackName : newStackName + '.yml';
// Send stackName directly (no .yml extension - backend creates directory)
const stackName = newStackName.trim();
try {
const response = await apiFetch('/stacks', {
method: 'POST',
body: JSON.stringify({ filename }),
body: JSON.stringify({ stackName }),
});
if (!response.ok) throw new Error('Failed to create stack');
setCreateDialogOpen(false);
@@ -388,18 +389,17 @@ export default function EditorLayout() {
const safeContent = content || '';
const safeEnvContent = envContent || '';
// Get stack name without extension
const stackName = selectedFile ? selectedFile.replace('.yml', '').replace('.yaml', '') : '';
// Stack name is now the same as selectedFile (no extension to strip)
const stackName = selectedFile || '';
// Filter files based on search query
const filteredFiles = files.filter(file => {
const nameWithoutExt = file.replace('.yml', '').replace('.yaml', '').toLowerCase();
return nameWithoutExt.includes(searchQuery.toLowerCase());
return file.toLowerCase().includes(searchQuery.toLowerCase());
});
// Get display name for stack (without extension)
const getDisplayName = (filename: string) => {
return filename.replace('.yml', '').replace('.yaml', '');
// Get display name for stack (now just returns the name as-is since no extension)
const getDisplayName = (stackName: string) => {
return stackName;
};
return (
+4 -3
View File
@@ -104,17 +104,18 @@ export default function HomeDashboard() {
const handleCreateStack = async () => {
if (!newStackName.trim() || !convertedYaml) return;
const filename = newStackName.endsWith('.yml') ? newStackName : newStackName + '.yml';
// Send stackName directly (no .yml extension - backend creates directory)
const stackName = newStackName.trim();
try {
// Create the stack
const createResponse = await apiFetch('/stacks', {
method: 'POST',
body: JSON.stringify({ filename }),
body: JSON.stringify({ stackName }),
});
if (!createResponse.ok) throw new Error('Failed to create stack');
// Save the converted YAML content
const saveResponse = await apiFetch(`/stacks/${filename}`, {
const saveResponse = await apiFetch(`/stacks/${stackName}`, {
method: 'PUT',
body: JSON.stringify({ content: convertedYaml }),
});