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