Skip to content

Conversation

@wei840222
Copy link

Overview

This PR enhances the todo widget functionality by adding support for server-side storage, allowing todo tasks to be persisted and synced across different devices and browsers.

Changes

Core Functionality

  • Added storage-type configuration option for todo widget with two modes:
    • browser (default): Tasks stored in browser's localStorage
    • server: Tasks stored on server in JSON files
  • Implemented server-side storage using afero filesystem abstraction
  • Added new API endpoints for todo data management:
    • GET /api/widgets/todo/{id} - Retrieve todo data
    • PUT /api/widgets/todo/{id} - Save todo data

Configuration

  • Added data-path server configuration option (default: ./data)
  • Automatic creation of todos data directory on startup
  • Updated server startup log to display configured data path

Code Quality

  • Converted Todo() function to async for better data loading
  • Improved code structure with loadFromStorage() and saveToStorage() helper functions

Documentation

  • Updated docs/configuration.md with:
    • New data-path property in Server section
    • New storage-type property in Todo widget section
    • Docker volume mounting examples for data persistence
    • Usage examples for both storage types

Files Changed

  • .gitignore - Added data directory
  • go.mod & go.sum - Added afero dependency
  • internal/glance/config.go - Added DataPath field
  • internal/glance/glance.go - Implemented data path initialization and API routes
  • internal/glance/static/js/todo.js - Refactored with storage abstraction
  • internal/glance/templates/todo.html - Added storage-type data attribute
  • internal/glance/widget-todo.go - Implemented server-side storage logic
  • docs/configuration.md - Updated documentation

Testing

  • Server-side storage creates data directory automatically
  • Browser storage maintains backward compatibility
  • API endpoints handle GET/PUT requests correctly
  • Multiple todo widgets can use different storage types
  • Tasks persist across server restarts (server mode)

Breaking Changes

None. This is a backward-compatible enhancement. Existing todo widgets will continue to use browser storage by default.

Example Configuration

server:
  data-path: ./data  # Optional, defaults to ./data

pages:
  - name: Home
    columns:
      - size: full
        widgets:
          # Browser storage (default, backward compatible)
          - type: todo
            title: My Local Tasks
            
          # Server storage (new feature)
          - type: todo
            title: My Synced Tasks
            storage-type: server
            id: shared-tasks

@russssl
Copy link

russssl commented Oct 4, 2025

amazing work

@wei840222
Copy link
Author

wei840222 commented Nov 1, 2025

Response to @tinyoverflow's Review
Thank you for the detailed feedback! I have addressed all of your concerns with a comprehensive refactor. Here's my response to each point:

  1. Removed Third-Party Dependencies
    ✅ Resolved - Completely removed the afero dependency and switched to Go's built-in os path/filepath packages.

Rationale
As you mentioned, the project should minimize third-party dependencies. The afero package was indeed overkill for this use case, and the standard library provides everything we need.

  1. Eliminated Hard-Coded Todo Widget Binding
    ✅ Resolved - Removed the explicit todo widget instantiation and route registration from glance.go.

Solution
Extended the existing widget interface with a getHandlerFunc() method
In the server method of glance.go, dynamically iterate through widgetByID to register API routes for all widgets
Any widget can now register its own API routes by implementing the getHandlerFunc() method.

  1. Created Universal Storage Abstraction
    ✅ Resolved - Built a generic storage system that's not limited to the todo widget.

Implementation
Created file-storage.go with common file storage functions
Data is automatically organized by widget type: {data-path}/{widget-type}/{id}
Frontend WidgetStorage class provides unified browser/server storage interface

  1. Improved Architectural Design
    ✅ Resolved - The application is now completely decoupled from specific widget implementations.

Architectural Improvements
Widgets are responsible for registering their own API routes (via getHandlerFunc())
Generic file storage system available to all widgets
Support for nested widgets (group and split-column widgets) in API route registration.

  1. Maintained Backward Compatibility
    ✅ Ensured - All existing functionality remains unchanged, this is a pure enhancement.

Key Technical Improvements

  • Dependency Removal afero → Go standard library
  • Decoupled Design Hard-coded binding → Dynamic interface discovery
  • Generalization Todo-specific → Available to all widgets
  • Standardization Special logic → Standardized interface

This refactor not only addresses all your concerns but also establishes a solid foundation for server-side storage functionality in future widgets. Any new widget can easily implement the getHandlerFunc() method to add its own API endpoints.

Thank you again for the valuable feedback! These suggestions helped me build a much cleaner and more extensible architecture.

Copy link

@tinyoverflow tinyoverflow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for all the effort you put into this PR! I really like your ideas!
After reviewing this more carefully, I've found a few more spots about which I'd like to give you my 2 cents and hear your opinion about.

@wei840222
Copy link
Author

Hi @tinyoverflow

Thank you for the detailed feedback! I've addressed all your concerns:

✅ Fixed Promise Return Issues
saveToBrowser() & loadFromBrowser() now properly return Promises.
Added try-catch error handling in todo.js

✅ Added Error Handling
In todo.js users can see informative alerts when operations fail.
Errors will also logged to console for debugging.

✅ Enhanced Error Messages
file-storage.go Added fmt.Errorf() for directory creation errors now include descriptive messages.

✅ Fixed Widget ID Issue
widget-todo.go Changed fallback from widget.GetID() to stable "default" string to prevents data loss when configuration changes.

✅ Updated Documentation
Corrected storage api path from todos/ to to-do/
Documented new default behavior and added Best Practices section with ID recommendations.

Copy link

@tinyoverflow tinyoverflow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you so much!
@svilenmarkov what do you think about this one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants