xref: /webtrees/resources/views/admin/data-fix-page.phtml (revision 7afd76dffa1031f0b39c55661deb3bb5722f932e)
1<?php
2
3declare(strict_types=1);
4
5use Fisharebest\Webtrees\Http\RequestHandlers\ControlPanel;
6use Fisharebest\Webtrees\Http\RequestHandlers\DataFixData;
7use Fisharebest\Webtrees\Http\RequestHandlers\DataFixPage;
8use Fisharebest\Webtrees\Http\RequestHandlers\DataFixUpdateAll;
9use Fisharebest\Webtrees\Http\RequestHandlers\HelpText;
10use Fisharebest\Webtrees\Http\RequestHandlers\ManageTrees;
11use Fisharebest\Webtrees\I18N;
12use Fisharebest\Webtrees\Module\ModuleDataFixInterface;
13use Fisharebest\Webtrees\Tree;
14use Fisharebest\Webtrees\View;
15
16/**
17 * @var ModuleDataFixInterface $data_fix
18 * @var string                 $latest_version
19 * @var string                 $title
20 * @var Tree                   $tree
21 * @var string                 $pending_url
22 */
23
24?>
25
26<?= view('components/breadcrumbs', ['links' => [route(ControlPanel::class) => I18N::translate('Control panel'), route(ManageTrees::class, ['tree' => $tree->name()]) => I18N::translate('Manage family trees'), route(DataFixPage::class, ['tree' => $tree->name()]) => view('icons/data-fix') . I18N::translate('Data fixes'), $title]]) ?>
27
28<h1><?= $title ?></h1>
29
30<form action="#" id="data-fix-options">
31    <p>
32        <?= $data_fix->description() ?>
33    </p>
34
35    <?= $data_fix->fixOptions($tree) ?>
36
37    <div class="row mb-3">
38        <div class="col-sm-3">
39        </div>
40
41        <div class="col-sm-9">
42            <button class="btn btn-primary" type="button" id="btn-search">
43                <?= view('icons/search') ?>
44                <?= I18N::translate('Search') ?>
45            </button>
46
47            <button class="btn btn-primary" type="button" id="btn-update-all">
48                <?= view('icons/data-fix') ?>
49                <?= I18N::translate('Update all') ?>
50            </button>
51        </div>
52    </div>
53</form>
54
55<div id="data-fix-table-container" class="d-none">
56    <table
57        id="data-fix-table"
58        class="table table-bordered table-sm table-hover wt-data-fix-table"
59        <?= view('lists/datatables-attributes') ?>
60        data-server-side="true"
61        data-filter="false"
62        data-processing="true"
63        data-sort="false"
64    >
65        <thead>
66            <tr>
67                <th class="w-75">
68                    <?= I18N::translate('Record') ?>
69                </th>
70                <th class="w-25">
71                    <?= view('icons/data-fix') ?>
72                    <?= I18N::translate('Data fix') ?>
73                </th>
74            </tr>
75        </thead>
76        <tbody>
77        </tbody>
78    </table>
79
80    <hr>
81
82    <a href="#" data-bs-toggle="modal" data-bs-backdrop="static" data-bs-target="#wt-ajax-modal" data-wt-href="<?= e(route(HelpText::class, ['topic' => 'data-fixes'])) ?>">
83        <?= view('icons/help') ?>
84        <?= I18N::translate('Why does this list include records that do not need to be updated?') ?>
85    </a>
86</div>
87
88<div id="data-fix-progress" class="d-none">
89    <div class="progress" role="progressbar">
90        <div class="progress-bar"></div>
91    </div>
92</div>
93
94<?= view('modals/ajax') ?>
95
96<?php View::push('javascript') ?>
97<script>
98  (function () {
99    let form = document.getElementById('data-fix-options');
100    let container = document.getElementById('data-fix-table-container');
101    let table = document.getElementById('data-fix-table');
102    let progress = document.getElementById('data-fix-progress');
103    let progressbar = progress.querySelector('.progress-bar');
104    let queue = [];
105
106    function getParams () {
107      let formData = new FormData(form);
108      let params = {};
109      formData.forEach(function (value, key) {
110        params[key] = value;
111      });
112
113      return params;
114    }
115
116    function addParamsToUrl (u) {
117      let url = new URL(u);
118      let formData = new FormData(form);
119      formData.forEach(function (value, key) {
120        url.searchParams.append(key, value);
121      });
122
123      return url.toString();
124
125    }
126
127    form.addEventListener('submit', function (event) {
128      event.preventDefault();
129    });
130
131    container.addEventListener('click', function (event) {
132      if ('updateUrl' in event.target.dataset) {
133        event.preventDefault();
134
135        webtrees.httpPost(event.target.dataset.updateUrl)
136          .then(function (response) {
137            $(table).DataTable().ajax.reload(null, false);
138          })
139          .catch(function (error) {
140            alert(error);
141        });
142      }
143    });
144
145    document.getElementById('btn-search').addEventListener('click', function (event) {
146      event.preventDefault();
147
148      // If we were in the middle of doing "update all", stop processing.
149      queue = [];
150
151      progress.classList.add('d-none');
152
153      if ($.fn.dataTable.isDataTable(table)) {
154        $(table).DataTable().ajax.reload();
155      } else {
156        $(table).DataTable({
157          'ajax': {
158            'url': <?= json_encode(route(DataFixData::class, ['tree' => $tree->name(), 'data_fix' => $data_fix->name()]), JSON_THROW_ON_ERROR) ?>,
159            'data': function (data) {
160              $.extend(data, getParams());
161            }
162          }
163        });
164      }
165
166      container.classList.remove('d-none');
167    });
168
169    document.getElementById('btn-update-all').addEventListener('click', function (event) {
170      event.preventDefault();
171
172      progressbar.innerHTML = '';
173      progressbar.style.width = '0%';
174
175      container.classList.add('d-none');
176      progress.classList.remove('d-none');
177
178      let url = addParamsToUrl(<?= json_encode(route(DataFixUpdateAll::class, ['tree' => $tree->name(), 'data_fix' => $data_fix->name()]), JSON_THROW_ON_ERROR) ?>);
179
180      webtrees.httpPost(url)
181        .then(function (response) {
182          return response.json();
183        })
184        .then(async function (data) {
185          queue = data;
186          while (queue.length > 0) {
187            let datum = queue.shift();
188            await webtrees.httpPost(datum.url)
189              .then(function () {
190                let progressbar = progress.querySelector('.progress-bar');
191                progressbar.innerHTML = datum.progress;
192                progressbar.style.width = datum.percent;
193              });
194          }
195        })
196        .catch(function (error) {
197          progress.innerHTML = error;
198        });
199    });
200  })();
201</script>
202<?php View::endpush() ?>
203