meerschaum 2.9.0rc3__py3-none-any.whl → 2.9.2__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.
- meerschaum/_internal/shell/Shell.py +79 -30
- meerschaum/api/dash/callbacks/__init__.py +5 -2
- meerschaum/api/dash/callbacks/custom.py +17 -25
- meerschaum/api/dash/callbacks/dashboard.py +5 -21
- meerschaum/api/dash/callbacks/settings/__init__.py +8 -0
- meerschaum/api/dash/callbacks/settings/password_reset.py +76 -0
- meerschaum/api/dash/components.py +110 -7
- meerschaum/api/dash/pages/__init__.py +1 -0
- meerschaum/api/dash/pages/pipes.py +9 -6
- meerschaum/api/dash/pages/settings/__init__.py +8 -0
- meerschaum/api/dash/pages/settings/password_reset.py +63 -0
- meerschaum/api/resources/static/css/dash.css +7 -0
- meerschaum/api/resources/templates/termpage.html +2 -0
- meerschaum/api/routes/_pipes.py +52 -37
- meerschaum/config/_version.py +1 -1
- meerschaum/connectors/__init__.py +1 -0
- meerschaum/connectors/api/_pipes.py +79 -30
- meerschaum/connectors/sql/_pipes.py +38 -5
- meerschaum/connectors/valkey/_pipes.py +1 -0
- meerschaum/core/Pipe/_data.py +10 -1
- meerschaum/core/Pipe/_verify.py +1 -0
- meerschaum/plugins/__init__.py +26 -4
- meerschaum/utils/dataframe.py +8 -1
- meerschaum/utils/dtypes/__init__.py +14 -13
- meerschaum/utils/misc.py +34 -1
- meerschaum/utils/packages/_packages.py +0 -1
- meerschaum/utils/sql.py +42 -4
- {meerschaum-2.9.0rc3.dist-info → meerschaum-2.9.2.dist-info}/METADATA +3 -4
- {meerschaum-2.9.0rc3.dist-info → meerschaum-2.9.2.dist-info}/RECORD +35 -36
- {meerschaum-2.9.0rc3.dist-info → meerschaum-2.9.2.dist-info}/WHEEL +1 -1
- meerschaum/_internal/gui/__init__.py +0 -43
- meerschaum/_internal/gui/app/__init__.py +0 -50
- meerschaum/_internal/gui/app/_windows.py +0 -74
- meerschaum/_internal/gui/app/actions.py +0 -30
- meerschaum/_internal/gui/app/pipes.py +0 -47
- {meerschaum-2.9.0rc3.dist-info → meerschaum-2.9.2.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.9.0rc3.dist-info → meerschaum-2.9.2.dist-info/licenses}/LICENSE +0 -0
- {meerschaum-2.9.0rc3.dist-info → meerschaum-2.9.2.dist-info/licenses}/NOTICE +0 -0
- {meerschaum-2.9.0rc3.dist-info → meerschaum-2.9.2.dist-info}/top_level.txt +0 -0
- {meerschaum-2.9.0rc3.dist-info → meerschaum-2.9.2.dist-info}/zip-safe +0 -0
@@ -10,6 +10,7 @@ import os
|
|
10
10
|
from copy import deepcopy
|
11
11
|
from itertools import chain
|
12
12
|
import shlex
|
13
|
+
import shutil
|
13
14
|
|
14
15
|
from meerschaum.utils.typing import Union, SuccessTuple, Any, Callable, Optional, List, Dict
|
15
16
|
from meerschaum.utils.packages import attempt_import
|
@@ -309,7 +310,7 @@ class Shell(cmd.Cmd):
|
|
309
310
|
try:
|
310
311
|
for c in hidden_commands:
|
311
312
|
self.hidden_commands.append(c)
|
312
|
-
except Exception
|
313
|
+
except Exception:
|
313
314
|
pass
|
314
315
|
|
315
316
|
### Finally, spawn the version update thread.
|
@@ -387,8 +388,9 @@ class Shell(cmd.Cmd):
|
|
387
388
|
username: Optional[str] = None,
|
388
389
|
executor_keys: Optional[str] = None,
|
389
390
|
):
|
390
|
-
from meerschaum.utils.formatting import ANSI, colored
|
391
|
+
from meerschaum.utils.formatting import ANSI, colored, UNICODE, get_console
|
391
392
|
from meerschaum._internal.entry import _shell, get_shell
|
393
|
+
from meerschaum.utils.misc import truncate_text_for_display, remove_ansi
|
392
394
|
|
393
395
|
cmd.__builtins__['input'] = input_with_sigint(
|
394
396
|
_old_input,
|
@@ -414,7 +416,6 @@ class Shell(cmd.Cmd):
|
|
414
416
|
|
415
417
|
if '{username}' in shell_attrs['_prompt']:
|
416
418
|
if username is None:
|
417
|
-
from meerschaum.utils.misc import remove_ansi
|
418
419
|
from meerschaum.connectors.parse import parse_instance_keys
|
419
420
|
from meerschaum.connectors.sql import SQLConnector
|
420
421
|
try:
|
@@ -422,15 +423,19 @@ class Shell(cmd.Cmd):
|
|
422
423
|
remove_ansi(shell_attrs['instance_keys']),
|
423
424
|
construct=False,
|
424
425
|
)
|
425
|
-
if 'username'
|
426
|
-
|
426
|
+
if conn_attrs and 'username' in conn_attrs:
|
427
|
+
username = conn_attrs.get('username', '(no username)')
|
428
|
+
elif conn_attrs and 'uri' in conn_attrs:
|
429
|
+
try:
|
427
430
|
username = SQLConnector.parse_uri(conn_attrs['uri'])['username']
|
431
|
+
except Exception:
|
432
|
+
username = '(no username)'
|
428
433
|
else:
|
429
|
-
username =
|
434
|
+
username = '(no username)'
|
430
435
|
except KeyError:
|
431
436
|
username = '(no username)'
|
432
|
-
except Exception
|
433
|
-
username =
|
437
|
+
except Exception:
|
438
|
+
username = None
|
434
439
|
if username is None:
|
435
440
|
username = '(no username)'
|
436
441
|
shell_attrs['username'] = (
|
@@ -463,12 +468,32 @@ class Shell(cmd.Cmd):
|
|
463
468
|
_c = colored(_c, **get_config('shell', 'ansi', 'prompt', 'rich'))
|
464
469
|
remainder_prompt[i] = _c
|
465
470
|
|
471
|
+
truncation_suffix = (
|
472
|
+
'…'
|
473
|
+
if UNICODE
|
474
|
+
else '...'
|
475
|
+
)
|
476
|
+
console = get_console()
|
477
|
+
truncation_kwargs = {
|
478
|
+
'suffix': truncation_suffix,
|
479
|
+
'max_length': int(console.size.width / 4),
|
480
|
+
}
|
481
|
+
|
466
482
|
self.prompt = ''.join(remainder_prompt).replace(
|
467
|
-
'{username}',
|
483
|
+
'{username}', truncate_text_for_display(
|
484
|
+
shell_attrs['username'],
|
485
|
+
**truncation_kwargs
|
486
|
+
)
|
468
487
|
).replace(
|
469
|
-
'{instance}',
|
488
|
+
'{instance}', truncate_text_for_display(
|
489
|
+
shell_attrs['instance'],
|
490
|
+
**truncation_kwargs
|
491
|
+
)
|
470
492
|
).replace(
|
471
|
-
'{executor_keys}',
|
493
|
+
'{executor_keys}', truncate_text_for_display(
|
494
|
+
shell_attrs['executor_keys'],
|
495
|
+
**truncation_kwargs
|
496
|
+
)
|
472
497
|
)
|
473
498
|
shell_attrs['prompt'] = self.prompt
|
474
499
|
### flush stdout
|
@@ -1018,15 +1043,14 @@ def input_with_sigint(_input, session, shell: Optional[Shell] = None):
|
|
1018
1043
|
"""
|
1019
1044
|
Replace built-in `input()` with prompt_toolkit.prompt.
|
1020
1045
|
"""
|
1021
|
-
from meerschaum.utils.formatting import CHARSET, ANSI, colored
|
1046
|
+
from meerschaum.utils.formatting import CHARSET, ANSI, colored, UNICODE
|
1022
1047
|
from meerschaum.connectors import is_connected, connectors
|
1023
|
-
from meerschaum.utils.misc import remove_ansi
|
1048
|
+
from meerschaum.utils.misc import remove_ansi, truncate_text_for_display
|
1024
1049
|
from meerschaum.config import get_config
|
1025
1050
|
import platform
|
1026
1051
|
if shell is None:
|
1027
1052
|
from meerschaum.actions import get_shell
|
1028
1053
|
shell = get_shell()
|
1029
|
-
|
1030
1054
|
style = prompt_toolkit_styles.Style.from_dict({
|
1031
1055
|
'bottom-toolbar': 'black',
|
1032
1056
|
})
|
@@ -1039,46 +1063,71 @@ def input_with_sigint(_input, session, shell: Optional[Shell] = None):
|
|
1039
1063
|
return shell_attrs['_old_bottom_toolbar']
|
1040
1064
|
size = os.get_terminal_size()
|
1041
1065
|
num_cols, num_lines = size.columns, size.lines
|
1042
|
-
|
1066
|
+
truncation_suffix = (
|
1067
|
+
'…'
|
1068
|
+
if UNICODE
|
1069
|
+
else '...'
|
1070
|
+
)
|
1071
|
+
truncation_kwargs = {
|
1072
|
+
'suffix': truncation_suffix,
|
1073
|
+
'max_length': int(num_cols / 4),
|
1074
|
+
}
|
1075
|
+
instance_text = truncate_text_for_display(
|
1076
|
+
remove_ansi(shell_attrs['instance_keys']),
|
1077
|
+
**truncation_kwargs
|
1078
|
+
)
|
1043
1079
|
instance_colored = (
|
1044
1080
|
colored(
|
1045
|
-
|
1081
|
+
instance_text,
|
1046
1082
|
'on ' + get_config('shell', 'ansi', 'instance', 'rich', 'style')
|
1047
1083
|
)
|
1048
1084
|
if ANSI
|
1049
|
-
else colored(
|
1085
|
+
else colored(instance_text, 'on white')
|
1086
|
+
)
|
1087
|
+
repo_text = truncate_text_for_display(
|
1088
|
+
remove_ansi(shell_attrs['repo_keys']),
|
1089
|
+
**truncation_kwargs
|
1050
1090
|
)
|
1051
1091
|
repo_colored = (
|
1052
1092
|
colored(
|
1053
|
-
|
1093
|
+
repo_text,
|
1054
1094
|
'on ' + get_config('shell', 'ansi', 'repo', 'rich', 'style')
|
1055
1095
|
)
|
1056
1096
|
if ANSI
|
1057
1097
|
else colored(shell_attrs['repo_keys'], 'on white')
|
1058
1098
|
)
|
1099
|
+
executor_text = truncate_text_for_display(
|
1100
|
+
remove_ansi(shell_attrs['executor_keys']),
|
1101
|
+
**truncation_kwargs
|
1102
|
+
)
|
1059
1103
|
executor_colored = (
|
1060
1104
|
colored(
|
1061
|
-
|
1105
|
+
executor_text,
|
1062
1106
|
'on ' + get_config('shell', 'ansi', 'executor', 'rich', 'style')
|
1063
1107
|
)
|
1064
1108
|
if ANSI
|
1065
|
-
else colored(
|
1109
|
+
else colored(executor_text, 'on white')
|
1066
1110
|
)
|
1067
1111
|
|
1068
1112
|
try:
|
1069
1113
|
typ, label = shell_attrs['instance_keys'].split(':', maxsplit=1)
|
1070
1114
|
connected = typ in connectors and label in connectors[typ]
|
1071
|
-
except Exception
|
1115
|
+
except Exception:
|
1072
1116
|
connected = False
|
1073
1117
|
last_connected = connected
|
1074
|
-
connected_str = (
|
1118
|
+
connected_str = truncate_text_for_display(
|
1119
|
+
('dis' if not connected else '') + 'connected',
|
1120
|
+
**truncation_kwargs
|
1121
|
+
)
|
1122
|
+
connected_icon = get_config(
|
1123
|
+
'formatting', connected_str, CHARSET, 'icon', warn=False,
|
1124
|
+
) or ''
|
1075
1125
|
connection_text = (
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
) + ' ') if ANSI else (colored(connected_str.capitalize(), 'on white') + ' ')
|
1126
|
+
connected_icon + ' ' + (
|
1127
|
+
colored(connected_str.capitalize(), 'on ' + (get_config(
|
1128
|
+
'formatting', connected_str, 'ansi', 'rich', 'style',
|
1129
|
+
warn=False,
|
1130
|
+
) or '') + ' ') if ANSI else (colored(connected_str.capitalize(), 'on white') + ' ')
|
1082
1131
|
)
|
1083
1132
|
)
|
1084
1133
|
|
@@ -1104,8 +1153,8 @@ def input_with_sigint(_input, session, shell: Optional[Shell] = None):
|
|
1104
1153
|
_args = []
|
1105
1154
|
for a in args:
|
1106
1155
|
try:
|
1107
|
-
_a = prompt_toolkit_formatted_text.ANSI(a)
|
1108
|
-
except Exception
|
1156
|
+
_a = prompt_toolkit_formatted_text.ANSI(a) if isinstance(a, str) else str(a)
|
1157
|
+
except Exception:
|
1109
1158
|
_a = a
|
1110
1159
|
_args.append(_a)
|
1111
1160
|
try:
|
@@ -6,13 +6,16 @@
|
|
6
6
|
Define callbacks for pages.
|
7
7
|
"""
|
8
8
|
|
9
|
+
from meerschaum.api import debug as _debug
|
9
10
|
import meerschaum.api.dash.callbacks.dashboard
|
10
11
|
import meerschaum.api.dash.callbacks.login
|
11
12
|
import meerschaum.api.dash.callbacks.plugins
|
12
13
|
import meerschaum.api.dash.callbacks.jobs
|
13
14
|
import meerschaum.api.dash.callbacks.register
|
14
15
|
import meerschaum.api.dash.callbacks.pipes
|
16
|
+
import meerschaum.api.dash.callbacks.settings
|
15
17
|
from meerschaum.api.dash.callbacks.custom import init_dash_plugins, add_plugin_pages
|
16
18
|
|
17
|
-
init_dash_plugins()
|
18
|
-
add_plugin_pages()
|
19
|
+
init_dash_plugins(debug=_debug)
|
20
|
+
add_plugin_pages(debug=_debug)
|
21
|
+
|
@@ -11,12 +11,12 @@ from typing import Any, Dict
|
|
11
11
|
|
12
12
|
from meerschaum.api.dash import dash_app
|
13
13
|
from meerschaum.plugins import _dash_plugins, _plugin_endpoints_to_pages
|
14
|
-
from meerschaum.utils.warnings import warn
|
14
|
+
from meerschaum.utils.warnings import warn, dprint
|
15
15
|
from meerschaum.api.dash.callbacks.dashboard import _paths, _required_login, _pages
|
16
16
|
from meerschaum.api.dash.components import pages_navbar
|
17
17
|
|
18
18
|
|
19
|
-
def init_dash_plugins():
|
19
|
+
def init_dash_plugins(debug: bool = False):
|
20
20
|
"""
|
21
21
|
Fire the initial callbacks for Dash plugins.
|
22
22
|
"""
|
@@ -32,29 +32,21 @@ def init_dash_plugins():
|
|
32
32
|
)
|
33
33
|
|
34
34
|
|
35
|
-
def add_plugin_pages():
|
35
|
+
def add_plugin_pages(debug: bool = False):
|
36
36
|
"""
|
37
37
|
Allow users to add pages via the `@web_page` decorator.
|
38
38
|
"""
|
39
|
-
for
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
page_layout
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
)
|
54
|
-
]
|
55
|
-
)
|
56
|
-
)
|
57
|
-
_pages[page_key] = _endpoint
|
58
|
-
_paths[_endpoint] = page_layout
|
59
|
-
if _page_dict['login_required']:
|
60
|
-
_required_login.add(_endpoint)
|
39
|
+
for plugin_name, pages_dicts in _plugin_endpoints_to_pages.items():
|
40
|
+
if debug:
|
41
|
+
dprint(f"Adding pages from plugin '{plugin_name}'...")
|
42
|
+
for _endpoint, _page_dict in pages_dicts.items():
|
43
|
+
page_layout = _page_dict['function']()
|
44
|
+
if not _page_dict['skip_navbar']:
|
45
|
+
if isinstance(page_layout, list):
|
46
|
+
page_layout = [pages_navbar] + page_layout
|
47
|
+
else:
|
48
|
+
page_layout = [pages_navbar, page_layout]
|
49
|
+
_pages[_page_dict['page_key']] = _endpoint
|
50
|
+
_paths[_endpoint] = page_layout
|
51
|
+
if _page_dict['login_required']:
|
52
|
+
_required_login.add(_endpoint)
|
@@ -33,7 +33,10 @@ from meerschaum.api.dash.users import get_users_cards
|
|
33
33
|
from meerschaum.api.dash.graphs import get_graphs_cards
|
34
34
|
from meerschaum.api.dash.webterm import get_webterm
|
35
35
|
from meerschaum.api.dash.components import (
|
36
|
-
alert_from_success_tuple,
|
36
|
+
alert_from_success_tuple,
|
37
|
+
console_div,
|
38
|
+
build_cards_grid,
|
39
|
+
build_pages_offcanvas_children,
|
37
40
|
)
|
38
41
|
from meerschaum.api.dash import pages
|
39
42
|
from meerschaum.utils.typing import Dict
|
@@ -1093,26 +1096,7 @@ def toggle_pages_offcanvas(n_clicks: Optional[int], is_open: bool):
|
|
1093
1096
|
"""
|
1094
1097
|
Toggle the pages sidebar.
|
1095
1098
|
"""
|
1096
|
-
pages_children =
|
1097
|
-
dbc.ListGroup(
|
1098
|
-
[
|
1099
|
-
dbc.ListGroupItem(
|
1100
|
-
dbc.Button(
|
1101
|
-
html.P(
|
1102
|
-
' '.join([word.capitalize() for word in page_key.split(' ')]),
|
1103
|
-
style={'text-decoration': 'none', 'fontSize': '18px'},
|
1104
|
-
),
|
1105
|
-
style={'width': '100%', 'text-align': 'left'},
|
1106
|
-
href=page_href,
|
1107
|
-
color='dark',
|
1108
|
-
)
|
1109
|
-
)
|
1110
|
-
for page_key, page_href in _pages.items()
|
1111
|
-
],
|
1112
|
-
flush=True,
|
1113
|
-
),
|
1114
|
-
outline=True,
|
1115
|
-
)
|
1099
|
+
pages_children = build_pages_offcanvas_children()
|
1116
1100
|
if n_clicks:
|
1117
1101
|
return not is_open, pages_children
|
1118
1102
|
return is_open, pages_children
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Define the callbacks for the password reset page.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import dash
|
9
|
+
from dash.exceptions import PreventUpdate
|
10
|
+
from dash.dependencies import Input, Output, State
|
11
|
+
import dash_bootstrap_components as dbc
|
12
|
+
|
13
|
+
from meerschaum.core.User import User
|
14
|
+
from meerschaum.config.static import STATIC_CONFIG
|
15
|
+
from meerschaum.api import get_api_connector, debug
|
16
|
+
from meerschaum.api.dash import dash_app
|
17
|
+
from meerschaum.api.dash.components import alert_from_success_tuple
|
18
|
+
from meerschaum.api.dash.sessions import get_username_from_session
|
19
|
+
|
20
|
+
|
21
|
+
@dash_app.callback(
|
22
|
+
Output('password-reset-alert-div', 'children'),
|
23
|
+
Input('password-reset-button', 'n_clicks'),
|
24
|
+
State('password-reset-input', 'value',),
|
25
|
+
State('session-store', 'data'),
|
26
|
+
)
|
27
|
+
def password_reset_button_click(n_clicks, new_password_value, session_store_data):
|
28
|
+
"""
|
29
|
+
Attempt the password reset with the form data.
|
30
|
+
"""
|
31
|
+
if not n_clicks:
|
32
|
+
raise PreventUpdate
|
33
|
+
|
34
|
+
session_id = session_store_data.get('session-id', None)
|
35
|
+
username = get_username_from_session(session_id)
|
36
|
+
if not username:
|
37
|
+
return alert_from_success_tuple(
|
38
|
+
(False, "Invalid session. Are you logged in correctly?")
|
39
|
+
)
|
40
|
+
|
41
|
+
instance_connector = get_api_connector()
|
42
|
+
user = User(username, new_password_value)
|
43
|
+
success, msg = instance_connector.edit_user(user, debug=debug)
|
44
|
+
return alert_from_success_tuple((success, msg))
|
45
|
+
|
46
|
+
|
47
|
+
@dash_app.callback(
|
48
|
+
Output('password-reset-input', 'valid'),
|
49
|
+
Output('password-reset-input', 'invalid'),
|
50
|
+
Input('password-reset-input', 'value'),
|
51
|
+
)
|
52
|
+
def validate_new_password(new_password_value):
|
53
|
+
if not new_password_value:
|
54
|
+
raise PreventUpdate
|
55
|
+
|
56
|
+
valid = (len(new_password_value) >= STATIC_CONFIG['users']['min_password_length'])
|
57
|
+
return valid, not valid
|
58
|
+
|
59
|
+
|
60
|
+
@dash_app.callback(
|
61
|
+
Output("password-reset-confirm-input", "valid"),
|
62
|
+
Output("password-reset-confirm-input", "invalid"),
|
63
|
+
Output("password-reset-button", 'disabled'),
|
64
|
+
Input("password-reset-confirm-input", "value"),
|
65
|
+
State("password-reset-input", "value"),
|
66
|
+
)
|
67
|
+
def validate_new_passwords_match(confirm_password_value, new_password_value):
|
68
|
+
if not confirm_password_value:
|
69
|
+
raise PreventUpdate
|
70
|
+
|
71
|
+
new_password_is_valid, _ = validate_new_password(new_password_value)
|
72
|
+
if not new_password_is_valid:
|
73
|
+
raise PreventUpdate
|
74
|
+
|
75
|
+
valid = confirm_password_value == new_password_value
|
76
|
+
return valid, not valid, not valid
|
@@ -110,6 +110,13 @@ instance_select = dbc.Select(
|
|
110
110
|
class_name='dbc_dark custom-select custom-select-sm',
|
111
111
|
)
|
112
112
|
|
113
|
+
sign_out_button = dbc.Button(
|
114
|
+
"Sign out",
|
115
|
+
color='link',
|
116
|
+
style={'margin-left': '30px'},
|
117
|
+
id='sign-out-button',
|
118
|
+
)
|
119
|
+
|
113
120
|
logo_row = dbc.Row(
|
114
121
|
[
|
115
122
|
dbc.Col(
|
@@ -128,7 +135,30 @@ logo_row = dbc.Row(
|
|
128
135
|
pages_navbar = html.Div(
|
129
136
|
[
|
130
137
|
pages_offcanvas,
|
131
|
-
dbc.Navbar(
|
138
|
+
dbc.Navbar(
|
139
|
+
dbc.Container(
|
140
|
+
[
|
141
|
+
logo_row,
|
142
|
+
dbc.NavbarToggler(id="navbar-toggler", n_clicks=0),
|
143
|
+
dbc.Collapse(
|
144
|
+
dbc.Row(
|
145
|
+
[
|
146
|
+
dbc.Col(
|
147
|
+
sign_out_button,
|
148
|
+
className="ms-auto",
|
149
|
+
),
|
150
|
+
],
|
151
|
+
className="g-0 ms-auto flex-nowrap mt-3 mt-md-0",
|
152
|
+
),
|
153
|
+
id='navbar-collapse',
|
154
|
+
is_open=False,
|
155
|
+
navbar=True,
|
156
|
+
),
|
157
|
+
]
|
158
|
+
),
|
159
|
+
dark=True,
|
160
|
+
color='dark'
|
161
|
+
),
|
132
162
|
],
|
133
163
|
id='pages-navbar-div',
|
134
164
|
)
|
@@ -143,12 +173,7 @@ navbar = dbc.Navbar(
|
|
143
173
|
[
|
144
174
|
dbc.Col(instance_select),
|
145
175
|
dbc.Col(
|
146
|
-
|
147
|
-
"Sign out",
|
148
|
-
color='link',
|
149
|
-
style={'margin-left': '30px'},
|
150
|
-
id='sign-out-button',
|
151
|
-
),
|
176
|
+
sign_out_button,
|
152
177
|
className="ms-auto",
|
153
178
|
),
|
154
179
|
],
|
@@ -207,3 +232,81 @@ def build_cards_grid(cards: List[dbc.Card], num_columns: int = 3) -> html.Div:
|
|
207
232
|
rows.append(r)
|
208
233
|
rows.append(html.Br())
|
209
234
|
return html.Div(rows)
|
235
|
+
|
236
|
+
|
237
|
+
def build_pages_offcanvas_children():
|
238
|
+
"""
|
239
|
+
Return the contents of the pages offcanvas.
|
240
|
+
"""
|
241
|
+
from meerschaum.api.dash.callbacks.dashboard import _pages
|
242
|
+
from meerschaum.api.dash.callbacks.custom import _plugin_endpoints_to_pages
|
243
|
+
pages_listgroup_items = []
|
244
|
+
custom_pages = []
|
245
|
+
for pages_dicts in _plugin_endpoints_to_pages.values():
|
246
|
+
for page_dict in pages_dicts.values():
|
247
|
+
custom_pages.append(page_dict['page_key'])
|
248
|
+
|
249
|
+
for page_key, page_href in _pages.items():
|
250
|
+
if page_key in custom_pages:
|
251
|
+
continue
|
252
|
+
pages_listgroup_items.append(
|
253
|
+
dbc.ListGroupItem(
|
254
|
+
dbc.Button(
|
255
|
+
' '.join([word.capitalize() for word in page_key.split(' ')]),
|
256
|
+
style={
|
257
|
+
'width': '100%',
|
258
|
+
'text-align': 'left',
|
259
|
+
'text-decoration': 'none',
|
260
|
+
'padding-left': '0',
|
261
|
+
},
|
262
|
+
href=page_href,
|
263
|
+
color='dark',
|
264
|
+
)
|
265
|
+
)
|
266
|
+
)
|
267
|
+
|
268
|
+
plugins_accordion_items = []
|
269
|
+
for page_group, pages_dicts in _plugin_endpoints_to_pages.items():
|
270
|
+
plugin_listgroup_items = [
|
271
|
+
dbc.ListGroupItem(
|
272
|
+
dbc.Button(
|
273
|
+
' '.join([word.capitalize() for word in page_dict['page_key'].split(' ')]),
|
274
|
+
style={
|
275
|
+
'width': '100%',
|
276
|
+
'text-align': 'left',
|
277
|
+
'text-decoration': 'none',
|
278
|
+
'padding-left': '0',
|
279
|
+
},
|
280
|
+
href=page_href,
|
281
|
+
color='dark',
|
282
|
+
)
|
283
|
+
)
|
284
|
+
for page_href, page_dict in pages_dicts.items()
|
285
|
+
]
|
286
|
+
plugin_listgroup = dbc.ListGroup(plugin_listgroup_items, flush=True)
|
287
|
+
plugin_accordion_item = dbc.AccordionItem(
|
288
|
+
plugin_listgroup,
|
289
|
+
title=(
|
290
|
+
page_group.capitalize()
|
291
|
+
if page_group and not page_group[0].isupper()
|
292
|
+
else page_group
|
293
|
+
),
|
294
|
+
class_name='pages-offcanvas-accordion',
|
295
|
+
)
|
296
|
+
plugins_accordion_items.append(plugin_accordion_item)
|
297
|
+
plugins_accordion = dbc.Accordion(
|
298
|
+
plugins_accordion_items,
|
299
|
+
start_collapsed=True,
|
300
|
+
flush=True,
|
301
|
+
always_open=True,
|
302
|
+
)
|
303
|
+
pages_listgroup_items.append(plugins_accordion)
|
304
|
+
|
305
|
+
pages_children = dbc.Card(
|
306
|
+
dbc.ListGroup(
|
307
|
+
pages_listgroup_items,
|
308
|
+
flush=True,
|
309
|
+
),
|
310
|
+
outline=True,
|
311
|
+
)
|
312
|
+
return pages_children
|
@@ -7,13 +7,16 @@ Display pipes via a shareable URL.
|
|
7
7
|
|
8
8
|
from meerschaum.api import CHECK_UPDATE
|
9
9
|
from meerschaum.utils.packages import import_html, import_dcc
|
10
|
-
from meerschaum.api.dash.components import download_dataframe
|
10
|
+
from meerschaum.api.dash.components import download_dataframe, pages_navbar
|
11
11
|
|
12
12
|
html, dcc = import_html(check_update=CHECK_UPDATE), import_dcc(check_update=CHECK_UPDATE)
|
13
13
|
import dash_bootstrap_components as dbc
|
14
14
|
|
15
|
-
layout =
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
layout = [
|
16
|
+
pages_navbar,
|
17
|
+
dbc.Container([
|
18
|
+
dcc.Location('pipes-location'),
|
19
|
+
download_dataframe,
|
20
|
+
html.Div(id='pipe-output-div'),
|
21
|
+
])
|
22
|
+
]
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Define the password reset page layout.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import dash_bootstrap_components as dbc
|
9
|
+
import dash.html as html
|
10
|
+
import dash.dcc as dcc
|
11
|
+
from meerschaum.plugins import web_page
|
12
|
+
|
13
|
+
|
14
|
+
@web_page('password-reset', login_required=True, page_group='Settings')
|
15
|
+
def page_layout():
|
16
|
+
"""
|
17
|
+
Return the layout for this page.
|
18
|
+
"""
|
19
|
+
return dbc.Container([
|
20
|
+
html.Br(),
|
21
|
+
html.H3('Password Reset'),
|
22
|
+
html.Br(),
|
23
|
+
html.Div(id="password-reset-alert-div"),
|
24
|
+
dbc.Form([
|
25
|
+
dbc.Row(
|
26
|
+
[
|
27
|
+
dbc.Label("New Password", html_for="password-reset-input", width=2),
|
28
|
+
dbc.Col(
|
29
|
+
dbc.Input(
|
30
|
+
type="password",
|
31
|
+
id="password-reset-input",
|
32
|
+
placeholder="Enter new password",
|
33
|
+
),
|
34
|
+
width=10,
|
35
|
+
),
|
36
|
+
],
|
37
|
+
className="mb-3",
|
38
|
+
),
|
39
|
+
dbc.Row(
|
40
|
+
[
|
41
|
+
dbc.Label("Confirm Password", html_for="password-reset-confirm-input", width=2),
|
42
|
+
dbc.Col(
|
43
|
+
dbc.Input(
|
44
|
+
type="password",
|
45
|
+
id="password-reset-confirm-input",
|
46
|
+
placeholder="Confirm new password",
|
47
|
+
),
|
48
|
+
width=10,
|
49
|
+
),
|
50
|
+
],
|
51
|
+
className="mb-3",
|
52
|
+
),
|
53
|
+
dbc.Row(
|
54
|
+
[
|
55
|
+
dbc.Col(
|
56
|
+
dbc.Button("Submit", id="password-reset-button", disabled=True),
|
57
|
+
),
|
58
|
+
],
|
59
|
+
justify="end",
|
60
|
+
className="mb-3",
|
61
|
+
),
|
62
|
+
]),
|
63
|
+
])
|
@@ -73,3 +73,10 @@ a {
|
|
73
73
|
.input-text {
|
74
74
|
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif !important;
|
75
75
|
}
|
76
|
+
.pages-offcanvas-accordion button {
|
77
|
+
background-color: var(--bs-dark) !important;
|
78
|
+
color: white !important;
|
79
|
+
}
|
80
|
+
.pages-offcanvas-accordion div {
|
81
|
+
padding: 0 !important;
|
82
|
+
}
|