337 lines
8.9 KiB
Markdown
337 lines
8.9 KiB
Markdown
# Zotero Collection Import Design
|
|
|
|
## Overview
|
|
|
|
This design upgrades the current left-panel import area from two temporary flows:
|
|
|
|
- import current selection from a bridge snapshot
|
|
- text-search fallback import
|
|
|
|
into one unified Zotero collection importer.
|
|
|
|
The new importer must visualize the user's current Zotero collection hierarchy, let the user browse collections, display the literature under the selected collection, remember cross-collection checkbox state, and batch-import selected items into the current project.
|
|
|
|
This work is intentionally scoped to the import surface only. The project card panel and writing panel remain in place.
|
|
|
|
## Goals
|
|
|
|
- Replace the current left-panel import widgets with one unified `Import From Zotero` section
|
|
- Visualize Zotero collections as a tree in the left panel
|
|
- When a collection is selected, show the literature under that collection and all descendant collections
|
|
- Support checkbox-based multi-selection across collection switches
|
|
- Remember previous selection state while the page remains open
|
|
- Support bulk actions:
|
|
- select all items from the current collection plus descendants
|
|
- clear all selected items
|
|
- import selected items into the current project
|
|
- Preserve the existing project panel, card panel, and writing panel structure
|
|
|
|
## Non-Goals
|
|
|
|
- Full drag-and-drop tree editing
|
|
- Editing Zotero collections
|
|
- Multi-pane import wizard
|
|
- Persisting import selections across browser restarts or across different users
|
|
- Replacing the bridge-based current-selection import flow at the API level
|
|
|
|
The bridge-based import endpoint may remain available, but it is no longer the main UI path.
|
|
|
|
## Product Scope
|
|
|
|
The importer is a left-panel replacement only.
|
|
|
|
### Unchanged Areas
|
|
|
|
- project creation
|
|
- project list
|
|
- project card list
|
|
- card detail viewer
|
|
- writing recommendation form
|
|
- writing plan form
|
|
|
|
### Replaced Area
|
|
|
|
The current pair of sections:
|
|
|
|
- `导入当前选中`
|
|
- `后备导入`
|
|
|
|
will be removed and replaced with:
|
|
|
|
- `从 Zotero 导入`
|
|
|
|
## User Flow
|
|
|
|
1. The user selects a project
|
|
2. The user browses the Zotero collection tree
|
|
3. The user clicks one collection
|
|
4. The UI loads all literature from that collection and all descendants
|
|
5. The user checks items to import
|
|
6. The user may switch to a different collection and continue selecting
|
|
7. Previously selected items remain selected
|
|
8. The user clicks `导入所选到当前项目`
|
|
9. The backend imports all selected items into the current project
|
|
10. The card panel refreshes with the newly imported cards
|
|
|
|
## Layout
|
|
|
|
The page stays three-column.
|
|
|
|
### Left Panel
|
|
|
|
The left panel contains:
|
|
|
|
1. `创建项目`
|
|
2. `项目列表`
|
|
3. `从 Zotero 导入`
|
|
|
|
### Import Section Structure
|
|
|
|
The import section has three internal regions:
|
|
|
|
1. collection tree
|
|
2. collection item list
|
|
3. sticky action bar
|
|
|
|
#### Collection Tree
|
|
|
|
- tree view with expand/collapse state
|
|
- current collection highlighted
|
|
- each node shows:
|
|
- collection name
|
|
- descendant-aware item count
|
|
|
|
#### Collection Item List
|
|
|
|
- shows items from the current collection and all descendant collections
|
|
- each row contains:
|
|
- checkbox
|
|
- title
|
|
- year
|
|
- item type
|
|
- compact metadata
|
|
- rows already selected in other collections remain checked when shown again
|
|
|
|
#### Sticky Action Bar
|
|
|
|
- selected count
|
|
- `全选当前目录及子目录`
|
|
- `清空选择`
|
|
- `导入所选到当前项目`
|
|
|
|
The action bar remains visible while scrolling within the import section.
|
|
|
|
## Interaction Semantics
|
|
|
|
### Collection Selection
|
|
|
|
Clicking a collection:
|
|
|
|
- sets it as the active collection
|
|
- loads all items under that collection plus descendants
|
|
- does not clear already selected items
|
|
|
|
### Checkbox State
|
|
|
|
Selection is tracked by `item_key`, not by visible row index.
|
|
|
|
This means:
|
|
|
|
- switching collections does not lose selection
|
|
- re-entering a collection restores prior checkbox state
|
|
- the selected count reflects the union of all selected items across the session
|
|
|
|
### Select-All Behavior
|
|
|
|
`全选当前目录及子目录` means:
|
|
|
|
- take the currently displayed item set
|
|
- merge all of those item keys into the global selected set
|
|
- keep existing selections from other collections intact
|
|
|
|
### Clear Behavior
|
|
|
|
`清空选择` means:
|
|
|
|
- clear the full selected item set
|
|
- uncheck all visible rows
|
|
- reset the selected count to zero
|
|
|
|
### Import Behavior
|
|
|
|
`导入所选到当前项目` means:
|
|
|
|
- require a currently selected project
|
|
- submit the full selected item key set to the backend
|
|
- keep the active collection and tree expansion state
|
|
- clear the selected item set on success
|
|
- refresh the project card list
|
|
|
|
## Frontend State Model
|
|
|
|
The page should maintain these state keys:
|
|
|
|
- `selectedCollectionKey`
|
|
- `expandedCollectionKeys`
|
|
- `selectedItemKeys`
|
|
- `visibleCollectionItems`
|
|
|
|
### State Rules
|
|
|
|
- `selectedCollectionKey` changes when the user clicks a tree node
|
|
- `expandedCollectionKeys` changes when nodes are opened or closed
|
|
- `selectedItemKeys` persists across collection switches during the current browser session
|
|
- `visibleCollectionItems` updates whenever the active collection changes
|
|
|
|
`selectedItemKeys` is the source of truth for checkbox rendering and batch import.
|
|
|
|
## Backend API Additions
|
|
|
|
Three API capabilities are required.
|
|
|
|
### 1. Collection Tree
|
|
|
|
`GET /api/zotero/collections/tree`
|
|
|
|
Returns the current Zotero collection hierarchy.
|
|
|
|
Each node must include:
|
|
|
|
- `collection_key`
|
|
- `name`
|
|
- `parent_key`
|
|
- `children`
|
|
- `direct_item_count`
|
|
- `descendant_item_count`
|
|
|
|
### 2. Collection Items
|
|
|
|
`GET /api/zotero/collections/{collection_key}/items?include_descendants=true`
|
|
|
|
Returns all regular Zotero items under the selected collection. In V1 of this feature, the UI will always request `include_descendants=true`.
|
|
|
|
Each returned item must include:
|
|
|
|
- `item_key`
|
|
- `title`
|
|
- `year`
|
|
- `item_type`
|
|
- `abstract`
|
|
- `collection_paths`
|
|
|
|
### 3. Batch Import
|
|
|
|
`POST /api/projects/{project_id}/imports/item-keys`
|
|
|
|
This endpoint already exists and should remain the import execution path for the new UI.
|
|
|
|
Input:
|
|
|
|
```json
|
|
{
|
|
"item_keys": ["ABCD1234", "EFGH5678"]
|
|
}
|
|
```
|
|
|
|
Output:
|
|
|
|
- `project_id`
|
|
- `imported_item_keys`
|
|
- `project_view`
|
|
|
|
## Reader Responsibilities
|
|
|
|
The Zotero reader must support collection-tree import without depending on bridge snapshots.
|
|
|
|
Required reader capabilities:
|
|
|
|
- build normalized collection tree data
|
|
- compute direct item counts per collection
|
|
- compute descendant-aware item counts per collection
|
|
- list all regular items under a collection with optional descendant inclusion
|
|
|
|
The reader should continue to ignore attachment, note, and annotation rows as import roots.
|
|
|
|
## Error Handling
|
|
|
|
### No Project Selected
|
|
|
|
- disable import submission or return a clear UI error
|
|
- do not clear selected checkboxes
|
|
|
|
### Collection Tree Load Failure
|
|
|
|
- show error state in the import section
|
|
- do not affect cards or writing sections
|
|
|
|
### Empty Collection
|
|
|
|
- show an empty-state list
|
|
- keep tree navigation usable
|
|
|
|
### Partial Import Failure
|
|
|
|
- report imported item keys and failed item keys separately if the backend can distinguish them
|
|
- do not silently report full success if part of the request failed
|
|
|
|
### Missing Local Zotero Data
|
|
|
|
- show import section unavailable
|
|
- preserve the rest of the application
|
|
|
|
## Testing Strategy
|
|
|
|
### Reader Tests
|
|
|
|
- build collection tree from fixture Zotero data
|
|
- compute descendant-aware item counts
|
|
- list collection items with descendant inclusion
|
|
|
|
### API Tests
|
|
|
|
- `GET /api/zotero/collections/tree`
|
|
- `GET /api/zotero/collections/{collection_key}/items?include_descendants=true`
|
|
- `POST /api/projects/{project_id}/imports/item-keys`
|
|
|
|
### UI Tests
|
|
|
|
The index template must include:
|
|
|
|
- collection tree container
|
|
- collection item list container
|
|
- selected count area
|
|
- select-all button
|
|
- clear-selection button
|
|
- import-selected button
|
|
|
|
## Constraints And Tradeoffs
|
|
|
|
### Why Tree + Side List Instead Of Tree-Mixed Items
|
|
|
|
The user explicitly chose:
|
|
|
|
- collection tree on one side
|
|
- item list shown after selecting a collection
|
|
|
|
This keeps scanning manageable for large libraries and avoids turning the tree itself into an overloaded mixed node structure.
|
|
|
|
### Why Session-Scoped Selection Memory
|
|
|
|
The user explicitly asked to remember previous selection state, but not to store durable drafts of import batches. Session-scoped state is enough for the workflow and avoids backend persistence complexity.
|
|
|
|
### Why Keep Cards And Writing Panels Unchanged
|
|
|
|
The import feature is a left-panel responsibility. Expanding it into a page-level mode would create unnecessary layout churn and broaden the implementation risk.
|
|
|
|
## Acceptance Criteria
|
|
|
|
This feature is complete when:
|
|
|
|
- the old `导入当前选中` and `后备导入` UI sections are gone
|
|
- the left panel shows a collection tree and descendant-aware collection item list
|
|
- selecting items survives collection switches during the session
|
|
- the user can select all items from a collection plus descendants
|
|
- the user can clear all current selections
|
|
- the user can batch-import the selected items into the active project
|
|
- the project card area refreshes after a successful import
|