feat(footer): help popover shows license state + Activate link

- Bump version to 3.0 (src/__init__.py).
- Switch support address to support@unalogix.com.
- Help popover now includes a License section that reads
  ``src.license.current_state()``:
  * When activated + valid: name + expiry date + days remaining.
  * Otherwise: "Not activated" + an ``Activate now →`` link
    pointing at ``./activate``.
  License-state queries are wrapped so a corrupted license file
  can't take the footer down — it falls through to the inactive
  branch.
- Popover HTML is now built in Python (so the license branch
  lives in one place) and passed to the JS as a single string.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-18 15:35:47 +00:00
parent dd231f5a38
commit 9e8b4b2ca9
4 changed files with 71 additions and 17 deletions

View File

@@ -5,4 +5,4 @@ the Windows Inno Setup script, the macOS DMG packaging script, and
the AppImage build. Bump here on release and CI propagates it. the AppImage build. Bump here on release and CI propagates it.
""" """
__version__ = "1.0.0" __version__ = "3.0"

View File

@@ -565,12 +565,58 @@ def render_sticky_footer() -> None:
help_version = _html.escape( help_version = _html.escape(
_t("footer.help_version").format(version=__version__) _t("footer.help_version").format(version=__version__)
) )
support_email = "support@datatools.app" support_email = "support@unalogix.com"
help_support = _html.escape( help_support_text = _t("footer.help_support").format(email=support_email)
_t("footer.help_support").format(email=support_email) help_support_html = _html.escape(help_support_text).replace(
_html.escape(support_email),
f'<a href="mailto:{_html.escape(support_email)}">'
f'{_html.escape(support_email)}</a>',
) )
license_label = _html.escape(_t("footer.help_license_label"))
help_dismiss = _html.escape(_t("footer.help_dismiss")) help_dismiss = _html.escape(_t("footer.help_dismiss"))
# License section — read state and branch on activated/valid. The
# query is wrapped because a corrupted license file MUST NOT stop
# the footer from rendering; in that case we fall back to the
# "ask to activate" branch.
try:
from src.license import current_state as _license_state
state = _license_state()
except Exception:
state = None
if state is not None and state.activated and state.valid:
active_line = _t("footer.help_license_active").format(
name=state.name or state.email or "",
)
expires_line = _t("footer.help_license_expires").format(
date=(state.expires_at or "")[:10],
days=state.days_remaining,
)
license_html = (
f'<div class="dt-help-row"><span class="dt-help-key">'
f'{license_label}:</span> {_html.escape(active_line)}</div>'
f'<div class="dt-help-row dt-help-sub">'
f'{_html.escape(expires_line)}</div>'
)
else:
inactive_line = _html.escape(_t("footer.help_license_inactive"))
activate_link = _html.escape(_t("footer.help_activate_link"))
license_html = (
f'<div class="dt-help-row"><span class="dt-help-key">'
f'{license_label}:</span> {inactive_line}</div>'
f'<div class="dt-help-row">'
f'<a href="./activate" target="_self">{activate_link}</a></div>'
)
popover_html = (
f'<div class="dt-help-title">{help_title}</div>'
f'<div class="dt-help-row">{help_version}</div>'
f'{license_html}'
f'<div class="dt-help-row">{help_support_html}</div>'
f'<button type="button" class="dt-help-dismiss">{help_dismiss}</button>'
)
st.markdown( st.markdown(
""" """
<style> <style>
@@ -646,6 +692,15 @@ def render_sticky_footer() -> None:
margin: 0.15rem 0 !important; margin: 0.15rem 0 !important;
line-height: 1.4 !important; line-height: 1.4 !important;
} }
#datatools-help-popover .dt-help-row.dt-help-sub {
color: rgb(90, 95, 110) !important;
font-size: 12px !important;
margin-left: 0.65rem !important;
}
#datatools-help-popover .dt-help-key {
color: rgb(90, 95, 110) !important;
font-weight: 500 !important;
}
#datatools-help-popover .dt-help-row a { #datatools-help-popover .dt-help-row a {
color: rgb(0, 102, 204) !important; color: rgb(0, 102, 204) !important;
text-decoration: none !important; text-decoration: none !important;
@@ -678,11 +733,7 @@ def render_sticky_footer() -> None:
var labels = {_json.dumps({ var labels = {_json.dumps({
"close": close_label, "close": close_label,
"help": help_label, "help": help_label,
"help_title": help_title, "popover_html": popover_html,
"help_version": help_version,
"help_support": help_support,
"help_dismiss": help_dismiss,
"support_email": support_email,
})}; })};
function build(doc) {{ function build(doc) {{
var prev = doc.getElementById('datatools-sticky-footer'); var prev = doc.getElementById('datatools-sticky-footer');
@@ -710,14 +761,7 @@ def render_sticky_footer() -> None:
var pop = doc.createElement('div'); var pop = doc.createElement('div');
pop.id = 'datatools-help-popover'; pop.id = 'datatools-help-popover';
pop.hidden = true; pop.hidden = true;
pop.innerHTML = pop.innerHTML = labels.popover_html;
'<div class="dt-help-title">' + labels.help_title + '</div>' +
'<div class="dt-help-row">' + labels.help_version + '</div>' +
'<div class="dt-help-row">' + labels.help_support.replace(
labels.support_email,
'<a href="mailto:' + labels.support_email + '">' + labels.support_email + '</a>'
) + '</div>' +
'<button type="button" class="dt-help-dismiss">' + labels.help_dismiss + '</button>';
helpBtn.addEventListener('click', function (e) {{ helpBtn.addEventListener('click', function (e) {{
e.preventDefault(); e.preventDefault();

View File

@@ -178,6 +178,11 @@
"help_title": "DataTools", "help_title": "DataTools",
"help_version": "Version {version}", "help_version": "Version {version}",
"help_support": "Support: {email}", "help_support": "Support: {email}",
"help_license_label": "License",
"help_license_inactive": "Not activated",
"help_license_active": "{name}",
"help_license_expires": "Expires {date} ({days} days)",
"help_activate_link": "Activate now →",
"help_dismiss": "Close" "help_dismiss": "Close"
} }
} }

View File

@@ -178,6 +178,11 @@
"help_title": "DataTools", "help_title": "DataTools",
"help_version": "Versión {version}", "help_version": "Versión {version}",
"help_support": "Soporte: {email}", "help_support": "Soporte: {email}",
"help_license_label": "Licencia",
"help_license_inactive": "No activada",
"help_license_active": "{name}",
"help_license_expires": "Caduca {date} ({days} días)",
"help_activate_link": "Activar ahora →",
"help_dismiss": "Cerrar" "help_dismiss": "Cerrar"
} }
} }