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