restiny 0.5.0__py3-none-any.whl → 0.6.1__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.
- restiny/__about__.py +1 -1
- restiny/__main__.py +2 -0
- restiny/assets/style.tcss +9 -1
- restiny/data/models.py +36 -15
- restiny/data/repos.py +107 -3
- restiny/entities.py +119 -1
- restiny/ui/__init__.py +2 -0
- restiny/ui/app.py +127 -41
- restiny/ui/collections_area.py +35 -10
- restiny/ui/environments_screen.py +270 -0
- restiny/ui/request_area.py +28 -1
- restiny/ui/response_area.py +4 -1
- restiny/ui/settings_screen.py +6 -13
- restiny/ui/top_bar_area.py +60 -0
- restiny/ui/url_area.py +4 -0
- restiny/widgets/collections_tree.py +5 -1
- {restiny-0.5.0.dist-info → restiny-0.6.1.dist-info}/METADATA +1 -1
- restiny-0.6.1.dist-info/RECORD +38 -0
- restiny-0.5.0.dist-info/RECORD +0 -36
- {restiny-0.5.0.dist-info → restiny-0.6.1.dist-info}/WHEEL +0 -0
- {restiny-0.5.0.dist-info → restiny-0.6.1.dist-info}/entry_points.txt +0 -0
- {restiny-0.5.0.dist-info → restiny-0.6.1.dist-info}/licenses/LICENSE +0 -0
- {restiny-0.5.0.dist-info → restiny-0.6.1.dist-info}/top_level.txt +0 -0
restiny/ui/app.py
CHANGED
|
@@ -1,34 +1,42 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
from collections.abc import Iterable
|
|
2
3
|
from http import HTTPStatus
|
|
3
4
|
|
|
4
5
|
import httpx
|
|
5
6
|
import pyperclip
|
|
6
7
|
from textual import on
|
|
7
|
-
from textual.app import App, ComposeResult
|
|
8
|
+
from textual.app import App, ComposeResult, SystemCommand
|
|
8
9
|
from textual.binding import Binding
|
|
9
10
|
from textual.containers import Horizontal, Vertical
|
|
10
11
|
from textual.events import DescendantFocus
|
|
12
|
+
from textual.screen import Screen
|
|
11
13
|
from textual.widget import Widget
|
|
12
14
|
from textual.widgets import Footer, Header
|
|
13
15
|
|
|
14
16
|
from restiny.__about__ import __version__
|
|
15
17
|
from restiny.assets import STYLE_TCSS
|
|
16
18
|
from restiny.consts import CUSTOM_THEMES
|
|
17
|
-
from restiny.data.repos import
|
|
19
|
+
from restiny.data.repos import (
|
|
20
|
+
EnvironmentsSQLRepo,
|
|
21
|
+
FoldersSQLRepo,
|
|
22
|
+
RequestsSQLRepo,
|
|
23
|
+
SettingsSQLRepo,
|
|
24
|
+
)
|
|
18
25
|
from restiny.entities import Request, Settings
|
|
19
26
|
from restiny.enums import (
|
|
20
27
|
AuthMode,
|
|
21
28
|
BodyMode,
|
|
22
29
|
BodyRawLanguage,
|
|
23
30
|
ContentType,
|
|
24
|
-
CustomThemes,
|
|
25
31
|
)
|
|
26
32
|
from restiny.ui import (
|
|
27
33
|
CollectionsArea,
|
|
28
34
|
RequestArea,
|
|
29
35
|
ResponseArea,
|
|
36
|
+
TopBarArea,
|
|
30
37
|
URLArea,
|
|
31
38
|
)
|
|
39
|
+
from restiny.ui.environments_screen import EnvironmentsScreen
|
|
32
40
|
from restiny.ui.response_area import ResponseAreaData
|
|
33
41
|
from restiny.ui.settings_screen import SettingsScreen
|
|
34
42
|
from restiny.widgets.custom_text_area import CustomTextArea
|
|
@@ -37,18 +45,11 @@ from restiny.widgets.custom_text_area import CustomTextArea
|
|
|
37
45
|
class RESTinyApp(App, inherit_bindings=False):
|
|
38
46
|
TITLE = f'RESTiny v{__version__}'
|
|
39
47
|
SUB_TITLE = 'Minimal HTTP client, no bullshit'
|
|
40
|
-
ENABLE_COMMAND_PALETTE = False
|
|
41
48
|
CSS_PATH = STYLE_TCSS
|
|
42
49
|
BINDINGS = [
|
|
43
50
|
Binding(
|
|
44
51
|
key='escape', action='quit', description='Quit the app', show=True
|
|
45
52
|
),
|
|
46
|
-
Binding(
|
|
47
|
-
key='ctrl+b',
|
|
48
|
-
action='toggle_collections',
|
|
49
|
-
description='Toggle collections',
|
|
50
|
-
show=True,
|
|
51
|
-
),
|
|
52
53
|
Binding(
|
|
53
54
|
key='ctrl+n',
|
|
54
55
|
action='prompt_add',
|
|
@@ -70,13 +71,13 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
70
71
|
Binding(
|
|
71
72
|
key='ctrl+s',
|
|
72
73
|
action='save',
|
|
73
|
-
description='Save
|
|
74
|
+
description='Save req',
|
|
74
75
|
show=True,
|
|
75
76
|
),
|
|
76
77
|
Binding(
|
|
77
|
-
key='
|
|
78
|
-
action='
|
|
79
|
-
description='
|
|
78
|
+
key='ctrl+b',
|
|
79
|
+
action='toggle_collections',
|
|
80
|
+
description='Toggle collections',
|
|
80
81
|
show=True,
|
|
81
82
|
),
|
|
82
83
|
Binding(
|
|
@@ -85,20 +86,14 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
85
86
|
description='Maximize/Minimize area',
|
|
86
87
|
show=True,
|
|
87
88
|
),
|
|
88
|
-
Binding(
|
|
89
|
-
key='f12',
|
|
90
|
-
action='open_settings',
|
|
91
|
-
description='Settings',
|
|
92
|
-
show=True,
|
|
93
|
-
),
|
|
94
89
|
]
|
|
95
|
-
# theme = 'textual-dark'
|
|
96
90
|
|
|
97
91
|
def __init__(
|
|
98
92
|
self,
|
|
99
93
|
folders_repo: FoldersSQLRepo,
|
|
100
94
|
requests_repo: RequestsSQLRepo,
|
|
101
95
|
settings_repo: SettingsSQLRepo,
|
|
96
|
+
environments_repo: EnvironmentsSQLRepo,
|
|
102
97
|
*args,
|
|
103
98
|
**kwargs,
|
|
104
99
|
) -> None:
|
|
@@ -106,18 +101,21 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
106
101
|
self.folders_repo = folders_repo
|
|
107
102
|
self.requests_repo = requests_repo
|
|
108
103
|
self.settings_repo = settings_repo
|
|
104
|
+
self.environments_repo = environments_repo
|
|
109
105
|
|
|
110
106
|
self.active_request_task: asyncio.Task | None = None
|
|
111
|
-
self.selected_request: Request | None = None
|
|
112
107
|
self.last_focused_widget: Widget | None = None
|
|
113
108
|
self.last_focused_maximizable_area: Widget | None = None
|
|
114
109
|
|
|
110
|
+
self._selected_request: Request | None = None
|
|
111
|
+
|
|
115
112
|
def compose(self) -> ComposeResult:
|
|
116
113
|
yield Header(show_clock=True)
|
|
117
114
|
with Horizontal():
|
|
118
115
|
yield CollectionsArea(classes='w-1fr')
|
|
119
116
|
with Vertical(classes='w-6fr'):
|
|
120
|
-
with
|
|
117
|
+
with Vertical(classes='h-auto'):
|
|
118
|
+
yield TopBarArea()
|
|
121
119
|
yield URLArea()
|
|
122
120
|
with Horizontal(classes='h-1fr'):
|
|
123
121
|
yield RequestArea()
|
|
@@ -126,16 +124,35 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
126
124
|
|
|
127
125
|
def on_mount(self) -> None:
|
|
128
126
|
self.collections_area = self.query_one(CollectionsArea)
|
|
127
|
+
self.top_bar_area = self.query_one(TopBarArea)
|
|
129
128
|
self.url_area = self.query_one(URLArea)
|
|
130
129
|
self.request_area = self.query_one(RequestArea)
|
|
131
130
|
self.response_area = self.query_one(ResponseArea)
|
|
132
131
|
|
|
133
|
-
self.
|
|
134
|
-
self.request_area.disabled = True
|
|
132
|
+
self.selected_request = None
|
|
135
133
|
|
|
136
134
|
self._register_themes()
|
|
137
135
|
self._apply_settings()
|
|
138
136
|
|
|
137
|
+
def get_system_commands(self, screen: Screen) -> Iterable[SystemCommand]:
|
|
138
|
+
yield SystemCommand('Copy as cURL', None, self.action_copy_as_curl)
|
|
139
|
+
yield SystemCommand(
|
|
140
|
+
'Show/Hide keys and help panel',
|
|
141
|
+
None,
|
|
142
|
+
self.action_toggle_help_panel,
|
|
143
|
+
)
|
|
144
|
+
yield SystemCommand(
|
|
145
|
+
'Save screenshot',
|
|
146
|
+
None,
|
|
147
|
+
lambda: self.set_timer(0.1, self.deliver_screenshot),
|
|
148
|
+
)
|
|
149
|
+
yield SystemCommand(
|
|
150
|
+
'Manage environments', None, self.action_manage_envs
|
|
151
|
+
)
|
|
152
|
+
yield SystemCommand(
|
|
153
|
+
'Manage settings', None, self.action_manage_settings
|
|
154
|
+
)
|
|
155
|
+
|
|
139
156
|
def action_toggle_collections(self) -> None:
|
|
140
157
|
if self.collections_area.display:
|
|
141
158
|
self.collections_area.display = False
|
|
@@ -146,12 +163,24 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
146
163
|
self.collections_area.prompt_add()
|
|
147
164
|
|
|
148
165
|
def action_prompt_update(self) -> None:
|
|
166
|
+
if not self.selected_request:
|
|
167
|
+
self.notify('No request selected', severity='warning')
|
|
168
|
+
return
|
|
169
|
+
|
|
149
170
|
self.collections_area.prompt_update()
|
|
150
171
|
|
|
151
172
|
def action_prompt_delete(self) -> None:
|
|
173
|
+
if not self.selected_request:
|
|
174
|
+
self.notify('No request selected', severity='warning')
|
|
175
|
+
return
|
|
176
|
+
|
|
152
177
|
self.collections_area.prompt_delete()
|
|
153
178
|
|
|
154
179
|
def action_save(self) -> None:
|
|
180
|
+
if not self.selected_request:
|
|
181
|
+
self.notify('No request selected', severity='warning')
|
|
182
|
+
return
|
|
183
|
+
|
|
155
184
|
req = self.get_request()
|
|
156
185
|
self.requests_repo.update(request=req)
|
|
157
186
|
self.collections_area._populate_children(
|
|
@@ -169,22 +198,28 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
169
198
|
else:
|
|
170
199
|
self.screen.maximize(self.last_focused_maximizable_area)
|
|
171
200
|
|
|
201
|
+
def action_toggle_help_panel(self) -> None:
|
|
202
|
+
if self.query('HelpPanel'):
|
|
203
|
+
self.action_hide_help_panel()
|
|
204
|
+
else:
|
|
205
|
+
self.action_show_help_panel()
|
|
206
|
+
|
|
172
207
|
def action_copy_as_curl(self) -> None:
|
|
173
208
|
if not self.selected_request:
|
|
174
209
|
self.notify(
|
|
175
|
-
'
|
|
210
|
+
'No request selected',
|
|
176
211
|
severity='warning',
|
|
177
212
|
)
|
|
178
213
|
return
|
|
179
214
|
|
|
180
|
-
request = self.
|
|
215
|
+
request = self.get_resolved_request()
|
|
181
216
|
self.copy_to_clipboard(request.to_curl())
|
|
182
217
|
self.notify(
|
|
183
|
-
'
|
|
218
|
+
'CURL command copied to clipboard',
|
|
184
219
|
severity='information',
|
|
185
220
|
)
|
|
186
221
|
|
|
187
|
-
def
|
|
222
|
+
def action_manage_settings(self) -> None:
|
|
188
223
|
def on_settings_result(result: dict | None) -> None:
|
|
189
224
|
if not result:
|
|
190
225
|
return
|
|
@@ -192,15 +227,19 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
192
227
|
self.settings_repo.set(Settings(theme=result['theme']))
|
|
193
228
|
self._apply_settings()
|
|
194
229
|
|
|
195
|
-
settings: Settings = self.settings_repo.get().data
|
|
196
230
|
self.push_screen(
|
|
197
|
-
screen=SettingsScreen(
|
|
198
|
-
themes=[theme.value for theme in CustomThemes],
|
|
199
|
-
theme=settings.theme,
|
|
200
|
-
),
|
|
231
|
+
screen=SettingsScreen(),
|
|
201
232
|
callback=on_settings_result,
|
|
202
233
|
)
|
|
203
234
|
|
|
235
|
+
def action_manage_envs(self) -> None:
|
|
236
|
+
def on_manage_environments_result(result) -> None:
|
|
237
|
+
self.top_bar_area.populate()
|
|
238
|
+
|
|
239
|
+
self.push_screen(
|
|
240
|
+
screen=EnvironmentsScreen(), callback=on_manage_environments_result
|
|
241
|
+
)
|
|
242
|
+
|
|
204
243
|
def copy_to_clipboard(self, text: str) -> None:
|
|
205
244
|
super().copy_to_clipboard(text)
|
|
206
245
|
try:
|
|
@@ -231,14 +270,26 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
231
270
|
def _on_request_selected(
|
|
232
271
|
self, message: CollectionsArea.RequestSelected
|
|
233
272
|
) -> None:
|
|
234
|
-
self.url_area.disabled = False
|
|
235
|
-
self.request_area.disabled = False
|
|
236
273
|
req = self.requests_repo.get_by_id(id=message.request_id).data
|
|
237
274
|
self.selected_request = req
|
|
238
275
|
self.set_request(request=req)
|
|
239
|
-
|
|
276
|
+
|
|
277
|
+
self.response_area.clear()
|
|
240
278
|
self.response_area.is_showing_response = False
|
|
241
279
|
|
|
280
|
+
@on(CollectionsArea.RequestUpdated)
|
|
281
|
+
def _on_request_updated(self, message) -> None:
|
|
282
|
+
req = self.requests_repo.get_by_id(id=message.request_id).data
|
|
283
|
+
self.selected_request = req
|
|
284
|
+
|
|
285
|
+
@on(CollectionsArea.RequestDeleted)
|
|
286
|
+
def _on_request_deleted(self, message) -> None:
|
|
287
|
+
self.selected_request = None
|
|
288
|
+
|
|
289
|
+
@on(CollectionsArea.FolderSelected)
|
|
290
|
+
def _on_folder_selected(self, message) -> None:
|
|
291
|
+
self.selected_request = None
|
|
292
|
+
|
|
242
293
|
def _apply_settings(self) -> None:
|
|
243
294
|
settings = self.settings_repo.get().data
|
|
244
295
|
self.theme = settings.theme
|
|
@@ -266,6 +317,27 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
266
317
|
return widget
|
|
267
318
|
widget = widget.parent
|
|
268
319
|
|
|
320
|
+
@property
|
|
321
|
+
def selected_request(self) -> Request | None:
|
|
322
|
+
return self._selected_request
|
|
323
|
+
|
|
324
|
+
@selected_request.setter
|
|
325
|
+
def selected_request(self, request: Request | None) -> None:
|
|
326
|
+
if request is None:
|
|
327
|
+
self.url_area.clear()
|
|
328
|
+
self.request_area.clear()
|
|
329
|
+
self.response_area.clear()
|
|
330
|
+
self.url_area.disabled = True
|
|
331
|
+
self.request_area.disabled = True
|
|
332
|
+
self.response_area.disabled = True
|
|
333
|
+
self.response_area.is_showing_response = False
|
|
334
|
+
else:
|
|
335
|
+
self.url_area.disabled = False
|
|
336
|
+
self.request_area.disabled = False
|
|
337
|
+
self.response_area.disabled = False
|
|
338
|
+
|
|
339
|
+
self._selected_request = request
|
|
340
|
+
|
|
269
341
|
def get_request(self) -> Request:
|
|
270
342
|
method = self.url_area.method
|
|
271
343
|
url = self.url_area.url
|
|
@@ -369,6 +441,20 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
369
441
|
options=options,
|
|
370
442
|
)
|
|
371
443
|
|
|
444
|
+
def get_resolved_request(self) -> Request:
|
|
445
|
+
global_environment = self.environments_repo.get_by_name(
|
|
446
|
+
name='global'
|
|
447
|
+
).data
|
|
448
|
+
request = self.get_request().resolve_variables(
|
|
449
|
+
global_environment.variables
|
|
450
|
+
)
|
|
451
|
+
if self.top_bar_area.environment:
|
|
452
|
+
environment = self.environments_repo.get_by_name(
|
|
453
|
+
name=self.top_bar_area.environment
|
|
454
|
+
).data
|
|
455
|
+
request = request.resolve_variables(environment.variables)
|
|
456
|
+
return request
|
|
457
|
+
|
|
372
458
|
def set_request(self, request: Request) -> None:
|
|
373
459
|
self.url_area.method = request.method
|
|
374
460
|
self.url_area.url = request.url
|
|
@@ -437,11 +523,11 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
437
523
|
self.request_area.option_timeout = str(request.options.timeout)
|
|
438
524
|
|
|
439
525
|
async def _send_request(self) -> None:
|
|
440
|
-
self.response_area.
|
|
526
|
+
self.response_area.clear()
|
|
441
527
|
self.response_area.loading = True
|
|
442
528
|
self.url_area.request_pending = True
|
|
443
529
|
try:
|
|
444
|
-
request = self.
|
|
530
|
+
request = self.get_resolved_request()
|
|
445
531
|
async with httpx.AsyncClient(
|
|
446
532
|
timeout=request.options.timeout,
|
|
447
533
|
follow_redirects=request.options.follow_redirects,
|
|
@@ -460,10 +546,10 @@ class RESTinyApp(App, inherit_bindings=False):
|
|
|
460
546
|
self.notify(f'{error_name}: {error_message}', severity='error')
|
|
461
547
|
else:
|
|
462
548
|
self.notify(f'{error_name}', severity='error')
|
|
463
|
-
self.response_area.
|
|
549
|
+
self.response_area.clear()
|
|
464
550
|
self.response_area.is_showing_response = False
|
|
465
551
|
except asyncio.CancelledError:
|
|
466
|
-
self.response_area.
|
|
552
|
+
self.response_area.clear()
|
|
467
553
|
self.response_area.is_showing_response = False
|
|
468
554
|
finally:
|
|
469
555
|
self.response_area.loading = False
|
restiny/ui/collections_area.py
CHANGED
|
@@ -16,6 +16,7 @@ from textual.widgets import (
|
|
|
16
16
|
Select,
|
|
17
17
|
Static,
|
|
18
18
|
)
|
|
19
|
+
from textual.widgets.tree import TreeNode
|
|
19
20
|
|
|
20
21
|
from restiny.entities import Folder, Request
|
|
21
22
|
from restiny.enums import HTTPMethod
|
|
@@ -170,8 +171,7 @@ class _BaseEditScreen(ModalScreen):
|
|
|
170
171
|
|
|
171
172
|
|
|
172
173
|
class _AddScreen(_BaseEditScreen):
|
|
173
|
-
|
|
174
|
-
app: RESTinyApp
|
|
174
|
+
app: 'RESTinyApp'
|
|
175
175
|
|
|
176
176
|
@on(Button.Pressed, '#confirm')
|
|
177
177
|
def _on_confirm(self, message: Button.Pressed) -> None:
|
|
@@ -220,8 +220,7 @@ class _AddScreen(_BaseEditScreen):
|
|
|
220
220
|
|
|
221
221
|
|
|
222
222
|
class _UpdateScreen(_BaseEditScreen):
|
|
223
|
-
|
|
224
|
-
app: RESTinyApp
|
|
223
|
+
app: 'RESTinyApp'
|
|
225
224
|
|
|
226
225
|
def __init__(self, id: int, *args, **kwargs) -> None:
|
|
227
226
|
super().__init__(*args, **kwargs)
|
|
@@ -284,8 +283,7 @@ class _UpdateScreen(_BaseEditScreen):
|
|
|
284
283
|
|
|
285
284
|
|
|
286
285
|
class CollectionsArea(Widget):
|
|
287
|
-
|
|
288
|
-
app: RESTinyApp
|
|
286
|
+
app: 'RESTinyApp'
|
|
289
287
|
|
|
290
288
|
ALLOW_MAXIMIZE = True
|
|
291
289
|
focusable = True
|
|
@@ -478,6 +476,15 @@ class CollectionsArea(Widget):
|
|
|
478
476
|
if not result.confirmed:
|
|
479
477
|
return
|
|
480
478
|
|
|
479
|
+
try:
|
|
480
|
+
prev_selected_index_in_parent = (
|
|
481
|
+
self.collections_tree.cursor_node.parent.children.index(
|
|
482
|
+
self.collections_tree.cursor_node
|
|
483
|
+
)
|
|
484
|
+
)
|
|
485
|
+
except ValueError:
|
|
486
|
+
prev_selected_index_in_parent = 0
|
|
487
|
+
|
|
481
488
|
if self.collections_tree.cursor_node.allow_expand:
|
|
482
489
|
self.app.folders_repo.delete_by_id(
|
|
483
490
|
self.collections_tree.cursor_node.data['id']
|
|
@@ -507,11 +514,24 @@ class CollectionsArea(Widget):
|
|
|
507
514
|
)
|
|
508
515
|
)
|
|
509
516
|
|
|
510
|
-
|
|
511
|
-
|
|
517
|
+
if self.collections_tree.cursor_node.parent.children:
|
|
518
|
+
next_index_to_select = min(
|
|
519
|
+
prev_selected_index_in_parent,
|
|
520
|
+
len(self.collections_tree.cursor_node.parent.children) - 1,
|
|
521
|
+
)
|
|
522
|
+
next_node_to_select = (
|
|
523
|
+
self.collections_tree.cursor_node.parent.children[
|
|
524
|
+
next_index_to_select
|
|
525
|
+
]
|
|
526
|
+
)
|
|
527
|
+
else:
|
|
528
|
+
next_node_to_select = self.collections_tree.cursor_node.parent
|
|
529
|
+
self.call_after_refresh(
|
|
530
|
+
lambda: self.collections_tree.select_node(next_node_to_select)
|
|
531
|
+
)
|
|
512
532
|
|
|
513
|
-
|
|
514
|
-
|
|
533
|
+
def _populate_children(self, node: TreeNode) -> None:
|
|
534
|
+
folder_id = node.data['id']
|
|
515
535
|
|
|
516
536
|
folders = self.app.folders_repo.list_by_parent_id(folder_id).data
|
|
517
537
|
requests = self.app.requests_repo.list_by_folder_id(folder_id).data
|
|
@@ -528,6 +548,9 @@ class CollectionsArea(Widget):
|
|
|
528
548
|
)
|
|
529
549
|
sorted_requests = sorted(requests, key=sort_requests)
|
|
530
550
|
|
|
551
|
+
for child_node in list(node.children):
|
|
552
|
+
self.collections_tree.remove(child_node)
|
|
553
|
+
|
|
531
554
|
for folder in sorted_folders:
|
|
532
555
|
self.collections_tree.add_folder(
|
|
533
556
|
parent_node=node, name=folder.name, id=folder.id
|
|
@@ -541,6 +564,8 @@ class CollectionsArea(Widget):
|
|
|
541
564
|
id=request.id,
|
|
542
565
|
)
|
|
543
566
|
|
|
567
|
+
node.refresh()
|
|
568
|
+
|
|
544
569
|
def _resolve_all_folder_paths(self) -> list[dict[str, str | int | None]]:
|
|
545
570
|
paths: list[dict[str, str | int | None]] = [{'path': '/', 'id': None}]
|
|
546
571
|
|