From d150d656bdab394f649a67490b146c5798361187 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 1 Sep 2022 18:44:48 +0200 Subject: [proxy] make it possible to enable and disable mapping versions from web UI --- src/hydrilla/proxy/state.py | 16 +++ .../_operations/recompute_dependencies.py | 28 +++-- src/hydrilla/proxy/state_impl/items.py | 127 ++++++++++++++++++++- src/hydrilla/proxy/web_ui/items.py | 14 ++- .../proxy/web_ui/templates/base.html.jinja | 18 ++- .../templates/items/item_viewversion.html.jinja | 34 +++--- .../templates/items/library_viewversion.html.jinja | 16 +++ .../templates/items/package_viewversion.html.jinja | 64 +++++++++++ 8 files changed, 286 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/hydrilla/proxy/state.py b/src/hydrilla/proxy/state.py index 1246c92..f882b2d 100644 --- a/src/hydrilla/proxy/state.py +++ b/src/hydrilla/proxy/state.py @@ -240,6 +240,14 @@ class MappingVersionDisplayInfo(item_infos.CorrespondsToMappingDCMixin): @dc.dataclass(frozen=True, unsafe_hash=True) # type: ignore[misc] class MappingRef(Ref, item_infos.CorrespondsToMappingDCMixin): """....""" + @abstractmethod + def update_status( + self, + enabled: EnabledStatus, + frozen: t.Optional[FrozenStatus] = None + ) -> None: + ... + @abstractmethod def get_version_display_infos(self) \ -> t.Sequence[MappingVersionDisplayInfo]: @@ -261,6 +269,14 @@ class MappingVersionRef(Ref, item_infos.CorrespondsToMappingDCMixin): def uninstall(self) -> t.Optional['MappingVersionRef']: ... + @abstractmethod + def update_mapping_status( + self, + enabled: EnabledStatus, + frozen: t.Optional[FrozenStatus] = None + ) -> None: + ... + @abstractmethod def get_all_version_display_infos(self) \ -> t.Sequence[MappingVersionDisplayInfo]: diff --git a/src/hydrilla/proxy/state_impl/_operations/recompute_dependencies.py b/src/hydrilla/proxy/state_impl/_operations/recompute_dependencies.py index 5403ec3..9419f91 100644 --- a/src/hydrilla/proxy/state_impl/_operations/recompute_dependencies.py +++ b/src/hydrilla/proxy/state_impl/_operations/recompute_dependencies.py @@ -49,21 +49,26 @@ AnyInfoVar = t.TypeVar( def _get_infos_of_type(cursor: sqlite3.Cursor, info_type: t.Type[AnyInfoVar],) \ -> t.Mapping[int, AnyInfoVar]: + join_mapping_statuses = 'JOIN mapping_statuses AS ms USING (item_id)' + condition = "i.type = 'M' AND ms.enabled != 'D'" + if info_type is item_infos.ResourceInfo: + join_mapping_statuses = '' + condition = "i.type = 'R'" + cursor.execute( - ''' + f''' SELECT ive.item_version_id, ive.definition, ive.repo, ive.repo_iteration FROM - item_versions_extra AS ive - JOIN items AS i USING (item_id) - LEFT JOIN mapping_statuses AS ms USING (item_id) + item_versions_extra AS ive + JOIN items AS i USING (item_id) + {join_mapping_statuses} WHERE - i.type = ? AND COALESCE(ms.enabled != 'D', TRUE); - ''', - (info_type.type.value[0].upper(),) + {condition}; + ''' ) result: dict[int, AnyInfoVar] = {} @@ -92,11 +97,14 @@ def _get_current_required_state( cursor.execute( ''' SELECT - definition, repo, repo_iteration + ive.definition, ive.repo, ive.repo_iteration FROM - item_versions_extra + item_versions_extra AS ive + JOIN items AS i USING (item_id) WHERE - item_id NOT IN __unlocked_ids AND active = 'R'; + i.type = 'M' AND + item_id NOT IN __unlocked_ids AND + ive.active = 'R'; ''', ) diff --git a/src/hydrilla/proxy/state_impl/items.py b/src/hydrilla/proxy/state_impl/items.py index ddfef7c..919223b 100644 --- a/src/hydrilla/proxy/state_impl/items.py +++ b/src/hydrilla/proxy/state_impl/items.py @@ -48,7 +48,7 @@ def _set_installed_status(cursor: sqlite3.Cursor, id: str, new_status: str) \ (new_status, id) ) -def _get_statuses(cursor: sqlite3.Cursor, id: str) -> t.Tuple[str, str]: +def _get_statuses(cursor: sqlite3.Cursor, id: str) -> tuple[str, str]: cursor.execute( ''' SELECT @@ -114,6 +114,105 @@ def _uninstall_version(ref: VersionRefVar) -> t.Optional[VersionRefVar]: class ConcreteMappingRef(st.MappingRef): state: base.HaketiloStateWithFields = dc.field(hash=False, compare=False) + def _get_status_data(self, cursor: sqlite3.Cursor) \ + -> tuple[str, str, int]: + cursor.execute( + ''' + SELECT + ms.enabled, ms.frozen, ms.active_version_id + FROM + mapping_statuses + WHERE + item_id = ?; + ''', + (self.id,) + ) + + rows = cursor.fetchall() + + if rows == []: + raise st.MissingItemError() + + (enabled_status, frozen_status, active_version_id), = rows + + return (enabled_status, frozen_status, active_version_id) + + + def update_status( + self, + enabled: st.EnabledStatus, + frozen: t.Optional[st.FrozenStatus] = None, + version_id_to_activate: t.Optional[str] = None + ) -> None: + assert frozen is None or enabled == st.EnabledStatus.ENABLED + assert version_id_to_activate is None or \ + frozen != st.FrozenStatus.NOT_FROZEN + + with self.state.cursor(transaction=True) as cursor: + cursor.execute( + ''' + SELECT + enabled, frozen, active_version_id + FROM + mapping_statuses + WHERE + item_id = ?; + ''', + (self.id,) + ) + + rows = cursor.fetchall() + + if rows == []: + raise st.MissingItemError() + + (old_enabled_status, old_frozen_status, + old_active_version_id), = rows + + if enabled.value == old_enabled_status and frozen is None: + return + + new_enabled_status = enabled.value + + new_frozen_status = None if frozen is None else frozen.value + + if version_id_to_activate is not None: + new_active_version_id = version_id_to_activate + elif enabled == st.EnabledStatus.ENABLED: + new_active_version_id = str(old_active_version_id) + else: + new_active_version_id = None + + cursor.execute( + ''' + UPDATE + mapping_statuses + SET + enabled = ?, + frozen = ?, + active_version_id = ? + WHERE + item_id = ?; + ''', ( + new_enabled_status, + new_frozen_status, + new_active_version_id, + self.id + )) + + if enabled == st.EnabledStatus.ENABLED: + if old_enabled_status == 'E' and \ + new_active_version_id == str(old_active_version_id) and \ + (new_frozen_status == 'E' or + old_frozen_status == 'N' or + new_frozen_status == old_frozen_status): + return + else: + if old_active_version_id is None: + return + + self.state.recompute_dependencies([int(self.id)]) + def get_version_display_infos(self) \ -> t.Sequence[st.MappingVersionDisplayInfo]: with self.state.cursor() as cursor: @@ -267,6 +366,32 @@ class ConcreteMappingVersionRef(st.MappingVersionRef): def uninstall(self) -> t.Optional['ConcreteMappingVersionRef']: return _uninstall_version(self) + def update_mapping_status( + self, + enabled: st.EnabledStatus, + frozen: t.Optional[st.FrozenStatus] = None + ) -> None: + with self.state.cursor(transaction=True) as cursor: + cursor.execute( + 'SELECT item_id FROM item_versions WHERE item_version_id = ?;', + (self.id,) + ) + + rows = cursor.fetchall() + + if rows == []: + raise st.MissingItemError() + + (mapping_id,), = rows + + mapping_ref = ConcreteMappingRef(str(mapping_id), self.state) + + id_to_pass: t.Optional[str] = self.id + if enabled.value != 'E' or frozen is None or frozen.value == 'N': + id_to_pass = None + + mapping_ref.update_status(enabled, frozen, id_to_pass) + def get_all_version_display_infos(self) \ -> t.Sequence[st.MappingVersionDisplayInfo]: with self.state.cursor() as cursor: diff --git a/src/hydrilla/proxy/web_ui/items.py b/src/hydrilla/proxy/web_ui/items.py index 4bfae0a..01ae406 100644 --- a/src/hydrilla/proxy/web_ui/items.py +++ b/src/hydrilla/proxy/web_ui/items.py @@ -234,7 +234,19 @@ def alter_item_version(item_version_id: str, item_type: item_infos.ItemType) \ store = item_version_store(_app.get_haketilo_state(), item_type) item_version_ref = store.get(item_version_id) - if action == 'install_item_version': + if action == 'disable_item': + assert isinstance(item_version_ref, st.MappingVersionRef) + item_version_ref.update_mapping_status(st.EnabledStatus.DISABLED) + elif action == 'unenable_item': + assert isinstance(item_version_ref, st.MappingVersionRef) + item_version_ref.update_mapping_status(st.EnabledStatus.NO_MARK) + elif action == 'enable_item_version': + assert isinstance(item_version_ref, st.MappingVersionRef) + item_version_ref.update_mapping_status( + enabled = st.EnabledStatus.ENABLED, + frozen = st.FrozenStatus.EXACT_VERSION, + ) + elif action == 'install_item_version': item_version_ref.install() elif action == 'uninstall_item_version': item_version_ref_after = item_version_ref.uninstall() diff --git a/src/hydrilla/proxy/web_ui/templates/base.html.jinja b/src/hydrilla/proxy/web_ui/templates/base.html.jinja index 8b8be4b..9520787 100644 --- a/src/hydrilla/proxy/web_ui/templates/base.html.jinja +++ b/src/hydrilla/proxy/web_ui/templates/base.html.jinja @@ -19,6 +19,22 @@ file's licenses. Although I request that you do not make use this code in a proprietary work, I am not going to enforce this in court. -#} + +{% macro button_row(buttons_data) %} +
+ {% for classes, text, action in buttons_data %} + {% if 'disabled-button' in classes %} + + {% else %} +
+ + +
+ {% endif %} + {% endfor %} +
+{% endmacro %} + {% block head %} @@ -88,7 +104,7 @@ in a proprietary work, I am not going to enforce this in court. background-color: #af504c; } - .red-button { + .blue-button { background-color: #504caf; } diff --git a/src/hydrilla/proxy/web_ui/templates/items/item_viewversion.html.jinja b/src/hydrilla/proxy/web_ui/templates/items/item_viewversion.html.jinja index 151a8b3..54cb3cf 100644 --- a/src/hydrilla/proxy/web_ui/templates/items/item_viewversion.html.jinja +++ b/src/hydrilla/proxy/web_ui/templates/items/item_viewversion.html.jinja @@ -46,6 +46,15 @@ in a proprietary work, I am not going to enforce this in court. TODO: add more info... {% endblock %} + {% if display_info.active == ActiveStatus.REQUIRED %} +
{% block item_required_msg required %}{% endblock %}
+ {% elif display_info.active == ActiveStatus.AUTO %} +
{% block item_auto_activated_msg required %}{% endblock %}
+ {% else %} + {# display_info.active == ActiveStatus.NOT_ACTIVE #} +
{% block item_not_activated_msg required %}{% endblock %}
+ {% endif %} + {% set install_but_classes = ['green-button', 'button-bordering-left'] %} {% set uninstall_but_classes = ['green-button', 'button-bordering-right'] %} {% if display_info.installed == InstalledStatus.FAILED_TO_INSTALL %} @@ -57,7 +66,7 @@ in a proprietary work, I am not going to enforce this in court. set uninstall_text = _('web_ui.items.single_version.leave_uninstalled_button') %} -
{% block item_install_failed_msg %}{% endblock %}
+
{% block item_install_failed_msg required %}{% endblock %}
{% else %} {% set install_text = _('web_ui.items.single_version.install_button') %} {% set uninstall_text = _('web_ui.items.single_version.uninstall_button') %} @@ -74,21 +83,10 @@ in a proprietary work, I am not going to enforce this in court. {% do uninstall_but_classes.append('disabled-button') %} {% endif %} {% endif %}{# else/ display_info.installed == InstalledStatus.FAILED_TO_I...#} -
- {% - for classes, text, action in [ - (uninstall_but_classes, uninstall_text, 'uninstall_item_version'), - (install_but_classes, install_text, 'install_item_version') - ] - %} - {% if 'disabled-button' in classes %} - - {% else %} -
- - -
- {% endif %} - {% endfor %} -
+ {{ + button_row([ + (uninstall_but_classes, uninstall_text, 'uninstall_item_version'), + (install_but_classes, install_text, 'install_item_version') + ]) + }} {% endblock main_info %} diff --git a/src/hydrilla/proxy/web_ui/templates/items/library_viewversion.html.jinja b/src/hydrilla/proxy/web_ui/templates/items/library_viewversion.html.jinja index 2176646..30e084d 100644 --- a/src/hydrilla/proxy/web_ui/templates/items/library_viewversion.html.jinja +++ b/src/hydrilla/proxy/web_ui/templates/items/library_viewversion.html.jinja @@ -19,18 +19,34 @@ file's licenses. Although I request that you do not make use this code in a proprietary work, I am not going to enforce this in court. #} {% extends "items/item_viewversion.html.jinja" %} + {% block title %} {{ _('web_ui.items.single_version.library.title') }} {% endblock %} + {% block heading %} {{ _('web_ui.items.single_version.library.heading.name_{}') .format(display_info.info.long_name) }} {% endblock %} + +{% block item_required_msg %} + {{ _('web_ui.items.single_version.library.item_required') }} +{% endblock %} + +{% block item_auto_activated_msg %} + {{ _('web_ui.items.single_version.library.item_auto_activated') }} +{% endblock %} + +{% block item_not_activated_msg %} + {{ _('web_ui.items.single_version.library.item_not_activated') }} +{% endblock %} + {% block item_install_failed_msg %} {{ _('web_ui.items.single_version.library.install_failed') }} {% endblock %} + {% block version_list_heading %} {{ _('web_ui.items.single_version.library.version_list_heading') }} {% endblock %} diff --git a/src/hydrilla/proxy/web_ui/templates/items/package_viewversion.html.jinja b/src/hydrilla/proxy/web_ui/templates/items/package_viewversion.html.jinja index 6671747..a532b5f 100644 --- a/src/hydrilla/proxy/web_ui/templates/items/package_viewversion.html.jinja +++ b/src/hydrilla/proxy/web_ui/templates/items/package_viewversion.html.jinja @@ -19,18 +19,82 @@ file's licenses. Although I request that you do not make use this code in a proprietary work, I am not going to enforce this in court. #} {% extends "items/item_viewversion.html.jinja" %} + {% block title %} {{ _('web_ui.items.single_version.package.title') }} {% endblock %} + {% block heading %} {{ _('web_ui.items.single_version.package.heading.name_{}') .format(display_info.info.long_name) }} {% endblock %} + +{% block item_required_msg %} + {{ _('web_ui.items.single_version.package.item_required') }} +{% endblock %} + +{% block item_auto_activated_msg %} + {{ _('web_ui.items.single_version.package.item_auto_activated') }} +{% endblock %} + +{% block item_not_activated_msg %} + {{ _('web_ui.items.single_version.package.item_not_activated') }} +{% endblock %} + {% block item_install_failed_msg %} {{ _('web_ui.items.single_version.package.install_failed') }} {% endblock %} + {% block version_list_heading %} {{ _('web_ui.items.single_version.package.version_list_heading') }} {% endblock %} + +{% block main_info_bulk %} + TODO: add more info... + + {% set enable_but_classes = ['blue-button', 'button-bordering-left'] %} + {% + set unenable_but_classes = [ + 'green-button', + 'button-bordering-right', + 'button-bordering-left' + ] + %} + {% set disable_but_classes = ['red-button', 'button-bordering-right'] %} + + {% set unenable_text = _('web_ui.items.single_version.unenable_button') %} + {% set disable_text = _('web_ui.items.single_version.disable_button') %} + {% + if display_info.mapping_enabled == EnabledStatus.ENABLED and + display_info.active == ActiveStatus.NOT_ACTIVE + %} + {% + set enable_text = + _('web_ui.items.single_version.freeze_to_this_button') + %} + {% else %} + {% set enable_text = _('web_ui.items.single_version.enable_button') %} + {% endif %} + + {% if display_info.mapping_enabled == EnabledStatus.NO_MARK %} + {% do unenable_but_classes.append('disabled-button') %} + {% elif display_info.mapping_enabled == EnabledStatus.DISABLED %} + {% do disable_but_classes.append('disabled-button') %} + {% else %} + {% if display_info.active == ActiveStatus.REQUIRED %} + {% do enable_but_classes.append('disabled-button') %} + {% else %} +
{{ _('web_ui.items.single_version.other_version_enabled') }}
+ {% endif %} + {% endif %} + + {{ + button_row([ + (disable_but_classes, disable_text, 'disable_item'), + (unenable_but_classes, unenable_text, 'unenable_item'), + (enable_but_classes, enable_text, 'enable_item_version') + ]) + }} +{% endblock main_info_bulk %} -- cgit v1.2.3