cjm-transcript-source-select 0.0.13__tar.gz → 0.0.15__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cjm_transcript_source_select-0.0.13/cjm_transcript_source_select.egg-info → cjm_transcript_source_select-0.0.15}/PKG-INFO +64 -27
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/README.md +63 -26
- cjm_transcript_source_select-0.0.15/cjm_transcript_source_select/__init__.py +1 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/_modidx.py +8 -2
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/components/local_files.py +4 -5
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/models.py +28 -3
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/routes/init.py +15 -8
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/routes/local_files.py +75 -18
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/routes/tabs.py +16 -13
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15/cjm_transcript_source_select.egg-info}/PKG-INFO +64 -27
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/settings.ini +1 -1
- cjm_transcript_source_select-0.0.13/cjm_transcript_source_select/__init__.py +0 -1
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/LICENSE +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/MANIFEST.in +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/components/__init__.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/components/helpers.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/components/preview_panel.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/components/selection_queue.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/components/source_browser.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/components/step_renderer.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/html_ids.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/routes/__init__.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/routes/core.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/routes/filtering.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/routes/queue.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/routes/source_browser.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/services/__init__.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/services/source.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/services/source_utils.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select/utils.py +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select.egg-info/SOURCES.txt +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select.egg-info/dependency_links.txt +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select.egg-info/entry_points.txt +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select.egg-info/not-zip-safe +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select.egg-info/requires.txt +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/cjm_transcript_source_select.egg-info/top_level.txt +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/pyproject.toml +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/setup.cfg +0 -0
- {cjm_transcript_source_select-0.0.13 → cjm_transcript_source_select-0.0.15}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: cjm-transcript-source-select
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.15
|
|
4
4
|
Summary: FastHTML source selection component for transcript decomposition workflows, with federated database browsing, drag-drop ordering, and keyboard navigation.
|
|
5
5
|
Home-page: https://github.com/cj-mills/cjm-transcript-source-select
|
|
6
6
|
Author: Christian J. Mills
|
|
@@ -106,57 +106,57 @@ graph LR
|
|
|
106
106
|
utils[utils<br/>utils]
|
|
107
107
|
|
|
108
108
|
components_helpers --> models
|
|
109
|
-
components_local_files --> components_helpers
|
|
110
109
|
components_local_files --> html_ids
|
|
110
|
+
components_local_files --> components_helpers
|
|
111
111
|
components_preview_panel --> html_ids
|
|
112
112
|
components_source_browser --> services_source_utils
|
|
113
113
|
components_source_browser --> utils
|
|
114
114
|
components_source_browser --> html_ids
|
|
115
|
+
components_step_renderer --> components_preview_panel
|
|
115
116
|
components_step_renderer --> components_selection_queue
|
|
116
|
-
components_step_renderer --> components_source_browser
|
|
117
117
|
components_step_renderer --> utils
|
|
118
118
|
components_step_renderer --> components_local_files
|
|
119
119
|
components_step_renderer --> html_ids
|
|
120
|
-
components_step_renderer --> components_preview_panel
|
|
121
120
|
components_step_renderer --> models
|
|
122
|
-
|
|
123
|
-
routes_core --> services_source
|
|
124
|
-
routes_core --> html_ids
|
|
121
|
+
components_step_renderer --> components_source_browser
|
|
125
122
|
routes_core --> models
|
|
123
|
+
routes_core --> services_source
|
|
124
|
+
routes_core --> components_selection_queue
|
|
126
125
|
routes_core --> components_step_renderer
|
|
126
|
+
routes_core --> html_ids
|
|
127
|
+
routes_filtering --> routes_core
|
|
127
128
|
routes_filtering --> services_source_utils
|
|
128
129
|
routes_filtering --> services_source
|
|
129
|
-
routes_filtering --> routes_core
|
|
130
130
|
routes_filtering --> models
|
|
131
131
|
routes_init --> routes_core
|
|
132
|
+
routes_init --> routes_queue
|
|
133
|
+
routes_init --> routes_tabs
|
|
134
|
+
routes_init --> routes_filtering
|
|
132
135
|
routes_init --> services_source
|
|
133
136
|
routes_init --> routes_source_browser
|
|
134
|
-
routes_init --> routes_filtering
|
|
135
137
|
routes_init --> routes_local_files
|
|
136
|
-
routes_init --> routes_queue
|
|
137
138
|
routes_init --> models
|
|
138
|
-
|
|
139
|
+
routes_local_files --> models
|
|
140
|
+
routes_local_files --> routes_core
|
|
139
141
|
routes_local_files --> components_local_files
|
|
140
142
|
routes_local_files --> services_source
|
|
141
|
-
routes_local_files --> routes_core
|
|
142
|
-
routes_local_files --> models
|
|
143
|
-
routes_queue --> services_source_utils
|
|
144
|
-
routes_queue --> services_source
|
|
145
143
|
routes_queue --> routes_core
|
|
144
|
+
routes_queue --> services_source_utils
|
|
146
145
|
routes_queue --> components_preview_panel
|
|
146
|
+
routes_queue --> services_source
|
|
147
147
|
routes_queue --> models
|
|
148
|
-
routes_source_browser --> routes_core
|
|
149
|
-
routes_source_browser --> services_source_utils
|
|
150
148
|
routes_source_browser --> components_source_browser
|
|
149
|
+
routes_source_browser --> components_preview_panel
|
|
150
|
+
routes_source_browser --> services_source_utils
|
|
151
151
|
routes_source_browser --> services_source
|
|
152
|
+
routes_source_browser --> routes_core
|
|
152
153
|
routes_source_browser --> html_ids
|
|
153
|
-
routes_source_browser --> components_preview_panel
|
|
154
154
|
routes_source_browser --> models
|
|
155
|
+
routes_tabs --> models
|
|
155
156
|
routes_tabs --> components_step_renderer
|
|
157
|
+
routes_tabs --> services_source
|
|
156
158
|
routes_tabs --> routes_core
|
|
157
159
|
routes_tabs --> services_source_utils
|
|
158
|
-
routes_tabs --> services_source
|
|
159
|
-
routes_tabs --> models
|
|
160
160
|
```
|
|
161
161
|
|
|
162
162
|
*52 cross-module dependencies detected*
|
|
@@ -426,7 +426,7 @@ def init_selection_routers(
|
|
|
426
426
|
source_service: SourceService, # The source service for queries
|
|
427
427
|
workflow_id: str, # The workflow identifier
|
|
428
428
|
prefix: str, # Base prefix for selection routes (e.g., "/workflow/selection")
|
|
429
|
-
) ->
|
|
429
|
+
) -> SelectionResult: # Selection router result with routers, urls, routes, and restore
|
|
430
430
|
"Initialize and return all selection routers with URL bundle."
|
|
431
431
|
```
|
|
432
432
|
|
|
@@ -526,8 +526,6 @@ def _handle_remove_external_source(
|
|
|
526
526
|
sess, # FastHTML session object
|
|
527
527
|
db_path: str, # Path to the .db file to remove
|
|
528
528
|
external_db_paths_ref: List[str], # Shared external paths list (mutated in place)
|
|
529
|
-
fb_state_getter: Callable[[], BrowserState], # File browser state getter
|
|
530
|
-
fb_state_setter: Callable[[BrowserState], None], # File browser state setter
|
|
531
529
|
fb_routers: FileBrowserRouters, # File browser routers (for targeted OOB)
|
|
532
530
|
remove_url: str, # URL for remove button in external sources list
|
|
533
531
|
): # Tuple of OOB elements (external sources list + checkbox cells)
|
|
@@ -541,7 +539,7 @@ def init_local_files_router(
|
|
|
541
539
|
source_service: SourceService, # The source service for external db ops
|
|
542
540
|
prefix: str, # Route prefix (e.g., "/workflow/selection/local_files")
|
|
543
541
|
urls: SelectionUrls, # URL bundle for rendering
|
|
544
|
-
) ->
|
|
542
|
+
) -> LocalFilesResult: # Router result with routers, routes, render, and restore
|
|
545
543
|
"Initialize local files browser routes with new file browser API."
|
|
546
544
|
```
|
|
547
545
|
|
|
@@ -560,10 +558,24 @@ _local_files_provider: Optional[LocalFileSystemProvider] = None
|
|
|
560
558
|
``` python
|
|
561
559
|
from cjm_transcript_source_select.models import (
|
|
562
560
|
SelectionStepState,
|
|
563
|
-
SelectionUrls
|
|
561
|
+
SelectionUrls,
|
|
562
|
+
LocalFilesResult,
|
|
563
|
+
SelectionResult
|
|
564
564
|
)
|
|
565
565
|
```
|
|
566
566
|
|
|
567
|
+
#### Functions
|
|
568
|
+
|
|
569
|
+
``` python
|
|
570
|
+
def _no_op_restore(session_id: str) -> None:
|
|
571
|
+
"""Default no-op for restore_state."""
|
|
572
|
+
pass
|
|
573
|
+
|
|
574
|
+
@dataclass
|
|
575
|
+
class LocalFilesResult
|
|
576
|
+
"Default no-op for restore_state."
|
|
577
|
+
```
|
|
578
|
+
|
|
567
579
|
#### Classes
|
|
568
580
|
|
|
569
581
|
``` python
|
|
@@ -593,6 +605,30 @@ class SelectionUrls:
|
|
|
593
605
|
tab_switch: str = '' # Switch source tabs
|
|
594
606
|
```
|
|
595
607
|
|
|
608
|
+
``` python
|
|
609
|
+
@dataclass
|
|
610
|
+
class LocalFilesResult:
|
|
611
|
+
"Return type from init_local_files_router."
|
|
612
|
+
|
|
613
|
+
routers: List[APIRouter] # Routers to register (custom + file browser + VC)
|
|
614
|
+
routes: Dict[str, Callable] # Named route handlers
|
|
615
|
+
render_panel: Callable # (error_message?, session_id?) -> rendered panel
|
|
616
|
+
restore_state: Callable = field(...) # (session_id) -> None, restore persisted state
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
``` python
|
|
620
|
+
@dataclass
|
|
621
|
+
class SelectionResult:
|
|
622
|
+
"Return type from init_selection_routers."
|
|
623
|
+
|
|
624
|
+
routers: List[APIRouter] # All selection routers to register
|
|
625
|
+
urls: 'SelectionUrls' = field(...) # URL bundle
|
|
626
|
+
routes: Dict[str, Callable] = field(...) # All named route handlers
|
|
627
|
+
render_local_files_panel: Optional[Callable] # Render fn for local files tab
|
|
628
|
+
sb_state: Any # SourceBrowserRouterState
|
|
629
|
+
restore_state: Callable = field(...) # (session_id) -> None, restore persisted state
|
|
630
|
+
```
|
|
631
|
+
|
|
596
632
|
### preview_panel (`preview_panel.ipynb`)
|
|
597
633
|
|
|
598
634
|
> Collapsible preview panel for displaying selected content
|
|
@@ -1436,15 +1472,16 @@ from cjm_transcript_source_select.routes.tabs import (
|
|
|
1436
1472
|
|
|
1437
1473
|
``` python
|
|
1438
1474
|
def _handle_tab_switch(
|
|
1439
|
-
state_store: WorkflowStateStore, # The workflow state store
|
|
1440
|
-
workflow_id: str, # The workflow identifier
|
|
1441
1475
|
source_service: SourceService, # The source service for queries
|
|
1442
1476
|
request, # FastHTML request object
|
|
1443
1477
|
sess, # FastHTML session object
|
|
1444
1478
|
direction: str, # Direction: "prev", "next", "db", or "files"
|
|
1445
1479
|
urls: SelectionUrls, # URL bundle for rendering
|
|
1480
|
+
current_tab_ref: List[str], # Mutable ref [current_tab] for closure-based tracking
|
|
1446
1481
|
render_local_files_panel: Optional[Callable] = None, # Render fn for Files tab
|
|
1447
1482
|
sb_state: Any = None, # SourceBrowserRouterState for DB tab VC rendering
|
|
1483
|
+
state_store: WorkflowStateStore = None, # State store (for reading step state)
|
|
1484
|
+
workflow_id: str = "", # Workflow ID (for reading step state)
|
|
1448
1485
|
): # Tuple of inner content, OOB tab headers, and tab switch script
|
|
1449
1486
|
"Switch between Plugin DB and Local Files tabs."
|
|
1450
1487
|
```
|
|
@@ -60,57 +60,57 @@ graph LR
|
|
|
60
60
|
utils[utils<br/>utils]
|
|
61
61
|
|
|
62
62
|
components_helpers --> models
|
|
63
|
-
components_local_files --> components_helpers
|
|
64
63
|
components_local_files --> html_ids
|
|
64
|
+
components_local_files --> components_helpers
|
|
65
65
|
components_preview_panel --> html_ids
|
|
66
66
|
components_source_browser --> services_source_utils
|
|
67
67
|
components_source_browser --> utils
|
|
68
68
|
components_source_browser --> html_ids
|
|
69
|
+
components_step_renderer --> components_preview_panel
|
|
69
70
|
components_step_renderer --> components_selection_queue
|
|
70
|
-
components_step_renderer --> components_source_browser
|
|
71
71
|
components_step_renderer --> utils
|
|
72
72
|
components_step_renderer --> components_local_files
|
|
73
73
|
components_step_renderer --> html_ids
|
|
74
|
-
components_step_renderer --> components_preview_panel
|
|
75
74
|
components_step_renderer --> models
|
|
76
|
-
|
|
77
|
-
routes_core --> services_source
|
|
78
|
-
routes_core --> html_ids
|
|
75
|
+
components_step_renderer --> components_source_browser
|
|
79
76
|
routes_core --> models
|
|
77
|
+
routes_core --> services_source
|
|
78
|
+
routes_core --> components_selection_queue
|
|
80
79
|
routes_core --> components_step_renderer
|
|
80
|
+
routes_core --> html_ids
|
|
81
|
+
routes_filtering --> routes_core
|
|
81
82
|
routes_filtering --> services_source_utils
|
|
82
83
|
routes_filtering --> services_source
|
|
83
|
-
routes_filtering --> routes_core
|
|
84
84
|
routes_filtering --> models
|
|
85
85
|
routes_init --> routes_core
|
|
86
|
+
routes_init --> routes_queue
|
|
87
|
+
routes_init --> routes_tabs
|
|
88
|
+
routes_init --> routes_filtering
|
|
86
89
|
routes_init --> services_source
|
|
87
90
|
routes_init --> routes_source_browser
|
|
88
|
-
routes_init --> routes_filtering
|
|
89
91
|
routes_init --> routes_local_files
|
|
90
|
-
routes_init --> routes_queue
|
|
91
92
|
routes_init --> models
|
|
92
|
-
|
|
93
|
+
routes_local_files --> models
|
|
94
|
+
routes_local_files --> routes_core
|
|
93
95
|
routes_local_files --> components_local_files
|
|
94
96
|
routes_local_files --> services_source
|
|
95
|
-
routes_local_files --> routes_core
|
|
96
|
-
routes_local_files --> models
|
|
97
|
-
routes_queue --> services_source_utils
|
|
98
|
-
routes_queue --> services_source
|
|
99
97
|
routes_queue --> routes_core
|
|
98
|
+
routes_queue --> services_source_utils
|
|
100
99
|
routes_queue --> components_preview_panel
|
|
100
|
+
routes_queue --> services_source
|
|
101
101
|
routes_queue --> models
|
|
102
|
-
routes_source_browser --> routes_core
|
|
103
|
-
routes_source_browser --> services_source_utils
|
|
104
102
|
routes_source_browser --> components_source_browser
|
|
103
|
+
routes_source_browser --> components_preview_panel
|
|
104
|
+
routes_source_browser --> services_source_utils
|
|
105
105
|
routes_source_browser --> services_source
|
|
106
|
+
routes_source_browser --> routes_core
|
|
106
107
|
routes_source_browser --> html_ids
|
|
107
|
-
routes_source_browser --> components_preview_panel
|
|
108
108
|
routes_source_browser --> models
|
|
109
|
+
routes_tabs --> models
|
|
109
110
|
routes_tabs --> components_step_renderer
|
|
111
|
+
routes_tabs --> services_source
|
|
110
112
|
routes_tabs --> routes_core
|
|
111
113
|
routes_tabs --> services_source_utils
|
|
112
|
-
routes_tabs --> services_source
|
|
113
|
-
routes_tabs --> models
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
*52 cross-module dependencies detected*
|
|
@@ -380,7 +380,7 @@ def init_selection_routers(
|
|
|
380
380
|
source_service: SourceService, # The source service for queries
|
|
381
381
|
workflow_id: str, # The workflow identifier
|
|
382
382
|
prefix: str, # Base prefix for selection routes (e.g., "/workflow/selection")
|
|
383
|
-
) ->
|
|
383
|
+
) -> SelectionResult: # Selection router result with routers, urls, routes, and restore
|
|
384
384
|
"Initialize and return all selection routers with URL bundle."
|
|
385
385
|
```
|
|
386
386
|
|
|
@@ -480,8 +480,6 @@ def _handle_remove_external_source(
|
|
|
480
480
|
sess, # FastHTML session object
|
|
481
481
|
db_path: str, # Path to the .db file to remove
|
|
482
482
|
external_db_paths_ref: List[str], # Shared external paths list (mutated in place)
|
|
483
|
-
fb_state_getter: Callable[[], BrowserState], # File browser state getter
|
|
484
|
-
fb_state_setter: Callable[[BrowserState], None], # File browser state setter
|
|
485
483
|
fb_routers: FileBrowserRouters, # File browser routers (for targeted OOB)
|
|
486
484
|
remove_url: str, # URL for remove button in external sources list
|
|
487
485
|
): # Tuple of OOB elements (external sources list + checkbox cells)
|
|
@@ -495,7 +493,7 @@ def init_local_files_router(
|
|
|
495
493
|
source_service: SourceService, # The source service for external db ops
|
|
496
494
|
prefix: str, # Route prefix (e.g., "/workflow/selection/local_files")
|
|
497
495
|
urls: SelectionUrls, # URL bundle for rendering
|
|
498
|
-
) ->
|
|
496
|
+
) -> LocalFilesResult: # Router result with routers, routes, render, and restore
|
|
499
497
|
"Initialize local files browser routes with new file browser API."
|
|
500
498
|
```
|
|
501
499
|
|
|
@@ -514,10 +512,24 @@ _local_files_provider: Optional[LocalFileSystemProvider] = None
|
|
|
514
512
|
``` python
|
|
515
513
|
from cjm_transcript_source_select.models import (
|
|
516
514
|
SelectionStepState,
|
|
517
|
-
SelectionUrls
|
|
515
|
+
SelectionUrls,
|
|
516
|
+
LocalFilesResult,
|
|
517
|
+
SelectionResult
|
|
518
518
|
)
|
|
519
519
|
```
|
|
520
520
|
|
|
521
|
+
#### Functions
|
|
522
|
+
|
|
523
|
+
``` python
|
|
524
|
+
def _no_op_restore(session_id: str) -> None:
|
|
525
|
+
"""Default no-op for restore_state."""
|
|
526
|
+
pass
|
|
527
|
+
|
|
528
|
+
@dataclass
|
|
529
|
+
class LocalFilesResult
|
|
530
|
+
"Default no-op for restore_state."
|
|
531
|
+
```
|
|
532
|
+
|
|
521
533
|
#### Classes
|
|
522
534
|
|
|
523
535
|
``` python
|
|
@@ -547,6 +559,30 @@ class SelectionUrls:
|
|
|
547
559
|
tab_switch: str = '' # Switch source tabs
|
|
548
560
|
```
|
|
549
561
|
|
|
562
|
+
``` python
|
|
563
|
+
@dataclass
|
|
564
|
+
class LocalFilesResult:
|
|
565
|
+
"Return type from init_local_files_router."
|
|
566
|
+
|
|
567
|
+
routers: List[APIRouter] # Routers to register (custom + file browser + VC)
|
|
568
|
+
routes: Dict[str, Callable] # Named route handlers
|
|
569
|
+
render_panel: Callable # (error_message?, session_id?) -> rendered panel
|
|
570
|
+
restore_state: Callable = field(...) # (session_id) -> None, restore persisted state
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
``` python
|
|
574
|
+
@dataclass
|
|
575
|
+
class SelectionResult:
|
|
576
|
+
"Return type from init_selection_routers."
|
|
577
|
+
|
|
578
|
+
routers: List[APIRouter] # All selection routers to register
|
|
579
|
+
urls: 'SelectionUrls' = field(...) # URL bundle
|
|
580
|
+
routes: Dict[str, Callable] = field(...) # All named route handlers
|
|
581
|
+
render_local_files_panel: Optional[Callable] # Render fn for local files tab
|
|
582
|
+
sb_state: Any # SourceBrowserRouterState
|
|
583
|
+
restore_state: Callable = field(...) # (session_id) -> None, restore persisted state
|
|
584
|
+
```
|
|
585
|
+
|
|
550
586
|
### preview_panel (`preview_panel.ipynb`)
|
|
551
587
|
|
|
552
588
|
> Collapsible preview panel for displaying selected content
|
|
@@ -1390,15 +1426,16 @@ from cjm_transcript_source_select.routes.tabs import (
|
|
|
1390
1426
|
|
|
1391
1427
|
``` python
|
|
1392
1428
|
def _handle_tab_switch(
|
|
1393
|
-
state_store: WorkflowStateStore, # The workflow state store
|
|
1394
|
-
workflow_id: str, # The workflow identifier
|
|
1395
1429
|
source_service: SourceService, # The source service for queries
|
|
1396
1430
|
request, # FastHTML request object
|
|
1397
1431
|
sess, # FastHTML session object
|
|
1398
1432
|
direction: str, # Direction: "prev", "next", "db", or "files"
|
|
1399
1433
|
urls: SelectionUrls, # URL bundle for rendering
|
|
1434
|
+
current_tab_ref: List[str], # Mutable ref [current_tab] for closure-based tracking
|
|
1400
1435
|
render_local_files_panel: Optional[Callable] = None, # Render fn for Files tab
|
|
1401
1436
|
sb_state: Any = None, # SourceBrowserRouterState for DB tab VC rendering
|
|
1437
|
+
state_store: WorkflowStateStore = None, # State store (for reading step state)
|
|
1438
|
+
workflow_id: str = "", # Workflow ID (for reading step state)
|
|
1402
1439
|
): # Tuple of inner content, OOB tab headers, and tab switch script
|
|
1403
1440
|
"Switch between Plugin DB and Local Files tabs."
|
|
1404
1441
|
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.15"
|
|
@@ -81,10 +81,16 @@ d = { 'settings': { 'branch': 'main',
|
|
|
81
81
|
'cjm_transcript_source_select/html_ids.py'),
|
|
82
82
|
'cjm_transcript_source_select.html_ids.SelectionHtmlIds.source_row': ( 'html_ids.html#selectionhtmlids.source_row',
|
|
83
83
|
'cjm_transcript_source_select/html_ids.py')},
|
|
84
|
-
'cjm_transcript_source_select.models': { 'cjm_transcript_source_select.models.
|
|
84
|
+
'cjm_transcript_source_select.models': { 'cjm_transcript_source_select.models.LocalFilesResult': ( 'models.html#localfilesresult',
|
|
85
|
+
'cjm_transcript_source_select/models.py'),
|
|
86
|
+
'cjm_transcript_source_select.models.SelectionResult': ( 'models.html#selectionresult',
|
|
87
|
+
'cjm_transcript_source_select/models.py'),
|
|
88
|
+
'cjm_transcript_source_select.models.SelectionStepState': ( 'models.html#selectionstepstate',
|
|
85
89
|
'cjm_transcript_source_select/models.py'),
|
|
86
90
|
'cjm_transcript_source_select.models.SelectionUrls': ( 'models.html#selectionurls',
|
|
87
|
-
'cjm_transcript_source_select/models.py')
|
|
91
|
+
'cjm_transcript_source_select/models.py'),
|
|
92
|
+
'cjm_transcript_source_select.models._no_op_restore': ( 'models.html#_no_op_restore',
|
|
93
|
+
'cjm_transcript_source_select/models.py')},
|
|
88
94
|
'cjm_transcript_source_select.routes.core': { 'cjm_transcript_source_select.routes.core._build_queue_response': ( 'routes/core.html#_build_queue_response',
|
|
89
95
|
'cjm_transcript_source_select/routes/core.py'),
|
|
90
96
|
'cjm_transcript_source_select.routes.core._find_duplicate_media_source': ( 'routes/core.html#_find_duplicate_media_source',
|
|
@@ -16,6 +16,7 @@ from cjm_fasthtml_interactions.core.context import InteractionContext
|
|
|
16
16
|
# DaisyUI components
|
|
17
17
|
from cjm_fasthtml_daisyui.components.actions.button import btn, btn_sizes, btn_styles
|
|
18
18
|
from cjm_fasthtml_daisyui.components.data_display.badge import badge, badge_colors, badge_sizes
|
|
19
|
+
from cjm_fasthtml_daisyui.components.data_display.list import list_ui, list_row
|
|
19
20
|
from cjm_fasthtml_daisyui.components.feedback.alert import alert, alert_colors
|
|
20
21
|
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui, border_dui
|
|
21
22
|
from cjm_fasthtml_daisyui.utilities.border_radius import border_radius
|
|
@@ -123,15 +124,13 @@ def _render_external_sources_list(
|
|
|
123
124
|
cls=combine_classes(btn, btn_styles.ghost, btn_sizes.xs, shrink._0),
|
|
124
125
|
hx_post=remove_url,
|
|
125
126
|
hx_vals=json.dumps({"db_path": db_path}),
|
|
126
|
-
|
|
127
|
-
hx_target=SelectionHtmlIds.as_selector(SelectionHtmlIds.SOURCE_LIST),
|
|
128
|
-
hx_swap="outerHTML",
|
|
127
|
+
hx_swap="none",
|
|
129
128
|
title=f"Remove {path.name}"
|
|
130
129
|
),
|
|
131
130
|
cls=combine_classes(flex_display, items.center, gap(2), p.y(1), p.x(2))
|
|
132
131
|
),
|
|
133
132
|
title=db_path,
|
|
134
|
-
cls=combine_classes(border_dui.base_300, border.b(), bg_dui.primary.opacity(10))
|
|
133
|
+
cls=combine_classes(list_row, border_dui.base_300, border.b(), bg_dui.primary.opacity(10))
|
|
135
134
|
))
|
|
136
135
|
|
|
137
136
|
return Div(
|
|
@@ -149,7 +148,7 @@ def _render_external_sources_list(
|
|
|
149
148
|
Ul(
|
|
150
149
|
*list_items,
|
|
151
150
|
id=SelectionHtmlIds.EXTERNAL_SOURCES_LIST,
|
|
152
|
-
cls=combine_classes(
|
|
151
|
+
cls=combine_classes(list_ui, m(0), p(0), overflow.y.auto, max_h(32))
|
|
153
152
|
),
|
|
154
153
|
id=SelectionHtmlIds.EXTERNAL_SOURCES_SECTION,
|
|
155
154
|
cls=combine_classes(m.t(2), shrink._0),
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/models.ipynb.
|
|
4
4
|
|
|
5
5
|
# %% auto #0
|
|
6
|
-
__all__ = ['SelectionStepState', 'SelectionUrls']
|
|
6
|
+
__all__ = ['SelectionStepState', 'SelectionUrls', 'LocalFilesResult', 'SelectionResult']
|
|
7
7
|
|
|
8
8
|
# %% ../nbs/models.ipynb #selection-models-imports
|
|
9
|
-
from typing import List, Dict, Any
|
|
9
|
+
from typing import List, Dict, Any, Callable, Optional
|
|
10
10
|
from typing_extensions import TypedDict
|
|
11
|
-
from dataclasses import dataclass
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
|
|
13
|
+
from fasthtml.common import APIRouter
|
|
12
14
|
|
|
13
15
|
from cjm_source_provider.models import SelectedSource
|
|
14
16
|
|
|
@@ -51,3 +53,26 @@ class SelectionUrls:
|
|
|
51
53
|
|
|
52
54
|
# Tab switching
|
|
53
55
|
tab_switch: str = "" # Switch source tabs
|
|
56
|
+
|
|
57
|
+
# %% ../nbs/models.ipynb #gxc6wl5o4mn
|
|
58
|
+
def _no_op_restore(session_id: str) -> None:
|
|
59
|
+
"""Default no-op for restore_state."""
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
@dataclass
|
|
63
|
+
class LocalFilesResult:
|
|
64
|
+
"""Return type from init_local_files_router."""
|
|
65
|
+
routers: List[APIRouter] # Routers to register (custom + file browser + VC)
|
|
66
|
+
routes: Dict[str, Callable] # Named route handlers
|
|
67
|
+
render_panel: Callable # (error_message?, session_id?) -> rendered panel
|
|
68
|
+
restore_state: Callable = field(default=_no_op_restore) # (session_id) -> None, restore persisted state
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class SelectionResult:
|
|
72
|
+
"""Return type from init_selection_routers."""
|
|
73
|
+
routers: List[APIRouter] # All selection routers to register
|
|
74
|
+
urls: "SelectionUrls" = field(default_factory=lambda: SelectionUrls()) # URL bundle
|
|
75
|
+
routes: Dict[str, Callable] = field(default_factory=dict) # All named route handlers
|
|
76
|
+
render_local_files_panel: Optional[Callable] = None # Render fn for local files tab
|
|
77
|
+
sb_state: Any = None # SourceBrowserRouterState
|
|
78
|
+
restore_state: Callable = field(default=_no_op_restore) # (session_id) -> None, restore persisted state
|
|
@@ -12,7 +12,7 @@ from fasthtml.common import APIRouter
|
|
|
12
12
|
|
|
13
13
|
from cjm_fasthtml_interactions.core.state_store import get_session_id
|
|
14
14
|
|
|
15
|
-
from ..models import SelectionUrls
|
|
15
|
+
from ..models import SelectionUrls, SelectionResult
|
|
16
16
|
from cjm_transcript_source_select.routes.core import (
|
|
17
17
|
WorkflowStateStore,
|
|
18
18
|
_rebuild_and_render_ref, _sync_items_ref,
|
|
@@ -32,7 +32,7 @@ def init_selection_routers(
|
|
|
32
32
|
source_service: SourceService, # The source service for queries
|
|
33
33
|
workflow_id: str, # The workflow identifier
|
|
34
34
|
prefix: str, # Base prefix for selection routes (e.g., "/workflow/selection")
|
|
35
|
-
) ->
|
|
35
|
+
) -> SelectionResult: # Selection router result with routers, urls, routes, and restore
|
|
36
36
|
"""Initialize and return all selection routers with URL bundle."""
|
|
37
37
|
urls = SelectionUrls()
|
|
38
38
|
|
|
@@ -42,7 +42,7 @@ def init_selection_routers(
|
|
|
42
42
|
filtering_router, filtering_routes = init_filtering_router(
|
|
43
43
|
state_store, workflow_id, source_service, f"{prefix}/filtering", urls
|
|
44
44
|
)
|
|
45
|
-
|
|
45
|
+
local_files = init_local_files_router(
|
|
46
46
|
state_store, workflow_id, source_service, f"{prefix}/local_files", urls
|
|
47
47
|
)
|
|
48
48
|
sb_state = init_source_browser_router(
|
|
@@ -92,7 +92,7 @@ def init_selection_routers(
|
|
|
92
92
|
|
|
93
93
|
tabs_router, tabs_routes = init_tabs_router(
|
|
94
94
|
state_store, workflow_id, source_service, f"{prefix}/tabs", urls,
|
|
95
|
-
render_local_files_panel=
|
|
95
|
+
render_local_files_panel=local_files.render_panel,
|
|
96
96
|
sb_state=sb_state,
|
|
97
97
|
)
|
|
98
98
|
|
|
@@ -108,16 +108,23 @@ def init_selection_routers(
|
|
|
108
108
|
urls.keyboard_reorder = filtering_routes["keyboard_reorder"].to()
|
|
109
109
|
urls.filter = filtering_routes["filter"].to()
|
|
110
110
|
urls.grouping_change = filtering_routes["grouping_change"].to()
|
|
111
|
-
urls.remove_external =
|
|
111
|
+
urls.remove_external = local_files.routes["remove_external"].to()
|
|
112
112
|
urls.tab_switch = tabs_routes["tab_switch"].to()
|
|
113
113
|
|
|
114
114
|
merged_routes = {
|
|
115
115
|
**queue_routes,
|
|
116
116
|
**filtering_routes,
|
|
117
|
-
**
|
|
117
|
+
**local_files.routes,
|
|
118
118
|
**tabs_routes,
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
routers = [queue_router, filtering_router, *
|
|
121
|
+
routers = [queue_router, filtering_router, *local_files.routers, tabs_router, sb_state.router]
|
|
122
122
|
|
|
123
|
-
return
|
|
123
|
+
return SelectionResult(
|
|
124
|
+
routers=routers,
|
|
125
|
+
urls=urls,
|
|
126
|
+
routes=merged_routes,
|
|
127
|
+
render_local_files_panel=local_files.render_panel,
|
|
128
|
+
sb_state=sb_state,
|
|
129
|
+
restore_state=local_files.restore_state,
|
|
130
|
+
)
|
|
@@ -17,7 +17,7 @@ from cjm_fasthtml_file_browser.routes.handlers import init_router as init_fb_rou
|
|
|
17
17
|
|
|
18
18
|
from cjm_fasthtml_interactions.core.state_store import get_session_id
|
|
19
19
|
|
|
20
|
-
from ..models import SelectionUrls
|
|
20
|
+
from ..models import SelectionUrls, LocalFilesResult
|
|
21
21
|
from cjm_transcript_source_select.routes.core import (
|
|
22
22
|
WorkflowStateStore, _get_step_state, _update_step_state
|
|
23
23
|
)
|
|
@@ -52,8 +52,6 @@ def _handle_remove_external_source(
|
|
|
52
52
|
sess, # FastHTML session object
|
|
53
53
|
db_path: str, # Path to the .db file to remove
|
|
54
54
|
external_db_paths_ref: List[str], # Shared external paths list (mutated in place)
|
|
55
|
-
fb_state_getter: Callable[[], BrowserState], # File browser state getter
|
|
56
|
-
fb_state_setter: Callable[[BrowserState], None], # File browser state setter
|
|
57
55
|
fb_routers: FileBrowserRouters, # File browser routers (for targeted OOB)
|
|
58
56
|
remove_url: str, # URL for remove button in external sources list
|
|
59
57
|
): # Tuple of OOB elements (external sources list + checkbox cells)
|
|
@@ -66,13 +64,8 @@ def _handle_remove_external_source(
|
|
|
66
64
|
_update_step_state(state_store, workflow_id, session_id, external_db_paths=list(external_db_paths_ref))
|
|
67
65
|
source_service.set_external_paths(list(external_db_paths_ref))
|
|
68
66
|
|
|
69
|
-
# Sync
|
|
70
|
-
|
|
71
|
-
browser_state.selection.selected_paths = list(external_db_paths_ref)
|
|
72
|
-
fb_state_setter(browser_state)
|
|
73
|
-
|
|
74
|
-
# Targeted OOB updates instead of full panel re-render
|
|
75
|
-
checkbox_oobs = fb_routers.render_selection_oobs([db_path])
|
|
67
|
+
# Sync selection + get targeted OOBs in one call
|
|
68
|
+
checkbox_oobs = fb_routers.update_selection_oobs(list(external_db_paths_ref), [db_path])
|
|
76
69
|
external_list_oob = _render_external_sources_list(
|
|
77
70
|
list(external_db_paths_ref), remove_url, oob=True,
|
|
78
71
|
)
|
|
@@ -85,7 +78,7 @@ def init_local_files_router(
|
|
|
85
78
|
source_service: SourceService, # The source service for external db ops
|
|
86
79
|
prefix: str, # Route prefix (e.g., "/workflow/selection/local_files")
|
|
87
80
|
urls: SelectionUrls, # URL bundle for rendering
|
|
88
|
-
) ->
|
|
81
|
+
) -> LocalFilesResult: # Router result with routers, routes, render, and restore
|
|
89
82
|
"""Initialize local files browser routes with new file browser API."""
|
|
90
83
|
provider = _get_local_files_provider()
|
|
91
84
|
config = _create_db_browser_config()
|
|
@@ -97,18 +90,57 @@ def init_local_files_router(
|
|
|
97
90
|
# --- File browser state accessors (shared, non-per-session) ---
|
|
98
91
|
_browser_state = BrowserState(current_path=home_path)
|
|
99
92
|
|
|
93
|
+
# --- Lazy state restoration from persisted store ---
|
|
94
|
+
_state_restored = [False]
|
|
95
|
+
|
|
96
|
+
def _restore_from_persisted(session_id: str) -> None:
|
|
97
|
+
"""Load persisted external_db_paths and file_browser_state on first call."""
|
|
98
|
+
if _state_restored[0]:
|
|
99
|
+
return
|
|
100
|
+
step_state = _get_step_state(state_store, workflow_id, session_id)
|
|
101
|
+
|
|
102
|
+
# Restore external_db_paths
|
|
103
|
+
persisted_paths = step_state.get("external_db_paths", [])
|
|
104
|
+
if persisted_paths:
|
|
105
|
+
_external_db_paths[:] = persisted_paths
|
|
106
|
+
source_service.set_external_paths(list(_external_db_paths))
|
|
107
|
+
|
|
108
|
+
# Restore browser state (current_path, sort)
|
|
109
|
+
persisted_browser = step_state.get("file_browser_state", {})
|
|
110
|
+
if persisted_browser:
|
|
111
|
+
restored = BrowserState.from_dict(persisted_browser)
|
|
112
|
+
_browser_state.current_path = restored.current_path
|
|
113
|
+
_browser_state.sort_by = restored.sort_by
|
|
114
|
+
_browser_state.sort_descending = restored.sort_descending
|
|
115
|
+
# Selection synced from _external_db_paths via _fb_state_getter
|
|
116
|
+
|
|
117
|
+
_state_restored[0] = True
|
|
118
|
+
|
|
100
119
|
def _fb_state_getter() -> BrowserState:
|
|
101
120
|
"""Get browser state with selection synced to external_db_paths."""
|
|
102
121
|
_browser_state.selection.selected_paths = list(_external_db_paths)
|
|
103
122
|
return _browser_state
|
|
104
123
|
|
|
105
|
-
def _fb_state_setter(state: BrowserState) -> None:
|
|
106
|
-
"""Save browser state from file browser."""
|
|
124
|
+
def _fb_state_setter(state: BrowserState, request=None) -> None:
|
|
125
|
+
"""Save browser state from file browser and persist to state store."""
|
|
126
|
+
# Lazy restore on first request
|
|
127
|
+
if request is not None and not _state_restored[0]:
|
|
128
|
+
_restore_from_persisted(get_session_id(request.session))
|
|
129
|
+
|
|
107
130
|
_browser_state.current_path = state.current_path
|
|
108
131
|
_browser_state.sort_by = state.sort_by
|
|
109
132
|
_browser_state.sort_descending = state.sort_descending
|
|
110
133
|
_browser_state.selection = state.selection
|
|
111
134
|
|
|
135
|
+
# Persist browser state
|
|
136
|
+
if request is not None:
|
|
137
|
+
session_id = get_session_id(request.session)
|
|
138
|
+
_update_step_state(
|
|
139
|
+
state_store, workflow_id, session_id,
|
|
140
|
+
file_browser_state=state.to_dict(),
|
|
141
|
+
current_browse_path=state.current_path,
|
|
142
|
+
)
|
|
143
|
+
|
|
112
144
|
# --- Callbacks for file browser ---
|
|
113
145
|
def _validate_selection(path: str) -> Tuple[bool, str]:
|
|
114
146
|
"""Validate .db schema before allowing selection (checkbox click path)."""
|
|
@@ -118,8 +150,12 @@ def init_local_files_router(
|
|
|
118
150
|
return (False, error)
|
|
119
151
|
return (True, "")
|
|
120
152
|
|
|
121
|
-
def _on_selection_change(selected_paths: List[str]) -> Tuple:
|
|
153
|
+
def _on_selection_change(selected_paths: List[str], request=None) -> Tuple:
|
|
122
154
|
"""Sync external_db_paths with validation and return OOB updates."""
|
|
155
|
+
# Lazy restore on first request
|
|
156
|
+
if request is not None and not _state_restored[0]:
|
|
157
|
+
_restore_from_persisted(get_session_id(request.session))
|
|
158
|
+
|
|
123
159
|
# Validate any newly added paths
|
|
124
160
|
old_set = set(_external_db_paths)
|
|
125
161
|
validated_paths = []
|
|
@@ -141,6 +177,14 @@ def init_local_files_router(
|
|
|
141
177
|
_external_db_paths[:] = validated_paths
|
|
142
178
|
source_service.set_external_paths(list(_external_db_paths))
|
|
143
179
|
|
|
180
|
+
# Persist external_db_paths
|
|
181
|
+
if request is not None:
|
|
182
|
+
session_id = get_session_id(request.session)
|
|
183
|
+
_update_step_state(
|
|
184
|
+
state_store, workflow_id, session_id,
|
|
185
|
+
external_db_paths=list(_external_db_paths),
|
|
186
|
+
)
|
|
187
|
+
|
|
144
188
|
return (
|
|
145
189
|
_render_external_sources_list(list(_external_db_paths), urls.remove_external, oob=True),
|
|
146
190
|
_render_error_alert(error_message, oob=True),
|
|
@@ -163,8 +207,12 @@ def init_local_files_router(
|
|
|
163
207
|
)
|
|
164
208
|
|
|
165
209
|
# --- Render function for the full local files panel ---
|
|
166
|
-
def _render_panel(error_message: Optional[str] = None) -> Any:
|
|
210
|
+
def _render_panel(error_message: Optional[str] = None, session_id: Optional[str] = None) -> Any:
|
|
167
211
|
"""Render the complete local files panel (file browser + external sources list)."""
|
|
212
|
+
# Restore persisted state and rebuild items before rendering
|
|
213
|
+
if session_id is not None and not _state_restored[0]:
|
|
214
|
+
_restore_from_persisted(session_id)
|
|
215
|
+
fb_routers.sync_items()
|
|
168
216
|
return _render_local_files_browser(
|
|
169
217
|
render_fn=fb_routers.render,
|
|
170
218
|
external_paths=list(_external_db_paths),
|
|
@@ -172,6 +220,12 @@ def init_local_files_router(
|
|
|
172
220
|
error_message=error_message,
|
|
173
221
|
)
|
|
174
222
|
|
|
223
|
+
# --- Restore callable for eager state restoration ---
|
|
224
|
+
def _restore_state(session_id: str) -> None:
|
|
225
|
+
"""Restore persisted local files state (external_db_paths + browser state)."""
|
|
226
|
+
_restore_from_persisted(session_id)
|
|
227
|
+
fb_routers.sync_items()
|
|
228
|
+
|
|
175
229
|
# --- Custom router for remove_external (needs session context) ---
|
|
176
230
|
custom_router = APIRouter(prefix=prefix)
|
|
177
231
|
|
|
@@ -182,8 +236,6 @@ def init_local_files_router(
|
|
|
182
236
|
state_store, workflow_id, source_service,
|
|
183
237
|
sess, db_path,
|
|
184
238
|
external_db_paths_ref=_external_db_paths,
|
|
185
|
-
fb_state_getter=_fb_state_getter,
|
|
186
|
-
fb_state_setter=_fb_state_setter,
|
|
187
239
|
fb_routers=fb_routers,
|
|
188
240
|
remove_url=urls.remove_external,
|
|
189
241
|
)
|
|
@@ -195,4 +247,9 @@ def init_local_files_router(
|
|
|
195
247
|
"remove_external": remove_external,
|
|
196
248
|
}
|
|
197
249
|
|
|
198
|
-
return
|
|
250
|
+
return LocalFilesResult(
|
|
251
|
+
routers=all_routers,
|
|
252
|
+
routes=routes,
|
|
253
|
+
render_panel=_render_panel,
|
|
254
|
+
restore_state=_restore_state,
|
|
255
|
+
)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
__all__ = ['init_tabs_router']
|
|
7
7
|
|
|
8
8
|
# %% ../../nbs/routes/tabs.ipynb #ca31d3ff
|
|
9
|
-
from typing import Any, Optional, Tuple, Dict, Callable
|
|
9
|
+
from typing import Any, Optional, Tuple, Dict, List, Callable
|
|
10
10
|
|
|
11
11
|
from fasthtml.common import APIRouter, Script
|
|
12
12
|
|
|
@@ -24,15 +24,16 @@ from ..services.source_utils import calculate_next_tab
|
|
|
24
24
|
|
|
25
25
|
# %% ../../nbs/routes/tabs.ipynb #4d0109d3
|
|
26
26
|
def _handle_tab_switch(
|
|
27
|
-
state_store: WorkflowStateStore, # The workflow state store
|
|
28
|
-
workflow_id: str, # The workflow identifier
|
|
29
27
|
source_service: SourceService, # The source service for queries
|
|
30
28
|
request, # FastHTML request object
|
|
31
29
|
sess, # FastHTML session object
|
|
32
30
|
direction: str, # Direction: "prev", "next", "db", or "files"
|
|
33
31
|
urls: SelectionUrls, # URL bundle for rendering
|
|
32
|
+
current_tab_ref: List[str], # Mutable ref [current_tab] for closure-based tracking
|
|
34
33
|
render_local_files_panel: Optional[Callable] = None, # Render fn for Files tab
|
|
35
34
|
sb_state: Any = None, # SourceBrowserRouterState for DB tab VC rendering
|
|
35
|
+
state_store: WorkflowStateStore = None, # State store (for reading step state)
|
|
36
|
+
workflow_id: str = "", # Workflow ID (for reading step state)
|
|
36
37
|
): # Tuple of inner content, OOB tab headers, and tab switch script
|
|
37
38
|
"""Switch between Plugin DB and Local Files tabs."""
|
|
38
39
|
session_id = get_session_id(sess)
|
|
@@ -41,14 +42,10 @@ def _handle_tab_switch(
|
|
|
41
42
|
selected_sources = step_state.get("selected_sources", [])
|
|
42
43
|
grouping_mode = step_state.get("grouping_mode", "media_path")
|
|
43
44
|
|
|
44
|
-
# Determine new tab
|
|
45
|
-
|
|
46
|
-
current_tab = workflow_state.get("source_tab", "db")
|
|
45
|
+
# Determine new tab from closure-based tracking (not persisted)
|
|
46
|
+
current_tab = current_tab_ref[0]
|
|
47
47
|
new_tab = calculate_next_tab(direction, current_tab, ["db", "files"])
|
|
48
|
-
|
|
49
|
-
# Save new tab state
|
|
50
|
-
workflow_state["source_tab"] = new_tab
|
|
51
|
-
state_store.update_state(workflow_id, session_id, workflow_state)
|
|
48
|
+
current_tab_ref[0] = new_tab
|
|
52
49
|
|
|
53
50
|
# Render the content for the new active tab
|
|
54
51
|
if new_tab == "db":
|
|
@@ -56,7 +53,7 @@ def _handle_tab_switch(
|
|
|
56
53
|
content = sb_state.rebuild_and_render(all_transcriptions, selected_sources, grouping_mode)
|
|
57
54
|
else:
|
|
58
55
|
if render_local_files_panel is not None:
|
|
59
|
-
content = render_local_files_panel()
|
|
56
|
+
content = render_local_files_panel(session_id=session_id)
|
|
60
57
|
else:
|
|
61
58
|
from cjm_transcript_source_select.components.local_files import _render_local_files_browser
|
|
62
59
|
content = _render_local_files_browser()
|
|
@@ -85,14 +82,20 @@ def init_tabs_router(
|
|
|
85
82
|
"""Initialize tab switching routes."""
|
|
86
83
|
router = APIRouter(prefix=prefix)
|
|
87
84
|
|
|
85
|
+
# Closure-based tab tracking (not persisted across restarts)
|
|
86
|
+
_current_tab: List[str] = ["db"]
|
|
87
|
+
|
|
88
88
|
@router
|
|
89
89
|
def tab_switch(request, sess, direction: str):
|
|
90
90
|
"""Switch between source tabs."""
|
|
91
91
|
return _handle_tab_switch(
|
|
92
|
-
|
|
93
|
-
request, sess, direction, urls=urls,
|
|
92
|
+
source_service=source_service,
|
|
93
|
+
request=request, sess=sess, direction=direction, urls=urls,
|
|
94
|
+
current_tab_ref=_current_tab,
|
|
94
95
|
render_local_files_panel=render_local_files_panel,
|
|
95
96
|
sb_state=sb_state,
|
|
97
|
+
state_store=state_store,
|
|
98
|
+
workflow_id=workflow_id,
|
|
96
99
|
)
|
|
97
100
|
|
|
98
101
|
routes = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: cjm-transcript-source-select
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.15
|
|
4
4
|
Summary: FastHTML source selection component for transcript decomposition workflows, with federated database browsing, drag-drop ordering, and keyboard navigation.
|
|
5
5
|
Home-page: https://github.com/cj-mills/cjm-transcript-source-select
|
|
6
6
|
Author: Christian J. Mills
|
|
@@ -106,57 +106,57 @@ graph LR
|
|
|
106
106
|
utils[utils<br/>utils]
|
|
107
107
|
|
|
108
108
|
components_helpers --> models
|
|
109
|
-
components_local_files --> components_helpers
|
|
110
109
|
components_local_files --> html_ids
|
|
110
|
+
components_local_files --> components_helpers
|
|
111
111
|
components_preview_panel --> html_ids
|
|
112
112
|
components_source_browser --> services_source_utils
|
|
113
113
|
components_source_browser --> utils
|
|
114
114
|
components_source_browser --> html_ids
|
|
115
|
+
components_step_renderer --> components_preview_panel
|
|
115
116
|
components_step_renderer --> components_selection_queue
|
|
116
|
-
components_step_renderer --> components_source_browser
|
|
117
117
|
components_step_renderer --> utils
|
|
118
118
|
components_step_renderer --> components_local_files
|
|
119
119
|
components_step_renderer --> html_ids
|
|
120
|
-
components_step_renderer --> components_preview_panel
|
|
121
120
|
components_step_renderer --> models
|
|
122
|
-
|
|
123
|
-
routes_core --> services_source
|
|
124
|
-
routes_core --> html_ids
|
|
121
|
+
components_step_renderer --> components_source_browser
|
|
125
122
|
routes_core --> models
|
|
123
|
+
routes_core --> services_source
|
|
124
|
+
routes_core --> components_selection_queue
|
|
126
125
|
routes_core --> components_step_renderer
|
|
126
|
+
routes_core --> html_ids
|
|
127
|
+
routes_filtering --> routes_core
|
|
127
128
|
routes_filtering --> services_source_utils
|
|
128
129
|
routes_filtering --> services_source
|
|
129
|
-
routes_filtering --> routes_core
|
|
130
130
|
routes_filtering --> models
|
|
131
131
|
routes_init --> routes_core
|
|
132
|
+
routes_init --> routes_queue
|
|
133
|
+
routes_init --> routes_tabs
|
|
134
|
+
routes_init --> routes_filtering
|
|
132
135
|
routes_init --> services_source
|
|
133
136
|
routes_init --> routes_source_browser
|
|
134
|
-
routes_init --> routes_filtering
|
|
135
137
|
routes_init --> routes_local_files
|
|
136
|
-
routes_init --> routes_queue
|
|
137
138
|
routes_init --> models
|
|
138
|
-
|
|
139
|
+
routes_local_files --> models
|
|
140
|
+
routes_local_files --> routes_core
|
|
139
141
|
routes_local_files --> components_local_files
|
|
140
142
|
routes_local_files --> services_source
|
|
141
|
-
routes_local_files --> routes_core
|
|
142
|
-
routes_local_files --> models
|
|
143
|
-
routes_queue --> services_source_utils
|
|
144
|
-
routes_queue --> services_source
|
|
145
143
|
routes_queue --> routes_core
|
|
144
|
+
routes_queue --> services_source_utils
|
|
146
145
|
routes_queue --> components_preview_panel
|
|
146
|
+
routes_queue --> services_source
|
|
147
147
|
routes_queue --> models
|
|
148
|
-
routes_source_browser --> routes_core
|
|
149
|
-
routes_source_browser --> services_source_utils
|
|
150
148
|
routes_source_browser --> components_source_browser
|
|
149
|
+
routes_source_browser --> components_preview_panel
|
|
150
|
+
routes_source_browser --> services_source_utils
|
|
151
151
|
routes_source_browser --> services_source
|
|
152
|
+
routes_source_browser --> routes_core
|
|
152
153
|
routes_source_browser --> html_ids
|
|
153
|
-
routes_source_browser --> components_preview_panel
|
|
154
154
|
routes_source_browser --> models
|
|
155
|
+
routes_tabs --> models
|
|
155
156
|
routes_tabs --> components_step_renderer
|
|
157
|
+
routes_tabs --> services_source
|
|
156
158
|
routes_tabs --> routes_core
|
|
157
159
|
routes_tabs --> services_source_utils
|
|
158
|
-
routes_tabs --> services_source
|
|
159
|
-
routes_tabs --> models
|
|
160
160
|
```
|
|
161
161
|
|
|
162
162
|
*52 cross-module dependencies detected*
|
|
@@ -426,7 +426,7 @@ def init_selection_routers(
|
|
|
426
426
|
source_service: SourceService, # The source service for queries
|
|
427
427
|
workflow_id: str, # The workflow identifier
|
|
428
428
|
prefix: str, # Base prefix for selection routes (e.g., "/workflow/selection")
|
|
429
|
-
) ->
|
|
429
|
+
) -> SelectionResult: # Selection router result with routers, urls, routes, and restore
|
|
430
430
|
"Initialize and return all selection routers with URL bundle."
|
|
431
431
|
```
|
|
432
432
|
|
|
@@ -526,8 +526,6 @@ def _handle_remove_external_source(
|
|
|
526
526
|
sess, # FastHTML session object
|
|
527
527
|
db_path: str, # Path to the .db file to remove
|
|
528
528
|
external_db_paths_ref: List[str], # Shared external paths list (mutated in place)
|
|
529
|
-
fb_state_getter: Callable[[], BrowserState], # File browser state getter
|
|
530
|
-
fb_state_setter: Callable[[BrowserState], None], # File browser state setter
|
|
531
529
|
fb_routers: FileBrowserRouters, # File browser routers (for targeted OOB)
|
|
532
530
|
remove_url: str, # URL for remove button in external sources list
|
|
533
531
|
): # Tuple of OOB elements (external sources list + checkbox cells)
|
|
@@ -541,7 +539,7 @@ def init_local_files_router(
|
|
|
541
539
|
source_service: SourceService, # The source service for external db ops
|
|
542
540
|
prefix: str, # Route prefix (e.g., "/workflow/selection/local_files")
|
|
543
541
|
urls: SelectionUrls, # URL bundle for rendering
|
|
544
|
-
) ->
|
|
542
|
+
) -> LocalFilesResult: # Router result with routers, routes, render, and restore
|
|
545
543
|
"Initialize local files browser routes with new file browser API."
|
|
546
544
|
```
|
|
547
545
|
|
|
@@ -560,10 +558,24 @@ _local_files_provider: Optional[LocalFileSystemProvider] = None
|
|
|
560
558
|
``` python
|
|
561
559
|
from cjm_transcript_source_select.models import (
|
|
562
560
|
SelectionStepState,
|
|
563
|
-
SelectionUrls
|
|
561
|
+
SelectionUrls,
|
|
562
|
+
LocalFilesResult,
|
|
563
|
+
SelectionResult
|
|
564
564
|
)
|
|
565
565
|
```
|
|
566
566
|
|
|
567
|
+
#### Functions
|
|
568
|
+
|
|
569
|
+
``` python
|
|
570
|
+
def _no_op_restore(session_id: str) -> None:
|
|
571
|
+
"""Default no-op for restore_state."""
|
|
572
|
+
pass
|
|
573
|
+
|
|
574
|
+
@dataclass
|
|
575
|
+
class LocalFilesResult
|
|
576
|
+
"Default no-op for restore_state."
|
|
577
|
+
```
|
|
578
|
+
|
|
567
579
|
#### Classes
|
|
568
580
|
|
|
569
581
|
``` python
|
|
@@ -593,6 +605,30 @@ class SelectionUrls:
|
|
|
593
605
|
tab_switch: str = '' # Switch source tabs
|
|
594
606
|
```
|
|
595
607
|
|
|
608
|
+
``` python
|
|
609
|
+
@dataclass
|
|
610
|
+
class LocalFilesResult:
|
|
611
|
+
"Return type from init_local_files_router."
|
|
612
|
+
|
|
613
|
+
routers: List[APIRouter] # Routers to register (custom + file browser + VC)
|
|
614
|
+
routes: Dict[str, Callable] # Named route handlers
|
|
615
|
+
render_panel: Callable # (error_message?, session_id?) -> rendered panel
|
|
616
|
+
restore_state: Callable = field(...) # (session_id) -> None, restore persisted state
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
``` python
|
|
620
|
+
@dataclass
|
|
621
|
+
class SelectionResult:
|
|
622
|
+
"Return type from init_selection_routers."
|
|
623
|
+
|
|
624
|
+
routers: List[APIRouter] # All selection routers to register
|
|
625
|
+
urls: 'SelectionUrls' = field(...) # URL bundle
|
|
626
|
+
routes: Dict[str, Callable] = field(...) # All named route handlers
|
|
627
|
+
render_local_files_panel: Optional[Callable] # Render fn for local files tab
|
|
628
|
+
sb_state: Any # SourceBrowserRouterState
|
|
629
|
+
restore_state: Callable = field(...) # (session_id) -> None, restore persisted state
|
|
630
|
+
```
|
|
631
|
+
|
|
596
632
|
### preview_panel (`preview_panel.ipynb`)
|
|
597
633
|
|
|
598
634
|
> Collapsible preview panel for displaying selected content
|
|
@@ -1436,15 +1472,16 @@ from cjm_transcript_source_select.routes.tabs import (
|
|
|
1436
1472
|
|
|
1437
1473
|
``` python
|
|
1438
1474
|
def _handle_tab_switch(
|
|
1439
|
-
state_store: WorkflowStateStore, # The workflow state store
|
|
1440
|
-
workflow_id: str, # The workflow identifier
|
|
1441
1475
|
source_service: SourceService, # The source service for queries
|
|
1442
1476
|
request, # FastHTML request object
|
|
1443
1477
|
sess, # FastHTML session object
|
|
1444
1478
|
direction: str, # Direction: "prev", "next", "db", or "files"
|
|
1445
1479
|
urls: SelectionUrls, # URL bundle for rendering
|
|
1480
|
+
current_tab_ref: List[str], # Mutable ref [current_tab] for closure-based tracking
|
|
1446
1481
|
render_local_files_panel: Optional[Callable] = None, # Render fn for Files tab
|
|
1447
1482
|
sb_state: Any = None, # SourceBrowserRouterState for DB tab VC rendering
|
|
1483
|
+
state_store: WorkflowStateStore = None, # State store (for reading step state)
|
|
1484
|
+
workflow_id: str = "", # Workflow ID (for reading step state)
|
|
1448
1485
|
): # Tuple of inner content, OOB tab headers, and tab switch script
|
|
1449
1486
|
"Switch between Plugin DB and Local Files tabs."
|
|
1450
1487
|
```
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.0.13"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|