Compare commits

...

5 Commits

Author SHA1 Message Date
dgtlmoon
dee23709a9 0.44.2 2023-08-28 19:01:59 +02:00
dgtlmoon
52df3b10e7 UI - Ability to highlight text and have it offered as a ignore-text option, really nice easy way to set ignores on changing text (#1746) 2023-08-24 14:29:48 +02:00
dgtlmoon
087d21c61e Update README.md 2023-08-22 11:36:15 +02:00
dgtlmoon
171faf465c Enable ARMv8 builds (for RaspberryPi and other portable devices) (#1733) 2023-08-13 23:33:49 +02:00
dgtlmoon
a3d8bd0b1a Updating in app links 2023-08-13 18:35:58 +02:00
12 changed files with 185 additions and 17 deletions

View File

@@ -95,7 +95,7 @@ jobs:
push: true
tags: |
${{ secrets.DOCKER_HUB_USERNAME }}/changedetection.io:dev,ghcr.io/${{ github.repository }}:dev
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7,linux/arm/v8
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
# Looks like this was disabled
@@ -115,7 +115,7 @@ jobs:
ghcr.io/dgtlmoon/changedetection.io:${{ github.event.release.tag_name }}
${{ secrets.DOCKER_HUB_USERNAME }}/changedetection.io:latest
ghcr.io/dgtlmoon/changedetection.io:latest
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7,linux/arm/v8
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
# Looks like this was disabled

View File

@@ -62,7 +62,7 @@ jobs:
with:
context: ./
file: ./Dockerfile
platforms: linux/arm/v6,linux/arm/v7,linux/amd64,linux/arm64,
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7,linux/arm/v8
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache

View File

@@ -54,5 +54,5 @@ $ changedetection.io -d /path/to/empty/data/dir -p 5000
Then visit http://127.0.0.1:5000 , You should now be able to access the UI.
See https://github.com/dgtlmoon/changedetection.io for more information.
See https://changedetection.io for more information.

View File

@@ -67,6 +67,7 @@ Requires Playwright to be enabled.
- Get alerts when new job positions are open on Bamboo HR and other job platforms
- Website defacement monitoring
- Pokémon Card Restock Tracker / Pokémon TCG Tracker
- RegTech - stay ahead of regulatory changes, regulatory compliance
_Need an actual Chrome runner with Javascript support? We support fetching via WebDriver and Playwright!</a>_

View File

@@ -38,7 +38,7 @@ from flask_paginate import Pagination, get_page_parameter
from changedetectionio import html_tools
from changedetectionio.api import api_v1
__version__ = '0.44.1'
__version__ = '0.44.2'
datastore = None
@@ -1430,6 +1430,27 @@ def changedetection_app(config=None, datastore_o=None):
# paste in etc
return redirect(url_for('index'))
@app.route("/highlight_submit_ignore_url", methods=['POST'])
def highlight_submit_ignore_url():
import re
mode = request.form.get('mode')
selection = request.form.get('selection')
uuid = request.args.get('uuid','')
if datastore.data["watching"].get(uuid):
if mode == 'exact':
for l in selection.splitlines():
datastore.data["watching"][uuid]['ignore_text'].append(l.strip())
elif mode == 'digit-regex':
for l in selection.splitlines():
# Replace any series of numbers with a regex
s = re.escape(l.strip())
s = re.sub(r'[0-9]+', r'\\d+', s)
datastore.data["watching"][uuid]['ignore_text'].append('/' + s + '/')
return f"<a href={url_for('preview_page', uuid=uuid)}>Click to preview</a>"
import changedetectionio.blueprint.browser_steps as browser_steps
app.register_blueprint(browser_steps.construct_blueprint(datastore), url_prefix='/browser-steps')

View File

@@ -1,4 +1,13 @@
$(document).ready(function () {
var csrftoken = $('input[name=csrf_token]').val();
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken)
}
}
})
// Load it when the #screenshot tab is in use, so we dont give a slow experience when waiting for the text diff to load
window.addEventListener('hashchange', function (e) {
toggle(location.hash);
@@ -15,11 +24,71 @@ $(document).ready(function () {
$("#settings").hide();
} else if (hash_name === '#extract') {
$("#settings").hide();
}
else {
} else {
$("#settings").show();
}
}
const article = $('.highlightable-filter')[0];
// We could also add the 'touchend' event for touch devices, but since
// most iOS/Android browsers already show a dialog when you select
// text (often with a Share option) we'll skip that
article.addEventListener('mouseup', dragTextHandler, false);
article.addEventListener('mousedown', clean, false);
function clean(event) {
$("#highlightSnippet").remove();
}
function dragTextHandler(event) {
console.log('mouseupped');
// Check if any text was selected
if (window.getSelection().toString().length > 0) {
// Find out how much (if any) user has scrolled
var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
// Get cursor position
const posX = event.clientX;
const posY = event.clientY + 20 + scrollTop;
// Append HTML to the body, create the "Tweet Selection" dialog
document.body.insertAdjacentHTML('beforeend', '<div id="highlightSnippet" style="position: absolute; top: ' + posY + 'px; left: ' + posX + 'px;"><div class="pure-form-message-inline" style="font-size: 70%">Ignore any change on any line which contains the selected text.</div><br><a data-mode="exact" href="javascript:void(0);" class="pure-button button-secondary button-xsmall">Ignore exact text</a>&nbsp;</div>');
if (/\d/.test(window.getSelection().toString())) {
// Offer regex replacement
document.getElementById("highlightSnippet").insertAdjacentHTML('beforeend', '<a data-mode="digit-regex" href="javascript:void(0);" class="pure-button button-secondary button-xsmall">Ignore text including number changes</a>');
}
$('#highlightSnippet a').bind('click', function (e) {
if(!window.getSelection().toString().trim().length) {
alert('Oops no text selected!');
return;
}
$.ajax({
type: "POST",
url: highlight_submit_ignore_url,
data: {'mode': $(this).data('mode'), 'selection': window.getSelection().toString()},
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.");
}
}
}).done(function (data) {
$("#highlightSnippet").append(data)
}).fail(function (data) {
console.log(data);
alert('There was an error communicating with the server.');
});
});
}
}
});

