meerschaum 2.8.4__py3-none-any.whl → 2.9.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.
- meerschaum/api/_chunks.py +67 -0
- meerschaum/api/dash/callbacks/__init__.py +5 -2
- meerschaum/api/dash/callbacks/custom.py +21 -8
- meerschaum/api/dash/callbacks/dashboard.py +26 -4
- meerschaum/api/dash/callbacks/settings/__init__.py +8 -0
- meerschaum/api/dash/callbacks/settings/password_reset.py +76 -0
- meerschaum/api/dash/components.py +136 -25
- meerschaum/api/dash/pages/__init__.py +1 -0
- meerschaum/api/dash/pages/dashboard.py +11 -9
- meerschaum/api/dash/pages/plugins.py +31 -27
- meerschaum/api/dash/pages/settings/__init__.py +8 -0
- meerschaum/api/dash/pages/settings/password_reset.py +63 -0
- meerschaum/api/dash/webterm.py +6 -3
- meerschaum/api/resources/static/css/dash.css +8 -1
- meerschaum/api/resources/templates/termpage.html +4 -0
- meerschaum/api/routes/_pipes.py +232 -79
- meerschaum/config/_default.py +4 -0
- meerschaum/config/_version.py +1 -1
- meerschaum/connectors/__init__.py +1 -0
- meerschaum/connectors/api/_APIConnector.py +12 -1
- meerschaum/connectors/api/_pipes.py +106 -45
- meerschaum/connectors/api/_plugins.py +51 -45
- meerschaum/connectors/api/_request.py +1 -1
- meerschaum/connectors/parse.py +1 -2
- meerschaum/connectors/sql/_SQLConnector.py +3 -0
- meerschaum/connectors/sql/_cli.py +1 -0
- meerschaum/connectors/sql/_create_engine.py +51 -4
- meerschaum/connectors/sql/_pipes.py +38 -6
- meerschaum/connectors/sql/_sql.py +35 -4
- meerschaum/connectors/valkey/_ValkeyConnector.py +2 -0
- meerschaum/connectors/valkey/_pipes.py +51 -39
- meerschaum/core/Pipe/__init__.py +1 -0
- meerschaum/core/Pipe/_data.py +1 -2
- meerschaum/core/Pipe/_sync.py +64 -4
- meerschaum/plugins/_Plugin.py +21 -5
- meerschaum/plugins/__init__.py +32 -8
- meerschaum/utils/dataframe.py +139 -2
- meerschaum/utils/dtypes/__init__.py +211 -1
- meerschaum/utils/dtypes/sql.py +296 -5
- meerschaum/utils/formatting/_shell.py +1 -4
- meerschaum/utils/misc.py +1 -1
- meerschaum/utils/packages/_packages.py +7 -1
- meerschaum/utils/sql.py +139 -11
- meerschaum/utils/venv/__init__.py +6 -1
- {meerschaum-2.8.4.dist-info → meerschaum-2.9.0.dist-info}/METADATA +17 -3
- {meerschaum-2.8.4.dist-info → meerschaum-2.9.0.dist-info}/RECORD +52 -52
- {meerschaum-2.8.4.dist-info → meerschaum-2.9.0.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.8.4.dist-info → meerschaum-2.9.0.dist-info}/LICENSE +0 -0
- {meerschaum-2.8.4.dist-info → meerschaum-2.9.0.dist-info}/NOTICE +0 -0
- {meerschaum-2.8.4.dist-info → meerschaum-2.9.0.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.8.4.dist-info → meerschaum-2.9.0.dist-info}/top_level.txt +0 -0
- {meerschaum-2.8.4.dist-info → meerschaum-2.9.0.dist-info}/zip-safe +0 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Utility functions for the retrieval, caching, and response of chunk data.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import random
|
9
|
+
from datetime import datetime, timedelta, timezone
|
10
|
+
from typing import Dict, Generator, Any, Union, Optional, List
|
11
|
+
|
12
|
+
import meerschaum as mrsm
|
13
|
+
from meerschaum.api import get_cache_connector
|
14
|
+
from meerschaum.utils.misc import generate_password
|
15
|
+
|
16
|
+
CHUNKS_TOKENS_GENERATORS: Dict[str, Dict[str, Union[Generator[Any, None, None], datetime, int]]]
|
17
|
+
DEFAULT_TTL_SECONDS = mrsm.get_config('system', 'api', 'data', 'chunks', 'ttl_seconds')
|
18
|
+
|
19
|
+
|
20
|
+
def generate_chunks_cursor_token(
|
21
|
+
pipe: mrsm.Pipe,
|
22
|
+
select_columns: Optional[List[str]] = None,
|
23
|
+
omit_columns: Optional[List[str]] = None,
|
24
|
+
begin: Union[datetime, int, None] = None,
|
25
|
+
end: Union[datetime, int, None] = None,
|
26
|
+
params: Optional[Dict[str, Any]] = None,
|
27
|
+
limit: Optional[int] = None,
|
28
|
+
order: Optional[str] = 'asc',
|
29
|
+
ttl_seconds: Optional[int] = None,
|
30
|
+
debug: bool = False,
|
31
|
+
) -> str:
|
32
|
+
"""
|
33
|
+
Store a generator in the `CHUNKS_TOKENS_GENERATORS`
|
34
|
+
"""
|
35
|
+
now = datetime.now(timezone.utc)
|
36
|
+
cache_connector = get_cache_connector()
|
37
|
+
if cache_connector is None:
|
38
|
+
pass
|
39
|
+
|
40
|
+
ttl_seconds = ttl_seconds or DEFAULT_TTL_SECONDS
|
41
|
+
chunk_bounds = pipe.get_chunk_bounds(
|
42
|
+
begin=begin,
|
43
|
+
end=end,
|
44
|
+
bounded=True,
|
45
|
+
)
|
46
|
+
|
47
|
+
while True:
|
48
|
+
chunk_token = prefix + generate_password(random.randint(6, 12))
|
49
|
+
if chunk_token in CHUNKS_TOKENS_GENERATORS:
|
50
|
+
continue
|
51
|
+
break
|
52
|
+
|
53
|
+
CHUNKS_TOKENS_GENERATORS[chunk_token] = {
|
54
|
+
'generator': chunk_generator,
|
55
|
+
'created': now,
|
56
|
+
'ttl': ttl_seconds,
|
57
|
+
'last_accessed': now,
|
58
|
+
}
|
59
|
+
|
60
|
+
return chunk_token
|
61
|
+
|
62
|
+
|
63
|
+
def deallocate_expired_generators():
|
64
|
+
"""
|
65
|
+
Periodically delete chunk tokens with an expired ttl timestamp.
|
66
|
+
"""
|
67
|
+
chunk_tokens = list(CHUNKS_TOKENS_GENERATORS)
|
@@ -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
|
+
|
@@ -7,13 +7,16 @@ Import custom callbacks created by plugins.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
import traceback
|
10
|
+
from typing import Any, Dict
|
11
|
+
|
10
12
|
from meerschaum.api.dash import dash_app
|
11
13
|
from meerschaum.plugins import _dash_plugins, _plugin_endpoints_to_pages
|
12
|
-
from meerschaum.utils.warnings import warn
|
13
|
-
from meerschaum.api.dash.callbacks.dashboard import _paths, _required_login
|
14
|
+
from meerschaum.utils.warnings import warn, dprint
|
15
|
+
from meerschaum.api.dash.callbacks.dashboard import _paths, _required_login, _pages
|
16
|
+
from meerschaum.api.dash.components import pages_navbar
|
14
17
|
|
15
18
|
|
16
|
-
def init_dash_plugins():
|
19
|
+
def init_dash_plugins(debug: bool = False):
|
17
20
|
"""
|
18
21
|
Fire the initial callbacks for Dash plugins.
|
19
22
|
"""
|
@@ -29,11 +32,21 @@ def init_dash_plugins():
|
|
29
32
|
)
|
30
33
|
|
31
34
|
|
32
|
-
def add_plugin_pages():
|
35
|
+
def add_plugin_pages(debug: bool = False):
|
33
36
|
"""
|
34
37
|
Allow users to add pages via the `@web_page` decorator.
|
35
38
|
"""
|
36
|
-
for
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
@@ -103,6 +106,10 @@ _paths = {
|
|
103
106
|
'job' : pages.job.layout,
|
104
107
|
}
|
105
108
|
_required_login = {''}
|
109
|
+
_pages = {
|
110
|
+
'Web Console': '/dash/',
|
111
|
+
'Plugins': '/dash/plugins',
|
112
|
+
}
|
106
113
|
|
107
114
|
|
108
115
|
@dash_app.callback(
|
@@ -696,7 +703,6 @@ dash_app.clientside_callback(
|
|
696
703
|
dash_app.clientside_callback(
|
697
704
|
"""
|
698
705
|
function(n_clicks){
|
699
|
-
console.log('fullscreen');
|
700
706
|
if (!n_clicks) { return dash_clientside.no_update; }
|
701
707
|
iframe = document.getElementById('webterm-iframe');
|
702
708
|
if (!iframe){ return dash_clientside.no_update; }
|
@@ -707,11 +713,11 @@ dash_app.clientside_callback(
|
|
707
713
|
if (leftCol.style.display === 'none') {
|
708
714
|
leftCol.style.display = '';
|
709
715
|
rightCol.className = 'col-6';
|
710
|
-
button.innerHTML = "
|
716
|
+
button.innerHTML = "⛶";
|
711
717
|
} else {
|
712
718
|
leftCol.style.display = 'none';
|
713
719
|
rightCol.className = 'col-12';
|
714
|
-
button.innerHTML = "
|
720
|
+
button.innerHTML = "🀲";
|
715
721
|
}
|
716
722
|
|
717
723
|
return dash_clientside.no_update;
|
@@ -1078,3 +1084,19 @@ def parameters_as_yaml_or_json_click(
|
|
1078
1084
|
if as_yaml:
|
1079
1085
|
return yaml.dump(pipe.parameters)
|
1080
1086
|
return json.dumps(pipe.parameters, indent=4, separators=(',', ': '), sort_keys=True)
|
1087
|
+
|
1088
|
+
|
1089
|
+
@dash_app.callback(
|
1090
|
+
Output('pages-offcanvas', 'is_open'),
|
1091
|
+
Output('pages-offcanvas', 'children'),
|
1092
|
+
Input('logo-img', 'n_clicks'),
|
1093
|
+
State('pages-offcanvas', 'is_open'),
|
1094
|
+
)
|
1095
|
+
def toggle_pages_offcanvas(n_clicks: Optional[int], is_open: bool):
|
1096
|
+
"""
|
1097
|
+
Toggle the pages sidebar.
|
1098
|
+
"""
|
1099
|
+
pages_children = build_pages_offcanvas_children()
|
1100
|
+
if n_clicks:
|
1101
|
+
return not is_open, pages_children
|
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
|
@@ -92,9 +92,9 @@ search_parameters_editor = dash_ace.DashAceEditor(
|
|
92
92
|
style={'height': 100},
|
93
93
|
)
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
95
|
+
pages_offcanvas = dbc.Offcanvas(
|
96
|
+
title='',
|
97
|
+
id='pages-offcanvas',
|
98
98
|
)
|
99
99
|
|
100
100
|
download_dataframe = dcc.Download(id='download-dataframe-csv')
|
@@ -110,38 +110,71 @@ 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
|
+
|
120
|
+
logo_row = dbc.Row(
|
121
|
+
[
|
122
|
+
dbc.Col(
|
123
|
+
html.Img(
|
124
|
+
src=endpoints['dash'] + "/assets/logo_48x48.png",
|
125
|
+
title=doc,
|
126
|
+
id="logo-img",
|
127
|
+
style={'cursor': 'pointer'},
|
128
|
+
),
|
129
|
+
),
|
130
|
+
],
|
131
|
+
align='center',
|
132
|
+
className='g-0 navbar-logo-row',
|
133
|
+
)
|
134
|
+
|
135
|
+
pages_navbar = html.Div(
|
136
|
+
[
|
137
|
+
pages_offcanvas,
|
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
|
+
),
|
162
|
+
],
|
163
|
+
id='pages-navbar-div',
|
164
|
+
)
|
113
165
|
|
114
166
|
navbar = dbc.Navbar(
|
115
167
|
dbc.Container(
|
116
168
|
[
|
117
|
-
|
118
|
-
dbc.Row(
|
119
|
-
[
|
120
|
-
dbc.Col(
|
121
|
-
html.Img(
|
122
|
-
src=endpoints['dash'] + "/assets/logo_48x48.png",
|
123
|
-
title=doc,
|
124
|
-
),
|
125
|
-
),
|
126
|
-
],
|
127
|
-
align='center',
|
128
|
-
className='g-0 navbar-logo-row',
|
129
|
-
),
|
130
|
-
href=('/docs' if docs_enabled else '#'),
|
131
|
-
style={"textDecoration": "none"},
|
132
|
-
),
|
169
|
+
logo_row,
|
133
170
|
dbc.NavbarToggler(id="navbar-toggler", n_clicks=0),
|
134
171
|
dbc.Collapse(
|
135
172
|
dbc.Row(
|
136
173
|
[
|
137
174
|
dbc.Col(instance_select),
|
138
175
|
dbc.Col(
|
139
|
-
|
140
|
-
|
141
|
-
color='link',
|
142
|
-
style={'margin-left': '30px'},
|
143
|
-
id='sign-out-button',
|
144
|
-
),
|
176
|
+
sign_out_button,
|
177
|
+
className="ms-auto",
|
145
178
|
),
|
146
179
|
],
|
147
180
|
className="g-0 ms-auto flex-nowrap mt-3 mt-md-0",
|
@@ -199,3 +232,81 @@ def build_cards_grid(cards: List[dbc.Card], num_columns: int = 3) -> html.Div:
|
|
199
232
|
rows.append(r)
|
200
233
|
rows.append(html.Br())
|
201
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
|
@@ -37,6 +37,7 @@ from meerschaum.api.dash.components import (
|
|
37
37
|
console_div,
|
38
38
|
download_dataframe,
|
39
39
|
navbar,
|
40
|
+
pages_offcanvas,
|
40
41
|
download_logs,
|
41
42
|
refresh_jobs_interval,
|
42
43
|
)
|
@@ -47,22 +48,23 @@ from meerschaum.api.dash.keys import (
|
|
47
48
|
)
|
48
49
|
|
49
50
|
layout = html.Div(
|
50
|
-
id
|
51
|
-
children
|
51
|
+
id='main-div',
|
52
|
+
children=[
|
52
53
|
keys_lists_content,
|
53
54
|
download_dataframe,
|
54
55
|
download_logs,
|
55
56
|
refresh_jobs_interval,
|
56
57
|
navbar,
|
58
|
+
pages_offcanvas,
|
57
59
|
html.Div(
|
58
60
|
dbc.Row(
|
59
|
-
id
|
60
|
-
children
|
61
|
+
id='content-row',
|
62
|
+
children=[
|
61
63
|
dbc.Col(
|
62
|
-
children
|
64
|
+
children=[
|
63
65
|
dbc.Tabs(
|
64
|
-
id
|
65
|
-
children
|
66
|
+
id='pipes-filter-tabs',
|
67
|
+
children=[
|
66
68
|
dbc.Tab(
|
67
69
|
dropdown_tab_content,
|
68
70
|
label='Filters',
|
@@ -107,9 +109,9 @@ layout = html.Div(
|
|
107
109
|
id='content-col-right',
|
108
110
|
),
|
109
111
|
],
|
110
|
-
style
|
112
|
+
style={'max-width': '100%', 'padding': '15px'},
|
111
113
|
), ### end of Row
|
112
|
-
className
|
114
|
+
className='container-fluid',
|
113
115
|
), ### end of Div
|
114
116
|
html.P('', id='line-buffer', style={'display': 'none'}),
|
115
117
|
],
|
@@ -13,6 +13,7 @@ html, dcc = import_html(check_update=CHECK_UPDATE), import_dcc(check_update=CHEC
|
|
13
13
|
import dash_bootstrap_components as dbc
|
14
14
|
from meerschaum.core import Plugin
|
15
15
|
from meerschaum.utils.typing import Optional
|
16
|
+
from meerschaum.api.dash.components import pages_navbar
|
16
17
|
|
17
18
|
search_box = dbc.Input(
|
18
19
|
id = "search-plugins-input",
|
@@ -20,32 +21,35 @@ search_box = dbc.Input(
|
|
20
21
|
type = "text",
|
21
22
|
)
|
22
23
|
|
23
|
-
layout =
|
24
|
-
|
25
|
-
|
26
|
-
html.Div(
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
(
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
24
|
+
layout = [
|
25
|
+
pages_navbar,
|
26
|
+
dbc.Container([
|
27
|
+
html.Div([
|
28
|
+
html.Br(),
|
29
|
+
html.Div(
|
30
|
+
dbc.Container([
|
31
|
+
html.H3('Plugins'),
|
32
|
+
html.P([
|
33
|
+
(
|
34
|
+
'Plugins extend the functionality of Meerschaum.'
|
35
|
+
' To find out more, check out the '
|
36
|
+
),
|
37
|
+
html.A(
|
38
|
+
'plugins documentation',
|
39
|
+
href='https://meerschaum.io/reference/plugins/',
|
40
|
+
rel="noreferrer noopener",
|
41
|
+
target="_blank",
|
42
|
+
),
|
43
|
+
'.',
|
44
|
+
]),
|
41
45
|
]),
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
className='page-header',
|
47
|
+
style={'background-color': 'var(--dark)', 'padding': '1em'},
|
48
|
+
),
|
49
|
+
html.Br(),
|
50
|
+
search_box,
|
51
|
+
html.Br(),
|
52
|
+
html.Div([], id='plugins-cards-div'),
|
53
|
+
])
|
50
54
|
])
|
51
|
-
]
|
55
|
+
]
|
@@ -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
|
+
])
|