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