View File

@@ -218,3 +218,10 @@ td#diff-col div {
text-align: center; }
.tab-pane-inner#screenshot img {
max-width: 99%; }
#highlightSnippet {
background: var(--color-background);
padding: 1em;
border-radius: 5px;
background: var(--color-background);
box-shadow: 1px 1px 4px var(--color-shadow-jump); }

View File

@@ -119,3 +119,11 @@ td#diff-col div {
max-width: 99%;
}
}
#highlightSnippet {
background: var(--color-background);
padding: 1em;
border-radius: 5px;
background: var(--color-background);
box-shadow: 1px 1px 4px var(--color-shadow-jump);
}

View File

@@ -37,7 +37,7 @@
<div class="header">
<div class="home-menu pure-menu pure-menu-horizontal pure-menu-fixed" id="nav-menu">
{% if has_password and not current_user.is_authenticated %}
<a class="pure-menu-heading" href="https://github.com/dgtlmoon/changedetection.io" rel="noopener">
<a class="pure-menu-heading" href="https://changedetection.io" rel="noopener">
<strong>Change</strong>Detection.io</a>
{% else %}
<a class="pure-menu-heading" href="{{url_for('index')}}">
@@ -49,7 +49,7 @@
{% else %}
{% if new_version_available and not(has_password and not current_user.is_authenticated) %}
<span id="new-version-text" class="pure-menu-heading">
<a href="https://github.com/dgtlmoon/changedetection.io">A new version is available</a>
<a href="https://changedetection.io">A new version is available</a>
</span>
{% endif %}
{% endif %}
@@ -77,7 +77,7 @@
{% endif %}
{% else %}
<li class="pure-menu-item">
<a class="pure-menu-link" href="https://github.com/dgtlmoon/changedetection.io">Website Change Detection and Notification.</a>
<a class="pure-menu-link" href="https://changedetection.io">Website Change Detection and Notification.</a>
</li>
{% endif %}
{% if current_user.is_authenticated %}

View File

