meerschaum 2.1.6__py3-none-any.whl → 2.2.0.dev1__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/arguments/_parser.py +3 -0
- meerschaum/_internal/entry.py +2 -1
- meerschaum/_internal/shell/Shell.py +1 -6
- meerschaum/actions/api.py +1 -1
- meerschaum/actions/install.py +7 -3
- meerschaum/actions/sync.py +7 -3
- meerschaum/api/dash/callbacks/dashboard.py +77 -8
- meerschaum/api/dash/callbacks/jobs.py +55 -3
- meerschaum/api/dash/jobs.py +34 -8
- meerschaum/api/dash/pipes.py +79 -11
- meerschaum/api/resources/static/js/xterm.js +1 -1
- meerschaum/config/_shell.py +0 -1
- meerschaum/config/_version.py +1 -1
- meerschaum/connectors/api/_plugins.py +2 -1
- meerschaum/connectors/sql/_create_engine.py +5 -5
- meerschaum/connectors/sql/_fetch.py +8 -11
- meerschaum/connectors/sql/_pipes.py +7 -1
- meerschaum/core/Pipe/_dtypes.py +2 -1
- meerschaum/core/Pipe/_sync.py +26 -13
- meerschaum/plugins/_Plugin.py +11 -2
- meerschaum/utils/daemon/Daemon.py +11 -3
- meerschaum/utils/dataframe.py +183 -8
- meerschaum/utils/dtypes/__init__.py +9 -5
- meerschaum/utils/formatting/_pipes.py +44 -10
- meerschaum/utils/misc.py +34 -2
- meerschaum/utils/packages/__init__.py +4 -3
- meerschaum/utils/packages/_packages.py +1 -1
- meerschaum/utils/typing.py +1 -1
- {meerschaum-2.1.6.dist-info → meerschaum-2.2.0.dev1.dist-info}/METADATA +5 -5
- {meerschaum-2.1.6.dist-info → meerschaum-2.2.0.dev1.dist-info}/RECORD +36 -36
- {meerschaum-2.1.6.dist-info → meerschaum-2.2.0.dev1.dist-info}/LICENSE +0 -0
- {meerschaum-2.1.6.dist-info → meerschaum-2.2.0.dev1.dist-info}/NOTICE +0 -0
- {meerschaum-2.1.6.dist-info → meerschaum-2.2.0.dev1.dist-info}/WHEEL +0 -0
- {meerschaum-2.1.6.dist-info → meerschaum-2.2.0.dev1.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.1.6.dist-info → meerschaum-2.2.0.dev1.dist-info}/top_level.txt +0 -0
- {meerschaum-2.1.6.dist-info → meerschaum-2.2.0.dev1.dist-info}/zip-safe +0 -0
@@ -346,6 +346,9 @@ groups['misc'].add_argument(
|
|
346
346
|
groups['misc'].add_argument(
|
347
347
|
'--nopretty', action="store_true", help="Print elements without 'pretty' formatting"
|
348
348
|
)
|
349
|
+
groups['misc'].add_argument(
|
350
|
+
'--skip-deps', action="store_true", help="Skip dependencies when installing plugins.",
|
351
|
+
)
|
349
352
|
groups['misc'].add_argument(
|
350
353
|
'-P', '--params', type=string_to_dict, help=(
|
351
354
|
"Parameters dictionary in JSON format or simple format. " +
|
meerschaum/_internal/entry.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#! /usr/bin/env python
|
2
2
|
# -*- coding: utf-8 -*-
|
3
3
|
# vim:fenc=utf-8
|
4
|
+
# type: ignore
|
4
5
|
|
5
6
|
"""
|
6
7
|
The entry point for launching Meerschaum actions.
|
@@ -61,7 +62,7 @@ def entry_with_args(
|
|
61
62
|
"""
|
62
63
|
import sys
|
63
64
|
from meerschaum.plugins import Plugin
|
64
|
-
from meerschaum.actions import
|
65
|
+
from meerschaum.actions import get_action, get_main_action_name
|
65
66
|
from meerschaum._internal.arguments import remove_leading_action
|
66
67
|
from meerschaum.utils.venv import Venv, active_venvs, deactivate_venv
|
67
68
|
if kw.get('trace', None):
|
@@ -11,11 +11,7 @@ from copy import deepcopy
|
|
11
11
|
from meerschaum.utils.typing import Union, SuccessTuple, Any, Callable, Optional, List, Dict
|
12
12
|
from meerschaum.utils.packages import attempt_import
|
13
13
|
from meerschaum.config import __doc__, __version__ as version, get_config
|
14
|
-
|
15
|
-
cmd_venv = None if cmd_import_name == 'cmd' else 'mrsm'
|
16
|
-
cmd = attempt_import(cmd_import_name, venv=cmd_venv, warn=False, lazy=False)
|
17
|
-
if cmd is None or isinstance(cmd, dict):
|
18
|
-
cmd = attempt_import('cmd', lazy=False, warn=False)
|
14
|
+
import cmd
|
19
15
|
_old_input = cmd.__builtins__['input']
|
20
16
|
prompt_toolkit = attempt_import('prompt_toolkit', lazy=False, warn=False, install=True)
|
21
17
|
(
|
@@ -53,7 +49,6 @@ hidden_commands = {
|
|
53
49
|
'os',
|
54
50
|
'sh',
|
55
51
|
'pass',
|
56
|
-
'exit',
|
57
52
|
'quit',
|
58
53
|
'eof',
|
59
54
|
'exit',
|
meerschaum/actions/api.py
CHANGED
@@ -44,7 +44,7 @@ def api(
|
|
44
44
|
sysargs = []
|
45
45
|
if len(action) == 0:
|
46
46
|
info(api.__doc__)
|
47
|
-
return False, "Please provide a command to
|
47
|
+
return False, "Please provide a command to execute (see above)."
|
48
48
|
|
49
49
|
boot_keywords = {'start', 'boot', 'init'}
|
50
50
|
if action[0] in boot_keywords:
|
meerschaum/actions/install.py
CHANGED
@@ -54,6 +54,7 @@ def _complete_install(
|
|
54
54
|
def _install_plugins(
|
55
55
|
action: Optional[List[str]] = None,
|
56
56
|
repository: Optional[str] = None,
|
57
|
+
skip_deps: bool = False,
|
57
58
|
force: bool = False,
|
58
59
|
debug: bool = False,
|
59
60
|
**kw: Any
|
@@ -87,11 +88,14 @@ def _install_plugins(
|
|
87
88
|
|
88
89
|
repo_connector = parse_repo_keys(repository)
|
89
90
|
|
90
|
-
successes = {}
|
91
91
|
for name in action:
|
92
92
|
info(f"Installing plugin '{name}' from Meerschaum repository '{repo_connector}'...")
|
93
|
-
success, msg = repo_connector.install_plugin(
|
94
|
-
|
93
|
+
success, msg = repo_connector.install_plugin(
|
94
|
+
name,
|
95
|
+
force = force,
|
96
|
+
skip_deps = skip_deps,
|
97
|
+
debug = debug,
|
98
|
+
)
|
95
99
|
print_tuple((success, msg))
|
96
100
|
|
97
101
|
reload_plugins(debug=debug)
|
meerschaum/actions/sync.py
CHANGED
@@ -453,16 +453,20 @@ def _wrap_pipe(
|
|
453
453
|
return False, msg
|
454
454
|
return True, "Success"
|
455
455
|
|
456
|
-
|
456
|
+
pre_hook_results, post_hook_results = [], []
|
457
457
|
def apply_hooks(is_pre_sync: bool):
|
458
458
|
_sync_hooks = (_pre_sync_hooks if is_pre_sync else _post_sync_hooks)
|
459
|
+
_hook_results = (pre_hook_results if is_pre_sync else post_hook_results)
|
459
460
|
for module_name, sync_hooks in _sync_hooks.items():
|
460
461
|
plugin_name = module_name.split('.')[-1] if module_name.startswith('plugins.') else None
|
461
462
|
for sync_hook in sync_hooks:
|
462
463
|
hook_result = pool.apply_async(call_sync_hook, (plugin_name, sync_hook))
|
463
|
-
|
464
|
+
_hook_results.append(hook_result)
|
464
465
|
|
465
466
|
apply_hooks(True)
|
467
|
+
for hook_result in pre_hook_results:
|
468
|
+
hook_success, hook_msg = hook_result.get()
|
469
|
+
mrsm.pprint((hook_success, hook_msg))
|
466
470
|
|
467
471
|
try:
|
468
472
|
with Venv(get_connector_plugin(pipe.connector), debug=debug):
|
@@ -480,7 +484,7 @@ def _wrap_pipe(
|
|
480
484
|
'sync_complete_timestamp': datetime.now(timezone.utc),
|
481
485
|
})
|
482
486
|
apply_hooks(False)
|
483
|
-
for hook_result in
|
487
|
+
for hook_result in post_hook_results:
|
484
488
|
hook_success, hook_msg = hook_result.get()
|
485
489
|
mrsm.pprint((hook_success, hook_msg))
|
486
490
|
|
@@ -488,11 +488,11 @@ def update_keys_options(
|
|
488
488
|
"""
|
489
489
|
ctx = dash.callback_context
|
490
490
|
trigger = ctx.triggered[0]['prop_id'].split('.')[0]
|
491
|
+
instance_click = trigger == 'instance-select'
|
491
492
|
|
492
493
|
### Update the instance first.
|
493
494
|
update_instance_keys = False
|
494
495
|
if not instance_keys:
|
495
|
-
# instance_keys = get_config('meerschaum', 'web_instance')
|
496
496
|
instance_keys = str(get_api_connector())
|
497
497
|
update_instance_keys = True
|
498
498
|
instance_alerts = []
|
@@ -519,9 +519,9 @@ def update_keys_options(
|
|
519
519
|
_ck_alone, _mk_alone, _lk_alone = False, False, False
|
520
520
|
_ck_filter, _mk_filter, _lk_filter = connector_keys, metric_keys, location_keys
|
521
521
|
|
522
|
-
_ck_alone = connector_keys and num_filter == 1
|
523
|
-
_mk_alone = metric_keys and num_filter == 1
|
524
|
-
_lk_alone = location_keys and num_filter == 1
|
522
|
+
_ck_alone = (connector_keys and num_filter == 1) or instance_click
|
523
|
+
_mk_alone = (metric_keys and num_filter == 1) or instance_click
|
524
|
+
_lk_alone = (location_keys and num_filter == 1) or instance_click
|
525
525
|
|
526
526
|
from meerschaum.utils import fetch_pipes_keys
|
527
527
|
|
@@ -545,15 +545,36 @@ def update_keys_options(
|
|
545
545
|
k = locals()[key_type]
|
546
546
|
if k not in _seen_keys[key_type]:
|
547
547
|
_k = 'None' if k in (None, '[None]', 'None', 'null') else k
|
548
|
-
options.append({'label'
|
548
|
+
options.append({'label': _k, 'value': _k})
|
549
549
|
_seen_keys[key_type].add(k)
|
550
550
|
|
551
551
|
add_options(_connectors_options, _all_keys if _ck_alone else _keys, 'ck')
|
552
552
|
add_options(_metrics_options, _all_keys if _mk_alone else _keys, 'mk')
|
553
553
|
add_options(_locations_options, _all_keys if _lk_alone else _keys, 'lk')
|
554
|
-
connector_keys = [
|
555
|
-
|
556
|
-
|
554
|
+
connector_keys = sorted([
|
555
|
+
ck
|
556
|
+
for ck in connector_keys
|
557
|
+
if ck in [
|
558
|
+
_ck['value']
|
559
|
+
for _ck in _connectors_options
|
560
|
+
]
|
561
|
+
])
|
562
|
+
metric_keys = sorted([
|
563
|
+
mk
|
564
|
+
for mk in metric_keys
|
565
|
+
if mk in [
|
566
|
+
_mk['value']
|
567
|
+
for _mk in _metrics_options
|
568
|
+
]
|
569
|
+
])
|
570
|
+
location_keys = sorted([
|
571
|
+
lk
|
572
|
+
for lk in location_keys
|
573
|
+
if lk in [
|
574
|
+
_lk['value']
|
575
|
+
for _lk in _locations_options
|
576
|
+
]
|
577
|
+
])
|
557
578
|
_connectors_datalist = [html.Option(value=o['value']) for o in _connectors_options]
|
558
579
|
_metrics_datalist = [html.Option(value=o['value']) for o in _metrics_options]
|
559
580
|
_locations_datalist = [html.Option(value=o['value']) for o in _locations_options]
|
@@ -680,6 +701,9 @@ dash_app.clientside_callback(
|
|
680
701
|
Input({'type': 'pipe-download-csv-button', 'index': ALL}, 'n_clicks'),
|
681
702
|
)
|
682
703
|
def download_pipe_csv(n_clicks):
|
704
|
+
"""
|
705
|
+
Download the most recent chunk as a CSV file.
|
706
|
+
"""
|
683
707
|
if not n_clicks:
|
684
708
|
raise PreventUpdate
|
685
709
|
ctx = dash.callback_context.triggered
|
@@ -818,6 +842,51 @@ def sync_documents_click(n_clicks, sync_editor_text):
|
|
818
842
|
return alert_from_success_tuple((success, msg))
|
819
843
|
|
820
844
|
|
845
|
+
dash_app.clientside_callback(
|
846
|
+
"""
|
847
|
+
function(n_clicks_arr, url){
|
848
|
+
display_block = {"display": "block"};
|
849
|
+
|
850
|
+
var clicked = false;
|
851
|
+
for (var i = 0; i < n_clicks_arr.length; i++){
|
852
|
+
if (n_clicks_arr[i]){
|
853
|
+
clicked = true;
|
854
|
+
break;
|
855
|
+
}
|
856
|
+
}
|
857
|
+
if (!clicked){ return dash_clientside.no_update; }
|
858
|
+
|
859
|
+
const triggered_id = dash_clientside.callback_context.triggered_id;
|
860
|
+
const action = triggered_id["action"];
|
861
|
+
const pipe_meta = JSON.parse(triggered_id["index"]);
|
862
|
+
|
863
|
+
iframe = document.getElementById('webterm-iframe');
|
864
|
+
if (!iframe){ return dash_clientside.no_update; }
|
865
|
+
var location = pipe_meta.location;
|
866
|
+
if (!pipe_meta.location){
|
867
|
+
location = "None";
|
868
|
+
}
|
869
|
+
|
870
|
+
iframe.contentWindow.postMessage(
|
871
|
+
{
|
872
|
+
action: action,
|
873
|
+
subaction: "pipes",
|
874
|
+
connector_keys: [pipe_meta.connector],
|
875
|
+
metric_keys: [pipe_meta.metric],
|
876
|
+
location_keys: [location],
|
877
|
+
instance: pipe_meta.instance,
|
878
|
+
},
|
879
|
+
url
|
880
|
+
);
|
881
|
+
dash_clientside.set_props("webterm-div", {"style": display_block});
|
882
|
+
return [];
|
883
|
+
}
|
884
|
+
""",
|
885
|
+
Output('content-div-right', 'children'),
|
886
|
+
Input({'type': 'manage-pipe-button', 'index': ALL, 'action': ALL}, 'n_clicks'),
|
887
|
+
State('location', 'href'),
|
888
|
+
)
|
889
|
+
|
821
890
|
@dash_app.callback(
|
822
891
|
Output("navbar-collapse", "is_open"),
|
823
892
|
[Input("navbar-toggler", "n_clicks")],
|
@@ -11,6 +11,7 @@ import json
|
|
11
11
|
import functools
|
12
12
|
import time
|
13
13
|
import traceback
|
14
|
+
from datetime import datetime, timezone
|
14
15
|
import meerschaum as mrsm
|
15
16
|
from meerschaum.utils.typing import Optional, Dict, Any
|
16
17
|
from meerschaum.api import get_api_connector, endpoints, CHECK_UPDATE
|
@@ -54,9 +55,14 @@ def download_job_logs(n_clicks):
|
|
54
55
|
component_dict = json.loads(ctx[0]['prop_id'].split('.' + 'n_clicks')[0])
|
55
56
|
daemon_id = component_dict['index']
|
56
57
|
daemon = Daemon(daemon_id=daemon_id)
|
58
|
+
now = datetime.now(timezone.utc)
|
59
|
+
filename = (
|
60
|
+
daemon.rotating_log.file_path.name[:(-1 * len('.log'))]
|
61
|
+
+ '_' + str(int(now.timestamp())) + '.log'
|
62
|
+
)
|
57
63
|
return {
|
58
64
|
'content': daemon.log_text,
|
59
|
-
'filename':
|
65
|
+
'filename': filename,
|
60
66
|
}
|
61
67
|
|
62
68
|
|
@@ -74,7 +80,7 @@ def manage_job_button_click(
|
|
74
80
|
session_data: Optional[Dict[str, Any]] = None,
|
75
81
|
):
|
76
82
|
"""
|
77
|
-
Start, stop, or
|
83
|
+
Start, stop, pause, or delete the given job.
|
78
84
|
"""
|
79
85
|
if not n_clicks:
|
80
86
|
raise PreventUpdate
|
@@ -98,12 +104,18 @@ def manage_job_button_click(
|
|
98
104
|
component_dict = json.loads(ctx[0]['prop_id'].split('.' + 'n_clicks')[0])
|
99
105
|
daemon_id = component_dict['index']
|
100
106
|
manage_job_action = component_dict['action']
|
101
|
-
|
107
|
+
try:
|
108
|
+
daemon = Daemon(daemon_id=daemon_id)
|
109
|
+
except Exception as e:
|
110
|
+
daemon = None
|
111
|
+
if daemon is None:
|
112
|
+
raise PreventUpdate
|
102
113
|
|
103
114
|
manage_functions = {
|
104
115
|
'start': functools.partial(daemon.run, allow_dirty_run=True),
|
105
116
|
'stop': daemon.quit,
|
106
117
|
'pause': daemon.pause,
|
118
|
+
'delete': daemon.cleanup,
|
107
119
|
}
|
108
120
|
if manage_job_action not in manage_functions:
|
109
121
|
return (
|
@@ -135,6 +147,46 @@ def manage_job_button_click(
|
|
135
147
|
build_process_timestamps_children(daemon),
|
136
148
|
)
|
137
149
|
|
150
|
+
dash_app.clientside_callback(
|
151
|
+
"""
|
152
|
+
function(n_clicks_arr, url){
|
153
|
+
display_block = {"display": "block"};
|
154
|
+
|
155
|
+
var clicked = false;
|
156
|
+
for (var i = 0; i < n_clicks_arr.length; i++){
|
157
|
+
if (n_clicks_arr[i]){
|
158
|
+
clicked = true;
|
159
|
+
break;
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
if (!clicked){
|
164
|
+
return dash_clientside.no_update;
|
165
|
+
}
|
166
|
+
|
167
|
+
const triggered_id = dash_clientside.callback_context.triggered_id;
|
168
|
+
const job_daemon_id = triggered_id["index"];
|
169
|
+
|
170
|
+
iframe = document.getElementById('webterm-iframe');
|
171
|
+
if (!iframe){ return dash_clientside.no_update; }
|
172
|
+
|
173
|
+
iframe.contentWindow.postMessage(
|
174
|
+
{
|
175
|
+
action: "show",
|
176
|
+
subaction: "logs",
|
177
|
+
subaction_text: job_daemon_id,
|
178
|
+
},
|
179
|
+
url
|
180
|
+
);
|
181
|
+
dash_clientside.set_props("webterm-div", {"style": display_block});
|
182
|
+
return [];
|
183
|
+
}
|
184
|
+
""",
|
185
|
+
Output('content-div-right', 'children'),
|
186
|
+
Input({'type': 'follow-logs-button', 'index': ALL}, 'n_clicks'),
|
187
|
+
State('location', 'href'),
|
188
|
+
)
|
189
|
+
|
138
190
|
|
139
191
|
@dash_app.callback(
|
140
192
|
Output({'type': 'manage-job-buttons-div', 'index': ALL}, 'children'),
|
meerschaum/api/dash/jobs.py
CHANGED
@@ -49,6 +49,17 @@ def get_jobs_cards(state: WebState):
|
|
49
49
|
build_process_timestamps_children(d),
|
50
50
|
id = {'type': 'process-timestamps-div', 'index': d.daemon_id},
|
51
51
|
)
|
52
|
+
follow_logs_button = dbc.DropdownMenuItem(
|
53
|
+
"Follow logs",
|
54
|
+
id = {'type': 'follow-logs-button', 'index': d.daemon_id},
|
55
|
+
)
|
56
|
+
download_logs_button = dbc.DropdownMenuItem(
|
57
|
+
"Download logs",
|
58
|
+
id = {'type': 'job-download-logs-button', 'index': d.daemon_id},
|
59
|
+
)
|
60
|
+
logs_menu_children = (
|
61
|
+
([follow_logs_button] if is_authenticated else []) + [download_logs_button]
|
62
|
+
)
|
52
63
|
header_children = [
|
53
64
|
html.Div(
|
54
65
|
build_status_children(d),
|
@@ -56,11 +67,13 @@ def get_jobs_cards(state: WebState):
|
|
56
67
|
style = {'float': 'left'},
|
57
68
|
),
|
58
69
|
html.Div(
|
59
|
-
dbc.
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
70
|
+
dbc.DropdownMenu(
|
71
|
+
logs_menu_children,
|
72
|
+
label = "Logs",
|
73
|
+
size = "sm",
|
74
|
+
align_end = True,
|
75
|
+
color = "secondary",
|
76
|
+
menu_variant = 'dark',
|
64
77
|
),
|
65
78
|
style = {'float': 'right'},
|
66
79
|
),
|
@@ -74,7 +87,7 @@ def get_jobs_cards(state: WebState):
|
|
74
87
|
className = "card-text job-card-text",
|
75
88
|
style = {"word-wrap": "break-word"}
|
76
89
|
),
|
77
|
-
style={"white-space": "pre-wrap"},
|
90
|
+
style = {"white-space": "pre-wrap"},
|
78
91
|
),
|
79
92
|
html.Div(
|
80
93
|
(
|
@@ -82,7 +95,7 @@ def get_jobs_cards(state: WebState):
|
|
82
95
|
if is_authenticated
|
83
96
|
else []
|
84
97
|
),
|
85
|
-
id={'type': 'manage-job-buttons-div', 'index': d.daemon_id}
|
98
|
+
id = {'type': 'manage-job-buttons-div', 'index': d.daemon_id},
|
86
99
|
),
|
87
100
|
html.Div(id={'type': 'manage-job-alert-div', 'index': d.daemon_id}),
|
88
101
|
]
|
@@ -108,7 +121,7 @@ def build_manage_job_buttons_div_children(daemon: Daemon):
|
|
108
121
|
return [
|
109
122
|
html.Br(),
|
110
123
|
dbc.Row([
|
111
|
-
dbc.Col(button, width=
|
124
|
+
dbc.Col(button, width=6)
|
112
125
|
for button in buttons
|
113
126
|
])
|
114
127
|
]
|
@@ -153,9 +166,22 @@ def build_manage_job_buttons(daemon: Daemon):
|
|
153
166
|
'index': daemon.daemon_id,
|
154
167
|
},
|
155
168
|
)
|
169
|
+
delete_button = dbc.Button(
|
170
|
+
'Delete',
|
171
|
+
size = 'sm',
|
172
|
+
color = 'danger',
|
173
|
+
style = {'width': '100%'},
|
174
|
+
id = {
|
175
|
+
'type': 'manage-job-button',
|
176
|
+
'action': 'delete',
|
177
|
+
'index': daemon.daemon_id,
|
178
|
+
},
|
179
|
+
)
|
156
180
|
buttons = []
|
157
181
|
if daemon.status in ('stopped', 'paused'):
|
158
182
|
buttons.append(start_button)
|
183
|
+
if daemon.status == 'stopped':
|
184
|
+
buttons.append(delete_button)
|
159
185
|
if daemon.status in ('running',):
|
160
186
|
buttons.append(pause_button)
|
161
187
|
if daemon.status in ('running', 'paused'):
|
meerschaum/api/dash/pipes.py
CHANGED
@@ -115,16 +115,72 @@ def get_pipes_cards(*keys, session_data: Optional[Dict[str, Any]] = None):
|
|
115
115
|
if not isinstance(_pipes, list):
|
116
116
|
_pipes = []
|
117
117
|
for p in _pipes:
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
118
|
+
meta_str = json.dumps(p.meta)
|
119
|
+
footer_children = dbc.Row(
|
120
|
+
[
|
121
|
+
dbc.Col(
|
122
|
+
(
|
123
|
+
dbc.DropdownMenu(
|
124
|
+
label = "Manage",
|
125
|
+
children = [
|
126
|
+
dbc.DropdownMenuItem(
|
127
|
+
'Sync',
|
128
|
+
id = {
|
129
|
+
'type': 'manage-pipe-button',
|
130
|
+
'index': meta_str,
|
131
|
+
'action': 'sync',
|
132
|
+
},
|
133
|
+
),
|
134
|
+
dbc.DropdownMenuItem(
|
135
|
+
'Drop',
|
136
|
+
id = {
|
137
|
+
'type': 'manage-pipe-button',
|
138
|
+
'index': meta_str,
|
139
|
+
'action': 'drop',
|
140
|
+
},
|
141
|
+
),
|
142
|
+
dbc.DropdownMenuItem(
|
143
|
+
'Delete',
|
144
|
+
id = {
|
145
|
+
'type': 'manage-pipe-button',
|
146
|
+
'index': meta_str,
|
147
|
+
'action': 'delete',
|
148
|
+
},
|
149
|
+
),
|
150
|
+
],
|
151
|
+
direction = "end",
|
152
|
+
menu_variant = "dark",
|
153
|
+
size = 'sm',
|
154
|
+
color = 'secondary',
|
155
|
+
)
|
156
|
+
) if authenticated else [],
|
157
|
+
width = 2,
|
158
|
+
),
|
159
|
+
# dbc.Col(
|
160
|
+
# (
|
161
|
+
# dbc.Button(
|
162
|
+
# 'Sync',
|
163
|
+
# size = 'sm',
|
164
|
+
# style = {'width': '100%'},
|
165
|
+
# id = {'type': 'pipe-sync-button', 'index': meta_str},
|
166
|
+
# ) if authenticated else []
|
167
|
+
# ),
|
168
|
+
# width = 2,
|
169
|
+
# ),
|
170
|
+
dbc.Col(width=6),
|
171
|
+
dbc.Col(
|
172
|
+
dbc.Button(
|
173
|
+
'Download recent data',
|
174
|
+
size = 'sm',
|
175
|
+
color = 'link',
|
176
|
+
style = {'float': 'right'},
|
177
|
+
id = {'type': 'pipe-download-csv-button', 'index': meta_str},
|
178
|
+
),
|
179
|
+
width = 4,
|
180
|
+
),
|
181
|
+
],
|
182
|
+
justify = 'start',
|
183
|
+
)
|
128
184
|
card_body_children = [
|
129
185
|
html.H5(
|
130
186
|
html.B(str(p)),
|
@@ -136,7 +192,7 @@ def get_pipes_cards(*keys, session_data: Optional[Dict[str, Any]] = None):
|
|
136
192
|
accordion_items_from_pipe(p, authenticated=authenticated),
|
137
193
|
flush = True,
|
138
194
|
start_collapsed = True,
|
139
|
-
id = {'type': 'pipe-accordion', 'index':
|
195
|
+
id = {'type': 'pipe-accordion', 'index': meta_str},
|
140
196
|
)
|
141
197
|
)
|
142
198
|
|
@@ -196,6 +252,18 @@ def accordion_items_from_pipe(
|
|
196
252
|
]
|
197
253
|
for col_key, col in pipe.columns.items():
|
198
254
|
overview_rows.append(html.Tr([html.Td(f"'{col_key}' Index"), html.Td(col)]))
|
255
|
+
tags = pipe.tags
|
256
|
+
if tags:
|
257
|
+
tags_items = html.Ul([
|
258
|
+
html.Li(tag)
|
259
|
+
for tag in tags
|
260
|
+
])
|
261
|
+
overview_rows.append(
|
262
|
+
html.Tr([
|
263
|
+
html.Td("Tags"),
|
264
|
+
html.Td(tags_items),
|
265
|
+
])
|
266
|
+
)
|
199
267
|
|
200
268
|
items_bodies['overview'] = dbc.Table(
|
201
269
|
overview_header + [html.Tbody(overview_rows)],
|