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