restiny 0.2.1__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.
Files changed (38) hide show
  1. restiny/__about__.py +1 -1
  2. restiny/__main__.py +28 -14
  3. restiny/assets/style.tcss +56 -2
  4. restiny/consts.py +236 -0
  5. restiny/data/db.py +60 -0
  6. restiny/data/models.py +111 -0
  7. restiny/data/repos.py +455 -0
  8. restiny/data/sql/__init__.py +3 -0
  9. restiny/entities.py +438 -0
  10. restiny/enums.py +14 -5
  11. restiny/httpx_auths.py +52 -0
  12. restiny/ui/__init__.py +17 -0
  13. restiny/ui/app.py +586 -0
  14. restiny/ui/collections_area.py +594 -0
  15. restiny/ui/environments_screen.py +270 -0
  16. restiny/ui/request_area.py +602 -0
  17. restiny/{core → ui}/response_area.py +4 -1
  18. restiny/ui/settings_screen.py +73 -0
  19. restiny/ui/top_bar_area.py +60 -0
  20. restiny/{core → ui}/url_area.py +54 -38
  21. restiny/utils.py +52 -15
  22. restiny/widgets/__init__.py +15 -1
  23. restiny/widgets/collections_tree.py +74 -0
  24. restiny/widgets/confirm_prompt.py +76 -0
  25. restiny/widgets/custom_input.py +20 -0
  26. restiny/widgets/dynamic_fields.py +65 -70
  27. restiny/widgets/password_input.py +161 -0
  28. restiny/widgets/path_chooser.py +12 -12
  29. {restiny-0.2.1.dist-info → restiny-0.6.1.dist-info}/METADATA +7 -5
  30. restiny-0.6.1.dist-info/RECORD +38 -0
  31. restiny/core/__init__.py +0 -15
  32. restiny/core/app.py +0 -348
  33. restiny/core/request_area.py +0 -337
  34. restiny-0.2.1.dist-info/RECORD +0 -24
  35. {restiny-0.2.1.dist-info → restiny-0.6.1.dist-info}/WHEEL +0 -0
  36. {restiny-0.2.1.dist-info → restiny-0.6.1.dist-info}/entry_points.txt +0 -0
  37. {restiny-0.2.1.dist-info → restiny-0.6.1.dist-info}/licenses/LICENSE +0 -0
  38. {restiny-0.2.1.dist-info → restiny-0.6.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,270 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from textual import on
4
+ from textual.app import ComposeResult
5
+ from textual.binding import Binding
6
+ from textual.containers import Horizontal, Vertical
7
+ from textual.screen import ModalScreen
8
+ from textual.widgets import Button, Label, ListItem, ListView, Rule
9
+
10
+ from restiny.entities import Environment
11
+ from restiny.widgets import DynamicFields, TextDynamicField
12
+ from restiny.widgets.custom_input import CustomInput
13
+
14
+ if TYPE_CHECKING:
15
+ from restiny.ui.app import RESTinyApp
16
+
17
+
18
+ class EnvironmentsScreen(ModalScreen):
19
+ app: 'RESTinyApp'
20
+
21
+ DEFAULT_CSS = """
22
+ EnvironmentsScreen {
23
+ align: center middle;
24
+ }
25
+
26
+ #modal-content {
27
+ width: 70%;
28
+ height: 80%;
29
+ border: heavy black;
30
+ border-title-color: gray;
31
+ background: $surface;
32
+ }
33
+
34
+ Label {
35
+ padding-left: 4;
36
+ }
37
+ """
38
+ AUTO_FOCUS = '#environments-list'
39
+
40
+ BINDINGS = [
41
+ Binding(
42
+ key='escape',
43
+ action='dismiss',
44
+ description='Quit the screen',
45
+ show=False,
46
+ ),
47
+ ]
48
+
49
+ def __init__(self) -> None:
50
+ super().__init__()
51
+
52
+ def compose(self) -> ComposeResult:
53
+ with Vertical(id='modal-content'):
54
+ with Horizontal(classes='w-auto p-1'):
55
+ with Vertical(classes='w-1fr h-auto'):
56
+ yield ListView(
57
+ classes='',
58
+ id='environments-list',
59
+ )
60
+ with Horizontal(classes='w-auto h-auto mt-1'):
61
+ yield CustomInput(
62
+ placeholder='Environment name',
63
+ classes='w-4fr',
64
+ id='environment-name',
65
+ )
66
+ yield Button(
67
+ label='➕',
68
+ tooltip='Add environment',
69
+ classes='',
70
+ id='add-environment',
71
+ )
72
+
73
+ yield Rule(orientation='vertical')
74
+
75
+ with Vertical(classes='w-2fr h-auto'):
76
+ with Horizontal(classes='w-auto h-auto'):
77
+ yield CustomInput(
78
+ placeholder='Environment name',
79
+ classes='w-5fr',
80
+ id='environment-rename',
81
+ )
82
+ yield Button(
83
+ '💾',
84
+ tooltip='Save environment',
85
+ classes='w-1fr',
86
+ id='save-environment',
87
+ )
88
+ yield Button(
89
+ '➖',
90
+ tooltip='Delete environment',
91
+ classes='w-1fr',
92
+ id='delete-environment',
93
+ )
94
+ yield DynamicFields(
95
+ fields=[
96
+ TextDynamicField(enabled=False, key='', value='')
97
+ ],
98
+ classes='mt-1',
99
+ id='variables',
100
+ )
101
+ yield Label(
102
+ "[i]Tip: You can use [b]'{{var}}'[/] or [b]'${var}'[/] in requests to reference variables.[/]",
103
+ classes='mt-1',
104
+ )
105
+ with Horizontal(classes='w-auto h-auto'):
106
+ yield Button(label='Close', classes='w-1fr', id='close')
107
+
108
+ async def on_mount(self) -> None:
109
+ self.modal_content = self.query_one('#modal-content', Vertical)
110
+ self.environments_list = self.query_one('#environments-list', ListView)
111
+ self.environment_name_input = self.query_one(
112
+ '#environment-name', CustomInput
113
+ )
114
+ self.add_environment_button = self.query_one(
115
+ '#add-environment', Button
116
+ )
117
+ self.environment_rename_input = self.query_one(
118
+ '#environment-rename', CustomInput
119
+ )
120
+ self.save_environment_button = self.query_one(
121
+ '#save-environment', Button
122
+ )
123
+ self.delete_environment_button = self.query_one(
124
+ '#delete-environment', Button
125
+ )
126
+ self.variables_dynamic_fields = self.query_one(
127
+ '#variables', DynamicFields
128
+ )
129
+ self.close_button = self.query_one('#close', Button)
130
+
131
+ self.modal_content.border_title = 'Environments'
132
+
133
+ await self._populate_environments()
134
+
135
+ @property
136
+ def _selected_env_id(self) -> int | None:
137
+ if self.environments_list.index is None:
138
+ return None
139
+
140
+ return int(
141
+ self.environments_list.children[
142
+ self.environments_list.index
143
+ ].id.rsplit('-', 1)[1]
144
+ )
145
+
146
+ @property
147
+ def _selected_env_name(self) -> str | None:
148
+ if self.environments_list.index is None:
149
+ return None
150
+
151
+ return (
152
+ self.environments_list.children[self.environments_list.index]
153
+ .children[0]
154
+ .content
155
+ )
156
+
157
+ @on(ListView.Selected, '#environments-list')
158
+ async def _on_select_environment(self) -> None:
159
+ self.environment_rename_input.value = self._selected_env_name
160
+ is_global = self._selected_env_name == 'global'
161
+ self.environment_rename_input.disabled = is_global
162
+ self.delete_environment_button.disabled = is_global
163
+
164
+ for field in self.variables_dynamic_fields.fields:
165
+ self.variables_dynamic_fields.remove_field(field=field)
166
+
167
+ environment = self.app.environments_repo.get_by_id(
168
+ self._selected_env_id
169
+ ).data
170
+ for variable in environment.variables:
171
+ await self.variables_dynamic_fields.add_field(
172
+ field=TextDynamicField(
173
+ enabled=variable.enabled,
174
+ key=variable.key,
175
+ value=variable.value,
176
+ ),
177
+ before_last=True,
178
+ )
179
+
180
+ @on(Button.Pressed, '#add-environment')
181
+ @on(CustomInput.Submitted, '#environment-name')
182
+ async def _on_add_environment(self) -> None:
183
+ if not self.environment_name_input.value.strip():
184
+ self.notify('Environment name is required', severity='error')
185
+ return
186
+
187
+ create_resp = self.app.environments_repo.create(
188
+ Environment(name=self.environment_name_input.value, variables=[])
189
+ )
190
+ if not create_resp.ok:
191
+ self.notify(
192
+ f'Failed to create environment ({create_resp.status})',
193
+ severity='error',
194
+ )
195
+ return
196
+
197
+ await self._add_environment(
198
+ name=create_resp.data.name, id=create_resp.data.id
199
+ )
200
+ self.environment_name_input.value = ''
201
+ self.environments_list.index = len(self.environments_list.children) - 1
202
+ await self._on_select_environment()
203
+ self.notify('Environment added', severity='information')
204
+
205
+ @on(Button.Pressed, '#save-environment')
206
+ @on(CustomInput.Submitted, '#environment-rename')
207
+ async def _on_save_environment(self) -> None:
208
+ if not self.environment_rename_input.value.strip():
209
+ self.notify('Environment name is required', severity='error')
210
+ return
211
+
212
+ update_resp = self.app.environments_repo.update(
213
+ Environment(
214
+ id=self._selected_env_id,
215
+ name=self.environment_rename_input.value,
216
+ variables=[
217
+ Environment.Variable(
218
+ enabled=variable.enabled,
219
+ key=variable.key,
220
+ value=variable.value,
221
+ )
222
+ for variable in self.variables_dynamic_fields.filled_fields
223
+ ],
224
+ )
225
+ )
226
+ if not update_resp.ok:
227
+ self.notify(
228
+ f'Failed to update environment ({update_resp.status})',
229
+ severity='error',
230
+ )
231
+ return
232
+
233
+ self.environments_list.children[self.environments_list.index].children[
234
+ 0
235
+ ].update(update_resp.data.name)
236
+ self.notify('Environment updated', severity='information')
237
+
238
+ @on(Button.Pressed, '#delete-environment')
239
+ async def _on_remove_environment(self) -> None:
240
+ if self.environments_list.index is None:
241
+ self.notify('No environment selected', severity='error')
242
+ return
243
+
244
+ self.app.environments_repo.delete_by_id(self._selected_env_id)
245
+ focus_target_index = max(0, self.environments_list.index - 1)
246
+ await self.environments_list.children[
247
+ self.environments_list.index
248
+ ].remove()
249
+ self.environments_list.index = focus_target_index
250
+ await self._on_select_environment()
251
+ self.notify('Environment removed', severity='information')
252
+
253
+ @on(Button.Pressed, '#close')
254
+ async def _on_close(self, message: Button.Pressed) -> None:
255
+ self.dismiss(result=None)
256
+
257
+ async def _populate_environments(self) -> None:
258
+ environments = self.app.environments_repo.list().data
259
+ for environment in environments:
260
+ await self._add_environment(
261
+ name=environment.name, id=environment.id
262
+ )
263
+
264
+ self.environments_list.index = 0
265
+ await self._on_select_environment()
266
+
267
+ async def _add_environment(self, name: str, id: int) -> None:
268
+ await self.environments_list.mount(
269
+ ListItem(Label(name), id=f'env-{id}')
270
+ )