From 1695b411e16ec89cb30f6520d010cef443042f78 Mon Sep 17 00:00:00 2001 From: LordMathis Date: Tue, 29 Oct 2024 20:41:11 +0100 Subject: [PATCH 1/5] Unify env var reading in backend --- backend/cmd/server/main.go | 8 +++++++- backend/internal/user/user.go | 12 +++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index 9fb8634..58eb9a1 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -39,7 +39,13 @@ func main() { // Initialize user service userService := user.NewUserService(database, fs) - if _, err := userService.SetupAdminUser(); err != nil { + + adminEmail := os.Getenv("NOVAMD_ADMIN_EMAIL") + adminPassword := os.Getenv("NOVAMD_ADMIN_PASSWORD") + if adminEmail == "" || adminPassword == "" { + log.Fatal("NOVAMD_ADMIN_EMAIL and NOVAMD_ADMIN_PASSWORD environment variables must be set") + } + if _, err := userService.SetupAdminUser(adminEmail, adminPassword); err != nil { log.Fatal(err) } diff --git a/backend/internal/user/user.go b/backend/internal/user/user.go index b725256..6c9e2be 100644 --- a/backend/internal/user/user.go +++ b/backend/internal/user/user.go @@ -3,7 +3,6 @@ package user import ( "fmt" "log" - "os" "golang.org/x/crypto/bcrypt" @@ -24,18 +23,13 @@ func NewUserService(database *db.DB, fs *filesystem.FileSystem) *UserService { } } -func (s *UserService) SetupAdminUser() (*models.User, error) { - // Get admin email and password from environment variables - adminEmail := os.Getenv("NOVAMD_ADMIN_EMAIL") - adminPassword := os.Getenv("NOVAMD_ADMIN_PASSWORD") - if adminEmail == "" || adminPassword == "" { - return nil, fmt.Errorf("NOVAMD_ADMIN_EMAIL and NOVAMD_ADMIN_PASSWORD environment variables must be set") - } - +func (s *UserService) SetupAdminUser(adminEmail, adminPassword string) (*models.User, error) { // Check if admin user exists adminUser, err := s.DB.GetUserByEmail(adminEmail) if adminUser != nil { return adminUser, nil // Admin user already exists + } else if err != nil { + return nil, err } // Hash the password From ad3fa28bc7d4225f3f50b177b52eee74e6e57f9f Mon Sep 17 00:00:00 2001 From: LordMathis Date: Tue, 29 Oct 2024 21:38:15 +0100 Subject: [PATCH 2/5] Show file list on load --- frontend/src/hooks/useFileList.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/hooks/useFileList.js b/frontend/src/hooks/useFileList.js index ef72c47..ec8ea1f 100644 --- a/frontend/src/hooks/useFileList.js +++ b/frontend/src/hooks/useFileList.js @@ -1,4 +1,4 @@ -import { useState, useCallback, useEffect } from 'react'; +import { useState, useCallback } from 'react'; import { fetchFileList } from '../services/api'; import { useWorkspace } from '../contexts/WorkspaceContext'; @@ -20,7 +20,7 @@ export const useFileList = () => { console.error('Failed to load file list:', error); setFiles([]); } - }, [currentWorkspace]); + }, [currentWorkspace, workspaceLoading]); return { files, loadFileList }; }; From 91f0ebe99c533c9b463239365c3d0a47e75a2bc3 Mon Sep 17 00:00:00 2001 From: LordMathis Date: Tue, 29 Oct 2024 21:38:36 +0100 Subject: [PATCH 3/5] Recursively sort filelist --- backend/internal/filesystem/filesystem.go | 52 ++++++++++++++++++----- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/backend/internal/filesystem/filesystem.go b/backend/internal/filesystem/filesystem.go index 6e01536..6ecfaa0 100644 --- a/backend/internal/filesystem/filesystem.go +++ b/backend/internal/filesystem/filesystem.go @@ -6,6 +6,7 @@ import ( "novamd/internal/gitutils" "os" "path/filepath" + "sort" "strings" ) @@ -82,26 +83,57 @@ func (fs *FileSystem) walkDirectory(dir, prefix string) ([]FileNode, error) { return nil, err } - nodes := make([]FileNode, 0) + // Split entries into directories and files + var dirs, files []os.DirEntry for _, entry := range entries { + if entry.IsDir() { + dirs = append(dirs, entry) + } else { + files = append(files, entry) + } + } + + // Sort directories and files separately + sort.Slice(dirs, func(i, j int) bool { + return strings.ToLower(dirs[i].Name()) < strings.ToLower(dirs[j].Name()) + }) + sort.Slice(files, func(i, j int) bool { + return strings.ToLower(files[i].Name()) < strings.ToLower(files[j].Name()) + }) + + // Create combined slice with directories first, then files + nodes := make([]FileNode, 0, len(entries)) + + // Add directories first + for _, entry := range dirs { name := entry.Name() path := filepath.Join(prefix, name) fullPath := filepath.Join(dir, name) + children, err := fs.walkDirectory(fullPath, path) + if err != nil { + return nil, err + } + + node := FileNode{ + ID: path, + Name: name, + Path: path, + Children: children, + } + nodes = append(nodes, node) + } + + // Then add files + for _, entry := range files { + name := entry.Name() + path := filepath.Join(prefix, name) + node := FileNode{ ID: path, Name: name, Path: path, } - - if entry.IsDir() { - children, err := fs.walkDirectory(fullPath, path) - if err != nil { - return nil, err - } - node.Children = children - } - nodes = append(nodes, node) } From 3ba9d57b118a6fefbc067a85be37c5fe4db15f75 Mon Sep 17 00:00:00 2001 From: LordMathis Date: Tue, 29 Oct 2024 21:46:59 +0100 Subject: [PATCH 4/5] Select default files when no files listed --- frontend/src/hooks/useFileNavigation.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/frontend/src/hooks/useFileNavigation.js b/frontend/src/hooks/useFileNavigation.js index 23ce637..15928b7 100644 --- a/frontend/src/hooks/useFileNavigation.js +++ b/frontend/src/hooks/useFileNavigation.js @@ -1,4 +1,4 @@ -import { useState, useCallback } from 'react'; +import { useState, useCallback, useEffect } from 'react'; // Added useEffect import { notifications } from '@mantine/notifications'; import { lookupFileByName } from '../services/api'; import { DEFAULT_FILE } from '../utils/constants'; @@ -10,8 +10,8 @@ export const useFileNavigation = () => { const { currentWorkspace } = useWorkspace(); const handleFileSelect = useCallback((filePath) => { - setSelectedFile(filePath); - setIsNewFile(filePath === DEFAULT_FILE.path); + setSelectedFile(filePath || DEFAULT_FILE.path); + setIsNewFile(filePath ? false : true); }, []); const handleLinkClick = useCallback( @@ -38,8 +38,13 @@ export const useFileNavigation = () => { }); } }, - [currentWorkspace] + [currentWorkspace, handleFileSelect] ); + // Reset to default file when workspace changes + useEffect(() => { + handleFileSelect(null); + }, [currentWorkspace, handleFileSelect]); + return { handleLinkClick, selectedFile, isNewFile, handleFileSelect }; }; From a62a6f8966e5c0bd4d1c03176dca8e497ca3344f Mon Sep 17 00:00:00 2001 From: LordMathis Date: Tue, 29 Oct 2024 22:01:13 +0100 Subject: [PATCH 5/5] Fix workspace initialization --- backend/internal/api/routes.go | 2 +- backend/internal/api/workspace_handlers.go | 7 ++++++- backend/internal/filesystem/filesystem.go | 7 ------- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/backend/internal/api/routes.go b/backend/internal/api/routes.go index af0b1f0..3682ca3 100644 --- a/backend/internal/api/routes.go +++ b/backend/internal/api/routes.go @@ -16,7 +16,7 @@ func SetupRoutes(r chi.Router, db *db.DB, fs *filesystem.FileSystem) { // Workspace routes r.Route("/workspaces", func(r chi.Router) { r.Get("/", ListWorkspaces(db)) - r.Post("/", CreateWorkspace(db)) + r.Post("/", CreateWorkspace(db, fs)) r.Get("/last", GetLastWorkspace(db)) r.Put("/last", UpdateLastWorkspace(db)) diff --git a/backend/internal/api/workspace_handlers.go b/backend/internal/api/workspace_handlers.go index c1c23c6..29415f5 100644 --- a/backend/internal/api/workspace_handlers.go +++ b/backend/internal/api/workspace_handlers.go @@ -27,7 +27,7 @@ func ListWorkspaces(db *db.DB) http.HandlerFunc { } } -func CreateWorkspace(db *db.DB) http.HandlerFunc { +func CreateWorkspace(db *db.DB, fs *filesystem.FileSystem) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { userID, err := getUserID(r) if err != nil { @@ -47,6 +47,11 @@ func CreateWorkspace(db *db.DB) http.HandlerFunc { return } + if err := fs.InitializeUserWorkspace(workspace.UserID, workspace.ID); err != nil { + http.Error(w, "Failed to initialize workspace directory", http.StatusInternalServerError) + return + } + respondJSON(w, workspace) } } diff --git a/backend/internal/filesystem/filesystem.go b/backend/internal/filesystem/filesystem.go index 6ecfaa0..38e29c1 100644 --- a/backend/internal/filesystem/filesystem.go +++ b/backend/internal/filesystem/filesystem.go @@ -39,13 +39,6 @@ func (fs *FileSystem) InitializeUserWorkspace(userID, workspaceID int) error { if err != nil { return fmt.Errorf("failed to create workspace directory: %w", err) } - // Optionally, create a welcome file in the new workspace - // welcomeFilePath := filepath.Join(workspacePath, "Welcome.md") - // welcomeContent := []byte("# Welcome to Your Main Workspace\n\nThis is your default workspace in NovaMD. You can start creating and editing files right away!") - // err = os.WriteFile(welcomeFilePath, welcomeContent, 0644) - // if err != nil { - // return fmt.Errorf("failed to create welcome file: %w", err) - // } return nil }