mirror of
https://github.com/Dvorinka/excalidraw-full.git
synced 2026-06-03 22:02:57 +00:00
feat(editor): implement autosave functionality and enhance UI
Docker Images / Build and push (push) Failing after 17s
Docker Images / Build and push (push) Failing after 17s
Implements an autosave mechanism to prevent data loss by periodically sending snapshots of the drawing to the backend. This includes new API endpoints on the server and updated frontend services. Additionally, improves the editor experience with: - Enhanced CSRF protection and origin validation in the backend. - Fix for React "Maximum update depth exceeded" error during scene mutations using a mutation guard. - New presentation slide thumbnails and navigation UI. - Expanded template library with various brainstorming layouts. - Refined dashboard statistics and layout styling. - Improved sidebar logo using SVG for better scaling.
This commit is contained in:
@@ -635,6 +635,47 @@ func (s *Store) UpdateDrawing(ctx context.Context, userID, drawingID string, req
|
||||
return s.GetDrawing(ctx, userID, drawingID)
|
||||
}
|
||||
|
||||
func (s *Store) AutosaveDrawing(ctx context.Context, userID, drawingID string, snapshot json.RawMessage) error {
|
||||
if err := s.ensureDrawingAccess(ctx, userID, drawingID, "edit"); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(snapshot) == 0 || !json.Valid(snapshot) {
|
||||
return fmt.Errorf("snapshot must be valid JSON")
|
||||
}
|
||||
now := time.Now().UTC()
|
||||
_, err := s.db.ExecContext(ctx, `UPDATE workspace_drawings SET updated_at = ? WHERE id = ?`, now, drawingID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Upsert the latest revision snapshot directly without creating a new revision entry
|
||||
var existingRevID string
|
||||
var revNumber int
|
||||
err = s.db.QueryRowContext(ctx, `SELECT id, revision_number FROM workspace_drawing_revisions WHERE drawing_id = ? ORDER BY revision_number DESC LIMIT 1`, drawingID).Scan(&existingRevID, &revNumber)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
// Create initial revision if none exists
|
||||
revID := newID()
|
||||
_, err = s.db.ExecContext(ctx, `INSERT INTO workspace_drawing_revisions
|
||||
(id, drawing_id, revision_number, snapshot_path, snapshot_size, content_hash, snapshot_json, created_by, created_at, change_summary)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
revID, drawingID, 1, fmt.Sprintf("teams/drawings/%s/revisions/1.json", drawingID), int64(len(snapshot)),
|
||||
func() string { sum := sha256.Sum256(snapshot); return hex.EncodeToString(sum[:]) }(),
|
||||
[]byte(snapshot), userID, now, "Auto-save",
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.db.ExecContext(ctx, `UPDATE workspace_drawings SET latest_revision_id = ?, updated_at = ? WHERE id = ?`, revID, now, drawingID)
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Update existing latest revision snapshot
|
||||
_, err = s.db.ExecContext(ctx, `UPDATE workspace_drawing_revisions SET snapshot_json = ?, snapshot_size = ?, content_hash = ?, updated_at = ? WHERE id = ?`,
|
||||
[]byte(snapshot), int64(len(snapshot)), func() string { sum := sha256.Sum256(snapshot); return hex.EncodeToString(sum[:]) }(), now, existingRevID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) ArchiveDrawing(ctx context.Context, userID, drawingID string) error {
|
||||
if err := s.ensureDrawingAccess(ctx, userID, drawingID, "edit"); err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user