Compare commits

...

2 Commits

Author SHA1 Message Date
dgtlmoon
1eadc8e398 test tweak 2026-01-17 18:11:37 +01:00
dgtlmoon
f9f7f103f0 UI - Global "mute" and "pause" buttons on main menu, move "Backups" to "Settings" 2026-01-17 18:00:19 +01:00
32 changed files with 99 additions and 34 deletions

View File

@@ -287,7 +287,9 @@ def main():
return dict(right_sticky="v{}".format(datastore.data['version_tag']), return dict(right_sticky="v{}".format(datastore.data['version_tag']),
new_version_available=app.config['NEW_VERSION_AVAILABLE'], new_version_available=app.config['NEW_VERSION_AVAILABLE'],
has_password=datastore.data['settings']['application']['password'] != False, has_password=datastore.data['settings']['application']['password'] != False,
socket_io_enabled=datastore.data['settings']['application']['ui'].get('socket_io_enabled', True) socket_io_enabled=datastore.data['settings']['application']['ui'].get('socket_io_enabled', True),
all_paused=datastore.data['settings']['application'].get('all_paused', False),
all_muted=datastore.data['settings']['application'].get('all_muted', False)
) )
# Monitored websites will not receive a Referer header when a user clicks on an outgoing link. # Monitored websites will not receive a Referer header when a user clicks on an outgoing link.

View File

@@ -193,4 +193,32 @@ def construct_blueprint(datastore: ChangeDetectionStore):
logs=notification_debug_log if len(notification_debug_log) else ["Notification logs are empty - no notifications sent yet."]) logs=notification_debug_log if len(notification_debug_log) else ["Notification logs are empty - no notifications sent yet."])
return output return output
@settings_blueprint.route("/toggle-all-paused", methods=['GET'])
@login_optionally_required
def toggle_all_paused():
current_state = datastore.data['settings']['application'].get('all_paused', False)
datastore.data['settings']['application']['all_paused'] = not current_state
datastore.needs_write_urgent = True
if datastore.data['settings']['application']['all_paused']:
flash(gettext("Automatic scheduling paused - checks will not be queued."), 'notice')
else:
flash(gettext("Automatic scheduling resumed - checks will be queued normally."), 'notice')
return redirect(url_for('watchlist.index'))
@settings_blueprint.route("/toggle-all-muted", methods=['GET'])
@login_optionally_required
def toggle_all_muted():
current_state = datastore.data['settings']['application'].get('all_muted', False)
datastore.data['settings']['application']['all_muted'] = not current_state
datastore.needs_write_urgent = True
if datastore.data['settings']['application']['all_muted']:
flash(gettext("All notifications muted."), 'notice')
else:
flash(gettext("All notifications unmuted."), 'notice')
return redirect(url_for('watchlist.index'))
return settings_blueprint return settings_blueprint

View File

@@ -25,6 +25,9 @@
<li class="tab"><a href="#ui-options">{{ _('UI Options') }}</a></li> <li class="tab"><a href="#ui-options">{{ _('UI Options') }}</a></li>
<li class="tab"><a href="#api">{{ _('API') }}</a></li> <li class="tab"><a href="#api">{{ _('API') }}</a></li>
<li class="tab"><a href="#rss">{{ _('RSS') }}</a></li> <li class="tab"><a href="#rss">{{ _('RSS') }}</a></li>
<li class="pure-menu-item menu-collapsible {% if request.endpoint.startswith('backups.') %}active{% endif %}">
<a href="{{ url_for('backups.index') }}" class="pure-menu-link">{{ _('Backups') }}</a>
</li>
<li class="tab"><a href="#timedate">{{ _('Time & Date') }}</a></li> <li class="tab"><a href="#timedate">{{ _('Time & Date') }}</a></li>
<li class="tab"><a href="#proxies">{{ _('CAPTCHA & Proxies') }}</a></li> <li class="tab"><a href="#proxies">{{ _('CAPTCHA & Proxies') }}</a></li>
{% if plugin_tabs %} {% if plugin_tabs %}

View File

