171 lines
5.5 KiB
Markdown
171 lines
5.5 KiB
Markdown
# URL and History Support Implementation Strategy
|
|
|
|
## Overview
|
|
|
|
This document outlines the strategy for implementing clean URL and history support in the Circles application, starting with the LibraryView component. The goal is to enable component state changes to trigger URL updates and allow initial component state to be calculated from URLs for link sharing and refresh support.
|
|
|
|
## Current State Analysis
|
|
|
|
### Strengths
|
|
- App-level routing already implemented with `AppView::to_path()` and `AppView::from_path()`
|
|
- Browser history API integration in `App::update()`
|
|
- Query parameter support for circles context (`?circles=url1,url2`)
|
|
|
|
### Gaps
|
|
- Component-level state changes don't update URLs
|
|
- Initial component state isn't derived from URLs
|
|
- No support for nested routing (e.g., `/library/collection/123/item/456`)
|
|
|
|
## Architecture Overview
|
|
|
|
```mermaid
|
|
graph TD
|
|
A[Browser URL] --> B[App Router]
|
|
B --> C[AppView Route Parser]
|
|
C --> D[Component Route Parser]
|
|
D --> E[Component State]
|
|
E --> F[Component Renders]
|
|
F --> G[User Interaction]
|
|
G --> H[State Change]
|
|
H --> I[URL Update]
|
|
I --> A
|
|
|
|
subgraph "URL Structure"
|
|
J["/library/collection/123/item/456?circles=ws1,ws2"]
|
|
K["Path: /library/collection/123/item/456"]
|
|
L["Query: ?circles=ws1,ws2"]
|
|
end
|
|
```
|
|
|
|
## Implementation Strategy
|
|
|
|
### Phase 1: Create URL Routing Infrastructure
|
|
|
|
#### 1.1 Router Trait Definition
|
|
Create a reusable `UrlRouter` trait that components can implement:
|
|
|
|
```rust
|
|
pub trait UrlRouter {
|
|
type RouteState;
|
|
fn parse_route(path: &str) -> Option<Self::RouteState>;
|
|
fn build_route(state: &Self::RouteState) -> String;
|
|
}
|
|
```
|
|
|
|
#### 1.2 History Manager
|
|
Centralized history management with:
|
|
- Prevention of duplicate history entries
|
|
- Handling of popstate events for back/forward navigation
|
|
- Smart decision between `pushState` and `replaceState`
|
|
|
|
### Phase 2: Extend App-Level Routing
|
|
|
|
#### 2.1 Enhanced AppView Routing
|
|
Modify `AppView::from_path()` to:
|
|
- Extract base view from path (e.g., `/library` from `/library/collection/123`)
|
|
- Pass remaining path segments to components
|
|
- Handle nested route parsing
|
|
|
|
#### 2.2 Route Segment Passing
|
|
Update component props to include:
|
|
- `initial_route: Option<String>` - route segment for component
|
|
- `on_route_change: Callback<String>` - notify app of route changes
|
|
|
|
### Phase 3: LibraryView URL Integration
|
|
|
|
#### 3.1 LibraryRoute Definition
|
|
```rust
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub enum LibraryRoute {
|
|
Collections,
|
|
Collection { collection_id: String },
|
|
Item { collection_id: String, item_id: String },
|
|
}
|
|
```
|
|
|
|
#### 3.2 URL Pattern Mapping
|
|
- `/library` → `LibraryRoute::Collections`
|
|
- `/library/collection/{id}` → `LibraryRoute::Collection`
|
|
- `/library/collection/{id}/item/{item_id}` → `LibraryRoute::Item`
|
|
|
|
#### 3.3 State Synchronization
|
|
- Parse initial route on component creation
|
|
- Update URL when `ViewState` changes
|
|
- Handle browser back/forward navigation
|
|
|
|
## Detailed Implementation Plan
|
|
|
|
### Step 1: Router Infrastructure
|
|
**Files to create:**
|
|
- `src/app/src/routing/mod.rs`
|
|
- `src/app/src/routing/url_router.rs`
|
|
- `src/app/src/routing/library_router.rs`
|
|
- `src/app/src/routing/route_parser.rs`
|
|
|
|
### Step 2: App.rs Modifications
|
|
**Changes to `App`:**
|
|
1. Enhanced route parsing in `AppView::from_path()`
|
|
2. Route segment extraction and passing to components
|
|
3. Popstate event handling for browser navigation
|
|
4. Updated URL building logic
|
|
|
|
### Step 3: LibraryView Transformation
|
|
**Key changes:**
|
|
1. Add `current_route: LibraryRoute` to component state
|
|
2. Initialize state from URL on component creation
|
|
3. Update URL when state changes via message handlers
|
|
4. Handle route changes from browser navigation
|
|
|
|
### Step 4: Component Props Enhancement
|
|
**New props structure:**
|
|
```rust
|
|
#[derive(Clone, PartialEq, Properties)]
|
|
pub struct LibraryViewProps {
|
|
pub ws_addresses: Vec<String>,
|
|
pub initial_route: Option<String>,
|
|
pub on_route_change: Callback<String>,
|
|
}
|
|
```
|
|
|
|
## URL Examples
|
|
|
|
### LibraryView Routes
|
|
- `/library` - Collections view
|
|
- `/library/collection/ws1_collection123` - Items in collection
|
|
- `/library/collection/ws1_collection123/item/item456` - Viewing specific item
|
|
|
|
### With Context
|
|
- `/library/collection/ws1_collection123/item/item456?circles=ws1,ws2` - With circles context
|
|
|
|
## Benefits
|
|
|
|
1. **Clean Separation**: Router logic separated from component logic
|
|
2. **Reusable**: Router trait can be implemented by other views
|
|
3. **Minimal Code**: Leverages existing URL infrastructure
|
|
4. **Link Sharing**: Full state encoded in URLs
|
|
5. **Browser Integration**: Proper back/forward navigation support
|
|
6. **SEO Friendly**: Meaningful URLs for each state
|
|
|
|
## Migration Strategy
|
|
|
|
1. **Backward Compatibility**: Existing URLs continue to work
|
|
2. **Gradual Rollout**: Start with LibraryView, extend to other components
|
|
3. **Fallback Handling**: Graceful degradation for invalid routes
|
|
4. **Progressive Enhancement**: Add URL support without breaking existing functionality
|
|
|
|
## Implementation Order
|
|
|
|
1. Create router infrastructure
|
|
2. Extend App.rs routing capabilities
|
|
3. Transform LibraryView to be URL-aware
|
|
4. Test and refine
|
|
5. Extend pattern to other views (Intelligence, Publishing, etc.)
|
|
|
|
## Testing Strategy
|
|
|
|
1. **Unit Tests**: Router parsing and building functions
|
|
2. **Integration Tests**: Component state synchronization with URLs
|
|
3. **Browser Tests**: Back/forward navigation, refresh behavior
|
|
4. **Link Sharing Tests**: URLs work when shared and opened in new tabs
|
|
|
|
This strategy provides a clean, scalable approach to URL and history support that can be extended to other components in the application. |