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