@@ -374,6 +374,9 @@ def changedetection_app(config=None, datastore_o=None):
global datastore, socketio_server global datastore, socketio_server
datastore = datastore_o datastore = datastore_o
# Set datastore reference in notification queue for all_muted checking
notification_q.set_datastore(datastore)
# Import and create a wrapper for is_safe_url that has access to app # Import and create a wrapper for is_safe_url that has access to app
from changedetectionio.is_safe_url import is_safe_url as _is_safe_url from changedetectionio.is_safe_url import is_safe_url as _is_safe_url
@@ -999,9 +1002,14 @@ def ticker_thread_check_time_launch_checks():
if health_result['status'] != 'healthy': if health_result['status'] != 'healthy':
logger.warning(f"Worker health check: {health_result['message']}") logger.warning(f"Worker health check: {health_result['message']}")
last_health_check = now last_health_check = now
# Check if all checks are paused
if datastore.data['settings']['application'].get('all_paused', False):
app.config.exit.wait(1)
continue
# Get a list of watches by UUID that are currently fetching data # Get a list of watches by UUID that are currently fetching data
running_uuids = worker_handler.get_running_uuids() running_uuids = worker_handler.get_running_uuids()

View File

@@ -37,6 +37,8 @@ class model(dict):
}, },
'application': { 'application': {
# Custom notification content # Custom notification content
'all_paused': False,
'all_muted': False,
'api_access_token_enabled': True, 'api_access_token_enabled': True,
'base_url' : None, 'base_url' : None,
'empty_pages_are_a_change': False, 'empty_pages_are_a_change': False,

View File

@@ -361,21 +361,31 @@ class NotificationQueue:
Simple wrapper around janus with bulletproof error handling. Simple wrapper around janus with bulletproof error handling.
""" """
def __init__(self, maxsize: int = 0): def __init__(self, maxsize: int = 0, datastore=None):
try: try:
self._janus_queue = janus.Queue(maxsize=maxsize) self._janus_queue = janus.Queue(maxsize=maxsize)
# BOTH interfaces required - see class docstring for why # BOTH interfaces required - see class docstring for why
self.sync_q = self._janus_queue.sync_q # Flask routes, threads self.sync_q = self._janus_queue.sync_q # Flask routes, threads
self.async_q = self._janus_queue.async_q # Async workers self.async_q = self._janus_queue.async_q # Async workers
self.notification_event_signal = signal('notification_event') self.notification_event_signal = signal('notification_event')
self.datastore = datastore # For checking all_muted setting
logger.debug("NotificationQueue initialized successfully") logger.debug("NotificationQueue initialized successfully")
except Exception as e: except Exception as e:
logger.critical(f"CRITICAL: Failed to initialize NotificationQueue: {str(e)}") logger.critical(f"CRITICAL: Failed to initialize NotificationQueue: {str(e)}")
raise raise
def set_datastore(self, datastore):
"""Set datastore reference after initialization (for circular dependency handling)"""
self.datastore = datastore
def put(self, item: Dict[str, Any], block: bool = True, timeout: Optional[float] = None): def put(self, item: Dict[str, Any], block: bool = True, timeout: Optional[float] = None):
"""Thread-safe sync put with signal emission""" """Thread-safe sync put with signal emission"""
try: try:
# Check if all notifications are muted
if self.datastore and self.datastore.data['settings']['application'].get('all_muted', False):
logger.debug(f"Notification blocked - all notifications are muted: {item.get('uuid', 'unknown')}")
return False
self.sync_q.put(item, block=block, timeout=timeout) self.sync_q.put(item, block=block, timeout=timeout)
self._emit_notification_signal(item) self._emit_notification_signal(item)
logger.debug(f"Successfully queued notification: {item.get('uuid', 'unknown')}") logger.debug(f"Successfully queued notification: {item.get('uuid', 'unknown')}")
@@ -387,6 +397,11 @@ class NotificationQueue:
async def async_put(self, item: Dict[str, Any]): async def async_put(self, item: Dict[str, Any]):
"""Pure async put with signal emission""" """Pure async put with signal emission"""
try: try:
# Check if all notifications are muted
if self.datastore and self.datastore.data['settings']['application'].get('all_muted', False):
logger.debug(f"Notification blocked - all notifications are muted: {item.get('uuid', 'unknown')}")
return False
await self.async_q.put(item) await self.async_q.put(item)
self._emit_notification_signal(item) self._emit_notification_signal(item)
logger.debug(f"Successfully async queued notification: {item.get('uuid', 'unknown')}") logger.debug(f"Successfully async queued notification: {item.get('uuid', 'unknown')}")

View File

@@ -1 +1 @@
.comparison-score{padding:1em;background:var(--color-table-stripe);border-radius:4px;margin:1em 0;border:1px solid var(--color-border-table-cell);color:var(--color-text)}.change-detected{color:#d32f2f;font-weight:bold}.no-change{color:#388e3c;font-weight:bold}.comparison-grid{display:grid;grid-template-columns:1fr 1fr;gap:1em;margin:1em 1em}@media(max-width: 1200px){.comparison-grid{grid-template-columns:1fr}}.image-comparison{position:relative;width:100%;overflow:hidden;border:1px solid var(--color-border-table-cell);box-shadow:0 2px 4px rgba(0, 0, 0, 0.1);user-select:none}.image-comparison img{display:block;width:100%;height:auto;max-width:100%;border:none;box-shadow:none}.comparison-image-wrapper{position:relative;width:100%;display:flex;align-items:flex-start;justify-content:center;background-color:var(--color-background);background-image:linear-gradient(45deg, var(--color-table-stripe) 25%, transparent 25%),linear-gradient(-45deg, var(--color-table-stripe) 25%, transparent 25%),linear-gradient(45deg, transparent 75%, var(--color-table-stripe) 75%),linear-gradient(-45deg, transparent 75%, var(--color-table-stripe) 75%);background-size:20px 20px;background-position:0 0,0 10px,10px -10px,-10px 0px}.comparison-after{position:absolute;top:0;left:0;width:100%;height:100%;clip-path:inset(0 0 0 50%)}.comparison-slider{position:absolute;top:0;left:50%;width:4px;height:100%;background:#0078e7;cursor:ew-resize;transform:translateX(-2px);z-index:10}.comparison-handle{position:absolute;top:50%;left:50%;width:48px;height:48px;background:#0078e7;border:3px solid #fff;border-radius:50%;transform:translate(-50%, -50%);box-shadow:0 2px 8px rgba(0, 0, 0, 0.3);display:flex;align-items:center;justify-content:center;cursor:ew-resize;transition:top .1s ease-out}.comparison-handle::after{content:"⇄";color:#fff;font-size:24px;font-weight:bold;pointer-events:none}.comparison-labels{position:absolute;top:10px;width:100%;display:flex;justify-content:space-between;padding:0 0px;z-index:5;pointer-events:none}.comparison-label{background:rgba(0, 0, 0, 0.7);color:#fff;padding:.5em 1em;border-radius:4px;font-size:.9em;font-weight:bold}.screenshot-panel{text-align:center;background:var(--color-background);border:1px solid var(--color-border-table-cell);border-radius:4px;padding:1em;box-shadow:0 2px 4px rgba(0, 0, 0, 0.05)}.screenshot-panel h3{margin:0 0 1em 0;font-size:1.1em;color:var(--color-text);border-bottom:2px solid var(--color-background-button-primary);padding-bottom:.5em}.screenshot-panel.diff h3{border-bottom-color:#d32f2f}.screenshot-panel img{max-width:100%;height:auto;border:1px solid var(--color-border-table-cell);box-shadow:0 2px 4px rgba(0, 0, 0, 0.1)}.version-selector{display:inline-block;margin:0 .5em}.version-selector label{font-weight:bold;margin-right:.5em;color:var(--color-text)}#settings{background:var(--color-background);padding:1.5em;border-radius:4px;box-shadow:0 2px 4px rgba(0, 0, 0, 0.05);margin-bottom:2em;border:1px solid var(--color-border-table-cell)}#settings h2{margin-top:0;color:var(--color-text)}.diff-fieldset{border:none;padding:0;margin:0}.edit-link{float:right;margin-top:-0.5em}.comparison-description{color:var(--color-text-input-description);font-size:.9em;margin-bottom:1em}.download-link{color:var(--color-link);text-decoration:none;display:inline-flex;align-items:center;gap:.3em;font-size:.85em}.download-link:hover{text-decoration:underline}.diff-section-header{color:#d32f2f;font-size:.9em;margin-bottom:1em;font-weight:bold;display:flex;align-items:center;justify-content:center;gap:1em}.comparison-history-section{margin-top:3em;padding:1em;background:var(--color-background);border:1px solid var(--color-border-table-cell);border-radius:4px;box-shadow:0 2px 4px rgba(0, 0, 0, 0.05)}.comparison-history-section h3{color:var(--color-text)}.comparison-history-section p{color:var(--color-text-input-description);font-size:.9em}.history-changed-yes{color:#d32f2f;font-weight:bold}.history-changed-no{color:#388e3c} .comparison-score{padding:1em;background:var(--color-table-stripe);border-radius:4px;margin:1em 0;border:1px solid var(--color-border-table-cell);color:var(--color-text)}.change-detected{color:#d32f2f;font-weight:bold}.no-change{color:#388e3c;font-weight:bold}.comparison-grid{display:grid;grid-template-columns:1fr 1fr;gap:1em;margin:1em 1em}@media(max-width: 1200px){.comparison-grid{grid-template-columns:1fr}}.image-comparison{position:relative;width:100%;overflow:hidden;border:1px solid var(--color-border-table-cell);box-shadow:0 2px 4px rgba(0,0,0,.1);user-select:none}.image-comparison img{display:block;width:100%;height:auto;max-width:100%;border:none;box-shadow:none}.comparison-image-wrapper{position:relative;width:100%;display:flex;align-items:flex-start;justify-content:center;background-color:var(--color-background);background-image:linear-gradient(45deg, var(--color-table-stripe) 25%, transparent 25%),linear-gradient(-45deg, var(--color-table-stripe) 25%, transparent 25%),linear-gradient(45deg, transparent 75%, var(--color-table-stripe) 75%),linear-gradient(-45deg, transparent 75%, var(--color-table-stripe) 75%);background-size:20px 20px;background-position:0 0,0 10px,10px -10px,-10px 0px}.comparison-after{position:absolute;top:0;left:0;width:100%;height:100%;clip-path:inset(0 0 0 50%)}.comparison-slider{position:absolute;top:0;left:50%;width:4px;height:100%;background:#0078e7;cursor:ew-resize;transform:translateX(-2px);z-index:10}.comparison-handle{position:absolute;top:50%;left:50%;width:48px;height:48px;background:#0078e7;border:3px solid #fff;border-radius:50%;transform:translate(-50%, -50%);box-shadow:0 2px 8px rgba(0,0,0,.3);display:flex;align-items:center;justify-content:center;cursor:ew-resize;transition:top .1s ease-out}.comparison-handle::after{content:"⇄";color:#fff;font-size:24px;font-weight:bold;pointer-events:none}.comparison-labels{position:absolute;top:10px;width:100%;display:flex;justify-content:space-between;padding:0 0px;z-index:5;pointer-events:none}.comparison-label{background:rgba(0,0,0,.7);color:#fff;padding:.5em 1em;border-radius:4px;font-size:.9em;font-weight:bold}.screenshot-panel{text-align:center;background:var(--color-background);border:1px solid var(--color-border-table-cell);border-radius:4px;padding:1em;box-shadow:0 2px 4px rgba(0,0,0,.05)}.screenshot-panel h3{margin:0 0 1em 0;font-size:1.1em;color:var(--color-text);border-bottom:2px solid var(--color-background-button-primary);padding-bottom:.5em}.screenshot-panel.diff h3{border-bottom-color:#d32f2f}.screenshot-panel img{max-width:100%;height:auto;border:1px solid var(--color-border-table-cell);box-shadow:0 2px 4px rgba(0,0,0,.1)}.version-selector{display:inline-block;margin:0 .5em}.version-selector label{font-weight:bold;margin-right:.5em;color:var(--color-text)}#settings{background:var(--color-background);padding:1.5em;border-radius:4px;box-shadow:0 2px 4px rgba(0,0,0,.05);margin-bottom:2em;border:1px solid var(--color-border-table-cell)}#settings h2{margin-top:0;color:var(--color-text)}.diff-fieldset{border:none;padding:0;margin:0}.edit-link{float:right;margin-top:-0.5em}.comparison-description{color:var(--color-text-input-description);font-size:.9em;margin-bottom:1em}.download-link{color:var(--color-link);text-decoration:none;display:inline-flex;align-items:center;gap:.3em;font-size:.85em}.download-link:hover{text-decoration:underline}.diff-section-header{color:#d32f2f;font-size:.9em;margin-bottom:1em;font-weight:bold;display:flex;align-items:center;justify-content:center;gap:1em}.comparison-history-section{margin-top:3em;padding:1em;background:var(--color-background);border:1px solid var(--color-border-table-cell);border-radius:4px;box-shadow:0 2px 4px rgba(0,0,0,.05)}.comparison-history-section h3{color:var(--color-text)}.comparison-history-section p{color:var(--color-text-input-description);font-size:.9em}.history-changed-yes{color:#d32f2f;font-weight:bold}.history-changed-no{color:#388e3c}

View File

@@ -1 +1 @@
#diff-form{background:rgba(0, 0, 0, 0.05);padding:1em;border-radius:10px;margin-bottom:1em;color:#fff;font-size:.9rem;text-align:center}#diff-form label.from-to-label{width:4rem;text-decoration:none;padding:.5rem}#diff-form label.from-to-label#change-from{color:#b30000;background:#fadad7}#diff-form label.from-to-label#change-to{background:#eaf2c2;color:#406619}#diff-form #diff-style>span{display:inline-block;padding:.3em}#diff-form #diff-style>span label{font-weight:normal}#diff-form *{vertical-align:middle}body.difference-page section.content{padding-top:40px}#diff-ui{background:var(--color-background);padding:1rem;border-radius:5px}@media(min-width: 767px){#diff-ui{min-width:50%}}#diff-ui #text{font-size:11px}#diff-ui pre{white-space:break-spaces}#diff-ui h1{display:inline;font-size:100%}#diff-ui #result{white-space:pre-wrap;word-break:break-word;overflow-wrap:break-word}#diff-ui .source{position:absolute;right:1%;top:.2em}@-moz-document url-prefix(){#diff-ui body{height:99%}}#diff-ui td#diff-col div{text-align:justify;white-space:pre-wrap}#diff-ui .ignored{background-color:#ccc;opacity:.7}#diff-ui .triggered{background-color:#1b98f8}#diff-ui .ignored.triggered{background-color:red}#diff-ui .tab-pane-inner#screenshot{text-align:center}#diff-ui .tab-pane-inner#screenshot img{max-width:99%}#diff-ui .pure-form button.reset-margin{margin:0px}#diff-ui .diff-fieldset{display:flex;align-items:center;gap:4px;flex-wrap:wrap}#diff-ui ul#highlightSnippetActions{list-style-type:none;display:flex;align-items:center;justify-content:center;gap:1.5rem;flex-wrap:wrap;padding:0;margin:0}#diff-ui ul#highlightSnippetActions li{display:flex;flex-direction:column;align-items:center;text-align:center;padding:.5rem;gap:.3rem}#diff-ui ul#highlightSnippetActions li button,#diff-ui ul#highlightSnippetActions li a{white-space:nowrap}#diff-ui ul#highlightSnippetActions span{font-size:.8rem;color:var(--color-text-input-description)}#diff-ui #cell-diff-jump-visualiser{display:flex;flex-direction:row;gap:1px;background:var(--color-background);border-radius:3px;overflow-x:hidden;position:sticky;top:0;z-index:10;padding-top:1rem;padding-bottom:1rem;justify-content:center}#diff-ui #cell-diff-jump-visualiser>div{flex:1;min-width:1px;max-width:10px;height:10px;background:var(--color-background-button-cancel);opacity:.3;border-radius:1px;transition:opacity .2s;position:relative}#diff-ui #cell-diff-jump-visualiser>div.deletion{background:#b30000;opacity:1}#diff-ui #cell-diff-jump-visualiser>div.insertion{background:#406619;opacity:1}#diff-ui #cell-diff-jump-visualiser>div.note{background:#406619;opacity:1}#diff-ui #cell-diff-jump-visualiser>div.mixed{background:linear-gradient(to right, #b30000 50%, #406619 50%);opacity:1}#diff-ui #cell-diff-jump-visualiser>div.current-position::after{content:"";position:absolute;bottom:-6px;left:50%;transform:translateX(-50%);width:0;height:0;border-left:4px solid rgba(0, 0, 0, 0);border-right:4px solid rgba(0, 0, 0, 0);border-bottom:4px solid var(--color-text)}#diff-ui #cell-diff-jump-visualiser>div:hover{opacity:.8;cursor:pointer}#text-diff-heading-area .snapshot-age{padding:4px;margin:.5rem 0;background-color:var(--color-background-snapshot-age);border-radius:3px;font-weight:bold;margin-bottom:4px}#text-diff-heading-area .snapshot-age.error{background-color:var(--color-error-background-snapshot-age);color:var(--color-error-text-snapshot-age)}#text-diff-heading-area .snapshot-age>*{padding-right:1rem} #diff-form{background:rgba(0,0,0,.05);padding:1em;border-radius:10px;margin-bottom:1em;color:#fff;font-size:.9rem;text-align:center}#diff-form label.from-to-label{width:4rem;text-decoration:none;padding:.5rem}#diff-form label.from-to-label#change-from{color:#b30000;background:#fadad7}#diff-form label.from-to-label#change-to{background:#eaf2c2;color:#406619}#diff-form #diff-style>span{display:inline-block;padding:.3em}#diff-form #diff-style>span label{font-weight:normal}#diff-form *{vertical-align:middle}body.difference-page section.content{padding-top:40px}#diff-ui{background:var(--color-background);padding:1rem;border-radius:5px}@media(min-width: 767px){#diff-ui{min-width:50%}}#diff-ui #text{font-size:11px}#diff-ui pre{white-space:break-spaces}#diff-ui h1{display:inline;font-size:100%}#diff-ui #result{white-space:pre-wrap;word-break:break-word;overflow-wrap:break-word}#diff-ui .source{position:absolute;right:1%;top:.2em}@-moz-document url-prefix(){#diff-ui body{height:99%}}#diff-ui td#diff-col div{text-align:justify;white-space:pre-wrap}#diff-ui .ignored{background-color:#ccc;opacity:.7}#diff-ui .triggered{background-color:#1b98f8}#diff-ui .ignored.triggered{background-color:red}#diff-ui .tab-pane-inner#screenshot{text-align:center}#diff-ui .tab-pane-inner#screenshot img{max-width:99%}#diff-ui .pure-form button.reset-margin{margin:0px}#diff-ui .diff-fieldset{display:flex;align-items:center;gap:4px;flex-wrap:wrap}#diff-ui ul#highlightSnippetActions{list-style-type:none;display:flex;align-items:center;justify-content:center;gap:1.5rem;flex-wrap:wrap;padding:0;margin:0}#diff-ui ul#highlightSnippetActions li{display:flex;flex-direction:column;align-items:center;text-align:center;padding:.5rem;gap:.3rem}#diff-ui ul#highlightSnippetActions li button,#diff-ui ul#highlightSnippetActions li a{white-space:nowrap}#diff-ui ul#highlightSnippetActions span{font-size:.8rem;color:var(--color-text-input-description)}#diff-ui #cell-diff-jump-visualiser{display:flex;flex-direction:row;gap:1px;background:var(--color-background);border-radius:3px;overflow-x:hidden;position:sticky;top:0;z-index:10;padding-top:1rem;padding-bottom:1rem;justify-content:center}#diff-ui #cell-diff-jump-visualiser>div{flex:1;min-width:1px;max-width:10px;height:10px;background:var(--color-background-button-cancel);opacity:.3;border-radius:1px;transition:opacity .2s;position:relative}#diff-ui #cell-diff-jump-visualiser>div.deletion{background:#b30000;opacity:1}#diff-ui #cell-diff-jump-visualiser>div.insertion{background:#406619;opacity:1}#diff-ui #cell-diff-jump-visualiser>div.note{background:#406619;opacity:1}#diff-ui #cell-diff-jump-visualiser>div.mixed{background:linear-gradient(to right, #b30000 50%, #406619 50%);opacity:1}#diff-ui #cell-diff-jump-visualiser>div.current-position::after{content:"";position:absolute;bottom:-6px;left:50%;transform:translateX(-50%);width:0;height:0;border-left:4px solid rgba(0,0,0,0);border-right:4px solid rgba(0,0,0,0);border-bottom:4px solid var(--color-text)}#diff-ui #cell-diff-jump-visualiser>div:hover{opacity:.8;cursor:pointer}#text-diff-heading-area .snapshot-age{padding:4px;margin:.5rem 0;background-color:var(--color-background-snapshot-age);border-radius:3px;font-weight:bold;margin-bottom:4px}#text-diff-heading-area .snapshot-age.error{background-color:var(--color-error-background-snapshot-age);color:var(--color-error-text-snapshot-age)}#text-diff-heading-area .snapshot-age>*{padding-right:1rem}

View File

@@ -110,6 +110,9 @@
background: var(--color-background-menu-link-hover); background: var(--color-background-menu-link-hover);
} }
} }
&#menu-pause, &#menu-mute {
display: none;
}
} }
} }
} }

