Compare commits

..

6 Commits

Author SHA1 Message Date
dgtlmoon
9d9d01863a 0.49.12
Some checks failed
Build and push containers / metadata (push) Has been cancelled
Build and push containers / build-push-containers (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built 📦 package works basically. (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Has been cancelled
ChangeDetection.io App Test / lint-code (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-10 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-11 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-12 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-13 (push) Has been cancelled
2025-04-04 09:30:24 +02:00
dgtlmoon
108cdf84a5 0.49.11
Some checks failed
Build and push containers / metadata (push) Has been cancelled
Build and push containers / build-push-containers (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built 📦 package works basically. (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Has been cancelled
ChangeDetection.io App Test / lint-code (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-10 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-11 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-12 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-13 (push) Has been cancelled
2025-04-03 18:54:20 +02:00
dgtlmoon
8c6f6f1578 0.49.10 2025-04-03 11:17:14 +02:00
dgtlmoon
df4ffaaff8 Update README.md
Some checks failed
Build and push containers / metadata (push) Has been cancelled
Build and push containers / build-push-containers (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built 📦 package works basically. (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Has been cancelled
ChangeDetection.io App Test / lint-code (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-10 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-11 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-12 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-13 (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-04-03 08:55:59 +02:00
dgtlmoon
d522c65e50 UI - "Conditions" section, making the Conditions setup table work better on mobile/responsive
Some checks failed
Build and push containers / metadata (push) Has been cancelled
Build and push containers / build-push-containers (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built 📦 package works basically. (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Has been cancelled
ChangeDetection.io App Test / lint-code (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-10 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-11 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-12 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-13 (push) Has been cancelled
2025-04-02 18:06:39 +02:00
dgtlmoon
c3b2a8b019 Adding a GC memory cleanup (releases cached libxml memory and others) (#3079)
Some checks failed
Build and push containers / metadata (push) Has been cancelled
Build and push containers / build-push-containers (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built 📦 package works basically. (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Has been cancelled
ChangeDetection.io App Test / lint-code (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-10 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-11 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-12 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-13 (push) Has been cancelled
ChangeDetection.io Container Build Test / test-container-build (push) Has been cancelled
2025-04-01 15:48:14 +02:00
10 changed files with 268 additions and 47 deletions

View File

@@ -89,7 +89,7 @@ _Need an actual Chrome runner with Javascript support? We support fetching via W
#### Key Features
- Lots of trigger filters, such as "Trigger on text", "Remove text by selector", "Ignore text", "Extract text", also using regular-expressions!
- Target elements with xPath(1.0) and CSS Selectors, Easily monitor complex JSON with JSONPath or jq
- Target elements with xPath 1 and xPath 2, CSS Selectors, Easily monitor complex JSON with JSONPath or jq
- Switch between fast non-JS and Chrome JS based "fetchers"
- Track changes in PDF files (Monitor text changed in the PDF, Also monitor PDF filesize and checksums)
- Easily specify how often a site should be checked

View File

@@ -2,7 +2,7 @@
# Read more https://github.com/dgtlmoon/changedetection.io/wiki
__version__ = '0.49.9'
__version__ = '0.49.12'
from changedetectionio.strtobool import strtobool
from json.decoder import JSONDecodeError
@@ -11,6 +11,7 @@ os.environ['EVENTLET_NO_GREENDNS'] = 'yes'
import eventlet
import eventlet.wsgi
import getopt
import platform
import signal
import socket
import sys
@@ -150,9 +151,13 @@ def main():
from changedetectionio.gc_cleanup import memory_cleanup
logger.info('SIGUSR1 received: Running memory cleanup')
return memory_cleanup(app)
# Register the SIGUSR1 signal handler
signal.signal(signal.SIGUSR1, sigusr_clean_handler)
# Only register the signal handler if running on Linux
if platform.system() == "Linux":
signal.signal(signal.SIGUSR1, sigusr_clean_handler)
else:
logger.info("SIGUSR1 handler only registered on Linux, skipped.")
# Go into cleanup mode
if do_cleanup:

View File

@@ -8,7 +8,7 @@ from . import default_plugin
# List of all supported JSON Logic operators
operator_choices = [
(None, "Choose one"),
(None, "Choose one - Operator"),
(">", "Greater Than"),
("<", "Less Than"),
(">=", "Greater Than or Equal To"),
@@ -21,7 +21,7 @@ operator_choices = [
# Fields available in the rules
field_choices = [
(None, "Choose one"),
(None, "Choose one - Field"),
]
# The data we will feed the JSON Rules to see if it passes the test/conditions or not

View File

@@ -19,7 +19,7 @@ class ConditionFormRow(Form):
validators=[validators.Optional()]
)
value = StringField("Value", validators=[validators.Optional()])
value = StringField("Value", validators=[validators.Optional()], render_kw={"placeholder": "A value"})
def validate(self, extra_validators=None):
# First, run the default validators

View File

@@ -8,7 +8,7 @@ $(document).ready(function () {
$(".addRuleRow").on("click", function(e) {
e.preventDefault();
let currentRow = $(this).closest("tr");
let currentRow = $(this).closest(".fieldlist-row");
// Clone without events
let newRow = currentRow.clone(false);
@@ -29,8 +29,8 @@ $(document).ready(function () {
e.preventDefault();
// Only remove if there's more than one row
if ($("#rulesTable tbody tr").length > 1) {
$(this).closest("tr").remove();
if ($("#rulesTable .fieldlist-row").length > 1) {
$(this).closest(".fieldlist-row").remove();
reindexRules();
}
});
@@ -39,7 +39,7 @@ $(document).ready(function () {
$(".verifyRuleRow").on("click", function(e) {
e.preventDefault();
let row = $(this).closest("tr");
let row = $(this).closest(".fieldlist-row");
let field = row.find("select[name$='field']").val();
let operator = row.find("select[name$='operator']").val();
let value = row.find("input[name$='value']").val();
@@ -128,7 +128,7 @@ $(document).ready(function () {
$(".addRuleRow, .removeRuleRow, .verifyRuleRow").off("click");
// Reindex all form elements
$("#rulesTable tbody tr").each(function(index) {
$("#rulesTable .fieldlist-row").each(function(index) {
$(this).find("select, input").each(function() {
let oldName = $(this).attr("name");
let oldId = $(this).attr("id");

View File

@@ -0,0 +1,135 @@
/* Styles for the flexbox-based table replacement for conditions */
.fieldlist_formfields {
width: 100%;
background-color: var(--color-background, #fff);
border-radius: 4px;
border: 1px solid var(--color-border-table-cell, #cbcbcb);
/* Header row */
.fieldlist-header {
display: flex;
background-color: var(--color-background-table-thead, #e0e0e0);
font-weight: bold;
border-bottom: 1px solid var(--color-border-table-cell, #cbcbcb);
}
.fieldlist-header-cell {
flex: 1;
padding: 0.5em 1em;
text-align: left;
&:last-child {
flex: 0 0 120px; /* Fixed width for actions column */
}
}
/* Body rows */
.fieldlist-body {
display: flex;
flex-direction: column;
}
.fieldlist-row {
display: flex;
border-bottom: 1px solid var(--color-border-table-cell, #cbcbcb);
&:last-child {
border-bottom: none;
}
&:nth-child(2n-1) {
background-color: var(--color-table-stripe, #f2f2f2);
}
&.error-row {
background-color: var(--color-error-input, #ffdddd);
}
}
.fieldlist-cell {
flex: 1;
padding: 0.5em 1em;
display: flex;
flex-direction: column;
justify-content: center;
/* Make inputs take up full width of their cell */
input, select {
width: 100%;
}
&.fieldlist-actions {
flex: 0 0 120px; /* Fixed width for actions column */
display: flex;
flex-direction: row;
align-items: center;
gap: 4px;
}
}
/* Error styling */
ul.errors {
margin-top: 0.5em;
margin-bottom: 0;
padding: 0.5em;
background-color: var(--color-error-background-snapshot-age, #ffdddd);
border-radius: 4px;
list-style-position: inside;
}
/* Responsive styles */
@media only screen and (max-width: 760px) {
.fieldlist-header, .fieldlist-row {
flex-direction: column;
}
.fieldlist-header-cell {
display: none;
}
.fieldlist-row {
padding: 0.5em 0;
border-bottom: 2px solid var(--color-border-table-cell, #cbcbcb);
}
.fieldlist-cell {
padding: 0.25em 0.5em;
&.fieldlist-actions {
flex: 1;
justify-content: flex-start;
padding-top: 0.5em;
}
}
/* Add some spacing between fields on mobile */
.fieldlist-cell:not(:last-child) {
margin-bottom: 0.5em;
}
/* Label each cell on mobile view */
.fieldlist-cell::before {
content: attr(data-label);
font-weight: bold;
margin-bottom: 0.25em;
}
}
}
/* Button styling */
.fieldlist_formfields {
.addRuleRow, .removeRuleRow, .verifyRuleRow {
cursor: pointer;
border: none;
padding: 4px 8px;
border-radius: 3px;
font-weight: bold;
background-color: #aaa;
color: var(--color-foreground-text, #fff);
&:hover {
background-color: #999;
}
}
}

View File

@@ -14,6 +14,7 @@
@import "parts/_love";
@import "parts/preview_text_filter";
@import "parts/_edit";
@import "parts/_conditions_table";
body {
color: var(--color-text);

View File

@@ -530,6 +530,99 @@ ul#conditions_match_logic {
ul#conditions_match_logic li {
padding-right: 1em; }
/* Styles for the flexbox-based table replacement for conditions */
.fieldlist_formfields {
width: 100%;
background-color: var(--color-background, #fff);
border-radius: 4px;
border: 1px solid var(--color-border-table-cell, #cbcbcb);
/* Header row */
/* Body rows */
/* Error styling */
/* Responsive styles */ }
.fieldlist_formfields .fieldlist-header {
display: flex;
background-color: var(--color-background-table-thead, #e0e0e0);
font-weight: bold;
border-bottom: 1px solid var(--color-border-table-cell, #cbcbcb); }
.fieldlist_formfields .fieldlist-header-cell {
flex: 1;
padding: 0.5em 1em;
text-align: left; }
.fieldlist_formfields .fieldlist-header-cell:last-child {
flex: 0 0 120px;
/* Fixed width for actions column */ }
.fieldlist_formfields .fieldlist-body {
display: flex;
flex-direction: column; }
.fieldlist_formfields .fieldlist-row {
display: flex;
border-bottom: 1px solid var(--color-border-table-cell, #cbcbcb); }
.fieldlist_formfields .fieldlist-row:last-child {
border-bottom: none; }
.fieldlist_formfields .fieldlist-row:nth-child(2n-1) {
background-color: var(--color-table-stripe, #f2f2f2); }
.fieldlist_formfields .fieldlist-row.error-row {
background-color: var(--color-error-input, #ffdddd); }
.fieldlist_formfields .fieldlist-cell {
flex: 1;
padding: 0.5em 1em;
display: flex;
flex-direction: column;
justify-content: center;
/* Make inputs take up full width of their cell */ }
.fieldlist_formfields .fieldlist-cell input, .fieldlist_formfields .fieldlist-cell select {
width: 100%; }
.fieldlist_formfields .fieldlist-cell.fieldlist-actions {
flex: 0 0 120px;
/* Fixed width for actions column */
display: flex;
flex-direction: row;
align-items: center;
gap: 4px; }
.fieldlist_formfields ul.errors {
margin-top: 0.5em;
margin-bottom: 0;
padding: 0.5em;
background-color: var(--color-error-background-snapshot-age, #ffdddd);
border-radius: 4px;
list-style-position: inside; }
@media only screen and (max-width: 760px) {
.fieldlist_formfields {
/* Add some spacing between fields on mobile */
/* Label each cell on mobile view */ }
.fieldlist_formfields .fieldlist-header, .fieldlist_formfields .fieldlist-row {
flex-direction: column; }
.fieldlist_formfields .fieldlist-header-cell {
display: none; }
.fieldlist_formfields .fieldlist-row {
padding: 0.5em 0;
border-bottom: 2px solid var(--color-border-table-cell, #cbcbcb); }
.fieldlist_formfields .fieldlist-cell {
padding: 0.25em 0.5em; }
.fieldlist_formfields .fieldlist-cell.fieldlist-actions {
flex: 1;
justify-content: flex-start;
padding-top: 0.5em; }
.fieldlist_formfields .fieldlist-cell:not(:last-child) {
margin-bottom: 0.5em; }
.fieldlist_formfields .fieldlist-cell::before {
content: attr(data-label);
font-weight: bold;
margin-bottom: 0.25em; } }
/* Button styling */
.fieldlist_formfields .addRuleRow, .fieldlist_formfields .removeRuleRow, .fieldlist_formfields .verifyRuleRow {
cursor: pointer;
border: none;
padding: 4px 8px;
border-radius: 3px;
font-weight: bold;
background-color: #aaa;
color: var(--color-foreground-text, #fff); }
.fieldlist_formfields .addRuleRow:hover, .fieldlist_formfields .removeRuleRow:hover, .fieldlist_formfields .verifyRuleRow:hover {
background-color: #999; }
body {
color: var(--color-text);
background: var(--color-background-page);

View File

@@ -61,21 +61,20 @@
{{ field(**kwargs)|safe }}
{% endmacro %}
{% macro render_fieldlist_of_formfields_as_table(fieldlist, table_id="rulesTable") %}
<table class="fieldlist_formfields pure-table" id="{{ table_id }}">
<thead>
<tr>
{% for subfield in fieldlist[0] %}
<th>{{ subfield.label }}</th>
{% endfor %}
<th>Actions</th>
</tr>
</thead>
<tbody>
{% macro render_conditions_fieldlist_of_formfields_as_table(fieldlist, table_id="rulesTable") %}
<div class="fieldlist_formfields" id="{{ table_id }}">
<div class="fieldlist-header">
{% for subfield in fieldlist[0] %}
<div class="fieldlist-header-cell">{{ subfield.label }}</div>
{% endfor %}
<div class="fieldlist-header-cell">Actions</div>
</div>
<div class="fieldlist-body">
{% for form_row in fieldlist %}
<tr {% if form_row.errors %} class="error-row" {% endif %}>
<div class="fieldlist-row {% if form_row.errors %}error-row{% endif %}">
{% for subfield in form_row %}
<td>
<div class="fieldlist-cell">
{{ subfield()|safe }}
{% if subfield.errors %}
<ul class="errors">
@@ -84,17 +83,17 @@
{% endfor %}
</ul>
{% endif %}
</td>
</div>
{% endfor %}
<td>
<button type="button" class="addRuleRow">+</button>
<button type="button" class="removeRuleRow">-</button>
<div class="fieldlist-cell fieldlist-actions">
<button type="button" class="addRuleRow" title="Add a row/rule after">+</button>
<button type="button" class="removeRuleRow" title="Remove this row/rule">-</button>
<button type="button" class="verifyRuleRow" title="Verify this rule against current snapshot"></button>
</td>
</tr>
</div>
</div>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endmacro %}

View File

@@ -1,6 +1,6 @@
{% extends 'base.html' %}
{% block content %}
{% from '_helpers.html' import render_field, render_checkbox_field, render_button, render_time_schedule_form, playwright_warning, only_webdriver_type_watches_warning, render_fieldlist_of_formfields_as_table %}
{% from '_helpers.html' import render_field, render_checkbox_field, render_button, render_time_schedule_form, playwright_warning, only_webdriver_type_watches_warning, render_conditions_fieldlist_of_formfields_as_table %}
{% from '_common_fields.html' import render_common_settings_form %}
<script src="{{url_for('static_content', group='js', filename='tabs.js')}}" defer></script>
<script src="{{url_for('static_content', group='js', filename='vis.js')}}" defer></script>
@@ -289,21 +289,9 @@ Math: {{ 1 + 1 }}") }}
<script>
const verify_condition_rule_url="{{url_for('conditions.verify_condition_single_rule', watch_uuid=uuid)}}";
</script>
<style>
.verifyRuleRow {
background-color: #4caf50;
color: white;
border: none;
cursor: pointer;
font-weight: bold;
}
.verifyRuleRow:hover {
background-color: #45a049;
}
</style>
<div class="pure-control-group">
{{ render_field(form.conditions_match_logic) }}
{{ render_fieldlist_of_formfields_as_table(form.conditions) }}
{{ render_conditions_fieldlist_of_formfields_as_table(form.conditions) }}
<div class="pure-form-message-inline">
<p id="verify-state-text">Use the verify (✓) button to test if a condition passes against the current snapshot.</p>