Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[proofing] search and replace matching strings across all pages in a project #476

Merged
merged 29 commits into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6ffb331
add validators for user creds
kvchitrapu Feb 22, 2023
d15a892
use get_x_validators() straight w/o unpacking
kvchitrapu Feb 23, 2023
53fd4ce
a better pythonic init and comparison of integers
kvchitrapu Feb 24, 2023
3111d54
ran py-lint
kvchitrapu Feb 24, 2023
0fb7887
change `update` to `replace` in project.py
kvchitrapu Mar 1, 2023
290e509
Merge branch 'main' of github.com:kvchitrapu/ambuda into feature-sear…
kvchitrapu Mar 4, 2023
e361b03
submit edits and confirm them (wip)
kvchitrapu Mar 15, 2023
8bea0b2
working all the way to add_revision() - wip
kvchitrapu Mar 16, 2023
4c266cf
search and replace is working now
kvchitrapu Mar 17, 2023
7406c3a
fixed lint and unit tests
kvchitrapu Mar 17, 2023
f91a755
added couple of simple tests
kvchitrapu Mar 17, 2023
d2d4b0f
minor edit to confirm confirm changes step.
kvchitrapu Mar 17, 2023
798017a
fixed lint issue
kvchitrapu Mar 17, 2023
a8f123c
added couple of tests to barely fix unittests
kvchitrapu Mar 17, 2023
dd98f24
add coverage report target in Makefile
kvchitrapu Mar 17, 2023
c598452
Merge branch 'clean' into feature-search-replace
kvchitrapu Mar 17, 2023
c09ef66
search and replace matching strings across all pages in a project
kvchitrapu Mar 18, 2023
ce583cf
search and replace matching strings across all pages in a project (#79)
kvchitrapu Mar 18, 2023
b330399
added regex query support
kvchitrapu Mar 21, 2023
7ca43aa
Merge branch 'main' into issue-470-search-replace
kvchitrapu Mar 21, 2023
26ff487
fixed lint issue
kvchitrapu Mar 21, 2023
4d97d26
Merge branch 'issue-470-search-replace' of github.com:kvchitrapu/ambu…
kvchitrapu Mar 21, 2023
3a6c4ae
Issue 470 search replace (#82)
kvchitrapu Mar 21, 2023
4c7b0c4
updated Search & Replace comment
kvchitrapu Mar 21, 2023
ff29a4f
Merge branch 'main' into issue-470-search-replace
kvchitrapu Mar 21, 2023
e34fba1
search and replace with regular expression query patterns (#83)
kvchitrapu Mar 21, 2023
ea65bfc
replace the revision
kvchitrapu Mar 22, 2023
2cffa01
add unittest for submit_changes
kvchitrapu Mar 22, 2023
c9d7566
Merge branch 'main' into issue-470-search-replace
kvchitrapu Mar 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ test: py-venv-check
coverage:
pytest --cov=ambuda --cov-report=html test/

coverage-report: coverage
coverage report --fail-under=80

# Generate Ambuda's technical documentation.
# After the command completes, open "docs/_build/index.html".
docs: py-venv-check
Expand Down Expand Up @@ -275,6 +278,8 @@ babel-update: py-venv-check
babel-compile: py-venv-check
pybabel compile -d ambuda/translations

# Clean up
# ===============================================
clean:
@rm -rf deploy/data/
@rm -rf ambuda/translations/*
44 changes: 44 additions & 0 deletions ambuda/templates/proofing/projects/confirm_changes.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{% extends 'proofing/base.html' %}
{% from "macros/forms.html" import field %}
{% import "macros/proofing.html" as m %}

{% block title %} Search and Replace | {{ project.title }}{% endblock %}

{% block content %}

{{ m.project_header_nested('Review and Confirm Changes', project) }}
{{ m.project_nav(project=project, active='edit') }}

<div class="prose">
<h1>Confirm Changes</h1>
{% macro sp(s, p, n) %}{% if n == 1 %}{{ s }}{% else %}{{ p }}{% endif %}{% endmacro %}
<p>Please carefully review and confirm the changes you selected:</p>
<form method="POST" action="{{ url_for('proofing.project.confirm_changes', slug=project.slug) }}" class="bg-slate-100 p-4 my-4">
{{ form.csrf_token }}
<input type="hidden" name="query" value="{{ query }}">
<input type="hidden" name="replace" value="{{ replace }}">

{% set match_counts = results|map(attribute='matches')|map('length')|list %}
{% set nr = match_counts|sum %}
<p>Confirm changes on {{ nr }} {{ sp("match", "matches", nr) }} that {{ sp("contains", "contain", nr) }} <span style="color: red;"><kbd>{{ query }}</kbd></span> to be replaced by <span style="color: green;"><kbd>{{ replace }}</kbd></span>.</p>

{% for result in results %}
{% set page = result.page %}
{% set page_url = url_for("proofing.page.edit", project_slug=project.slug, page_slug=page.slug) %}
{% set matches = result.matches %}
{% for match in matches %}
<div class="match" style="background-color: rgb(243, 239, 239);">
<p>Page <a href="{{ page_url }}">{{ project.title }}/{{ page.slug }}:</a> Line {{ match.line_num }}</p>
<label for="match{{ page.slug }}-{{ match.line_num }}">{{ match.query }}</label>
<input type="hidden" name="match{{ page.slug }}-{{ match.line_num }}-query" value="{{ match.query }}">
<br>
<label for="match{{ page.slug }}-{{ match.line_num }}-replace" style="color: rgb(97, 86, 66); background-color: rgb(219, 215, 215);"> {{ match.replace }} </label>
<input type="hidden" name="match{{ page.slug }}-{{ match.line_num }}-replace" value="{{ match.replace }}">
</div>
{% endfor %}
{% endfor %}
<button class="btn btn-submit" type="submit" name="cancel" value="cancel">Cancel</button>
<button class="btn btn-submit" type="submit" name="confirm" value="confirm">Confirm</button>
</form>
</div>
{% endblock %}
111 changes: 84 additions & 27 deletions ambuda/templates/proofing/projects/replace.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,95 @@
{{ m.project_nav(project=project, active='edit') }}

<div class="prose">
<p>Use this simple search and replace form to make edits across this project.</p>
<h1>Replace</h1>
<p>Use this simple search and replace form to make edits across this project. The search supports regular expressions.</p>
<form method="POST" class="bg-slate-100 p-4 my-4">

{{ field(form.query) }}
{{ field(form.replace) }}
<input class="btn btn-submit" type="submit" name="search" value="Project-wide Search & Replace">
</form>
</div>

<form method="GET" class="bg-slate-100 p-4 my-4">
{{ field(form.query) }}
{{ field(form.replace) }}
<input class="btn btn-submit" type="submit" value="Project-wide Search & Replace">
</form>

{% if query %}
{% if results %}
<div class="prose">
<h1>Matches</h1>
{% macro sp(s, p, n) %}{% if n == 1 %}{{ s }}{% else %}{{ p }}{% endif %}{% endmacro %}
<form method="POST" action="{{ url_for('proofing.project.submit_changes', slug=project.slug) }}" class="bg-slate-100 p-4 my-4">
{{ submit_changes_form.csrf_token }}
<input type="hidden" name="query" value="{{ query }}">
<input type="hidden" name="replace" value="{{ replace }}">

{% macro sp(s, p, n) %}{% if n == 1 %}{{ s }}{% else %}{{ p }}{% endif %}{% endmacro %}

{% set nr = results|length %}
<p>Found {{ nr }} {{ sp("page", "pages", nr) }} that {{ sp("contains", "contain", nr) }} <kbd>{{ query }}</kbd>.</p>

<ul>
{% for page in results %}
{% set page_url = url_for("proofing.page.edit", project_slug=project.slug, page_slug=page.slug) %}
<li>
<a href="{{ page_url }}">{{ project.title }}/{{ page.slug }}</a>
<div class="p-2 border-l my-2">
{% for match in page.matches %}
<pre class="p-0.5">{{ match.query }}</pre>
<pre class="p-0.5">{{ match.update }}</pre>
{%- endfor %}
{% set nr = results|length %}
<p>Found {{ nr }} {{ sp("page", "pages", nr) }} that {{ sp("contains", "contain", nr) }} <kbd>{{ query }}</kbd>.</p>
<ul>
<div class="match">
<input type="checkbox" name="select-all" id="select-all">
<label for="select-all">Select all in this page </label>
</div>
</li>
{% endfor %}
</ul>

{% for page in results %}
{% set page_url = url_for("proofing.page.edit", project_slug=project.slug, page_slug=page.slug) %}
<li>
<a href="{{ page_url }}">{{ project.title }}/{{ page.slug }}</a>
<div class="p-2 border-l my-2">
{% for match in page.matches %}
<div class="match" style="background-color: rgb(243, 239, 239);">
<input type="checkbox" name="match{{ page.slug }}-{{ match.line_num }}" id="match{{ page.slug }}-{{ match.line_num }}" value="selected">
<p>Page <a href="{{ page_url }}">{{ project.title }}/{{ page.slug }}:</a> Line {{ match.line_num }}</p>
<label for="match{{ page.slug }}-{{ match.line_num }}">{{ match.query|safe }}</label>
<br>
<label for="match{{ page.slug }}-{{ match.line_num }}-replace" style="color: rgb(97, 86, 66); background-color: rgb(219, 215, 215);"> {{ match.replace|safe }} </label>
<input type="hidden" name="match{{ page.slug }}-{{ match.line_num }}-replace" id="match{{ page.slug }}-{{ match.line_num }}-replace" value="{{ match.replace }}">
</div>
<br>
{% endfor %}
</div>
</li>
{% endfor %}
{% if submit_changes_form %}
{{ submit_changes_form.submit(class="btn btn-submit") }}
{% else %}
<input class="btn btn-submit" type="submit" name="submit" value="Submit Changes">
{% endif %}
</form>
</ul>
<script>
(function() {
// Get references to the "select-all" checkbox and all the other checkboxes
const checkAll = document.querySelector("#select-all");
const checkboxes = document.querySelectorAll('input[type="checkbox"][name^="match"]');

// Function to update the visibility of the replaceField element
function updateReplaceFieldVisibility(checkbox) {
const replaceField = document.querySelector(`#${checkbox.id}-replace`);
if (checkbox.checked) {
replaceField.style.display = "";
} else {
replaceField.style.display = "none";
}
}

// Add a change event listener to the "select-all" checkbox
checkAll.addEventListener("change", function(event) {
// If the "select-all" checkbox is checked, check all the other checkboxes
// and update the replaceField visibility
checkboxes.forEach(function(checkbox) {
checkbox.checked = event.target.checked;
updateReplaceFieldVisibility(checkbox);
});
});

// Add change event listeners to each individual checkbox
checkboxes.forEach(function(checkbox) {
checkbox.addEventListener("change", function(event) {
updateReplaceFieldVisibility(event.target);

// Update the state of the 'select-all' checkbox
checkAll.checked = Array.from(checkboxes).every(checkbox => checkbox.checked);
});
});
})();
</script>
</div>
{% endif %}
{% endblock %}
Loading