mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-06 16:04:23 +00:00
Make logging in work on frontend
This commit is contained in:
@@ -45,8 +45,8 @@ func SetupRoutes(r chi.Router, db *db.DB, fs *filesystem.FileSystem, authMiddlew
|
|||||||
r.Route("/workspaces", func(r chi.Router) {
|
r.Route("/workspaces", func(r chi.Router) {
|
||||||
r.Get("/", handler.ListWorkspaces())
|
r.Get("/", handler.ListWorkspaces())
|
||||||
r.Post("/", handler.CreateWorkspace())
|
r.Post("/", handler.CreateWorkspace())
|
||||||
r.Get("/last", handler.GetLastWorkspace())
|
r.Get("/last", handler.GetLastWorkspaceName())
|
||||||
r.Put("/last", handler.UpdateLastWorkspace())
|
r.Put("/last", handler.UpdateLastWorkspaceName())
|
||||||
|
|
||||||
// Single workspace routes
|
// Single workspace routes
|
||||||
r.Route("/{workspaceName}", func(r chi.Router) {
|
r.Route("/{workspaceName}", func(r chi.Router) {
|
||||||
|
|||||||
@@ -120,9 +120,26 @@ func (db *DB) UpdateUser(user *models.User) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) UpdateLastWorkspace(userID, workspaceID int) error {
|
func (db *DB) UpdateLastWorkspace(userID int, workspaceName string) error {
|
||||||
_, err := db.Exec("UPDATE users SET last_workspace_id = ? WHERE id = ?", workspaceID, userID)
|
tx, err := db.Begin()
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
var workspaceID int
|
||||||
|
|
||||||
|
err = tx.QueryRow("SELECT id FROM workspaces WHERE user_id = ? AND name = ?", userID, workspaceName).Scan(&workspaceID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tx.Exec("UPDATE users SET last_workspace_id = ? WHERE id = ?", workspaceID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) DeleteUser(id int) error {
|
func (db *DB) DeleteUser(id int) error {
|
||||||
@@ -147,8 +164,14 @@ func (db *DB) DeleteUser(id int) error {
|
|||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) GetLastWorkspaceID(userID int) (int, error) {
|
func (db *DB) GetLastWorkspaceName(userID int) (string, error) {
|
||||||
var workspaceID int
|
var workspaceName string
|
||||||
err := db.QueryRow("SELECT last_workspace_id FROM users WHERE id = ?", userID).Scan(&workspaceID)
|
err := db.QueryRow(`
|
||||||
return workspaceID, err
|
SELECT
|
||||||
|
w.name
|
||||||
|
FROM workspaces w
|
||||||
|
JOIN users u ON u.last_workspace_id = w.id
|
||||||
|
WHERE u.id = ?`, userID).
|
||||||
|
Scan(&workspaceName)
|
||||||
|
return workspaceName, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"novamd/internal/httpcontext"
|
"novamd/internal/httpcontext"
|
||||||
@@ -151,10 +152,12 @@ func (h *Handler) DeleteWorkspace() http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find another workspace to set as last
|
// Find another workspace to set as last
|
||||||
|
var nextWorkspaceName string
|
||||||
var nextWorkspaceID int
|
var nextWorkspaceID int
|
||||||
for _, ws := range workspaces {
|
for _, ws := range workspaces {
|
||||||
if ws.ID != ctx.Workspace.ID {
|
if ws.ID != ctx.Workspace.ID {
|
||||||
nextWorkspaceID = ws.ID
|
nextWorkspaceID = ws.ID
|
||||||
|
nextWorkspaceName = ws.Name
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,28 +191,28 @@ func (h *Handler) DeleteWorkspace() http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the next workspace ID in the response so frontend knows where to redirect
|
// Return the next workspace ID in the response so frontend knows where to redirect
|
||||||
respondJSON(w, map[string]int{"nextWorkspaceId": nextWorkspaceID})
|
respondJSON(w, map[string]string{"nextWorkspaceName": nextWorkspaceName})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) GetLastWorkspace() http.HandlerFunc {
|
func (h *Handler) GetLastWorkspaceName() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := httpcontext.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
workspaceID, err := h.DB.GetLastWorkspaceID(ctx.UserID)
|
workspaceName, err := h.DB.GetLastWorkspaceName(ctx.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Failed to get last workspace", http.StatusInternalServerError)
|
http.Error(w, "Failed to get last workspace", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
respondJSON(w, map[string]int{"lastWorkspaceId": workspaceID})
|
respondJSON(w, map[string]string{"lastWorkspaceName": workspaceName})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) UpdateLastWorkspace() http.HandlerFunc {
|
func (h *Handler) UpdateLastWorkspaceName() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, ok := httpcontext.GetRequestContext(w, r)
|
ctx, ok := httpcontext.GetRequestContext(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -217,15 +220,17 @@ func (h *Handler) UpdateLastWorkspace() http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var requestBody struct {
|
var requestBody struct {
|
||||||
WorkspaceID int `json:"workspaceId"`
|
WorkspaceName string `json:"workspaceName"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.DB.UpdateLastWorkspace(ctx.UserID, requestBody.WorkspaceID); err != nil {
|
if err := h.DB.UpdateLastWorkspace(ctx.UserID, requestBody.WorkspaceName); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
http.Error(w, "Failed to update last workspace", http.StatusInternalServerError)
|
http.Error(w, "Failed to update last workspace", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
32
frontend/package-lock.json
generated
32
frontend/package-lock.json
generated
@@ -28,6 +28,7 @@
|
|||||||
"rehype-mathjax": "^6.0.0",
|
"rehype-mathjax": "^6.0.0",
|
||||||
"rehype-prism": "^2.3.3",
|
"rehype-prism": "^2.3.3",
|
||||||
"rehype-react": "^8.0.0",
|
"rehype-react": "^8.0.0",
|
||||||
|
"remark": "^15.0.1",
|
||||||
"remark-math": "^6.0.0",
|
"remark-math": "^6.0.0",
|
||||||
"remark-parse": "^11.0.0",
|
"remark-parse": "^11.0.0",
|
||||||
"remark-rehype": "^11.1.1",
|
"remark-rehype": "^11.1.1",
|
||||||
@@ -4975,6 +4976,22 @@
|
|||||||
"url": "https://opencollective.com/unified"
|
"url": "https://opencollective.com/unified"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/remark": {
|
||||||
|
"version": "15.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz",
|
||||||
|
"integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/mdast": "^4.0.0",
|
||||||
|
"remark-parse": "^11.0.0",
|
||||||
|
"remark-stringify": "^11.0.0",
|
||||||
|
"unified": "^11.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/remark-math": {
|
"node_modules/remark-math": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz",
|
||||||
@@ -5024,6 +5041,21 @@
|
|||||||
"url": "https://opencollective.com/unified"
|
"url": "https://opencollective.com/unified"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/remark-stringify": {
|
||||||
|
"version": "11.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz",
|
||||||
|
"integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/mdast": "^4.0.0",
|
||||||
|
"mdast-util-to-markdown": "^2.0.0",
|
||||||
|
"unified": "^11.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/require-from-string": {
|
"node_modules/require-from-string": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
"rehype-mathjax": "^6.0.0",
|
"rehype-mathjax": "^6.0.0",
|
||||||
"rehype-prism": "^2.3.3",
|
"rehype-prism": "^2.3.3",
|
||||||
"rehype-react": "^8.0.0",
|
"rehype-react": "^8.0.0",
|
||||||
|
"remark": "^15.0.1",
|
||||||
"remark-math": "^6.0.0",
|
"remark-math": "^6.0.0",
|
||||||
"remark-parse": "^11.0.0",
|
"remark-parse": "^11.0.0",
|
||||||
"remark-rehype": "^11.1.1",
|
"remark-rehype": "^11.1.1",
|
||||||
|
|||||||
@@ -21,15 +21,10 @@ const MarkdownPreview = ({ content, handleFileSelect }) => {
|
|||||||
|
|
||||||
if (href.startsWith(`${baseUrl}/internal/`)) {
|
if (href.startsWith(`${baseUrl}/internal/`)) {
|
||||||
// For existing files, extract the path and directly select it
|
// For existing files, extract the path and directly select it
|
||||||
const [filePath, heading] = decodeURIComponent(
|
const [filePath] = decodeURIComponent(
|
||||||
href.replace(`${baseUrl}/internal/`, '')
|
href.replace(`${baseUrl}/internal/`, '')
|
||||||
).split('#');
|
).split('#');
|
||||||
handleFileSelect(filePath);
|
handleFileSelect(filePath);
|
||||||
|
|
||||||
// TODO: Handle heading navigation if needed
|
|
||||||
if (heading) {
|
|
||||||
console.debug('Heading navigation not implemented:', heading);
|
|
||||||
}
|
|
||||||
} else if (href.startsWith(`${baseUrl}/notfound/`)) {
|
} else if (href.startsWith(`${baseUrl}/notfound/`)) {
|
||||||
// For non-existent files, show a notification
|
// For non-existent files, show a notification
|
||||||
const fileName = decodeURIComponent(
|
const fileName = decodeURIComponent(
|
||||||
@@ -47,7 +42,7 @@ const MarkdownPreview = ({ content, handleFileSelect }) => {
|
|||||||
() =>
|
() =>
|
||||||
unified()
|
unified()
|
||||||
.use(remarkParse)
|
.use(remarkParse)
|
||||||
.use(remarkWikiLinks, currentWorkspace?.id)
|
.use(remarkWikiLinks, currentWorkspace?.name)
|
||||||
.use(remarkMath)
|
.use(remarkMath)
|
||||||
.use(remarkRehype)
|
.use(remarkRehype)
|
||||||
.use(rehypeMathjax)
|
.use(rehypeMathjax)
|
||||||
@@ -90,7 +85,7 @@ const MarkdownPreview = ({ content, handleFileSelect }) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[baseUrl, handleFileSelect, currentWorkspace?.id]
|
[baseUrl, handleFileSelect, currentWorkspace?.name]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const WorkspaceSwitcher = () => {
|
|||||||
|
|
||||||
const handleWorkspaceCreated = async (newWorkspace) => {
|
const handleWorkspaceCreated = async (newWorkspace) => {
|
||||||
await loadWorkspaces();
|
await loadWorkspaces();
|
||||||
switchWorkspace(newWorkspace.id);
|
switchWorkspace(newWorkspace.name);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -102,10 +102,10 @@ const WorkspaceSwitcher = () => {
|
|||||||
</Center>
|
</Center>
|
||||||
) : (
|
) : (
|
||||||
workspaces.map((workspace) => {
|
workspaces.map((workspace) => {
|
||||||
const isSelected = workspace.id === currentWorkspace?.id;
|
const isSelected = workspace.name === currentWorkspace?.name;
|
||||||
return (
|
return (
|
||||||
<Paper
|
<Paper
|
||||||
key={workspace.id}
|
key={workspace.name}
|
||||||
p="xs"
|
p="xs"
|
||||||
withBorder
|
withBorder
|
||||||
style={{
|
style={{
|
||||||
@@ -125,7 +125,7 @@ const WorkspaceSwitcher = () => {
|
|||||||
<UnstyledButton
|
<UnstyledButton
|
||||||
style={{ flex: 1 }}
|
style={{ flex: 1 }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
switchWorkspace(workspace.id);
|
switchWorkspace(workspace.name);
|
||||||
setPopoverOpened(false);
|
setPopoverOpened(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import React, {
|
|||||||
import { useMantineColorScheme } from '@mantine/core';
|
import { useMantineColorScheme } from '@mantine/core';
|
||||||
import { notifications } from '@mantine/notifications';
|
import { notifications } from '@mantine/notifications';
|
||||||
import {
|
import {
|
||||||
fetchLastWorkspaceId,
|
fetchLastWorkspaceName,
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
updateWorkspace,
|
updateWorkspace,
|
||||||
updateLastWorkspace,
|
updateLastWorkspaceName,
|
||||||
deleteWorkspace,
|
deleteWorkspace,
|
||||||
listWorkspaces,
|
listWorkspaces,
|
||||||
} from '../services/api';
|
} from '../services/api';
|
||||||
@@ -41,9 +41,9 @@ export const WorkspaceProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const loadWorkspaceData = useCallback(async (workspaceId) => {
|
const loadWorkspaceData = useCallback(async (workspaceName) => {
|
||||||
try {
|
try {
|
||||||
const workspace = await getWorkspace(workspaceId);
|
const workspace = await getWorkspace(workspaceName);
|
||||||
setCurrentWorkspace(workspace);
|
setCurrentWorkspace(workspace);
|
||||||
setColorScheme(workspace.theme);
|
setColorScheme(workspace.theme);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -61,8 +61,8 @@ export const WorkspaceProvider = ({ children }) => {
|
|||||||
const allWorkspaces = await listWorkspaces();
|
const allWorkspaces = await listWorkspaces();
|
||||||
if (allWorkspaces.length > 0) {
|
if (allWorkspaces.length > 0) {
|
||||||
const firstWorkspace = allWorkspaces[0];
|
const firstWorkspace = allWorkspaces[0];
|
||||||
await updateLastWorkspace(firstWorkspace.id);
|
await updateLastWorkspaceName(firstWorkspace.name);
|
||||||
await loadWorkspaceData(firstWorkspace.id);
|
await loadWorkspaceData(firstWorkspace.name);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load first available workspace:', error);
|
console.error('Failed to load first available workspace:', error);
|
||||||
@@ -77,9 +77,9 @@ export const WorkspaceProvider = ({ children }) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initializeWorkspace = async () => {
|
const initializeWorkspace = async () => {
|
||||||
try {
|
try {
|
||||||
const { lastWorkspaceId } = await fetchLastWorkspaceId();
|
const { lastWorkspaceName } = await fetchLastWorkspaceName();
|
||||||
if (lastWorkspaceId) {
|
if (lastWorkspaceName) {
|
||||||
await loadWorkspaceData(lastWorkspaceId);
|
await loadWorkspaceData(lastWorkspaceName);
|
||||||
} else {
|
} else {
|
||||||
await loadFirstAvailableWorkspace();
|
await loadFirstAvailableWorkspace();
|
||||||
}
|
}
|
||||||
@@ -95,11 +95,11 @@ export const WorkspaceProvider = ({ children }) => {
|
|||||||
initializeWorkspace();
|
initializeWorkspace();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const switchWorkspace = useCallback(async (workspaceId) => {
|
const switchWorkspace = useCallback(async (workspaceName) => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await updateLastWorkspace(workspaceId);
|
await updateLastWorkspaceName(workspaceName);
|
||||||
await loadWorkspaceData(workspaceId);
|
await loadWorkspaceData(workspaceName);
|
||||||
await loadWorkspaces();
|
await loadWorkspaces();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to switch workspace:', error);
|
console.error('Failed to switch workspace:', error);
|
||||||
@@ -129,10 +129,10 @@ export const WorkspaceProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete workspace and get the next workspace ID
|
// Delete workspace and get the next workspace ID
|
||||||
const response = await deleteWorkspace(currentWorkspace.id);
|
const response = await deleteWorkspace(currentWorkspace.name);
|
||||||
|
|
||||||
// Load the new workspace data
|
// Load the new workspace data
|
||||||
await loadWorkspaceData(response.nextWorkspaceId);
|
await loadWorkspaceData(response.nextWorkspaceName);
|
||||||
|
|
||||||
notifications.show({
|
notifications.show({
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
@@ -162,7 +162,7 @@ export const WorkspaceProvider = ({ children }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const response = await updateWorkspace(
|
const response = await updateWorkspace(
|
||||||
currentWorkspace.id,
|
currentWorkspace.name,
|
||||||
updatedWorkspace
|
updatedWorkspace
|
||||||
);
|
);
|
||||||
setCurrentWorkspace(response);
|
setCurrentWorkspace(response);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export const useFileContent = (selectedFile) => {
|
|||||||
if (filePath === DEFAULT_FILE.path) {
|
if (filePath === DEFAULT_FILE.path) {
|
||||||
newContent = DEFAULT_FILE.content;
|
newContent = DEFAULT_FILE.content;
|
||||||
} else if (!isImageFile(filePath)) {
|
} else if (!isImageFile(filePath)) {
|
||||||
newContent = await fetchFileContent(currentWorkspace.id, filePath);
|
newContent = await fetchFileContent(currentWorkspace.name, filePath);
|
||||||
} else {
|
} else {
|
||||||
newContent = ''; // Set empty content for image files
|
newContent = ''; // Set empty content for image files
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const useFileList = () => {
|
|||||||
if (!currentWorkspace || workspaceLoading) return;
|
if (!currentWorkspace || workspaceLoading) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const fileList = await fetchFileList(currentWorkspace.id);
|
const fileList = await fetchFileList(currentWorkspace.name);
|
||||||
if (Array.isArray(fileList)) {
|
if (Array.isArray(fileList)) {
|
||||||
setFiles(fileList);
|
setFiles(fileList);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const useFileOperations = () => {
|
|||||||
if (!currentWorkspace) return false;
|
if (!currentWorkspace) return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await saveFileContent(currentWorkspace.id, filePath, content);
|
await saveFileContent(currentWorkspace.name, filePath, content);
|
||||||
notifications.show({
|
notifications.show({
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: 'File saved successfully',
|
message: 'File saved successfully',
|
||||||
@@ -55,7 +55,7 @@ export const useFileOperations = () => {
|
|||||||
if (!currentWorkspace) return false;
|
if (!currentWorkspace) return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await deleteFile(currentWorkspace.id, filePath);
|
await deleteFile(currentWorkspace.name, filePath);
|
||||||
notifications.show({
|
notifications.show({
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: 'File deleted successfully',
|
message: 'File deleted successfully',
|
||||||
@@ -81,7 +81,7 @@ export const useFileOperations = () => {
|
|||||||
if (!currentWorkspace) return false;
|
if (!currentWorkspace) return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await saveFileContent(currentWorkspace.id, fileName, initialContent);
|
await saveFileContent(currentWorkspace.name, fileName, initialContent);
|
||||||
notifications.show({
|
notifications.show({
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: 'File created successfully',
|
message: 'File created successfully',
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const useGitOperations = () => {
|
|||||||
if (!currentWorkspace || !settings.gitEnabled) return false;
|
if (!currentWorkspace || !settings.gitEnabled) return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await pullChanges(currentWorkspace.id);
|
await pullChanges(currentWorkspace.name);
|
||||||
notifications.show({
|
notifications.show({
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: 'Successfully pulled latest changes',
|
message: 'Successfully pulled latest changes',
|
||||||
@@ -33,7 +33,7 @@ export const useGitOperations = () => {
|
|||||||
if (!currentWorkspace || !settings.gitEnabled) return false;
|
if (!currentWorkspace || !settings.gitEnabled) return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await commitAndPush(currentWorkspace.id, message);
|
await commitAndPush(currentWorkspace.name, message);
|
||||||
notifications.show({
|
notifications.show({
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
message: 'Successfully committed and pushed changes',
|
message: 'Successfully committed and pushed changes',
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const useLastOpenedFile = () => {
|
|||||||
if (!currentWorkspace) return null;
|
if (!currentWorkspace) return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await getLastOpenedFile(currentWorkspace.id);
|
const response = await getLastOpenedFile(currentWorkspace.name);
|
||||||
return response.lastOpenedFilePath || null;
|
return response.lastOpenedFilePath || null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load last opened file:', error);
|
console.error('Failed to load last opened file:', error);
|
||||||
@@ -22,7 +22,7 @@ export const useLastOpenedFile = () => {
|
|||||||
if (!currentWorkspace) return;
|
if (!currentWorkspace) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateLastOpenedFile(currentWorkspace.id, filePath);
|
await updateLastOpenedFile(currentWorkspace.name, filePath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to save last opened file:', error);
|
console.error('Failed to save last opened file:', error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
import { API_BASE_URL } from '../utils/constants';
|
import { API_BASE_URL } from '../utils/constants';
|
||||||
import { apiCall } from './authApi';
|
import { apiCall } from './authApi';
|
||||||
|
|
||||||
export const fetchLastWorkspaceId = async () => {
|
export const fetchLastWorkspaceName = async () => {
|
||||||
const response = await apiCall(`${API_BASE_URL}/workspaces/last`);
|
const response = await apiCall(`${API_BASE_URL}/workspaces/last`);
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchFileList = async (workspaceId) => {
|
export const fetchFileList = async (workspaceName) => {
|
||||||
const response = await apiCall(
|
const response = await apiCall(
|
||||||
`${API_BASE_URL}/workspaces/${workspaceId}/files`
|
`${API_BASE_URL}/workspaces/${workspaceName}/files`
|
||||||
);
|
);
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchFileContent = async (workspaceId, filePath) => {
|
export const fetchFileContent = async (workspaceName, filePath) => {
|
||||||
const response = await apiCall(
|
const response = await apiCall(
|
||||||
`${API_BASE_URL}/workspaces/${workspaceId}/files/${filePath}`
|
`${API_BASE_URL}/workspaces/${workspaceName}/files/${filePath}`
|
||||||
);
|
);
|
||||||
return response.text();
|
return response.text();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const saveFileContent = async (workspaceId, filePath, content) => {
|
export const saveFileContent = async (workspaceName, filePath, content) => {
|
||||||
const response = await apiCall(
|
const response = await apiCall(
|
||||||
`${API_BASE_URL}/workspaces/${workspaceId}/files/${filePath}`,
|
`${API_BASE_URL}/workspaces/${workspaceName}/files/${filePath}`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -34,9 +34,9 @@ export const saveFileContent = async (workspaceId, filePath, content) => {
|
|||||||
return response.text();
|
return response.text();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteFile = async (workspaceId, filePath) => {
|
export const deleteFile = async (workspaceName, filePath) => {
|
||||||
const response = await apiCall(
|
const response = await apiCall(
|
||||||
`${API_BASE_URL}/workspaces/${workspaceId}/files/${filePath}`,
|
`${API_BASE_URL}/workspaces/${workspaceName}/files/${filePath}`,
|
||||||
{
|
{
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
}
|
}
|
||||||
@@ -44,26 +44,29 @@ export const deleteFile = async (workspaceId, filePath) => {
|
|||||||
return response.text();
|
return response.text();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getWorkspace = async (workspaceId) => {
|
export const getWorkspace = async (workspaceName) => {
|
||||||
const response = await apiCall(`${API_BASE_URL}/workspaces/${workspaceId}`);
|
const response = await apiCall(`${API_BASE_URL}/workspaces/${workspaceName}`);
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Combined function to update workspace data including settings
|
// Combined function to update workspace data including settings
|
||||||
export const updateWorkspace = async (workspaceId, workspaceData) => {
|
export const updateWorkspace = async (workspaceName, workspaceData) => {
|
||||||
const response = await apiCall(`${API_BASE_URL}/workspaces/${workspaceId}`, {
|
const response = await apiCall(
|
||||||
method: 'PUT',
|
`${API_BASE_URL}/workspaces/${workspaceName}`,
|
||||||
headers: {
|
{
|
||||||
'Content-Type': 'application/json',
|
method: 'PUT',
|
||||||
},
|
headers: {
|
||||||
body: JSON.stringify(workspaceData),
|
'Content-Type': 'application/json',
|
||||||
});
|
},
|
||||||
|
body: JSON.stringify(workspaceData),
|
||||||
|
}
|
||||||
|
);
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const pullChanges = async (workspaceId) => {
|
export const pullChanges = async (workspaceName) => {
|
||||||
const response = await apiCall(
|
const response = await apiCall(
|
||||||
`${API_BASE_URL}/workspaces/${workspaceId}/git/pull`,
|
`${API_BASE_URL}/workspaces/${workspaceName}/git/pull`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
}
|
}
|
||||||
@@ -71,9 +74,9 @@ export const pullChanges = async (workspaceId) => {
|
|||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const commitAndPush = async (workspaceId, message) => {
|
export const commitAndPush = async (workspaceName, message) => {
|
||||||
const response = await apiCall(
|
const response = await apiCall(
|
||||||
`${API_BASE_URL}/workspaces/${workspaceId}/git/commit`,
|
`${API_BASE_URL}/workspaces/${workspaceName}/git/commit`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -85,13 +88,13 @@ export const commitAndPush = async (workspaceId, message) => {
|
|||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getFileUrl = (workspaceId, filePath) => {
|
export const getFileUrl = (workspaceName, filePath) => {
|
||||||
return `${API_BASE_URL}/workspaces/${workspaceId}/files/${filePath}`;
|
return `${API_BASE_URL}/workspaces/${workspaceName}/files/${filePath}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const lookupFileByName = async (workspaceId, filename) => {
|
export const lookupFileByName = async (workspaceName, filename) => {
|
||||||
const response = await apiCall(
|
const response = await apiCall(
|
||||||
`${API_BASE_URL}/workspaces/${workspaceId}/files/lookup?filename=${encodeURIComponent(
|
`${API_BASE_URL}/workspaces/${workspaceName}/files/lookup?filename=${encodeURIComponent(
|
||||||
filename
|
filename
|
||||||
)}`
|
)}`
|
||||||
);
|
);
|
||||||
@@ -99,9 +102,9 @@ export const lookupFileByName = async (workspaceId, filename) => {
|
|||||||
return data.paths;
|
return data.paths;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateLastOpenedFile = async (workspaceId, filePath) => {
|
export const updateLastOpenedFile = async (workspaceName, filePath) => {
|
||||||
const response = await apiCall(
|
const response = await apiCall(
|
||||||
`${API_BASE_URL}/workspaces/${workspaceId}/files/last`,
|
`${API_BASE_URL}/workspaces/${workspaceName}/files/last`,
|
||||||
{
|
{
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -113,9 +116,9 @@ export const updateLastOpenedFile = async (workspaceId, filePath) => {
|
|||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getLastOpenedFile = async (workspaceId) => {
|
export const getLastOpenedFile = async (workspaceName) => {
|
||||||
const response = await apiCall(
|
const response = await apiCall(
|
||||||
`${API_BASE_URL}/workspaces/${workspaceId}/files/last`
|
`${API_BASE_URL}/workspaces/${workspaceName}/files/last`
|
||||||
);
|
);
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
@@ -136,20 +139,23 @@ export const createWorkspace = async (name) => {
|
|||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteWorkspace = async (workspaceId) => {
|
export const deleteWorkspace = async (workspaceName) => {
|
||||||
const response = await apiCall(`${API_BASE_URL}/workspaces/${workspaceId}`, {
|
const response = await apiCall(
|
||||||
method: 'DELETE',
|
`${API_BASE_URL}/workspaces/${workspaceName}`,
|
||||||
});
|
{
|
||||||
|
method: 'DELETE',
|
||||||
|
}
|
||||||
|
);
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateLastWorkspace = async (workspaceId) => {
|
export const updateLastWorkspaceName = async (workspaceName) => {
|
||||||
const response = await apiCall(`${API_BASE_URL}/workspaces/last`, {
|
const response = await apiCall(`${API_BASE_URL}/workspaces/last`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ workspaceId }),
|
body: JSON.stringify({ workspaceName }),
|
||||||
});
|
});
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ function createFileLink(filePath, displayText, heading, baseUrl) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createImageNode(workspaceId, filePath, displayText) {
|
function createImageNode(workspaceName, filePath, displayText) {
|
||||||
return {
|
return {
|
||||||
type: 'image',
|
type: 'image',
|
||||||
url: getFileUrl(workspaceId, filePath),
|
url: getFileUrl(workspaceName, filePath),
|
||||||
alt: displayText,
|
alt: displayText,
|
||||||
title: displayText,
|
title: displayText,
|
||||||
};
|
};
|
||||||
@@ -43,9 +43,9 @@ function addMarkdownExtension(fileName) {
|
|||||||
return `${fileName}.md`;
|
return `${fileName}.md`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function remarkWikiLinks(workspaceId) {
|
export function remarkWikiLinks(workspaceName) {
|
||||||
return async function transformer(tree) {
|
return async function transformer(tree) {
|
||||||
if (!workspaceId) {
|
if (!workspaceName) {
|
||||||
console.warn('No workspace ID provided to remarkWikiLinks plugin');
|
console.warn('No workspace ID provided to remarkWikiLinks plugin');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -113,13 +113,13 @@ export function remarkWikiLinks(workspaceId) {
|
|||||||
? match.fileName
|
? match.fileName
|
||||||
: addMarkdownExtension(match.fileName);
|
: addMarkdownExtension(match.fileName);
|
||||||
|
|
||||||
const paths = await lookupFileByName(workspaceId, lookupFileName);
|
const paths = await lookupFileByName(workspaceName, lookupFileName);
|
||||||
|
|
||||||
if (paths && paths.length > 0) {
|
if (paths && paths.length > 0) {
|
||||||
const filePath = paths[0];
|
const filePath = paths[0];
|
||||||
if (match.isImage) {
|
if (match.isImage) {
|
||||||
newNodes.push(
|
newNodes.push(
|
||||||
createImageNode(workspaceId, filePath, match.displayText)
|
createImageNode(workspaceName, filePath, match.displayText)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
newNodes.push(
|
newNodes.push(
|
||||||
|
|||||||
@@ -52,11 +52,16 @@ export default defineConfig(({ mode }) => ({
|
|||||||
|
|
||||||
// Markdown processing
|
// Markdown processing
|
||||||
markdown: [
|
markdown: [
|
||||||
'react-markdown',
|
|
||||||
'react-syntax-highlighter',
|
'react-syntax-highlighter',
|
||||||
'rehype-katex',
|
'rehype-mathjax',
|
||||||
|
'rehype-prism',
|
||||||
|
'rehype-react',
|
||||||
|
'remark',
|
||||||
'remark-math',
|
'remark-math',
|
||||||
'katex',
|
'remark-parse',
|
||||||
|
'remark-rehype',
|
||||||
|
'unified',
|
||||||
|
'unist-util-visit',
|
||||||
],
|
],
|
||||||
|
|
||||||
// Icons and utilities
|
// Icons and utilities
|
||||||
|
|||||||
Reference in New Issue
Block a user