data-sourcerer 0.2.2__py3-none-any.whl → 0.3.0__py3-none-any.whl
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.
- {data_sourcerer-0.2.2.dist-info → data_sourcerer-0.3.0.dist-info}/METADATA +1 -1
- {data_sourcerer-0.2.2.dist-info → data_sourcerer-0.3.0.dist-info}/RECORD +43 -29
- sourcerer/__init__.py +1 -1
- sourcerer/domain/access_credentials/entities.py +3 -1
- sourcerer/domain/access_credentials/repositories.py +1 -1
- sourcerer/domain/storage/__init__.py +0 -0
- sourcerer/domain/storage/entities.py +27 -0
- sourcerer/domain/storage/repositories.py +31 -0
- sourcerer/infrastructure/access_credentials/repositories.py +3 -2
- sourcerer/infrastructure/access_credentials/services.py +9 -25
- sourcerer/infrastructure/db/models.py +33 -2
- sourcerer/infrastructure/storage/__init__.py +0 -0
- sourcerer/infrastructure/storage/repositories.py +72 -0
- sourcerer/infrastructure/storage/services.py +37 -0
- sourcerer/infrastructure/storage_provider/services/gcp.py +1 -1
- sourcerer/infrastructure/utils.py +2 -1
- sourcerer/presentation/di_container.py +15 -0
- sourcerer/presentation/screens/file_system_finder/main.py +7 -6
- sourcerer/presentation/screens/file_system_finder/widgets/file_system_navigator.py +16 -13
- sourcerer/presentation/screens/main/main.py +63 -8
- sourcerer/presentation/screens/main/messages/select_storage_item.py +1 -0
- sourcerer/presentation/screens/main/mixins/resize_containers_watcher_mixin.py +2 -1
- sourcerer/presentation/screens/main/widgets/storage_content.py +191 -85
- sourcerer/presentation/screens/main/widgets/storage_list_sidebar.py +99 -31
- sourcerer/presentation/screens/preview_content/main.py +15 -3
- sourcerer/presentation/screens/provider_creds_list/main.py +29 -8
- sourcerer/presentation/screens/provider_creds_registration/main.py +7 -4
- sourcerer/presentation/screens/shared/widgets/labeled_input.py +2 -2
- sourcerer/presentation/screens/shared/widgets/spinner.py +57 -0
- sourcerer/presentation/screens/storage_action_progress/main.py +7 -11
- sourcerer/presentation/screens/storages_list/__init__.py +0 -0
- sourcerer/presentation/screens/storages_list/main.py +180 -0
- sourcerer/presentation/screens/storages_list/messages/__init__.py +0 -0
- sourcerer/presentation/screens/storages_list/messages/reload_storages_request.py +8 -0
- sourcerer/presentation/screens/storages_list/styles.tcss +55 -0
- sourcerer/presentation/screens/storages_registration/__init__.py +0 -0
- sourcerer/presentation/screens/storages_registration/main.py +100 -0
- sourcerer/presentation/screens/storages_registration/styles.tcss +41 -0
- sourcerer/presentation/settings.py +29 -16
- sourcerer/presentation/utils.py +9 -1
- sourcerer/presentation/screens/shared/widgets/loader.py +0 -31
- {data_sourcerer-0.2.2.dist-info → data_sourcerer-0.3.0.dist-info}/WHEEL +0 -0
- {data_sourcerer-0.2.2.dist-info → data_sourcerer-0.3.0.dist-info}/entry_points.txt +0 -0
- {data_sourcerer-0.2.2.dist-info → data_sourcerer-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -21,6 +21,7 @@ from sourcerer.presentation.screens.shared.containers import (
|
|
21
21
|
ScrollHorizontalContainerWithNoBindings,
|
22
22
|
ScrollVerticalContainerWithNoBindings,
|
23
23
|
)
|
24
|
+
from sourcerer.presentation.settings import KeyBindings
|
24
25
|
from sourcerer.settings import DIRECTORY_ICON, DOUBLE_CLICK_THRESHOLD, FILE_ICON
|
25
26
|
|
26
27
|
|
@@ -48,7 +49,7 @@ class FileSystemWidget(Widget):
|
|
48
49
|
background: $block-cursor-blurred-background;
|
49
50
|
text-style: $block-cursor-blurred-text-style;
|
50
51
|
}
|
51
|
-
|
52
|
+
|
52
53
|
.folder-name {
|
53
54
|
text-overflow: ellipsis;
|
54
55
|
text-wrap: nowrap;
|
@@ -161,7 +162,7 @@ class FileSystemWidget(Widget):
|
|
161
162
|
Calls the `on_click` method if the pressed key is "enter", which may trigger
|
162
163
|
folder navigation or file opening depending on the widget's context.
|
163
164
|
"""
|
164
|
-
if event.key ==
|
165
|
+
if event.key == KeyBindings.ENTER.value:
|
165
166
|
self.on_file_select()
|
166
167
|
|
167
168
|
def on_file_select(self):
|
@@ -232,11 +233,13 @@ class FileSystemNavigator(ScrollHorizontalContainerWithNoBindings):
|
|
232
233
|
|
233
234
|
# Consolidate key binding data
|
234
235
|
BINDINGS: ClassVar[list[BindingType]] = [
|
235
|
-
Binding(
|
236
|
-
Binding(
|
237
|
-
Binding(
|
238
|
-
Binding(
|
239
|
-
Binding(
|
236
|
+
Binding(KeyBindings.ENTER.value, "select_cursor", "Select", show=False),
|
237
|
+
Binding(KeyBindings.ARROW_UP.value, "cursor_up", "Cursor up", show=False),
|
238
|
+
Binding(KeyBindings.ARROW_DOWN.value, "cursor_down", "Cursor down", show=False),
|
239
|
+
Binding(KeyBindings.ARROW_LEFT.value, "cursor_left", "Cursor left", show=False),
|
240
|
+
Binding(
|
241
|
+
KeyBindings.ARROW_RIGHT.value, "cursor_right", "Cursor right", show=False
|
242
|
+
),
|
240
243
|
]
|
241
244
|
|
242
245
|
MAIN_CONTAINER_ID: ClassVar[str] = "dirs_content"
|
@@ -306,9 +309,9 @@ class FileSystemNavigator(ScrollHorizontalContainerWithNoBindings):
|
|
306
309
|
)
|
307
310
|
self._focus_first_child(path_listing_container)
|
308
311
|
|
309
|
-
self.path_listing_containers_uuids[
|
310
|
-
|
311
|
-
|
312
|
+
self.path_listing_containers_uuids[
|
313
|
+
str(self.work_dir)
|
314
|
+
] = path_listing_container.id
|
312
315
|
|
313
316
|
def action_cursor_down(self) -> None:
|
314
317
|
"""
|
@@ -626,9 +629,9 @@ class FileSystemNavigator(ScrollHorizontalContainerWithNoBindings):
|
|
626
629
|
await self._mount_path_listing_container(path_listing_container)
|
627
630
|
|
628
631
|
if str(folder_path) not in self.path_listing_containers_uuids:
|
629
|
-
self.path_listing_containers_uuids[
|
630
|
-
|
631
|
-
|
632
|
+
self.path_listing_containers_uuids[
|
633
|
+
str(folder_path)
|
634
|
+
] = path_listing_container.id
|
632
635
|
|
633
636
|
@on(FileSystemWidget.Focus)
|
634
637
|
def on_folder_focus(self, event: FileSystemWidget.Focus):
|
@@ -2,19 +2,23 @@ import time
|
|
2
2
|
import traceback
|
3
3
|
from concurrent.futures import ThreadPoolExecutor
|
4
4
|
from pathlib import Path
|
5
|
+
from typing import ClassVar
|
5
6
|
|
7
|
+
from dependency_injector.wiring import Provide
|
6
8
|
from textual import on, work
|
7
9
|
from textual.app import App, ComposeResult
|
8
|
-
from textual.binding import Binding
|
10
|
+
from textual.binding import Binding, BindingType
|
9
11
|
from textual.containers import Horizontal
|
10
12
|
from textual.reactive import reactive
|
11
13
|
from textual.widgets import Footer
|
12
14
|
|
15
|
+
from sourcerer.domain.storage_provider.entities import Storage
|
13
16
|
from sourcerer.infrastructure.access_credentials.services import CredentialsService
|
14
17
|
from sourcerer.infrastructure.storage_provider.exceptions import (
|
15
18
|
ListStorageItemsError,
|
16
19
|
)
|
17
20
|
from sourcerer.infrastructure.utils import generate_uuid
|
21
|
+
from sourcerer.presentation.di_container import DiContainer
|
18
22
|
from sourcerer.presentation.screens.critical_error.main import CriticalErrorScreen
|
19
23
|
from sourcerer.presentation.screens.file_system_finder.main import (
|
20
24
|
FileSystemNavigationModal,
|
@@ -55,6 +59,8 @@ from sourcerer.presentation.screens.storage_action_progress.main import (
|
|
55
59
|
StorageActionProgressScreen,
|
56
60
|
UploadKey,
|
57
61
|
)
|
62
|
+
from sourcerer.presentation.screens.storages_list.main import StoragesListScreen
|
63
|
+
from sourcerer.presentation.settings import KeyBindings
|
58
64
|
from sourcerer.presentation.themes.github_dark import github_dark_theme
|
59
65
|
from sourcerer.presentation.utils import (
|
60
66
|
get_provider_service_by_access_credentials,
|
@@ -93,12 +99,28 @@ class Sourcerer(App, ResizeContainersWatcherMixin):
|
|
93
99
|
"""
|
94
100
|
|
95
101
|
CSS_PATH = "styles.tcss"
|
96
|
-
BINDINGS = [
|
102
|
+
BINDINGS: ClassVar[list[BindingType]] = [
|
103
|
+
Binding("ctrl+r", "registrations", "Registrations list"),
|
104
|
+
Binding("ctrl+s", "storages", "Storages list"),
|
105
|
+
Binding(
|
106
|
+
KeyBindings.ARROW_LEFT.value, "focus_sidebar", "Focus sidebar", show=False
|
107
|
+
),
|
108
|
+
Binding(
|
109
|
+
KeyBindings.ARROW_RIGHT.value, "focus_content", "Focus content", show=False
|
110
|
+
),
|
111
|
+
]
|
97
112
|
is_storage_list_loading = reactive(False, recompose=True)
|
98
113
|
|
99
|
-
def __init__(
|
114
|
+
def __init__(
|
115
|
+
self,
|
116
|
+
credentials_service: CredentialsService = Provide[
|
117
|
+
DiContainer.credentials_service
|
118
|
+
],
|
119
|
+
*args,
|
120
|
+
**kwargs,
|
121
|
+
):
|
100
122
|
super().__init__(*args, **kwargs)
|
101
|
-
self.credentials_service =
|
123
|
+
self.credentials_service = credentials_service
|
102
124
|
self.storage_list_sidebar = StorageListSidebar(id="storage_list_sidebar")
|
103
125
|
self.storage_content = StorageContentContainer(id="storage_content_container")
|
104
126
|
self.load_percentage = 0
|
@@ -130,6 +152,18 @@ class Sourcerer(App, ResizeContainersWatcherMixin):
|
|
130
152
|
self.theme = "github-dark"
|
131
153
|
self.init_storages_list()
|
132
154
|
|
155
|
+
def action_focus_content(self):
|
156
|
+
"""
|
157
|
+
Focuses the storage content container.
|
158
|
+
"""
|
159
|
+
self.storage_content.focus()
|
160
|
+
|
161
|
+
def action_focus_sidebar(self):
|
162
|
+
"""
|
163
|
+
Focuses the storage list sidebar.
|
164
|
+
"""
|
165
|
+
self.storage_list_sidebar.focus()
|
166
|
+
|
133
167
|
def action_registrations(self):
|
134
168
|
"""
|
135
169
|
Opens the provider credentials list screen and refreshes the storage list.
|
@@ -142,6 +176,9 @@ class Sourcerer(App, ResizeContainersWatcherMixin):
|
|
142
176
|
"""
|
143
177
|
self.app.push_screen(ProviderCredsListScreen(), callback=self.refresh_storages)
|
144
178
|
|
179
|
+
def action_storages(self):
|
180
|
+
self.app.push_screen(StoragesListScreen(), callback=self.refresh_storages)
|
181
|
+
|
145
182
|
def refresh_storages(self, *args, **kwargs):
|
146
183
|
"""
|
147
184
|
Refreshes the storage list by clearing the current storages and
|
@@ -206,7 +243,11 @@ class Sourcerer(App, ResizeContainersWatcherMixin):
|
|
206
243
|
5. Notify the user if an error occurs during the retrieval process.
|
207
244
|
"""
|
208
245
|
self.refresh_storage_content(
|
209
|
-
event.access_credentials_uuid,
|
246
|
+
event.access_credentials_uuid,
|
247
|
+
event.name,
|
248
|
+
event.path,
|
249
|
+
event.prefix,
|
250
|
+
event.focus_content,
|
210
251
|
)
|
211
252
|
|
212
253
|
@on(UploadRequest)
|
@@ -381,7 +422,12 @@ class Sourcerer(App, ResizeContainersWatcherMixin):
|
|
381
422
|
self.uncheck_files_request(UncheckFilesRequest(keys=[]))
|
382
423
|
|
383
424
|
def refresh_storage_content(
|
384
|
-
self,
|
425
|
+
self,
|
426
|
+
access_credentials_uuid,
|
427
|
+
storage_name,
|
428
|
+
path,
|
429
|
+
prefix=None,
|
430
|
+
focus_content=False,
|
385
431
|
):
|
386
432
|
"""
|
387
433
|
Refreshes the storage content display with items from the specified storage path.
|
@@ -407,6 +453,7 @@ class Sourcerer(App, ResizeContainersWatcherMixin):
|
|
407
453
|
self.storage_content.storage_content = None
|
408
454
|
self.storage_content.selected_files = set()
|
409
455
|
self.storage_content.selected_files_n = 0
|
456
|
+
self.storage_content.focus_content = focus_content
|
410
457
|
|
411
458
|
provider_service = get_provider_service_by_access_uuid(
|
412
459
|
access_credentials_uuid, self.credentials_service
|
@@ -421,7 +468,7 @@ class Sourcerer(App, ResizeContainersWatcherMixin):
|
|
421
468
|
**params
|
422
469
|
)
|
423
470
|
except ListStorageItemsError as e:
|
424
|
-
self.notify_error(f"""Could not extract storage content \n{
|
471
|
+
self.notify_error(f"""Could not extract storage content \n{e}""")
|
425
472
|
|
426
473
|
def _upload_file(
|
427
474
|
self,
|
@@ -509,7 +556,15 @@ class Sourcerer(App, ResizeContainersWatcherMixin):
|
|
509
556
|
|
510
557
|
try:
|
511
558
|
storages = provider_service.list_storages()
|
512
|
-
|
559
|
+
storage_names = [storage.storage for storage in storages]
|
560
|
+
registered_storages = [
|
561
|
+
Storage(credentials.provider, storage.name, storage.created_at)
|
562
|
+
for storage in credentials.storages
|
563
|
+
if storage.name not in storage_names
|
564
|
+
]
|
565
|
+
self.storage_list_sidebar.storages[credentials.uuid] = (
|
566
|
+
storages + registered_storages
|
567
|
+
)
|
513
568
|
self.storage_list_sidebar.last_update_timestamp = time.time()
|
514
569
|
except Exception:
|
515
570
|
self.notify_error(f"Could not get storages list for {credentials.name}!")
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import time
|
2
|
+
from typing import ClassVar
|
2
3
|
|
3
4
|
from textual.events import MouseMove, MouseUp
|
4
5
|
|
@@ -28,7 +29,7 @@ class ResizeContainersWatcherMixin:
|
|
28
29
|
and is inherited from textual App.
|
29
30
|
"""
|
30
31
|
|
31
|
-
required_methods = ["query_one", "refresh"]
|
32
|
+
required_methods: ClassVar[list[str]] = ["query_one", "refresh"]
|
32
33
|
|
33
34
|
def __init_subclass__(cls, **kwargs):
|
34
35
|
super().__init_subclass__(**kwargs)
|