mirror of
https://github.com/netinvent/npbackup.git
synced 2025-10-06 11:36:04 +08:00
WIP: refactor config UI
This commit is contained in:
parent
65d4b4fb60
commit
8874b94676
7 changed files with 62 additions and 93 deletions
|
@ -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
|
||||
|
@ -329,23 +328,30 @@ def get_repo_config(full_config: dict, repo_name: str = 'default', eval_variable
|
|||
# TODO: Lists containing dicts won't be updated in repo_config here
|
||||
# we need to have
|
||||
# for elt in list:
|
||||
# recurse into elt if elt is dict
|
||||
# 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
|
@ -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)
|
||||
current_state, backup_tz, snapshot_list = get_gui_data(repo_config)
|
||||
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")
|
||||
|
@ -783,4 +787,8 @@ def main_gui():
|
|||
_main_gui()
|
||||
except _tkinter.TclError as exc:
|
||||
logger.critical(f'Tkinter error: "{exc}". Is this a headless server ?')
|
||||
sys.exit(250)
|
||||
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)
|
|
@ -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
|
||||
|
||||
|
|
|
@ -107,4 +107,9 @@ en:
|
|||
daily: daily copies
|
||||
weekly: weekly copies
|
||||
monthly: monthly copies
|
||||
yearly: yearly copies
|
||||
yearly: yearly copies
|
||||
|
||||
group_inherited: Group inherited
|
||||
repo_group_config: Repo group configuration
|
||||
global_config: Global config
|
||||
select_object: Select configuration object
|
||||
|
|
|
@ -107,4 +107,10 @@ fr:
|
|||
daily: copies journalières
|
||||
weekly: copies hebdomadaires
|
||||
monthly: copies mensuelles
|
||||
yearly: copies annuelles
|
||||
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
|
||||
|
BIN
resources/inheritance_icon.png
Normal file
BIN
resources/inheritance_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 442 B |
Loading…
Add table
Reference in a new issue