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:
@@ -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"
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user