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