@@ -6,6 +6,9 @@
{% if last_error_screenshot %}
const error_screenshot_url="{{url_for('static_content', group='screenshot', filename=uuid, error_screenshot=1) }}";
{% endif %}
const highlight_submit_ignore_url="{{url_for('highlight_submit_ignore_url', uuid=uuid)}}";
</script>
<script src="{{url_for('static_content', group='js', filename='diff-overview.js')}}" defer></script>
@@ -76,7 +79,7 @@
</div>
<div class="tab-pane-inner" id="text">
<div class="tip">Pro-tip: Use <strong>show current snapshot</strong> tab to visualise what will be ignored.</div>
<div class="tip">Pro-tip: Use <strong>show current snapshot</strong> tab to visualise what will be ignored, highlight text to add to ignore filters</div>
{% if password_enabled_and_share_is_off %}
<div class="tip">Pro-tip: You can enable <strong>"share access when password is enabled"</strong> from settings</div>
@@ -91,7 +94,7 @@
<td id="a" style="display: none;">{{previous}}</td>
<td id="b" style="display: none;">{{newest}}</td>
<td id="diff-col">
<span id="result"></span>
<span id="result" class="highlightable-filter"></span>
</td>
</tr>
</tbody>

View File

@@ -6,6 +6,7 @@
{% if last_error_screenshot %}
const error_screenshot_url="{{url_for('static_content', group='screenshot', filename=uuid, error_screenshot=1) }}";
{% endif %}
const highlight_submit_ignore_url="{{url_for('highlight_submit_ignore_url', uuid=uuid)}}";
</script>
<script src="{{url_for('static_content', group='js', filename='diff-overview.js')}}" defer></script>
@@ -20,7 +21,7 @@
{% endif %}
</ul>
</div>
<form><input type="hidden" name="csrf_token" value="{{ csrf_token() }}"></form>
<div id="diff-ui">
<div class="tab-pane-inner" id="error-text">
<div class="snapshot-age error">{{watch.error_text_ctime|format_seconds_ago}} seconds ago</div>
@@ -36,11 +37,12 @@
<div class="tab-pane-inner" id="text">
<div class="snapshot-age">{{watch.snapshot_text_ctime|format_timestamp_timeago}}</div>
<span class="ignored">Grey lines are ignored</span> <span class="triggered">Blue lines are triggers</span>
<span class="ignored">Grey lines are ignored</span> <span class="triggered">Blue lines are triggers</span> <span class="tip"><strong>Pro-tip</strong>: Highlight text to add to ignore filters</span>
<table>
<tbody>
<tr>
<td id="diff-col">
<td id="diff-col" class="highlightable-filter">
{% for row in content %}
<div class="{{row.classes}}">{{row.line}}</div>
{% endfor %}

View File

@@ -0,0 +1,57 @@
#!/usr/bin/python3
import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks
from changedetectionio import html_tools
from . util import extract_UUID_from_client
def set_original_ignore_response():
test_return_data = """<html>
<body>
Some initial text<br>
<p>Which is across multiple lines</p>
<br>
So let's see what happens. <br>
<p>oh yeah 456</p>
</body>
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
f.write(test_return_data)
def test_highlight_ignore(client, live_server):
live_server_setup(live_server)
set_original_ignore_response()
test_url = url_for('test_endpoint', _external=True)
res = client.post(
url_for("import_page"),
data={"urls": test_url},
follow_redirects=True
)
assert b"1 Imported" in res.data
# Give the thread time to pick it up
wait_for_all_checks(client)
uuid = extract_UUID_from_client(client)
# use the highlighter endpoint
res = client.post(
url_for("highlight_submit_ignore_url", uuid=uuid),
data={"mode": 'digit-regex', 'selection': 'oh yeah 123'},
follow_redirects=True
)
res = client.get(url_for("edit_page", uuid=uuid))
# should be a regex now
assert b'/oh\ yeah\ \d+/' in res.data
# Should return a link
assert b'href' in res.data
# And it should register in the preview page
res = client.get(url_for("preview_page", uuid=uuid))
assert b'<div class="ignored">oh yeah 456' in res.data