Connect up each row buttons
This commit is contained in:
@@ -3,6 +3,7 @@ from flask import Blueprint, request, redirect, url_for, flash, render_template,
|
|||||||
from loguru import logger
|
from loguru import logger
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
|
from changedetectionio.blueprint.ui.ajax import constuct_ui_ajax_blueprint
|
||||||
from changedetectionio.store import ChangeDetectionStore
|
from changedetectionio.store import ChangeDetectionStore
|
||||||
from changedetectionio.blueprint.ui.edit import construct_blueprint as construct_edit_blueprint
|
from changedetectionio.blueprint.ui.edit import construct_blueprint as construct_edit_blueprint
|
||||||
from changedetectionio.blueprint.ui.notification import construct_blueprint as construct_notification_blueprint
|
from changedetectionio.blueprint.ui.notification import construct_blueprint as construct_notification_blueprint
|
||||||
@@ -23,6 +24,9 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
|
|||||||
views_blueprint = construct_views_blueprint(datastore, update_q, queuedWatchMetaData, watch_check_completed)
|
views_blueprint = construct_views_blueprint(datastore, update_q, queuedWatchMetaData, watch_check_completed)
|
||||||
ui_blueprint.register_blueprint(views_blueprint)
|
ui_blueprint.register_blueprint(views_blueprint)
|
||||||
|
|
||||||
|
ui_ajax_blueprint = constuct_ui_ajax_blueprint(datastore, update_q, running_update_threads, queuedWatchMetaData, watch_check_completed)
|
||||||
|
ui_blueprint.register_blueprint(ui_ajax_blueprint)
|
||||||
|
|
||||||
# Import the login decorator
|
# Import the login decorator
|
||||||
from changedetectionio.auth_decorator import login_optionally_required
|
from changedetectionio.auth_decorator import login_optionally_required
|
||||||
|
|
||||||
|
|||||||
35
changedetectionio/blueprint/ui/ajax.py
Normal file
35
changedetectionio/blueprint/ui/ajax.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
from blinker import signal
|
||||||
|
from flask import Blueprint, request, redirect, url_for, flash, render_template, session
|
||||||
|
|
||||||
|
|
||||||
|
from changedetectionio.store import ChangeDetectionStore
|
||||||
|
|
||||||
|
def constuct_ui_ajax_blueprint(datastore: ChangeDetectionStore, update_q, running_update_threads, queuedWatchMetaData, watch_check_completed):
|
||||||
|
ui_ajax_blueprint = Blueprint('ajax', __name__, template_folder="templates", url_prefix='/ajax')
|
||||||
|
|
||||||
|
# Import the login decorator
|
||||||
|
from changedetectionio.auth_decorator import login_optionally_required
|
||||||
|
|
||||||
|
@ui_ajax_blueprint.route("/toggle", methods=['POST'])
|
||||||
|
@login_optionally_required
|
||||||
|
def ajax_toggler():
|
||||||
|
op = request.values.get('op')
|
||||||
|
uuid = request.values.get('uuid')
|
||||||
|
if op and datastore.data['watching'].get(uuid):
|
||||||
|
if op == 'pause':
|
||||||
|
datastore.data['watching'][uuid].toggle_pause()
|
||||||
|
elif op == 'mute':
|
||||||
|
datastore.data['watching'][uuid].toggle_mute()
|
||||||
|
elif op == 'recheck':
|
||||||
|
update_q.put(queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': uuid}))
|
||||||
|
|
||||||
|
watch_check_completed = signal('watch_check_completed')
|
||||||
|
if watch_check_completed:
|
||||||
|
watch_check_completed.send(watch_uuid=uuid)
|
||||||
|
|
||||||
|
return 'OK'
|
||||||
|
|
||||||
|
|
||||||
|
return ui_ajax_blueprint
|
||||||
@@ -72,31 +72,33 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
|
|||||||
per_page=datastore.data['settings']['application'].get('pager_size', 50), css_framework="semantic")
|
per_page=datastore.data['settings']['application'].get('pager_size', 50), css_framework="semantic")
|
||||||
|
|
||||||
sorted_tags = sorted(datastore.data['settings']['application'].get('tags').items(), key=lambda x: x[1]['title'])
|
sorted_tags = sorted(datastore.data['settings']['application'].get('tags').items(), key=lambda x: x[1]['title'])
|
||||||
|
|
||||||
output = render_template(
|
output = render_template(
|
||||||
"watch-overview.html",
|
"watch-overview.html",
|
||||||
active_tag=active_tag,
|
active_tag=active_tag,
|
||||||
active_tag_uuid=active_tag_uuid,
|
active_tag_uuid=active_tag_uuid,
|
||||||
app_rss_token=datastore.data['settings']['application'].get('rss_access_token'),
|
app_rss_token=datastore.data['settings']['application'].get('rss_access_token'),
|
||||||
datastore=datastore,
|
ajax_toggle_url=url_for('ui.ajax.ajax_toggler'),
|
||||||
errored_count=errored_count,
|
datastore=datastore,
|
||||||
form=form,
|
errored_count=errored_count,
|
||||||
guid=datastore.data['app_guid'],
|
form=form,
|
||||||
has_proxies=datastore.proxy_list,
|
guid=datastore.data['app_guid'],
|
||||||
has_unviewed=datastore.has_unviewed,
|
has_proxies=datastore.proxy_list,
|
||||||
hosted_sticky=os.getenv("SALTED_PASS", False) == False,
|
has_unviewed=datastore.has_unviewed,
|
||||||
now_time_server=round(time.time()),
|
hosted_sticky=os.getenv("SALTED_PASS", False) == False,
|
||||||
pagination=pagination,
|
now_time_server=round(time.time()),
|
||||||
queued_uuids=[q_uuid.item['uuid'] for q_uuid in update_q.queue],
|
pagination=pagination,
|
||||||
search_q=request.args.get('q', '').strip(),
|
queued_uuids=[q_uuid.item['uuid'] for q_uuid in update_q.queue],
|
||||||
sort_attribute=request.args.get('sort') if request.args.get('sort') else request.cookies.get('sort'),
|
search_q=request.args.get('q', '').strip(),
|
||||||
sort_order=request.args.get('order') if request.args.get('order') else request.cookies.get('order'),
|
sort_attribute=request.args.get('sort') if request.args.get('sort') else request.cookies.get('sort'),
|
||||||
system_default_fetcher=datastore.data['settings']['application'].get('fetch_backend'),
|
sort_order=request.args.get('order') if request.args.get('order') else request.cookies.get('order'),
|
||||||
tags=sorted_tags,
|
system_default_fetcher=datastore.data['settings']['application'].get('fetch_backend'),
|
||||||
watches=sorted_watches
|
tags=sorted_tags,
|
||||||
)
|
watches=sorted_watches
|
||||||
|
)
|
||||||
|
|
||||||
if session.get('share-link'):
|
if session.get('share-link'):
|
||||||
del(session['share-link'])
|
del (session['share-link'])
|
||||||
|
|
||||||
resp = make_response(output)
|
resp = make_response(output)
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<script src="{{url_for('static_content', group='js', filename='jquery-3.6.0.min.js')}}"></script>
|
<script src="{{url_for('static_content', group='js', filename='jquery-3.6.0.min.js')}}"></script>
|
||||||
<script src="{{url_for('static_content', group='js', filename='watch-overview.js')}}" defer></script>
|
<script src="{{url_for('static_content', group='js', filename='watch-overview.js')}}" defer></script>
|
||||||
<script>let nowtimeserver={{ now_time_server }};</script>
|
<script>let nowtimeserver={{ now_time_server }};</script>
|
||||||
|
<script>let ajax_toggle_url="{{ ajax_toggle_url }}";</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.checking-now .last-checked {
|
.checking-now .last-checked {
|
||||||
@@ -111,16 +112,15 @@
|
|||||||
{% if watch.has_restock_info %} has-restock-info {% if watch['restock']['in_stock'] %}in-stock{% else %}not-in-stock{% endif %} {% else %}no-restock-info{% endif %}
|
{% if watch.has_restock_info %} has-restock-info {% if watch['restock']['in_stock'] %}in-stock{% else %}not-in-stock{% endif %} {% else %}no-restock-info{% endif %}
|
||||||
{% if watch.uuid in queued_uuids %}queued{% endif %}
|
{% if watch.uuid in queued_uuids %}queued{% endif %}
|
||||||
{% if checking_now %}checking-now{% endif %}
|
{% if checking_now %}checking-now{% endif %}
|
||||||
|
{% if watch.notification_muted %}notification_muted{% endif %}
|
||||||
">
|
">
|
||||||
<td class="inline checkbox-uuid" ><input name="uuids" type="checkbox" value="{{ watch.uuid}} " > <span>{{ loop.index+pagination.skip }}</span></td>
|
<td class="inline checkbox-uuid" ><input name="uuids" type="checkbox" value="{{ watch.uuid}} " > <span>{{ loop.index+pagination.skip }}</span></td>
|
||||||
<td class="inline watch-controls">
|
<td class="inline watch-controls">
|
||||||
{% if not watch.paused %}
|
<a class="ajax-op state-off pause-toggle" data-op="pause" href="{{url_for('watchlist.index', op='pause', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='pause.svg')}}" alt="Pause checks" title="Pause checks" class="icon icon-pause" ></a>
|
||||||
<a class="state-off" href="{{url_for('watchlist.index', op='pause', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='pause.svg')}}" alt="Pause checks" title="Pause checks" class="icon icon-pause" ></a>
|
<a class="ajax-op state-on pause-toggle" data-op="pause" style="display: none" href="{{url_for('watchlist.index', op='pause', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='play.svg')}}" alt="UnPause checks" title="UnPause checks" class="icon icon-unpause" ></a>
|
||||||
{% else %}
|
|
||||||
<a class="state-on" href="{{url_for('watchlist.index', op='pause', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='play.svg')}}" alt="UnPause checks" title="UnPause checks" class="icon icon-unpause" ></a>
|
<a class="ajax-op state-off mute-toggle" data-op="mute" href="{{url_for('watchlist.index', op='mute', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='bell-off.svg')}}" alt="Mute notification" title="Mute notification" class="icon icon-mute" ></a>
|
||||||
{% endif %}
|
<a class="ajax-op state-on mute-toggle" data-op="mute" style="display: none" href="{{url_for('watchlist.index', op='mute', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='bell-off.svg')}}" alt="UnMute notification" title="UnMute notification" class="icon icon-mute" ></a>
|
||||||
{% set mute_label = 'UnMute notification' if watch.notification_muted else 'Mute notification' %}
|
|
||||||
<a class="link-mute state-{{'on' if watch.notification_muted else 'off'}}" href="{{url_for('watchlist.index', op='mute', uuid=watch.uuid, tag=active_tag_uuid)}}"><img src="{{url_for('static_content', group='images', filename='bell-off.svg')}}" alt="{{ mute_label }}" title="{{ mute_label }}" class="icon icon-mute" ></a>
|
|
||||||
</td>
|
</td>
|
||||||
<td class="title-col inline">{{watch.title if watch.title is not none and watch.title|length > 0 else watch.url}}
|
<td class="title-col inline">{{watch.title if watch.title is not none and watch.title|length > 0 else watch.url}}
|
||||||
<a class="external" target="_blank" rel="noopener" href="{{ watch.link.replace('source:','') }}"></a>
|
<a class="external" target="_blank" rel="noopener" href="{{ watch.link.replace('source:','') }}"></a>
|
||||||
@@ -207,7 +207,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<a href="" class="already-in-queue-button recheck pure-button pure-button-primary" style="display: none;" disabled="disabled">Queued</a>
|
<a href="" class="already-in-queue-button recheck pure-button pure-button-primary" style="display: none;" disabled="disabled">Queued</a>
|
||||||
|
|
||||||
<a href="{{ url_for('ui.form_watch_checknow', uuid=watch.uuid, tag=request.args.get('tag')) }}" class="recheck pure-button pure-button-primary">Recheck</a>
|
<a href="{{ url_for('ui.form_watch_checknow', uuid=watch.uuid, tag=request.args.get('tag')) }}" data-op='recheck' class="ajax-op recheck pure-button pure-button-primary">Recheck</a>
|
||||||
<a href="{{ url_for('ui.ui_edit.edit_page', uuid=watch.uuid, tag=active_tag_uuid)}}#general" class="pure-button pure-button-primary">Edit</a>
|
<a href="{{ url_for('ui.ui_edit.edit_page', uuid=watch.uuid, tag=active_tag_uuid)}}#general" class="pure-button pure-button-primary">Edit</a>
|
||||||
|
|
||||||
{% if watch.history_n >= 2 %}
|
{% if watch.history_n >= 2 %}
|
||||||
|
|||||||
@@ -106,6 +106,8 @@ class ChangeDetectionSocketIO:
|
|||||||
'last_checked_text': _jinja2_filter_datetime(watch),
|
'last_checked_text': _jinja2_filter_datetime(watch),
|
||||||
'last_changed_text': timeago.format(int(watch['last_changed']), time.time()) if watch.history_n >=2 and int(watch.get('last_changed',0)) >0 else 'Not yet',
|
'last_changed_text': timeago.format(int(watch['last_changed']), time.time()) if watch.history_n >=2 and int(watch.get('last_changed',0)) >0 else 'Not yet',
|
||||||
'queued': True if watch.get('uuid') in queue_list else False,
|
'queued': True if watch.get('uuid') in queue_list else False,
|
||||||
|
'paused': True if watch.get('paused') else False,
|
||||||
|
'notification_muted': True if watch.get('notification_muted') else False,
|
||||||
'unviewed': watch.has_unviewed,
|
'unviewed': watch.has_unviewed,
|
||||||
'uuid': watch.get('uuid'),
|
'uuid': watch.get('uuid'),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,23 @@
|
|||||||
// Socket.IO client-side integration for changedetection.io
|
// Socket.IO client-side integration for changedetection.io
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
$('.ajax-op').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: ajax_toggle_url,
|
||||||
|
data: {'op': $(this).data('op'), 'uuid': $(this).closest('tr').data('watch-uuid')},
|
||||||
|
statusCode: {
|
||||||
|
400: function () {
|
||||||
|
// More than likely the CSRF token was lost when the server restarted
|
||||||
|
alert("There was a problem processing the request, please reload the page.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Try to create the socket connection to port 5005 - if it fails, the site will still work normally
|
// Try to create the socket connection to port 5005 - if it fails, the site will still work normally
|
||||||
try {
|
try {
|
||||||
// Connect to the dedicated Socket.IO server on port 5005
|
// Connect to the dedicated Socket.IO server on port 5005
|
||||||
@@ -15,32 +32,19 @@ $(document).ready(function () {
|
|||||||
console.log('Socket.IO disconnected');
|
console.log('Socket.IO disconnected');
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('checking_now', function (uuid_list) {
|
|
||||||
console.log("Got checking now update");
|
|
||||||
// Remove 'checking-now' class where it should no longer be
|
|
||||||
$('.watch-table tbody tr.checking-now').each(function () {
|
|
||||||
if (!uuid_list.includes($(this).data('watch-uuid'))) {
|
|
||||||
$(this).removeClass('checking-now');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add the class on the rows where it should be
|
|
||||||
uuid_list.forEach(function (uuid) {
|
|
||||||
$('.watch-table tbody tr[data-watch-uuid="' + uuid + '"]').addClass('checking-now');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Listen for periodically emitted watch data
|
// Listen for periodically emitted watch data
|
||||||
socket.on('watch_update', function (watch) {
|
socket.on('watch_update', function (watch) {
|
||||||
console.log(`Watch update ${watch.uuid}`);
|
console.log(`Watch update ${watch.uuid}`);
|
||||||
|
|
||||||
|
|
||||||
const $watchRow = $('tr[data-watch-uuid="' + watch.uuid + '"]');
|
const $watchRow = $('tr[data-watch-uuid="' + watch.uuid + '"]');
|
||||||
if ($watchRow.length) {
|
if ($watchRow.length) {
|
||||||
$($watchRow).toggleClass('checking-now', watch.checking_now);
|
$($watchRow).toggleClass('checking-now', watch.checking_now);
|
||||||
$($watchRow).toggleClass('queued', watch.queued);
|
$($watchRow).toggleClass('queued', watch.queued);
|
||||||
$($watchRow).toggleClass('unviewed', watch.unviewed);
|
$($watchRow).toggleClass('unviewed', watch.unviewed);
|
||||||
$($watchRow).toggleClass('error', watch.has_error);
|
$($watchRow).toggleClass('error', watch.has_error);
|
||||||
|
$($watchRow).toggleClass('notification_muted', watch.notification_muted);
|
||||||
|
$($watchRow).toggleClass('paused', watch.paused);
|
||||||
|
|
||||||
$('td.last-changed', $watchRow).text(watch.last_checked_text)
|
$('td.last-changed', $watchRow).text(watch.last_checked_text)
|
||||||
$('td.last-checked .innertext', $watchRow).text(watch.last_checked_text)
|
$('td.last-checked .innertext', $watchRow).text(watch.last_checked_text)
|
||||||
$('td.last-checked', $watchRow).data('timestamp', watch.last_checked).data('fetchduration', watch.fetch_time);
|
$('td.last-checked', $watchRow).data('timestamp', watch.last_checked).data('fetchduration', watch.fetch_time);
|
||||||
|
|||||||
@@ -68,5 +68,25 @@
|
|||||||
display: inline-block !important;
|
display: inline-block !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tr.paused {
|
||||||
|
a.pause-toggle {
|
||||||
|
&.state-on {
|
||||||
|
display: inline !important;
|
||||||
|
}
|
||||||
|
&.state-off {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tr.notification_muted {
|
||||||
|
a.mute-toggle {
|
||||||
|
&.state-on {
|
||||||
|
display: inline !important;
|
||||||
|
}
|
||||||
|
&.state-off {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -559,6 +559,14 @@ body.preview-text-enabled {
|
|||||||
display: none !important; }
|
display: none !important; }
|
||||||
.watch-table tr.queued a.already-in-queue-button {
|
.watch-table tr.queued a.already-in-queue-button {
|
||||||
display: inline-block !important; }
|
display: inline-block !important; }
|
||||||
|
.watch-table tr.paused a.pause-toggle.state-on {
|
||||||
|
display: inline !important; }
|
||||||
|
.watch-table tr.paused a.pause-toggle.state-off {
|
||||||
|
display: none !important; }
|
||||||
|
.watch-table tr.notification_muted a.mute-toggle.state-on {
|
||||||
|
display: inline !important; }
|
||||||
|
.watch-table tr.notification_muted a.mute-toggle.state-off {
|
||||||
|
display: none !important; }
|
||||||
|
|
||||||
ul#conditions_match_logic {
|
ul#conditions_match_logic {
|
||||||
list-style: none; }
|
list-style: none; }
|
||||||
|
|||||||
Reference in New Issue
Block a user