WIP: refactor config UI

This commit is contained in:
Orsiris de Jong 2023-12-15 20:48:12 +01:00
parent 65d4b4fb60
commit 8874b94676
7 changed files with 62 additions and 93 deletions

View file

@ -7,12 +7,12 @@ __intname__ = "npbackup.configuration"
__author__ = "Orsiris de Jong"
__copyright__ = "Copyright (C) 2022-2023 NetInvent"
__license__ = "GPL-3.0-only"
__build__ = "2023121301"
__build__ = "2023121501"
__version__ = "2.0.0 for npbackup 2.3.0+"
CONF_VERSION = 2.3
from typing import Tuple, Optional, List, Callable, Any, Union
from typing import Tuple, Optional, List, Any, Union
import sys
import os
from copy import deepcopy
@ -304,7 +304,6 @@ def get_repo_config(full_config: dict, repo_name: str = 'default', eval_variable
Returns a dict containing the repo config, with expanded variables
and a dict containing the repo interitance status
"""
def inherit_group_settings(repo_config: dict, group_config: dict) -> Tuple[dict, dict]:
"""
iter over group settings, update repo_config, and produce an identical version of repo_config
@ -332,20 +331,27 @@ def get_repo_config(full_config: dict, repo_name: str = 'default', eval_variable
# recurse into elt if elt is dict
if isinstance(_repo_config.g(key), list):
merged_lists = _repo_config.g(key) + _group_config.g(key)
# Case where repo config already contains non list info but group config has list
elif _repo_config.g(key):
merged_lists = [_repo_config.g(key)] + _group_config.g(key)
else:
merged_lists = _group_config.g(key)
_repo_config.s(key, merged_lists)
_config_inheritance.s(key, True)
else:
# Tricky part
# repo_config may already contain a struct
# repo_config may or may not already contain data
if not _repo_config:
_repo_config = CommentedMap()
_config_inheritance = CommentedMap()
if not _repo_config.g(key):
_repo_config.s(key, value)
_config_inheritance.s(key, True)
# Case where repo_config contains list but group info has single str
elif isinstance(_repo_config.g(key), list) and value:
merged_lists = _repo_config.g(key) + [value]
_repo_config.s(key, merged_lists)
else:
# In other cases, just keep repo confg
_config_inheritance.s(key, False)

File diff suppressed because one or more lines are too long

View file

@ -207,7 +207,7 @@ def _gui_update_state(
)
elif current_state is False:
window["state-button"].Update(
"{}: {}".format(_t("generic.too_old"), backup_tz),
"{}: {}".format(_t("generic.too_old"), backup_tz.replace(microsecond=0)),
button_color=GUI_STATE_OLD_BUTTON,
)
elif current_state is None:
@ -570,8 +570,7 @@ def _main_gui():
logger.info(f"Using configuration file {config_file}")
full_config = npbackup.configuration.load_config(config_file)
# TODO add a repo selector
repo_config, inherit_config = npbackup.configuration.get_repo_config(full_config)
repo_config, config_inheritance = npbackup.configuration.get_repo_config(full_config)
repo_list = npbackup.configuration.get_repo_list(full_config)
backup_destination = _t("main_gui.local_folder")
@ -661,7 +660,12 @@ def _main_gui():
window["snapshot-list"].expand(True, True)
window.read(timeout=1)
try:
current_state, backup_tz, snapshot_list = get_gui_data(repo_config)
except ValueError:
current_state = None
backup_tz = None
snapshot_list = []
_gui_update_state(window, current_state, backup_tz, snapshot_list)
while True:
event, values = window.read(timeout=60000)
@ -671,7 +675,7 @@ def _main_gui():
if event == "-active_repo-":
active_repo = values['-active_repo-']
if full_config.g(f"repos.{active_repo}"):
repo_config = npbackup.configuration.get_repo_config(full_config, active_repo)
repo_config, config_inheriteance = npbackup.configuration.get_repo_config(full_config, active_repo)
current_state, backup_tz, snapshot_list = get_gui_data(repo_config)
else:
sg.PopupError("Repo not existent in config")
@ -784,3 +788,7 @@ def main_gui():
except _tkinter.TclError as exc:
logger.critical(f'Tkinter error: "{exc}". Is this a headless server ?')
sys.exit(250)
except Exception as exc:
sg.Popup(_t("config_gui.bogus_config_file") + f': {exc}')
raise #TODO replace with logger
sys.exit(251)

View file

@ -15,11 +15,12 @@ import os
from logging import getLogger
from copy import deepcopy
import PySimpleGUI as sg
from ruamel.yaml.comments import CommentedMap
import npbackup.configuration as configuration
from ofunctions.misc import get_key_from_value
from npbackup.core.i18n_helper import _t
from npbackup.path_helper import CURRENT_EXECUTABLE
from npbackup.core.nuitka_helper import IS_COMPILED
from npbackup.customization import INHERITANCE_ICON
if os.name == "nt":
from npbackup.windows.task import create_scheduled_task
@ -108,7 +109,7 @@ def config_gui(full_config: dict, config_file: str):
"""
if key == "backup_admin_password":
return
if key == "repo_uri":
if key in ("repo_uri", "repo_group"):
if object_type == "group":
window[key].Disabled = True
else:
@ -137,10 +138,10 @@ def config_gui(full_config: dict, config_file: str):
else:
window[key].Update(value)
# Set inheritance on
# Enable inheritance icon when needed
inheritance_key = f'inherited.{key}'
if inheritance_key in window.AllKeysDict:
window[f'inherited.{key}'].update(visible=True if inherited else False)
window[inheritance_key].update(visible=True if inherited else False)
except KeyError:
logger.error(f"No GUI equivalent for key {key}.")
@ -177,31 +178,28 @@ def config_gui(full_config: dict, config_file: str):
# First we need to clear the whole GUI to reload new values
for key in window.AllKeysDict:
# We only clear config keys, wihch have '.' separator
if "." in str(key):
if "." in str(key) and not "inherited" in str(key):
window[key]('')
object_type, object_name = get_object_from_combo(object_name)
if object_type == 'repo':
object_config, config_inheritance = configuration.get_repo_config(full_config, object_name, eval_variables=False)
if object_type == 'group':
object_config = configuration.get_group_config(full_config, object_name, eval_variables=False)
config_inheritance = None
# Now let's iter over the whole config object and update keys accordingly
iter_over_config(object_config, config_inheritance, object_type, unencrypted, None)
def update_global_gui(full_config, unencrypted=False):
# TODO
return
global_config = deepcopy(full_config)
global_config = CommentedMap()
# Only update global options gui with identified global keys
for key in global_config.keys():
if key not in ('identity', 'global_prometheus', 'global_options'):
global_config.pop(key)
print(global_config)
iter_over_config(global_config, None, None, unencrypted, None)
for key in full_config.keys():
if key in ('identity', 'global_options'):
global_config.s(key, full_config.g(key))
iter_over_config(global_config, None, 'group', unencrypted, None)
def update_config_dict(values, full_config):
@ -239,13 +237,14 @@ def config_gui(full_config: dict, config_file: str):
return full_config
def object_layout(object_type: str = "repo") -> List[list]:
def object_layout() -> List[list]:
"""
Returns the GUI layout depending on the object type
"""
backup_col = [
[
sg.Text(_t("config_gui.compression"), size=(40, 1)),
sg.pin(sg.Image(INHERITANCE_ICON, key="inherited.backup_opts.compression", tooltip=_t("config_gui.group_inherited"))),
sg.Combo(
list(combo_boxes["compression"].values()),
key="backup_opts.compression",
@ -259,10 +258,12 @@ def config_gui(full_config: dict, config_file: str):
),
size=(40, 2),
),
sg.pin(sg.Image(INHERITANCE_ICON, expand_x=True, expand_y=True, key="inherited.backup_opts.paths", tooltip=_t("config_gui.group_inherited"))),
sg.Multiline(key="backup_opts.paths", size=(48, 4)),
],
[
sg.Text(_t("config_gui.source_type"), size=(40, 1)),
sg.pin(sg.Image(INHERITANCE_ICON, expand_x=True, expand_y=True, key="inherited.backup_opts.source_type", tooltip=_t("config_gui.group_inherited"))),
sg.Combo(
list(combo_boxes["source_type"].values()),
key="backup_opts.source_type",
@ -276,7 +277,7 @@ def config_gui(full_config: dict, config_file: str):
),
size=(40, 2),
),
sg.Text("inherited", key="inherited.backup_opts.use_fs_snapshot", visible=False),
sg.pin(sg.Image(INHERITANCE_ICON, expand_x=True, expand_y=True, key="inherited.backup_opts.use_fs_snapshot", tooltip=_t("config_gui.group_inherited"))),
sg.Checkbox("", key="backup_opts.use_fs_snapshot", size=(41, 1)),
],
[
@ -533,7 +534,7 @@ def config_gui(full_config: dict, config_file: str):
[
sg.Tab(
_t("config_gui.backup"),
[[sg.Column(backup_col, scrollable=True, vertical_scroll_only=True)]],
[[sg.Column(backup_col, scrollable=True, vertical_scroll_only=True, size=(700, 450))]],
font="helvetica 16",
key="--tab-backup--",
element_justification="L",
@ -542,7 +543,7 @@ def config_gui(full_config: dict, config_file: str):
[
sg.Tab(
_t("config_gui.backup_destination"),
repo_col,
[[sg.Column(repo_col, scrollable=True, vertical_scroll_only=True, size=(700, 450))]],
font="helvetica 16",
key="--tab-repo--",
element_justification="L",
@ -590,54 +591,6 @@ def config_gui(full_config: dict, config_file: str):
sg.Input(key="identity.machine_group", size=(50, 1)),
],
]
prometheus_col = [
[sg.Text(_t("config_gui.available_variables"))],
[
sg.Text(_t("config_gui.enable_prometheus"), size=(40, 1)),
sg.Checkbox("", key="global_prometheus.metrics", size=(41, 1)),
],
[
sg.Text(_t("config_gui.job_name"), size=(40, 1)),
sg.Input(key="global_prometheus.backup_job", size=(50, 1)),
],
[
sg.Text(_t("config_gui.metrics_destination"), size=(40, 1)),
sg.Input(key="global_prometheus.destination", size=(50, 1)),
],
[
sg.Text(_t("config_gui.no_cert_verify"), size=(40, 1)),
sg.Checkbox("", key="global_prometheus.no_cert_verify", size=(41, 1)),
],
[
sg.Text(_t("config_gui.metrics_username"), size=(40, 1)),
sg.Input(key="global_prometheus.http_username", size=(50, 1)),
],
[
sg.Text(_t("config_gui.metrics_password"), size=(40, 1)),
sg.Input(key="global_prometheus.http_password", size=(50, 1)),
],
[
sg.Text(_t("config_gui.instance"), size=(40, 1)),
sg.Input(key="global_prometheus.instance", size=(50, 1)),
],
[
sg.Text(_t("generic.group"), size=(40, 1)),
sg.Input(key="global_prometheus.group", size=(50, 1)),
],
[
sg.Text(
"{}\n({}\n{})".format(
_t("config_gui.additional_labels"),
_t("config_gui.one_per_line"),
_t("config_gui.format_equals"),
),
size=(40, 3),
),
sg.Multiline(key="global_prometheus.additional_labels", size=(48, 3)),
],
]
global_options_col = [
[sg.Text(_t("config_gui.available_variables"))],
[
@ -691,15 +644,6 @@ def config_gui(full_config: dict, config_file: str):
element_justification="L",
)
],
[
sg.Tab(
_t("config_gui.prometheus_config"),
prometheus_col,
font="helvetica 16",
key="--tab-global-prometheus--",
element_justification="L",
)
],
[
sg.Tab(
_t("generic.options"),
@ -743,8 +687,7 @@ def config_gui(full_config: dict, config_file: str):
_global_layout = [
[sg.TabGroup(tab_group_layout, enable_events=True, key="--configtabgroup--")],
[sg.Column(buttons, element_justification="L")],
[sg.Button("trololo")]
[sg.Push(), sg.Column(buttons, element_justification="L")],
]
return _global_layout

View file

@ -108,3 +108,8 @@ en:
weekly: weekly copies
monthly: monthly copies
yearly: yearly copies
group_inherited: Group inherited
repo_group_config: Repo group configuration
global_config: Global config
select_object: Select configuration object

View file

@ -108,3 +108,9 @@ fr:
weekly: copies hebdomadaires
monthly: copies mensuelles
yearly: copies annuelles
group_inherited: Hérité du groupe
repo_group_config: Configuration de groupe de dépots
global_config: Configuration globale
select_object: Selectionner l'object à configurer

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B