xref: /webtrees/resources/views/admin/control-panel.phtml (revision 4991f2057a6647447a648c5d6743dab00378e98e)
1<?php
2
3use Fisharebest\Webtrees\Http\RequestHandlers\BroadcastPage;
4use Fisharebest\Webtrees\Http\RequestHandlers\CleanDataFolder;
5use Fisharebest\Webtrees\Http\RequestHandlers\ControlPanel;
6use Fisharebest\Webtrees\Http\RequestHandlers\CreateTreePage;
7use Fisharebest\Webtrees\Http\RequestHandlers\EmailPreferencesPage;
8use Fisharebest\Webtrees\Http\RequestHandlers\FixLevel0MediaPage;
9use Fisharebest\Webtrees\Http\RequestHandlers\ImportThumbnailsPage;
10use Fisharebest\Webtrees\Http\RequestHandlers\ManageMediaPage;
11use Fisharebest\Webtrees\Http\RequestHandlers\ManageTrees;
12use Fisharebest\Webtrees\Http\RequestHandlers\MapDataList;
13use Fisharebest\Webtrees\Http\RequestHandlers\MergeTreesPage;
14use Fisharebest\Webtrees\Http\RequestHandlers\ModulesAllPage;
15use Fisharebest\Webtrees\Http\RequestHandlers\ModulesAnalyticsPage;
16use Fisharebest\Webtrees\Http\RequestHandlers\ModulesBlocksPage;
17use Fisharebest\Webtrees\Http\RequestHandlers\ModulesChartsPage;
18use Fisharebest\Webtrees\Http\RequestHandlers\ModulesCustomTagsPage;
19use Fisharebest\Webtrees\Http\RequestHandlers\ModulesDataFixesPage;
20use Fisharebest\Webtrees\Http\RequestHandlers\ModulesFootersPage;
21use Fisharebest\Webtrees\Http\RequestHandlers\ModulesHistoricEventsPage;
22use Fisharebest\Webtrees\Http\RequestHandlers\ModulesLanguagesPage;
23use Fisharebest\Webtrees\Http\RequestHandlers\ModulesListsPage;
24use Fisharebest\Webtrees\Http\RequestHandlers\ModulesMapAutocompletePage;
25use Fisharebest\Webtrees\Http\RequestHandlers\ModulesMapGeoLocationsPage;
26use Fisharebest\Webtrees\Http\RequestHandlers\ModulesMapLinksPage;
27use Fisharebest\Webtrees\Http\RequestHandlers\ModulesMapProvidersPage;
28use Fisharebest\Webtrees\Http\RequestHandlers\ModulesMenusPage;
29use Fisharebest\Webtrees\Http\RequestHandlers\ModulesReportsPage;
30use Fisharebest\Webtrees\Http\RequestHandlers\ModulesSharesPage;
31use Fisharebest\Webtrees\Http\RequestHandlers\ModulesSidebarsPage;
32use Fisharebest\Webtrees\Http\RequestHandlers\ModulesTabsPage;
33use Fisharebest\Webtrees\Http\RequestHandlers\ModulesThemesPage;
34use Fisharebest\Webtrees\Http\RequestHandlers\PendingChanges;
35use Fisharebest\Webtrees\Http\RequestHandlers\PhpInformation;
36use Fisharebest\Webtrees\Http\RequestHandlers\SiteLogsPage;
37use Fisharebest\Webtrees\Http\RequestHandlers\SitePreferencesPage;
38use Fisharebest\Webtrees\Http\RequestHandlers\SiteRegistrationPage;
39use Fisharebest\Webtrees\Http\RequestHandlers\SiteTagsPage;
40use Fisharebest\Webtrees\Http\RequestHandlers\TreePageDefaultEdit;
41use Fisharebest\Webtrees\Http\RequestHandlers\UpgradeWizardPage;
42use Fisharebest\Webtrees\Http\RequestHandlers\UploadMediaPage;
43use Fisharebest\Webtrees\Http\RequestHandlers\UserAddPage;
44use Fisharebest\Webtrees\Http\RequestHandlers\UserEditPage;
45use Fisharebest\Webtrees\Http\RequestHandlers\UserListPage;
46use Fisharebest\Webtrees\Http\RequestHandlers\UserPageDefaultEdit;
47use Fisharebest\Webtrees\Http\RequestHandlers\UsersCleanupPage;
48use Fisharebest\Webtrees\I18N;
49use Fisharebest\Webtrees\Module\FamilyListModule;
50use Fisharebest\Webtrees\Module\IndividualListModule;
51use Fisharebest\Webtrees\Module\MediaListModule;
52use Fisharebest\Webtrees\Module\ModuleAnalyticsInterface;
53use Fisharebest\Webtrees\Module\ModuleBlockInterface;
54use Fisharebest\Webtrees\Module\ModuleChartInterface;
55use Fisharebest\Webtrees\Module\ModuleConfigInterface;
56use Fisharebest\Webtrees\Module\ModuleCustomInterface;
57use Fisharebest\Webtrees\Module\ModuleCustomTagsInterface;
58use Fisharebest\Webtrees\Module\ModuleDataFixInterface;
59use Fisharebest\Webtrees\Module\ModuleFooterInterface;
60use Fisharebest\Webtrees\Module\ModuleHistoricEventsInterface;
61use Fisharebest\Webtrees\Module\ModuleInterface;
62use Fisharebest\Webtrees\Module\ModuleLanguageInterface;
63use Fisharebest\Webtrees\Module\ModuleListInterface;
64use Fisharebest\Webtrees\Module\ModuleMapAutocompleteInterface;
65use Fisharebest\Webtrees\Module\ModuleMapGeoLocationInterface;
66use Fisharebest\Webtrees\Module\ModuleMapLinkInterface;
67use Fisharebest\Webtrees\Module\ModuleMapProviderInterface;
68use Fisharebest\Webtrees\Module\ModuleMenuInterface;
69use Fisharebest\Webtrees\Module\ModuleReportInterface;
70use Fisharebest\Webtrees\Module\ModuleShareInterface;
71use Fisharebest\Webtrees\Module\ModuleSidebarInterface;
72use Fisharebest\Webtrees\Module\ModuleTabInterface;
73use Fisharebest\Webtrees\Module\ModuleThemeInterface;
74use Fisharebest\Webtrees\Module\NoteListModule;
75use Fisharebest\Webtrees\Module\RepositoryListModule;
76use Fisharebest\Webtrees\Module\SourceListModule;
77use Fisharebest\Webtrees\Module\SubmitterListModule;
78use Fisharebest\Webtrees\Tree;
79use Fisharebest\Webtrees\User;
80use Fisharebest\Webtrees\Webtrees;
81use Illuminate\Support\Collection;
82
83/**
84 * @var Collection<int,User>                           $administrators
85 * @var Collection<int,ModuleInterface>                $all_modules_disabled
86 * @var Collection<int,ModuleInterface>                $all_modules_enabled
87 * @var Collection<int,Tree>                           $all_trees
88 * @var Collection<int,User>                           $all_users
89 * @var Collection<int,ModuleAnalyticsInterface>       $analytics_modules_disabled
90 * @var Collection<int,ModuleAnalyticsInterface>       $analytics_modules_enabled
91 * @var Collection<int,ModuleBlockInterface>           $block_modules_disabled
92 * @var Collection<int,ModuleBlockInterface>           $block_modules_enabled
93 * @var array<string,int>                              $changes
94 * @var Collection<int,ModuleChartInterface>           $chart_modules_disabled
95 * @var Collection<int,ModuleChartInterface>           $chart_modules_enabled
96 * @var Collection<int,ModuleCustomInterface>          $custom_updates
97 * @var Collection<int,ModuleCustomTagsInterface>      $custom_tags_modules_disabled
98 * @var Collection<int,ModuleCustomTagsInterface>      $custom_tags_modules_enabled
99 * @var Collection<int,ModuleDataFixInterface>         $data_fix_modules_disabled
100 * @var Collection<int,ModuleDataFixInterface>         $data_fix_modules_enabled
101 * @var Collection<array-key,int>                      $families
102 * @var FamilyListModule|null                          $family_list_module
103 * @var Collection<int,ModuleFooterInterface>          $footer_modules_disabled
104 * @var Collection<int,ModuleFooterInterface>          $footer_modules_enabled
105 * @var Collection<int,ModuleHistoricEventsInterface>  $history_modules_disabled
106 * @var Collection<int,ModuleHistoricEventsInterface>  $history_modules_enabled
107 * @var Collection<array-key,int>                      $individuals
108 * @var IndividualListModule|null                      $individual_list_module
109 * @var Collection<int,ModuleLanguageInterface>        $language_modules_disabled
110 * @var Collection<int,ModuleLanguageInterface>        $language_modules_enabled
111 * @var string                                         $latest_version
112 * @var Collection<int,ModuleListInterface>            $list_modules_disabled
113 * @var Collection<int,ModuleListInterface>            $list_modules_enabled
114 * @var Collection<int,ModuleMapLinkInterface>         $map_link_modules_disabled
115 * @var Collection<int,ModuleMapLinkInterface>         $map_link_modules_enabled
116 * @var Collection<int,ModuleMapAutocompleteInterface> $map_autocomplete_modules_disabled
117 * @var Collection<int,ModuleMapAutocompleteInterface> $map_autocomplete_modules_enabled
118 * @var Collection<int,ModuleMapProviderInterface>     $map_provider_modules_disabled
119 * @var Collection<int,ModuleMapProviderInterface>     $map_provider_modules_enabled
120 * @var Collection<int,ModuleMapGeoLocationInterface>  $map_search_modules_disabled
121 * @var Collection<int,ModuleMapGeoLocationInterface>  $map_search_modules_enabled
122 * @var Collection<int,User>                           $managers
123 * @var Collection<array-key,int>                      $media
124 * @var MediaListModule|null                           $media_list_module
125 * @var Collection<int,ModuleMenuInterface>            $menu_modules_disabled
126 * @var Collection<int,ModuleMenuInterface>            $menu_modules_enabled
127 * @var Collection<int,User>                           $moderators
128 * @var Collection<array-key,int>                      $notes
129 * @var NoteListModule|null                            $note_list_module
130 * @var Collection<int,ModuleInterface>                $other_modules
131 * @var array<string,string>                           $recipients
132 * @var Collection<int,ModuleReportInterface>          $report_modules_disabled
133 * @var Collection<int,ModuleReportInterface>          $report_modules_enabled
134 * @var Collection<array-key,int>                      $repositories
135 * @var RepositoryListModule|null                      $repository_list_module
136 * @var Collection<int,string>                         $server_errors
137 * @var Collection<int,string>                         $server_warnings
138 * @var bool                                           $show_synchronize
139 * @var Collection<int,ModuleShareInterface>           $share_modules_disabled
140 * @var Collection<int,ModuleShareInterface>           $share_modules_enabled
141 * @var Collection<int,ModuleSidebarInterface>         $sidebar_modules_disabled
142 * @var Collection<int,ModuleSidebarInterface>         $sidebar_modules_enabled
143 * @var Collection<array-key,int>                      $sources
144 * @var SourceListModule|null                          $source_list_module
145 * @var Collection<array-key,int>                      $submitters
146 * @var SubmitterListModule|null                       $submitter_list_module
147 * @var Collection<int,ModuleTabInterface>             $tab_modules_disabled
148 * @var Collection<int,ModuleTabInterface>             $tab_modules_enabled
149 * @var Collection<int,ModuleThemeInterface>           $theme_modules_disabled
150 * @var Collection<int,ModuleThemeInterface>           $theme_modules_enabled
151 * @var string                                         $title
152 * @var Collection<int,User>                           $unapproved
153 * @var Collection<int,User>                           $unverified
154 */
155
156?>
157
158<h1><?= $title ?></h1>
159
160<!-- WEBSITE / WEBTREES -->
161<div class="card mb-4">
162    <div class="card-header">
163        <h2 class="mb-0">
164            <?= I18N::translate('Website') ?>
165            <span class="badge bg-secondary" dir="ltr">
166                <?= e(Webtrees::VERSION) ?>
167            </span>
168        </h2>
169    </div>
170    <div class="card-body">
171        <?php foreach ($server_errors as $server_error) : ?>
172            <p class="alert alert-danger"><?= $server_error ?></p>
173        <?php endforeach ?>
174
175        <?php foreach ($server_warnings as $server_warning) : ?>
176            <p class="alert alert-warning"><?= $server_warning ?></p>
177        <?php endforeach ?>
178
179        <p class="card-text">
180            <?= /* I18N: %s is a URL/link to the project website */
181            I18N::translate('Support and documentation can be found at %s.', '<a href="https://webtrees.net/">webtrees.net</a>') ?>
182        </p>
183
184        <?php if ($latest_version === '') : ?>
185            <p class="card-text">
186                <?= I18N::translate('No upgrade information is available.') ?>
187            </p>
188        <?php elseif (version_compare(Webtrees::VERSION, $latest_version) < 0) : ?>
189            <p class="card-text alert alert-info">
190                <?= I18N::translate('A new version of webtrees is available.') ?>
191                <a href="<?= e(route(UpgradeWizardPage::class)) ?>" class="alert-link">
192                    <?= /* I18N: %s is a version number */
193                    I18N::translate('Upgrade to webtrees %s.', e($latest_version)) ?>
194                </a>
195            </p>
196        <?php else : ?>
197            <p class="card-text">
198                <?= I18N::translate('This is the latest version of webtrees. No upgrade is available.') ?>
199            </p>
200        <?php endif ?>
201
202        <?php foreach ($custom_updates as $module) : ?>
203        <div class="alert alert-info">
204            <?= view('icons/information') ?>
205            <?= I18N::translate('An upgrade is available.') ?>
206            <br>
207            <?= $module->title() ?><?= e($module->customModuleVersion()) ?><?= e($module->customModuleLatestVersion()) ?>
208            <?php if ($module->customModuleSupportUrl() !== '') : ?>
209                <br>
210                <?= I18N::translate('For more information, see %s.', '<a href="' . e($module->customModuleSupportUrl()) . '">' . e($module->customModuleSupportUrl()) . '</a>') ?>
211            <?php endif ?>
212        </div>
213        <?php endforeach ?>
214
215        <div class="row">
216            <div class="col-sm">
217                <ul class="fa-ul mx-0">
218                    <li>
219                        <span class="fa-li"><?= view('icons/preferences') ?></span>
220                        <a href="<?= e(route(SitePreferencesPage::class)) ?>">
221                            <?= I18N::translate('Website preferences') ?>
222                        </a>
223                    </li>
224                    <li>
225                        <span class="fa-li"><?= view('icons/email') ?></span>
226                        <a href="<?= e(route(EmailPreferencesPage::class)) ?>">
227                            <?= I18N::translate('Sending email') ?>
228                        </a>
229                    </li>
230                    <li>
231                        <span class="fa-li"><?= view('icons/user') ?></span>
232                        <a href="<?= e(route(SiteRegistrationPage::class)) ?>">
233                            <?= I18N::translate('Sign-in and registration') ?>
234                        </a>
235                    </li>
236                </ul>
237            </div>
238            <div class="col-sm">
239                <ul class="fa-ul mx-0">
240                    <li>
241                        <span class="fa-li"><?= view('icons/list') ?></span>
242                        <a href="<?= e(route(SiteLogsPage::class)) ?>">
243                            <?= I18N::translate('Website logs') ?>
244                        </a>
245                    </li>
246                    <li>
247                        <span class="fa-li"><?= view('icons/delete') ?></span>
248                        <a href="<?= e(route(CleanDataFolder::class)) ?>">
249                            <?= I18N::translate('Clean up data folder') ?>
250                        </a>
251                    </li>
252                    <li>
253                        <span class="fa-li"><?= view('icons/help') ?></span>
254                        <a href="<?= e(route(PhpInformation::class)) ?>">
255                            <?= I18N::translate('Server information') ?>
256                        </a>
257                    </li>
258                </ul>
259            </div>
260            <div class="col-sm">
261                <ul class="fa-ul mx-0">
262                    <li>
263                        <span class="fa-li"><?= view('icons/tag') ?></span>
264                        <a href="<?= e(route(SiteTagsPage::class)) ?>">
265                            <?= I18N::translate('GEDCOM tags') ?>
266                        </a>
267                    </li>
268                </ul>
269            </div>
270        </div>
271    </div>
272</div>
273
274<!-- FAMILY TREES -->
275<div class="card mb-4 <?= array_sum($changes) ? 'card-outline-danger' : '' ?>">
276    <div class="card-header">
277        <h2 class="mb-0">
278            <?= I18N::translate('Family trees') ?>
279            <span class="badge bg-secondary">
280                    <?= I18N::number($all_trees->count()) ?>
281                </span>
282        </h2>
283    </div>
284
285    <div class="card-body">
286        <?php if ($all_trees->isEmpty()) : ?>
287            <p class="alert alert-info">
288                <?= I18N::translate('You need to create a family tree.') ?>
289            </p>
290        <?php endif ?>
291
292        <ul class="fa-ul mx-0">
293            <li>
294                <span class="fa-li"><?= view('icons/add') ?></span>
295                <a href="<?= e(route(CreateTreePage::class)) ?>">
296                    <?= I18N::translate('Create a family tree') ?>
297                </a>
298            </li>
299            <li>
300                <span class="fa-li"><?= view('icons/block') ?></span>
301                <a href="<?= e(route(TreePageDefaultEdit::class)) ?>">
302                    <?= I18N::translate('Set the default blocks for new family trees') ?>
303                </a>
304            </li>
305            <?php if (count($all_trees) > 1) : ?>
306                <li>
307                    <span class="fa-li"><?= view('icons/merge') ?></span>
308                    <a href="<?= e(route(MergeTreesPage::class)) ?>">
309                        <?= I18N::translate('Merge family trees') ?>
310                    </a>
311                </li>
312            <?php endif ?>
313        </ul>
314
315        <table class="table table-sm">
316            <caption class="visually-hidden">
317                <?= I18N::translate('Family trees') ?>
318            </caption>
319
320            <thead>
321                <tr>
322                    <th><?= I18N::translate('Family tree') ?></th>
323                    <th class="align-digits"><?= I18N::translate('Pending changes') ?></th>
324                    <th class="d-none d-sm-table-cell align-digits"><?= I18N::translate('Individuals') ?></th>
325                    <th class="d-none d-lg-table-cell align-digits"><?= I18N::translate('Families') ?></th>
326                    <th class="d-none d-sm-table-cell align-digits"><?= I18N::translate('Sources') ?></th>
327                    <th class="d-none d-lg-table-cell align-digits"><?= I18N::translate('Repositories') ?></th>
328                    <th class="d-none d-sm-table-cell align-digits"><?= I18N::translate('Media') ?></th>
329                    <th class="d-none d-lg-table-cell align-digits"><?= I18N::translate('Notes') ?></th>
330                    <th class="d-none d-lg-table-cell align-digits"><?= I18N::translate('Submitters') ?></th>
331                </tr>
332            </thead>
333
334            <tbody>
335                <?php foreach ($all_trees as $tree) : ?>
336                    <tr class="<?= $changes[$tree->id()] ? 'danger' : '' ?>">
337                        <th scope="row">
338                            <?= view('icons/preferences') ?>
339                            <a href="<?= e(route(ManageTrees::class, ['tree' => $tree->name()])) ?>">
340                                <?= e($tree->name()) ?>
341                                -
342                                <?= e($tree->title()) ?>
343                            </a>
344                        </th>
345                        <td style="text-align: right;">
346                            <?php if ($changes[$tree->id()]) : ?>
347                                <a href="<?= e(route(PendingChanges::class, ['tree' => $tree->name(), 'url' => route(ControlPanel::class)])) ?>">
348                                    <?= I18N::number($changes[$tree->id()]) ?>
349                                    <span class="visually-hidden"><?= I18N::translate('Pending changes') ?> <?= e($tree->title()) ?></span>
350                                </a>
351                            <?php else : ?>
352                                -
353                            <?php endif ?>
354                        </td>
355                        <td class="d-none d-sm-table-cell align-digits">
356                            <?php if ($individuals[$tree->id()] > 0) : ?>
357                                <?php if ($individual_list_module instanceof IndividualListModule) : ?>
358                                    <a href="<?= e($individual_list_module->listUrl($tree)) ?>"><?= I18N::number($individuals[$tree->id()]) ?></a>
359                                <?php else : ?>
360                                    <?= I18N::number($individuals[$tree->id()]) ?>
361                                <?php endif ?>
362                            <?php else : ?>
363                                -
364                            <?php endif ?>
365                        </td>
366                        <td class="d-none d-lg-table-cell align-digits">
367                            <?php if ($families[$tree->id()] > 0) : ?>
368                                <?php if ($family_list_module instanceof FamilyListModule) : ?>
369                                    <a href="<?= e($family_list_module->listUrl($tree)) ?>"><?= I18N::number($families[$tree->id()]) ?></a>
370                                <?php else : ?>
371                                    <?= I18N::number($families[$tree->id()]) ?>
372                                <?php endif ?>
373                            <?php else : ?>
374                                -
375                            <?php endif ?>
376                        </td>
377                        <td class="d-none d-sm-table-cell align-digits">
378                            <?php if ($sources[$tree->id()] > 0) : ?>
379                                <?php if ($source_list_module instanceof SourceListModule) : ?>
380                                    <a href="<?= e($source_list_module->listUrl($tree)) ?>"><?= I18N::number($sources[$tree->id()]) ?></a>
381                                <?php else : ?>
382                                    <?= I18N::number($sources[$tree->id()]) ?>
383                                <?php endif ?>
384                            <?php else : ?>
385                                -
386                            <?php endif ?>
387                        </td>
388                        <td class="d-none d-lg-table-cell align-digits">
389                            <?php if ($repositories[$tree->id()] > 0) : ?>
390                                <?php if ($repository_list_module instanceof RepositoryListModule) : ?>
391                                    <a href="<?= e($repository_list_module->listUrl($tree)) ?>"><?= I18N::number($repositories[$tree->id()]) ?></a>
392                                <?php else : ?>
393                                    <?= I18N::number($repositories[$tree->id()]) ?>
394                                <?php endif ?>
395                            <?php else : ?>
396                                -
397                            <?php endif ?>
398                        </td>
399                        <td class="d-none d-sm-table-cell align-digits">
400                            <?php if ($media[$tree->id()] > 0) : ?>
401                                <?php if ($media_list_module instanceof MediaListModule) : ?>
402                                    <a href="<?= e($media_list_module->listUrl($tree)) ?>"><?= I18N::number($media[$tree->id()]) ?></a>
403                                <?php else : ?>
404                                    <?= I18N::number($media[$tree->id()]) ?>
405                                <?php endif ?>
406                            <?php else : ?>
407                                -
408                            <?php endif ?>
409                        </td>
410                        <td class="d-none d-lg-table-cell align-digits">
411                            <?php if ($notes[$tree->id()] > 0) : ?>
412                                <?php if ($note_list_module instanceof NoteListModule) : ?>
413                                    <a href="<?= e($note_list_module->listUrl($tree)) ?>"><?= I18N::number($notes[$tree->id()]) ?></a>
414                                <?php else : ?>
415                                    <?= I18N::number($notes[$tree->id()]) ?>
416                                <?php endif ?>
417                            <?php else : ?>
418                                -
419                            <?php endif ?>
420                        </td>
421                         <td class="d-none d-lg-table-cell align-digits">
422                            <?php if ($submitters[$tree->id()] > 0) : ?>
423                                <?php if ($submitter_list_module instanceof SubmitterListModule) : ?>
424                                    <a href="<?= e($submitter_list_module->listUrl($tree)) ?>"><?= I18N::number($submitters[$tree->id()]) ?></a>
425                                <?php else : ?>
426                                    <?= I18N::number($submitters[$tree->id()]) ?>
427                                <?php endif ?>
428                            <?php else : ?>
429                                -
430                            <?php endif ?>
431                        </td>
432                    </tr>
433                <?php endforeach ?>
434            </tbody>
435
436            <tfoot>
437                <tr>
438                    <th scope="row">
439                        <?= I18N::translate('Total') ?>
440                    </th>
441                    <td class="align-digits">
442                        <?= I18N::number(array_sum($changes)) ?>
443                    </td>
444                    <td class="d-none d-sm-table-cell align-digits">
445                        <?= I18N::number($individuals->sum()) ?>
446                    </td>
447                    <td class="d-none d-lg-table-cell align-digits">
448                        <?= I18N::number($families->sum()) ?>
449                    </td>
450                    <td class="d-none d-sm-table-cell align-digits">
451                        <?= I18N::number($sources->sum()) ?>
452                    </td>
453                    <td class="d-none d-lg-table-cell align-digits">
454                        <?= I18N::number($repositories->sum()) ?>
455                    </td>
456                    <td class="d-none d-sm-table-cell align-digits">
457                        <?= I18N::number($media->sum()) ?>
458                    </td>
459                    <td class="d-none d-lg-table-cell align-digits">
460                        <?= I18N::number($notes->sum()) ?>
461                    </td>
462                    <td class="d-none d-lg-table-cell align-digits">
463                        <?= I18N::number($submitters->sum()) ?>
464                    </td>
465                </tr>
466            </tfoot>
467        </table>
468    </div>
469</div>
470
471<?php if ($show_synchronize): ?>
472    <?= view('admin/synchronize-trees') ?>
473<?php endif ?>
474
475<!-- USERS -->
476<div class="card mb-4 <?= $unapproved || $unverified ? 'card-outline-danger' : '' ?>">
477    <div class="card-header">
478        <h2 class="mb-0">
479            <?= I18N::translate('Users') ?>
480            <span class="badge bg-secondary">
481                    <?= I18N::number(count($all_users)) ?>
482                </span>
483        </h2>
484    </div>
485    <div class="card-body">
486        <dl class="row">
487            <?php foreach ([I18N::translate('Administrators') => $administrators, I18N::translate('Managers') => $managers, I18N::translate('Moderators') => $moderators, I18N::translate('Not verified by the user') => $unverified, I18N::translate('Not approved by an administrator') => $unapproved] as $label => $list) : ?>
488                <?php if (!empty($list)) : ?>
489                    <dt class="col-sm-6">
490                        <?= $label ?>
491                    </dt>
492                    <dd class="col-sm-6">
493                        <?php foreach ($list as $n => $user) : ?>
494                            <?= $n ? I18N::$list_separator : '' ?>
495                            <a href="<?= e(route(UserEditPage::class, ['user_id' => $user->id()])) ?>" dir="auto">
496                                <?= e($user->realName()) ?>
497                            </a>
498                        <?php endforeach ?>
499                        <?php if ($list->isEmpty()) : ?>
500501                        <?php endif ?>
502                    </dd>
503                <?php endif ?>
504            <?php endforeach ?>
505        </dl>
506
507        <div class="row">
508            <div class="col-sm-6">
509                <ul class="fa-ul mx-0">
510                    <li>
511                        <span class="fa-li"><?= view('icons/preferences') ?></span>
512                        <a href="<?= e(route(UserListPage::class)) ?>">
513                            <?= I18N::translate('User administration') ?>
514                        </a>
515                    </li>
516                    <li>
517                        <span class="fa-li"><?= view('icons/add') ?></span>
518                        <a href="<?= e(route(UserAddPage::class)) ?>">
519                            <?= I18N::translate('Add a user') ?>
520                        </a>
521                    </li>
522                    <li>
523                        <span class="fa-li"><?= view('icons/delete') ?></span>
524                        <a href="<?= e(route(UsersCleanupPage::class)) ?>">
525                            <?= I18N::translate('Delete inactive users') ?>
526                        </a>
527                    </li>
528                    <li>
529                        <span class="fa-li"><?= view('icons/block') ?></span>
530                        <a href="<?= e(route(UserPageDefaultEdit::class)) ?>">
531                            <?= I18N::translate('Set the default blocks for new users') ?>
532                        </a>
533                    </li>
534                </ul>
535            </div>
536            <div class="col-sm-6">
537                <ul class="fa-ul mx-0">
538                    <?php foreach ($recipients as $to => $recipient) : ?>
539                    <li>
540                        <span class="fa-li"><?= view('icons/email') ?></span>
541                        <a href="<?= e(route(BroadcastPage::class, ['to' => $to])) ?>">
542                            <?= $recipient ?>
543                        </a>
544                    </li>
545                    <?php endforeach ?>
546                </ul>
547            </div>
548        </div>
549    </div>
550</div>
551
552<!-- MODULES -->
553<div class="card mb-4">
554    <div class="card-header">
555        <h2 class="mb-0">
556            <?= I18N::translate('Modules') ?>
557            <?= view('components/badge', ['count' => $all_modules_enabled->count(), 'total' => $all_modules_disabled->count(), 'context' => 'secondary']) ?>
558        </h2>
559    </div>
560
561    <div class="card-body">
562        <ul class="fa-ul mx-0">
563            <li>
564                <span class="fa-li"><?= view('icons/module') ?></span>
565                <a href="<?= e(route(ModulesAllPage::class)) ?>">
566                    <?= I18N::translate('All modules') ?>
567                </a>
568                <?= view('components/badge', ['count' => $all_modules_enabled->count(), 'total' => $all_modules_disabled->count(), 'context' => 'primary']) ?>
569            </li>
570        </ul>
571
572        <div class="row">
573            <div class="col-sm-4">
574                <h3>
575                    <?= I18N::translate('Website') ?>
576                </h3>
577
578                <ul class="fa-ul mx-0">
579                    <li>
580                        <span class="fa-li"><?= view('icons/footer') ?></span>
581                        <a href="<?= e(route(ModulesFootersPage::class)) ?>">
582                            <?= I18N::translate('Footers') ?>
583                        </a>
584                        <?= view('components/badge', ['count' => $footer_modules_enabled->count(), 'total' => $footer_modules_disabled->count(), 'context' => 'primary']) ?>
585                    </li>
586                    <li>
587                        <span class="fa-li"><?= view('icons/analytics') ?></span>
588                        <a href="<?= e(route(ModulesAnalyticsPage::class)) ?>">
589                            <?= I18N::translate('Tracking and analytics') ?>
590                        </a>
591                        <?= view('components/badge', ['count' => $analytics_modules_enabled->count(), 'total' => $analytics_modules_disabled->count(), 'context' => 'primary']) ?>
592                    </li>
593                    <li>
594                        <span class="fa-li"><?= view('icons/theme') ?></span>
595                        <a href="<?= e(route(ModulesThemesPage::class)) ?>">
596                            <?= I18N::translate('Themes') ?>
597                        </a>
598                        <?= view('components/badge', ['count' => $theme_modules_enabled->count(), 'total' => $theme_modules_disabled->count(), 'context' => 'primary']) ?>
599                    </li>
600                    <li>
601                        <span class="fa-li"><?= view('icons/language') ?></span>
602                        <a href="<?= e(route(ModulesLanguagesPage::class)) ?>">
603                            <?= I18N::translate('Languages') ?>
604                        </a>
605                        <?= view('components/badge', ['count' => $language_modules_enabled->count(), 'total' => $language_modules_disabled->count(), 'context' => 'primary']) ?>
606                    </li>
607                </ul>
608
609                <h3>
610                    <?= I18N::translate('Home page') ?>
611                </h3>
612
613                <ul class="fa-ul mx-0">
614                    <li>
615                        <span class="fa-li"><?= view('icons/block') ?></span>
616                        <a href="<?= e(route(ModulesBlocksPage::class)) ?>">
617                            <?= I18N::translate('Blocks') ?>
618                        </a>
619                        <?= view('components/badge', ['count' => $block_modules_enabled->count(), 'total' => $block_modules_disabled->count(), 'context' => 'primary']) ?>
620                    </li>
621                </ul>
622
623                <h3>
624                    <?= I18N::translate('Geographic data') ?>
625                </h3>
626
627                <ul class="fa-ul mx-0">
628                    <li>
629                        <span class="fa-li"><?= view('icons/search') ?></span>
630                        <a href="<?= e(route(ModulesMapAutocompletePage::class)) ?>">
631                            <?= /* I18N: Automatic suggestions when you type */ I18N::translate('Autocomplete') ?>
632                        </a>
633                        <?= view('components/badge', ['count' => $map_autocomplete_modules_enabled->count(), 'total' => $map_autocomplete_modules_disabled->count(), 'context' => 'primary']) ?>
634                    </li>
635                    <li>
636                        <span class="fa-li"><?= view('icons/search-location') ?></span>
637                        <a href="<?= e(route(ModulesMapGeoLocationsPage::class)) ?>">
638                            <?= /* I18N: find latitude/longitude for a place */ I18N::translate('Geolocation') ?>
639                        </a>
640                        <?= view('components/badge', ['count' => $map_search_modules_enabled->count(), 'total' => $map_search_modules_disabled->count(), 'context' => 'primary']) ?>
641                    </li>
642                    <li>
643                        <span class="fa-li"><?= view('icons/location') ?></span>
644                        <a href="<?= e(route(ModulesMapLinksPage::class)) ?>">
645                            <?= /* I18N: Links to maps */ I18N::translate('Map links') ?>
646                        </a>
647                        <?= view('components/badge', ['count' => $map_link_modules_enabled->count(), 'total' => $map_link_modules_disabled->count(), 'context' => 'primary']) ?>
648                    </li>
649                    <li>
650                        <span class="fa-li"><?= view('icons/map') ?></span>
651                        <a href="<?= e(route(ModulesMapProvidersPage::class)) ?>">
652                            <?= I18N::translate('Map providers') ?>
653                        </a>
654                        <?= view('components/badge', ['count' => $map_provider_modules_enabled->count(), 'total' => $map_provider_modules_disabled->count(), 'context' => 'primary']) ?>
655                    </li>
656                </ul>
657            </div>
658
659            <div class="col-sm-4">
660                <h3>
661                    <?= I18N::translate('Genealogy') ?>
662                </h3>
663
664                <ul class="fa-ul mx-0">
665                    <li>
666                        <span class="fa-li"><?= view('icons/menu') ?></span>
667                        <a href="<?= e(route(ModulesMenusPage::class)) ?>">
668                            <?= I18N::translate('Menus') ?>
669                        </a>
670                        <?= view('components/badge', ['count' => $menu_modules_enabled->count(), 'total' => $menu_modules_disabled->count(), 'context' => 'primary']) ?>
671                    </li>
672                    <li>
673                        <span class="fa-li"><?= view('icons/chart') ?></span>
674                        <a href="<?= e(route(ModulesChartsPage::class)) ?>">
675                            <?= I18N::translate('Charts') ?>
676                        </a>
677                        <?= view('components/badge', ['count' => $chart_modules_enabled->count(), 'total' => $chart_modules_disabled->count(), 'context' => 'primary']) ?>
678                    </li>
679                    <li>
680                        <span class="fa-li"><?= view('icons/list') ?></span>
681                        <a href="<?= e(route(ModulesListsPage::class)) ?>">
682                            <?= I18N::translate('Lists') ?>
683                        </a>
684                        <?= view('components/badge', ['count' => $list_modules_enabled->count(), 'total' => $list_modules_disabled->count(), 'context' => 'primary']) ?>
685                    </li>
686                    <li>
687                        <span class="fa-li"><?= view('icons/report') ?></span>
688                        <a href="<?= e(route(ModulesReportsPage::class)) ?>">
689                            <?= I18N::translate('Reports') ?>
690                        </a>
691                        <?= view('components/badge', ['count' => $report_modules_enabled->count(), 'total' => $report_modules_disabled->count(), 'context' => 'primary']) ?>
692                    </li>
693                    <li>
694                        <span class="fa-li"><?= view('icons/data-fix') ?></span>
695                        <a href="<?= e(route(ModulesDataFixesPage::class)) ?>">
696                            <?= I18N::translate('Data fixes') ?>
697                        </a>
698                        <?= view('components/badge', ['count' => $data_fix_modules_enabled->count(), 'total' => $data_fix_modules_disabled->count(), 'context' => 'primary']) ?>
699                    </li>
700                    <li>
701                        <span class="fa-li"><?= view('icons/tag') ?></span>
702                        <a href="<?= e(route(ModulesCustomTagsPage::class)) ?>">
703                            <?= I18N::translate('Custom GEDCOM tags') ?>
704                        </a>
705                        <?= view('components/badge', ['count' => $custom_tags_modules_enabled->count(), 'total' => $custom_tags_modules_disabled->count(), 'context' => 'primary']) ?>
706                    </li>
707                </ul>
708
709                <h3>
710                    <?= I18N::translate('Individual page') ?>
711                </h3>
712
713                <ul class="fa-ul mx-0">
714                    <li>
715                        <span class="fa-li"><?= view('icons/tab') ?></span>
716                        <a href="<?= e(route(ModulesTabsPage::class)) ?>">
717                            <?= I18N::translate('Tabs') ?>
718                            <?= view('components/badge', ['count' => $tab_modules_enabled->count(), 'total' => $tab_modules_disabled->count(), 'context' => 'primary']) ?>
719                        </a>
720                    </li>
721                    <li>
722                        <span class="fa-li"><?= view('icons/sidebar') ?></span>
723                        <a href="<?= e(route(ModulesSidebarsPage::class)) ?>">
724                            <?= I18N::translate('Sidebars') ?>
725                        </a>
726                        <?= view('components/badge', ['count' => $sidebar_modules_enabled->count(), 'total' => $sidebar_modules_disabled->count(), 'context' => 'primary']) ?>
727                    </li>
728                    <li>
729                        <span class="fa-li"><?= view('icons/history') ?></span>
730                        <a href="<?= e(route(ModulesHistoricEventsPage::class)) ?>">
731                            <?= I18N::translate('Historic events') ?>
732                        </a>
733                        <?= view('components/badge', ['count' => $history_modules_enabled->count(), 'total' => $history_modules_disabled->count(), 'context' => 'primary']) ?>
734                    </li>
735                    <li>
736                        <span class="fa-li"><?= view('icons/share') ?></span>
737                        <a href="<?= e(route(ModulesSharesPage::class)) ?>">
738                            <?= /* I18N: plural noun - things that can be shared */  I18N::translate('Shares') ?>
739                        </a>
740                        <?= view('components/badge', ['count' => $share_modules_enabled->count(), 'total' => $share_modules_disabled->count(), 'context' => 'primary']) ?>
741                    </li>
742                </ul>
743            </div>
744
745            <div class="col-sm-4">
746
747                <h3>
748                    <?= I18N::translate('Other') ?>
749                </h3>
750
751                <ul class="fa-ul mx-0">
752                    <?php foreach ($other_modules as $module) : ?>
753                        <li>
754                            <?php if ($module->isEnabled()) : ?>
755                                <span class="fa-li"><?= view('icons/module') ?></span>
756                                <?php if ($module instanceof ModuleConfigInterface) : ?>
757                                    <a href="<?= e($module->getConfigLink()) ?>">
758                                    <?= $module->title() ?>
759                                    <?= view('icons/preferences') ?>
760                                    </a>
761                                <?php else : ?>
762                                    <?= $module->title() ?>
763                                <?php endif ?>
764                            <?php else : ?>
765                                <span class="text-muted">
766                                    <span class="fa-li"><?= view('icons/module') ?></span>
767                                    <?= $module->title() ?>
768                                    <?php if ($module instanceof ModuleConfigInterface) : ?>
769                                        <?= view('icons/preferences') ?>
770                                    <?php endif ?>
771                                </span>
772                            <?php endif ?>
773
774                            <?php if ($module instanceof ModuleCustomInterface) : ?>
775                                <?= view('admin/custom-module-info', ['module' => $module]) ?>
776                            <?php endif ?>
777                        </li>
778                    <?php endforeach ?>
779                </ul>
780            </div>
781        </div>
782    </div>
783</div>
784
785<!-- MEDIA -->
786<div class="card mb-4">
787    <div class="card-header">
788        <h2 class="mb-0">
789            <?= I18N::translate('Media') ?>
790        </h2>
791    </div>
792    <div class="card-body">
793        <ul class="fa-ul mx-0">
794            <li>
795                <span class="fa-li"><?= view('icons/preferences') ?></span>
796                <a href="<?= e(route(ManageMediaPage::class)) ?>">
797                    <?= I18N::translate('Manage media') ?>
798                </a>
799            </li>
800            <li>
801                <span class="fa-li"><?= view('icons/upload') ?></span>
802                <a href="<?= e(route(UploadMediaPage::class)) ?>">
803                    <?= I18N::translate('Upload media files') ?>
804                </a>
805            </li>
806            <li>
807                <span class="fa-li"><?= view('icons/link') ?></span>
808                <a href="<?= e(route(FixLevel0MediaPage::class)) ?>">
809                    <?= I18N::translate('Link media objects to facts and events') ?>
810                </a>
811            </li>
812            <li>
813                <span class="fa-li"><?= view('icons/upload') ?></span>
814                <a href="<?= e(route(ImportThumbnailsPage::class)) ?>">
815                    <?= I18N::translate('Import custom thumbnails from webtrees version 1') ?>
816                </a>
817            </li>
818        </ul>
819    </div>
820</div>
821
822<!-- MAPS -->
823<div class="card mb-4">
824    <div class="card-header">
825        <h2 class="mb-0">
826            <?= I18N::translate('Map') ?>
827        </h2>
828    </div>
829    <div class="card-body">
830        <div class="row">
831            <div class="col-sm-12">
832                <ul class="fa-ul mx-0">
833                    <li>
834                        <span class="fa-li"><?= view('icons/location') ?></span>
835                        <a href="<?= e(route(MapDataList::class)) ?>">
836                            <?= I18N::translate('Geographic data') ?>
837                        </a>
838                    </li>
839                </ul>
840            </div>
841        </div>
842    </div>
843</div>
844
845<!-- OLD FILES -->
846<?php if (!empty($files_to_delete)) : ?>
847    <div class="card mb-4 card-outline-danger">
848        <div class="card-header">
849            <h2 class="mb-0">
850                <?= I18N::translate('Old files found') ?>
851            </h2>
852        </div>
853        <div class="card-body">
854            <p>
855                <?= I18N::translate('Files have been found from a previous version of webtrees. Old files can sometimes be a security risk. You should delete them.') ?>
856            </p>
857            <ul class="list-unstyled">
858                <?php foreach ($files_to_delete as $file_to_delete) : ?>
859                    <li dir="ltr">
860                        <code><?= e($file_to_delete) ?></code>
861                    </li>
862                <?php endforeach ?>
863            </ul>
864        </div>
865    </div>
866<?php endif ?>
867