View File

@@ -2,6 +2,13 @@
padding: 0.5rem 1em; padding: 0.5rem 1em;
line-height: 1.2rem; line-height: 1.2rem;
} }
#menu-mute, #menu-pause {
padding-left: 0.3rem;
padding-right: 0.3rem;
img {
height: 1.2rem;
}
}
.pure-menu-item { .pure-menu-item {
svg { svg {

View File

@@ -184,24 +184,24 @@ html[data-darkmode=true] {
// Mobile adjustments // Mobile adjustments
@media only screen and (max-width: 768px) { @media only screen and (max-width: 768px) {
.toast-container { .toast-container {
left: 10px !important; left: 50% !important;
right: 10px !important; right: auto !important;
top: 10px !important; top: 80px !important;
transform: none !important; transform: translateX(-50%) !important;
align-items: stretch; align-items: center;
&.toast-bottom-right, &.toast-bottom-right,
&.toast-bottom-center, &.toast-bottom-center,
&.toast-bottom-left { &.toast-bottom-left {
top: auto !important; top: auto !important;
bottom: 10px !important; bottom: 80px !important;
} }
} }
.toast { .toast {
min-width: auto; min-width: auto;
max-width: none; max-width: none;
width: 100%; width: 80vw;
transform: translateY(-100px); transform: translateY(-100px);
&.toast-show { &.toast-show {

File diff suppressed because one or more lines are too long

View File

@@ -13,8 +13,11 @@
<li class="pure-menu-item menu-collapsible {% if request.endpoint.startswith('imports.') %}active{% endif %}"> <li class="pure-menu-item menu-collapsible {% if request.endpoint.startswith('imports.') %}active{% endif %}">
<a href="{{ url_for('imports.import_page') }}" class="pure-menu-link">{{ _('IMPORT') }}</a> <a href="{{ url_for('imports.import_page') }}" class="pure-menu-link">{{ _('IMPORT') }}</a>
</li> </li>
<li class="pure-menu-item menu-collapsible {% if request.endpoint.startswith('backups.') %}active{% endif %}"> <li class="pure-menu-item" id="menu-pause">
<a href="{{ url_for('backups.index') }}" class="pure-menu-link">{{ _('BACKUPS') }}</a> <a href="{{ url_for('settings.toggle_all_paused') }}" ><img src="{{url_for('static_content', group='images', filename='pause.svg')}}" alt="{% if all_paused %}Resume automatic scheduling{% else %}Pause auto-queue scheduling of watches{% endif %}" title="{% if all_paused %}Scheduling is paused - click to resume{% else %}Pause auto-queue scheduling of watches{% endif %}" class="icon icon-pause"{% if not all_paused %} style="opacity: 0.3"{% endif %}></a>
</li>
<li class="pure-menu-item " id="menu-mute">
<a href="{{ url_for('settings.toggle_all_muted') }}" ><img src="{{url_for('static_content', group='images', filename='bell-off.svg')}}" alt="{% if all_muted %}Unmute notifications{% else %}Mute notifications{% endif %}" title="{% if all_muted %}Notifications are muted - click to unmute{% else %}Mute notifications{% endif %}" class="icon icon-mute"{% if not all_muted %} style="opacity: 0.3"{% endif %}></a>
</li> </li>
{% else %} {% else %}
<li class="pure-menu-item menu-collapsible"> <li class="pure-menu-item menu-collapsible">

View File

@@ -124,7 +124,6 @@ def test_check_access_control(app, client, live_server, measure_memory_usage, da
# Menu should be available now # Menu should be available now
assert b"SETTINGS" in res.data assert b"SETTINGS" in res.data
assert b"BACKUP" in res.data
assert b"IMPORT" in res.data assert b"IMPORT" in res.data
assert b"LOG OUT" in res.data assert b"LOG OUT" in res.data
assert b"time_between_check-minutes" in res.data assert b"time_between_check-minutes" in res.data

View File

@@ -38,7 +38,6 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
# Default no password set, this stuff should be always available. # Default no password set, this stuff should be always available.
assert b"SETTINGS" in res.data assert b"SETTINGS" in res.data
assert b"BACKUP" in res.data
assert b"IMPORT" in res.data assert b"IMPORT" in res.data
##################### #####################

View File

@@ -2153,8 +2153,8 @@ msgid "IMPORT"
msgstr "IMPORTOVAT" msgstr "IMPORTOVAT"
#: changedetectionio/templates/base.html:86 #: changedetectionio/templates/base.html:86
msgid "BACKUPS" msgid "Backups"
msgstr "BACKUPS" msgstr "Backups"
#: changedetectionio/templates/base.html:90 #: changedetectionio/templates/base.html:90
msgid "EDIT" msgid "EDIT"

View File

@@ -579,7 +579,7 @@ msgstr "Backups wurden gelöscht."
#: changedetectionio/blueprint/backups/templates/overview.html:6 #: changedetectionio/blueprint/backups/templates/overview.html:6
msgid "Backups" msgid "Backups"
msgstr "BACKUPS" msgstr "Backups"
#: changedetectionio/blueprint/backups/templates/overview.html:9 #: changedetectionio/blueprint/backups/templates/overview.html:9
msgid "A backup is running!" msgid "A backup is running!"
@@ -1210,7 +1210,7 @@ msgstr "Möglicherweise möchten Sie die verwenden"
#: changedetectionio/blueprint/ui/templates/clear_all_history.html:13 #: changedetectionio/blueprint/ui/templates/clear_all_history.html:13
msgid "BACKUP" msgid "BACKUP"
msgstr "BACKUPS" msgstr "Backups"
#: changedetectionio/blueprint/ui/templates/clear_all_history.html:13 #: changedetectionio/blueprint/ui/templates/clear_all_history.html:13
msgid "link first." msgid "link first."
@@ -2154,8 +2154,8 @@ msgid "IMPORT"
msgstr "IMPORTIEREN" msgstr "IMPORTIEREN"
#: changedetectionio/templates/base.html:86 #: changedetectionio/templates/base.html:86
msgid "BACKUPS" msgid "Backups"
msgstr "BACKUPS" msgstr "Backups"
#: changedetectionio/templates/base.html:90 #: changedetectionio/templates/base.html:90
msgid "EDIT" msgid "EDIT"

View File

@@ -2153,7 +2153,7 @@ msgid "IMPORT"
msgstr "" msgstr ""
#: changedetectionio/templates/base.html:86 #: changedetectionio/templates/base.html:86
msgid "BACKUPS" msgid "Backups"
msgstr "" msgstr ""
#: changedetectionio/templates/base.html:90 #: changedetectionio/templates/base.html:90

View File

@@ -2153,7 +2153,7 @@ msgid "IMPORT"
msgstr "" msgstr ""
#: changedetectionio/templates/base.html:86 #: changedetectionio/templates/base.html:86
msgid "BACKUPS" msgid "Backups"
msgstr "" msgstr ""
#: changedetectionio/templates/base.html:90 #: changedetectionio/templates/base.html:90

View File

@@ -2153,7 +2153,7 @@ msgid "IMPORT"
msgstr "IMPORTER" msgstr "IMPORTER"
#: changedetectionio/templates/base.html:86 #: changedetectionio/templates/base.html:86
msgid "BACKUPS" msgid "Backups"
msgstr "SAUVEGARDES" msgstr "SAUVEGARDES"
#: changedetectionio/templates/base.html:90 #: changedetectionio/templates/base.html:90

View File

@@ -2173,7 +2173,7 @@ msgid "IMPORT"
msgstr "IMPORTA" msgstr "IMPORTA"
#: changedetectionio/templates/base.html:86 #: changedetectionio/templates/base.html:86
msgid "BACKUPS" msgid "Backups"
msgstr "BACKUP" msgstr "BACKUP"
#: changedetectionio/templates/base.html:90 #: changedetectionio/templates/base.html:90

View File

@@ -2199,7 +2199,7 @@ msgid "IMPORT"
msgstr "가져오기" msgstr "가져오기"
#: changedetectionio/templates/base.html:86 #: changedetectionio/templates/base.html:86
msgid "BACKUPS" msgid "Backups"
msgstr "백업" msgstr "백업"
#: changedetectionio/templates/base.html:90 #: changedetectionio/templates/base.html:90

View File

@@ -2216,10 +2216,6 @@ msgstr ""
msgid "IMPORT" msgid "IMPORT"
msgstr "" msgstr ""
#: changedetectionio/templates/base.html:86
msgid "BACKUPS"
msgstr ""
#: changedetectionio/templates/base.html:90 #: changedetectionio/templates/base.html:90
msgid "EDIT" msgid "EDIT"
msgstr "" msgstr ""

View File

@@ -2153,7 +2153,7 @@ msgid "IMPORT"
msgstr "导入" msgstr "导入"
#: changedetectionio/templates/base.html:86 #: changedetectionio/templates/base.html:86
msgid "BACKUPS" msgid "Backups"
msgstr "备份" msgstr "备份"
#: changedetectionio/templates/base.html:90 #: changedetectionio/templates/base.html:90

View File

@@ -2153,7 +2153,7 @@ msgid "IMPORT"
msgstr "匯入" msgstr "匯入"
#: changedetectionio/templates/base.html:86 #: changedetectionio/templates/base.html:86
msgid "BACKUPS" msgid "Backups"
msgstr "備份" msgstr "備份"
#: changedetectionio/templates/base.html:90 #: changedetectionio/templates/base.html:90