diff --git a/changedetectionio/conditions/__init__.py b/changedetectionio/conditions/__init__.py index aa005859..13079180 100644 --- a/changedetectionio/conditions/__init__.py +++ b/changedetectionio/conditions/__init__.py @@ -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 diff --git a/changedetectionio/conditions/form.py b/changedetectionio/conditions/form.py index 8ff6f986..8effbdef 100644 --- a/changedetectionio/conditions/form.py +++ b/changedetectionio/conditions/form.py @@ -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 diff --git a/changedetectionio/static/js/conditions.js b/changedetectionio/static/js/conditions.js index a33fafc6..6bbfbc66 100644 --- a/changedetectionio/static/js/conditions.js +++ b/changedetectionio/static/js/conditions.js @@ -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"); diff --git a/changedetectionio/static/styles/scss/parts/_conditions_table.scss b/changedetectionio/static/styles/scss/parts/_conditions_table.scss new file mode 100644 index 00000000..c4e583bd --- /dev/null +++ b/changedetectionio/static/styles/scss/parts/_conditions_table.scss @@ -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; + } + } + +} \ No newline at end of file diff --git a/changedetectionio/static/styles/scss/styles.scss b/changedetectionio/static/styles/scss/styles.scss index 8e87dc5e..21075079 100644 --- a/changedetectionio/static/styles/scss/styles.scss +++ b/changedetectionio/static/styles/scss/styles.scss @@ -14,6 +14,7 @@ @import "parts/_love"; @import "parts/preview_text_filter"; @import "parts/_edit"; +@import "parts/_conditions_table"; body { color: var(--color-text); diff --git a/changedetectionio/static/styles/styles.css b/changedetectionio/static/styles/styles.css index 104fe012..28cb0ec2 100644 --- a/changedetectionio/static/styles/styles.css +++ b/changedetectionio/static/styles/styles.css @@ -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); diff --git a/changedetectionio/templates/_helpers.html b/changedetectionio/templates/_helpers.html index 2ed75a30..669755ee 100644 --- a/changedetectionio/templates/_helpers.html +++ b/changedetectionio/templates/_helpers.html @@ -61,21 +61,20 @@ {{ field(**kwargs)|safe }} {% endmacro %} -{% macro render_fieldlist_of_formfields_as_table(fieldlist, table_id="rulesTable") %} - - - - {% for subfield in fieldlist[0] %} - - {% endfor %} - - - - +{% macro render_conditions_fieldlist_of_formfields_as_table(fieldlist, table_id="rulesTable") %} +
+
+ {% for subfield in fieldlist[0] %} +
{{ subfield.label }}
+ {% endfor %} +
Actions
+
+
{% for form_row in fieldlist %} -
+
{% for subfield in form_row %} -
+ {% endfor %} - - + + {% endfor %} - -
{{ subfield.label }}Actions
+
+ {{ subfield()|safe }} {% if subfield.errors %}
    @@ -84,17 +83,17 @@ {% endfor %}
{% endif %} -
- - +
+ + -
+ + {% endmacro %} diff --git a/changedetectionio/templates/edit.html b/changedetectionio/templates/edit.html index 59fc1f06..2914d73a 100644 --- a/changedetectionio/templates/edit.html +++ b/changedetectionio/templates/edit.html @@ -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 %} @@ -289,21 +289,9 @@ Math: {{ 1 + 1 }}") }} -
{{ render_field(form.conditions_match_logic) }} - {{ render_fieldlist_of_formfields_as_table(form.conditions) }} + {{ render_conditions_fieldlist_of_formfields_as_table(form.conditions) }}

Use the verify (✓) button to test if a condition passes against the current snapshot.