xref: /webtrees/resources/views/admin/control-panel.phtml (revision 579298a3a674b773d5faf22489187529a3b4cfc0)
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            <?php if ($module->customModuleSupportUrl() !== '') : ?>
208                <br>
209                <?= I18N::translate('For more information, see %s.', '<a href="' . e($module->customModuleSupportUrl()) . '">' . e($module->customModuleSupportUrl()) . '</a>') ?>
210            <?php endif ?>
211        </div>
212        <?php endforeach ?>
213
214        <div class="row">
215            <div class="col-sm">
216                <ul class="fa-ul">
217                    <li>
218                        <span class="fa-li"><?= view('icons/preferences') ?></span>
219                        <a href="<?= e(route(SitePreferencesPage::class)) ?>">
220                            <?= I18N::translate('Website preferences') ?>
221                        </a>
222                    </li>
223                    <li>
224                        <span class="fa-li"><?= view('icons/email') ?></span>
225                        <a href="<?= e(route(EmailPreferencesPage::class)) ?>">
226                            <?= I18N::translate('Sending email') ?>
227                        </a>
228                    </li>
229                    <li>
230                        <span class="fa-li"><?= view('icons/user') ?></span>
231                        <a href="<?= e(route(SiteRegistrationPage::class)) ?>">
232                            <?= I18N::translate('Sign-in and registration') ?>
233                        </a>
234                    </li>
235                </ul>
236            </div>
237            <div class="col-sm">
238                <ul class="fa-ul">
239                    <li>
240                        <span class="fa-li"><?= view('icons/list') ?></span>
241                        <a href="<?= e(route(SiteLogsPage::class)) ?>">
242                            <?= I18N::translate('Website logs') ?>
243                        </a>
244                    </li>
245                    <li>
246                        <span class="fa-li"><?= view('icons/delete') ?></span>
247                        <a href="<?= e(route(CleanDataFolder::class)) ?>">
248                            <?= I18N::translate('Clean up data folder') ?>
249                        </a>
250                    </li>
251                    <li>
252                        <span class="fa-li"><?= view('icons/help') ?></span>
253                        <a href="<?= e(route(PhpInformation::class)) ?>">
254                            <?= I18N::translate('Server information') ?>
255                        </a>
256                    </li>
257                </ul>
258            </div>
259            <div class="col-sm">
260                <ul class="fa-ul">
261                    <li>
262                        <span class="fa-li"><?= view('icons/tag') ?></span>
263                        <a href="<?= e(route(SiteTagsPage::class)) ?>">
264                            <?= I18N::translate('GEDCOM tags') ?>
265                        </a>
266                    </li>
267                </ul>
268            </div>
269        </div>
270    </div>
271</div>
272
273<!-- FAMILY TREES -->
274<div class="card mb-4 <?= array_sum($changes) ? 'card-outline-danger' : '' ?>">
275    <div class="card-header">
276        <h2 class="mb-0">
277            <?= I18N::translate('Family trees') ?>
278            <span class="badge badge-secondary">
279                    <?= I18N::number($all_trees->count()) ?>
280                </span>
281        </h2>
282    </div>
283
284    <div class="card-body">
285        <?php if ($all_trees->isEmpty()) : ?>
286            <p class="alert alert-info">
287                <?= I18N::translate('You need to create a family tree.') ?>
288            </p>
289        <?php endif ?>
290
291        <ul class="fa-ul">
292            <li>
293                <span class="fa-li"><?= view('icons/add') ?></span>
294                <a href="<?= e(route(CreateTreePage::class)) ?>">
295                    <?= I18N::translate('Create a family tree') ?>
296                </a>
297            </li>
298            <li>
299                <span class="fa-li"><?= view('icons/block') ?></span>
300                <a href="<?= e(route(TreePageDefaultEdit::class)) ?>">
301                    <?= I18N::translate('Set the default blocks for new family trees') ?>
302                </a>
303            </li>
304            <?php if (count($all_trees) > 1) : ?>
305                <li>
306                    <span class="fa-li"><?= view('icons/merge') ?></span>
307                    <a href="<?= e(route(MergeTreesPage::class)) ?>">
308                        <?= I18N::translate('Merge family trees') ?>
309                    </a>
310                </li>
311            <?php endif ?>
312        </ul>
313
314        <table class="table table-sm">
315            <caption class="sr-only">
316                <?= I18N::translate('Family trees') ?>
317            </caption>
318
319            <thead>
320                <tr>
321                    <th><?= I18N::translate('Family tree') ?></th>
322                    <th class="align-digits"><?= I18N::translate('Pending changes') ?></th>
323                    <th class="d-none d-sm-table-cell align-digits"><?= I18N::translate('Individuals') ?></th>
324                    <th class="d-none d-lg-table-cell align-digits"><?= I18N::translate('Families') ?></th>
325                    <th class="d-none d-sm-table-cell align-digits"><?= I18N::translate('Sources') ?></th>
326                    <th class="d-none d-lg-table-cell align-digits"><?= I18N::translate('Repositories') ?></th>
327                    <th class="d-none d-sm-table-cell align-digits"><?= I18N::translate('Media') ?></th>
328                    <th class="d-none d-lg-table-cell align-digits"><?= I18N::translate('Notes') ?></th>
329                    <th class="d-none d-lg-table-cell align-digits"><?= I18N::translate('Submitters') ?></th>
330                </tr>
331            </thead>
332
333            <tbody>
334                <?php foreach ($all_trees as $tree) : ?>
335                    <tr class="<?= $changes[$tree->id()] ? 'danger' : '' ?>">
336                        <th scope="row">
337                            <?= view('icons/preferences') ?>
338                            <a href="<?= e(route(ManageTrees::class, ['tree' => $tree->name()])) ?>">
339                                <?= e($tree->name()) ?>
340                                -
341                                <?= e($tree->title()) ?>
342                            </a>
343                        </th>
344                        <td style="text-align: right;">
345                            <?php if ($changes[$tree->id()]) : ?>
346                                <a href="<?= e(route(PendingChanges::class, ['tree' => $tree->name(), 'url' => route(ControlPanel::class)])) ?>">
347                                    <?= I18N::number($changes[$tree->id()]) ?>
348                                    <span class="sr-only"><?= I18N::translate('Pending changes') ?> <?= e($tree->title()) ?></span>
349                                </a>
350                            <?php else : ?>
351                                -
352                            <?php endif ?>
353                        </td>
354                        <td class="d-none d-sm-table-cell align-digits">
355                            <?php if ($individuals[$tree->id()] > 0) : ?>
356                                <?php if ($individual_list_module instanceof IndividualListModule) : ?>
357                                    <a href="<?= e($individual_list_module->listUrl($tree)) ?>"><?= I18N::number($individuals[$tree->id()]) ?></a>
358                                <?php else : ?>
359                                    <?= I18N::number($individuals[$tree->id()]) ?>
360                                <?php endif ?>
361                            <?php else : ?>
362                                -
363                            <?php endif ?>
364                        </td>
365                        <td class="d-none d-lg-table-cell align-digits">
366                            <?php if ($families[$tree->id()] > 0) : ?>
367                                <?php if ($family_list_module instanceof FamilyListModule) : ?>
368                                    <a href="<?= e($family_list_module->listUrl($tree)) ?>"><?= I18N::number($families[$tree->id()]) ?></a>
369                                <?php else : ?>
370                                    <?= I18N::number($families[$tree->id()]) ?>
371                                <?php endif ?>
372                            <?php else : ?>
373                                -
374                            <?php endif ?>
375                        </td>
376                        <td class="d-none d-sm-table-cell align-digits">
377                            <?php if ($sources[$tree->id()] > 0) : ?>
378                                <?php if ($source_list_module instanceof SourceListModule) : ?>
379                                    <a href="<?= e($source_list_module->listUrl($tree)) ?>"><?= I18N::number($sources[$tree->id()]) ?></a>
380                                <?php else : ?>
381                                    <?= I18N::number($sources[$tree->id()]) ?>
382                                <?php endif ?>
383                            <?php else : ?>
384                                -
385                            <?php endif ?>
386                        </td>
387                        <td class="d-none d-lg-table-cell align-digits">
388                            <?php if ($repositories[$tree->id()] > 0) : ?>
389                                <?php if ($repository_list_module instanceof RepositoryListModule) : ?>
390                                    <a href="<?= e($repository_list_module->listUrl($tree)) ?>"><?= I18N::number($repositories[$tree->id()]) ?></a>
391                                <?php else : ?>
392                                    <?= I18N::number($repositories[$tree->id()]) ?>
393                                <?php endif ?>
394                            <?php else : ?>
395                                -
396                            <?php endif ?>
397                        </td>
398                        <td class="d-none d-sm-table-cell align-digits">
399                            <?php if ($media[$tree->id()] > 0) : ?>
400                                <?php if ($media_list_module instanceof MediaListModule) : ?>
401                                    <a href="<?= e($media_list_module->listUrl($tree)) ?>"><?= I18N::number($media[$tree->id()]) ?></a>
402                                <?php else : ?>
403                                    <?= I18N::number($media[$tree->id()]) ?>
404                                <?php endif ?>
405                            <?php else : ?>
406                                -
407                            <?php endif ?>
408                        </td>
409                        <td class="d-none d-lg-table-cell align-digits">
410                            <?php if ($notes[$tree->id()] > 0) : ?>
411                                <?php if ($note_list_module instanceof NoteListModule) : ?>
412                                    <a href="<?= e($note_list_module->listUrl($tree)) ?>"><?= I18N::number($notes[$tree->id()]) ?></a>
413                                <?php else : ?>
414                                    <?= I18N::number($notes[$tree->id()]) ?>
415                                <?php endif ?>
416                            <?php else : ?>
417                                -
418                            <?php endif ?>
419                        </td>
420                         <td class="d-none d-lg-table-cell align-digits">
421                            <?php if ($submitters[$tree->id()] > 0) : ?>
422                                <?php if ($submitter_list_module instanceof SubmitterListModule) : ?>
423                                    <a href="<?= e($submitter_list_module->listUrl($tree)) ?>"><?= I18N::number($submitters[$tree->id()]) ?></a>
424                                <?php else : ?>
425                                    <?= I18N::number($submitters[$tree->id()]) ?>
426                                <?php endif ?>
427                            <?php else : ?>
428                                -
429                            <?php endif ?>
430                        </td>
431                    </tr>
432                <?php endforeach ?>
433            </tbody>
434
435            <tfoot>
436                <tr>
437                    <th scope="row">
438                        <?= I18N::translate('Total') ?>
439                    </th>
440                    <td class="align-digits">
441                        <?= I18N::number(array_sum($changes)) ?>
442                    </td>
443                    <td class="d-none d-sm-table-cell align-digits">
444                        <?= I18N::number($individuals->sum()) ?>
445                    </td>
446                    <td class="d-none d-lg-table-cell align-digits">
447                        <?= I18N::number($families->sum()) ?>
448                    </td>
449                    <td class="d-none d-sm-table-cell align-digits">
450                        <?= I18N::number($sources->sum()) ?>
451                    </td>
452                    <td class="d-none d-lg-table-cell align-digits">
453                        <?= I18N::number($repositories->sum()) ?>
454                    </td>
455                    <td class="d-none d-sm-table-cell align-digits">
456                        <?= I18N::number($media->sum()) ?>
457                    </td>
458                    <td class="d-none d-lg-table-cell align-digits">
459                        <?= I18N::number($notes->sum()) ?>
460                    </td>
461                </tr>
462            </tfoot>
463        </table>
464    </div>
465</div>
466
467<?php if ($show_synchronize): ?>
468    <?= view('admin/synchronize-trees') ?>
469<?php endif ?>
470
471<!-- USERS -->
472<div class="card mb-4 <?= $unapproved || $unverified ? 'card-outline-danger' : '' ?>">
473    <div class="card-header">
474        <h2 class="mb-0">
475            <?= I18N::translate('Users') ?>
476            <span class="badge badge-secondary">
477                    <?= I18N::number(count($all_users)) ?>
478                </span>
479        </h2>
480    </div>
481    <div class="card-body">
482        <dl class="row">
483            <?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) : ?>
484                <?php if (!empty($list)) : ?>
485                    <dt class="col-sm-6">
486                        <?= $label ?>
487                    </dt>
488                    <dd class="col-sm-6">
489                        <?php foreach ($list as $n => $user) : ?>
490                            <?= $n ? I18N::$list_separator : '' ?>
491                            <a href="<?= e(route(UserEditPage::class, ['user_id' => $user->id()])) ?>" dir="auto">
492                                <?= e($user->realName()) ?>
493                            </a>
494                        <?php endforeach ?>
495                        <?php if ($list->isEmpty()) : ?>
496497                        <?php endif ?>
498                    </dd>
499                <?php endif ?>
500            <?php endforeach ?>
501        </dl>
502
503        <div class="row">
504            <div class="col-sm-6">
505                <ul class="fa-ul">
506                    <li>
507                        <span class="fa-li"><?= view('icons/preferences') ?></span>
508                        <a href="<?= e(route(UserListPage::class)) ?>">
509                            <?= I18N::translate('User administration') ?>
510                        </a>
511                    </li>
512                    <li>
513                        <span class="fa-li"><?= view('icons/add') ?></span>
514                        <a href="<?= e(route(UserAddPage::class)) ?>">
515                            <?= I18N::translate('Add a user') ?>
516                        </a>
517                    </li>
518                    <li>
519                        <span class="fa-li"><?= view('icons/delete') ?></span>
520                        <a href="<?= e(route(UsersCleanupPage::class)) ?>">
521                            <?= I18N::translate('Delete inactive users') ?>
522                        </a>
523                    </li>
524                    <li>
525                        <span class="fa-li"><?= view('icons/block') ?></span>
526                        <a href="<?= e(route(UserPageDefaultEdit::class)) ?>">
527                            <?= I18N::translate('Set the default blocks for new users') ?>
528                        </a>
529                    </li>
530                </ul>
531            </div>
532            <div class="col-sm-6">
533                <ul class="fa-ul">
534                    <li>
535                        <span class="fa-li"><?= view('icons/email') ?></span>
536                        <a href="<?= e(route(BroadcastPage::class, ['to' => 'all'])) ?>">
537                            <?= I18N::translate('Send a message to all users') ?>
538                        </a>
539                    </li>
540                    <li>
541                        <span class="fa-li"><?= view('icons/email') ?></span>
542                        <a href="<?= e(route(BroadcastPage::class, ['to' => 'never_logged'])) ?>">
543                            <?= I18N::translate('Send a message to users who have never signed in') ?>
544                        </a>
545                    </li>
546                    <li>
547                        <span class="fa-li"><?= view('icons/email') ?></span>
548                        <a href="<?= e(route(BroadcastPage::class, ['to' => 'last_6mo'])) ?>">
549                            <?= I18N::translate('Send a message to users who have not signed in for 6 months') ?>
550                        </a>
551                    </li>
552                </ul>
553            </div>
554        </div>
555    </div>
556</div>
557
558<!-- MODULES -->
559<div class="card mb-4">
560    <div class="card-header">
561        <h2 class="mb-0">
562            <?= I18N::translate('Modules') ?>
563            <?= view('components/badge', ['count' => $all_modules_enabled->count(), 'total' => $all_modules_disabled->count(), 'context' => 'secondary']) ?>
564        </h2>
565    </div>
566
567    <div class="card-body">
568        <ul class="fa-ul">
569            <li>
570                <span class="fa-li"><?= view('icons/module') ?></span>
571                <a href="<?= e(route(ModulesAllPage::class)) ?>">
572                    <?= I18N::translate('All modules') ?>
573                </a>
574                <?= view('components/badge', ['count' => $all_modules_enabled->count(), 'total' => $all_modules_disabled->count(), 'context' => 'primary']) ?>
575            </li>
576        </ul>
577
578        <div class="row">
579            <div class="col-sm-4">
580                <h3>
581                    <?= I18N::translate('Website') ?>
582                </h3>
583
584                <ul class="fa-ul">
585                    <li>
586                        <span class="fa-li"><?= view('icons/footer') ?></span>
587                        <a href="<?= e(route(ModulesFootersPage::class)) ?>">
588                            <?= I18N::translate('Footers') ?>
589                        </a>
590                        <?= view('components/badge', ['count' => $footer_modules_enabled->count(), 'total' => $footer_modules_disabled->count(), 'context' => 'primary']) ?>
591                    </li>
592                    <li>
593                        <span class="fa-li"><?= view('icons/analytics') ?></span>
594                        <a href="<?= e(route(ModulesAnalyticsPage::class)) ?>">
595                            <?= I18N::translate('Tracking and analytics') ?>
596                        </a>
597                        <?= view('components/badge', ['count' => $analytics_modules_enabled->count(), 'total' => $analytics_modules_disabled->count(), 'context' => 'primary']) ?>
598                    </li>
599                    <li>
600                        <span class="fa-li"><?= view('icons/theme') ?></span>
601                        <a href="<?= e(route(ModulesThemesPage::class)) ?>">
602                            <?= I18N::translate('Themes') ?>
603                        </a>
604                        <?= view('components/badge', ['count' => $theme_modules_enabled->count(), 'total' => $theme_modules_disabled->count(), 'context' => 'primary']) ?>
605                    </li>
606                    <li>
607                        <span class="fa-li"><?= view('icons/language') ?></span>
608                        <a href="<?= e(route(ModulesLanguagesPage::class)) ?>">
609                            <?= I18N::translate('Languages') ?>
610                        </a>
611                        <?= view('components/badge', ['count' => $language_modules_enabled->count(), 'total' => $language_modules_disabled->count(), 'context' => 'primary']) ?>
612                    </li>
613                </ul>
614
615                <h3>
616                    <?= I18N::translate('Home page') ?>
617                </h3>
618
619                <ul class="fa-ul">
620                    <li>
621                        <span class="fa-li"><?= view('icons/block') ?></span>
622                        <a href="<?= e(route(ModulesBlocksPage::class)) ?>">
623                            <?= I18N::translate('Blocks') ?>
624                        </a>
625                        <?= view('components/badge', ['count' => $block_modules_enabled->count(), 'total' => $block_modules_disabled->count(), 'context' => 'primary']) ?>
626                    </li>
627                </ul>
628
629                <h3>
630                    <?= I18N::translate('Geographic data') ?>
631                </h3>
632
633                <ul class="fa-ul">
634                    <li>
635                        <span class="fa-li"><?= view('icons/search') ?></span>
636                        <a href="<?= e(route(ModulesMapAutocompletePage::class)) ?>">
637                            <?= /* I18N: Automatic suggestions when you type */ I18N::translate('Autocomplete') ?>
638                        </a>
639                        <?= view('components/badge', ['count' => $map_autocomplete_modules_enabled->count(), 'total' => $map_autocomplete_modules_disabled->count(), 'context' => 'primary']) ?>
640                    </li>
641                    <li>
642                        <span class="fa-li"><?= view('icons/search-location') ?></span>
643                        <a href="<?= e(route(ModulesMapGeoLocationsPage::class)) ?>">
644                            <?= /* I18N: find latitude/longitude for a place */ I18N::translate('Geolocation') ?>
645                        </a>
646                        <?= view('components/badge', ['count' => $map_search_modules_enabled->count(), 'total' => $map_search_modules_disabled->count(), 'context' => 'primary']) ?>
647                    </li>
648                    <li>
649                        <span class="fa-li"><?= view('icons/location') ?></span>
650                        <a href="<?= e(route(ModulesMapLinksPage::class)) ?>">
651                            <?= /* I18N: Links to maps */ I18N::translate('Map links') ?>
652                        </a>
653                        <?= view('components/badge', ['count' => $map_link_modules_enabled->count(), 'total' => $map_link_modules_disabled->count(), 'context' => 'primary']) ?>
654                    </li>
655                    <li>
656                        <span class="fa-li"><?= view('icons/map') ?></span>
657                        <a href="<?= e(route(ModulesMapProvidersPage::class)) ?>">
658                            <?= I18N::translate('Map providers') ?>
659                        </a>
660                        <?= view('components/badge', ['count' => $map_provider_modules_enabled->count(), 'total' => $map_provider_modules_disabled->count(), 'context' => 'primary']) ?>
661                    </li>
662                </ul>
663            </div>
664
665            <div class="col-sm-4">
666                <h3>
667                    <?= I18N::translate('Genealogy') ?>
668                </h3>
669
670                <ul class="fa-ul">
671                    <li>
672                        <span class="fa-li"><?= view('icons/menu') ?></span>
673                        <a href="<?= e(route(ModulesMenusPage::class)) ?>">
674                            <?= I18N::translate('Menus') ?>
675                        </a>
676                        <?= view('components/badge', ['count' => $menu_modules_enabled->count(), 'total' => $menu_modules_disabled->count(), 'context' => 'primary']) ?>
677                    </li>
678                    <li>
679                        <span class="fa-li"><?= view('icons/chart') ?></span>
680                        <a href="<?= e(route(ModulesChartsPage::class)) ?>">
681                            <?= I18N::translate('Charts') ?>
682                        </a>
683                        <?= view('components/badge', ['count' => $chart_modules_enabled->count(), 'total' => $chart_modules_disabled->count(), 'context' => 'primary']) ?>
684                    </li>
685                    <li>
686                        <span class="fa-li"><?= view('icons/list') ?></span>
687                        <a href="<?= e(route(ModulesListsPage::class)) ?>">
688                            <?= I18N::translate('Lists') ?>
689                        </a>
690                        <?= view('components/badge', ['count' => $list_modules_enabled->count(), 'total' => $list_modules_disabled->count(), 'context' => 'primary']) ?>
691                    </li>
692                    <li>
693                        <span class="fa-li"><?= view('icons/report') ?></span>
694                        <a href="<?= e(route(ModulesReportsPage::class)) ?>">
695                            <?= I18N::translate('Reports') ?>
696                        </a>
697                        <?= view('components/badge', ['count' => $report_modules_enabled->count(), 'total' => $report_modules_disabled->count(), 'context' => 'primary']) ?>
698                    </li>
699                    <li>
700                        <span class="fa-li"><?= view('icons/data-fix') ?></span>
701                        <a href="<?= e(route(ModulesDataFixesPage::class)) ?>">
702                            <?= I18N::translate('Data fixes') ?>
703                        </a>
704                        <?= view('components/badge', ['count' => $data_fix_modules_enabled->count(), 'total' => $data_fix_modules_disabled->count(), 'context' => 'primary']) ?>
705                    </li>
706                    <li>
707                        <span class="fa-li"><?= view('icons/tag') ?></span>
708                        <a href="<?= e(route(ModulesCustomTagsPage::class)) ?>">
709                            <?= I18N::translate('Custom GEDCOM tags') ?>
710                        </a>
711                        <?= view('components/badge', ['count' => $custom_tags_modules_enabled->count(), 'total' => $custom_tags_modules_disabled->count(), 'context' => 'primary']) ?>
712                    </li>
713                </ul>
714
715                <h3>
716                    <?= I18N::translate('Individual page') ?>
717                </h3>
718
719                <ul class="fa-ul">
720                    <li>
721                        <span class="fa-li"><?= view('icons/tab') ?></span>
722                        <a href="<?= e(route(ModulesTabsPage::class)) ?>">
723                            <?= I18N::translate('Tabs') ?>
724                            <?= view('components/badge', ['count' => $tab_modules_enabled->count(), 'total' => $tab_modules_disabled->count(), 'context' => 'primary']) ?>
725                        </a>
726                    </li>
727                    <li>
728                        <span class="fa-li"><?= view('icons/sidebar') ?></span>
729                        <a href="<?= e(route(ModulesSidebarsPage::class)) ?>">
730                            <?= I18N::translate('Sidebars') ?>
731                        </a>
732                        <?= view('components/badge', ['count' => $sidebar_modules_enabled->count(), 'total' => $sidebar_modules_disabled->count(), 'context' => 'primary']) ?>
733                    </li>
734                    <li>
735                        <span class="fa-li"><?= view('icons/history') ?></span>
736                        <a href="<?= e(route(ModulesHistoricEventsPage::class)) ?>">
737                            <?= I18N::translate('Historic events') ?>
738                        </a>
739                        <?= view('components/badge', ['count' => $history_modules_enabled->count(), 'total' => $history_modules_disabled->count(), 'context' => 'primary']) ?>
740                    </li>
741                    <li>
742                        <span class="fa-li"><?= view('icons/share') ?></span>
743                        <a href="<?= e(route(ModulesSharesPage::class)) ?>">
744                            <?= /* I18N: plural noun - things that can be shared */  I18N::translate('Shares') ?>
745                        </a>
746                        <?= view('components/badge', ['count' => $share_modules_enabled->count(), 'total' => $share_modules_disabled->count(), 'context' => 'primary']) ?>
747                    </li>
748                </ul>
749            </div>
750
751            <div class="col-sm-4">
752
753                <h3>
754                    <?= I18N::translate('Other') ?>
755                </h3>
756
757                <ul class="fa-ul">
758                    <?php foreach ($other_modules as $module) : ?>
759                        <li>
760                            <?php if ($module->isEnabled()) : ?>
761                                <span class="fa-li"><?= view('icons/module') ?></span>
762                                <?php if ($module instanceof ModuleConfigInterface) : ?>
763                                    <a href="<?= e($module->getConfigLink()) ?>">
764                                    <?= $module->title() ?>
765                                    <?= view('icons/preferences') ?>
766                                    </a>
767                                <?php else : ?>
768                                    <?= $module->title() ?>
769                                <?php endif ?>
770                            <?php else : ?>
771                                <span class="text-muted">
772                                    <span class="fa-li"><?= view('icons/module') ?></span>
773                                    <?= $module->title() ?>
774                                    <?php if ($module instanceof ModuleConfigInterface) : ?>
775                                        <?= view('icons/preferences') ?>
776                                    <?php endif ?>
777                                    </span>
778                                </span>
779                            <?php endif ?>
780
781                            <?php if ($module instanceof ModuleCustomInterface) : ?>
782                                <?= view('admin/custom-module-info', ['module' => $module]) ?>
783                            <?php endif ?>
784                        </li>
785                    <?php endforeach ?>
786                </ul>
787            </div>
788        </div>
789    </div>
790</div>
791
792<!-- MEDIA -->
793<div class="card mb-4">
794    <div class="card-header">
795        <h2 class="mb-0">
796            <?= I18N::translate('Media') ?>
797        </h2>
798    </div>
799    <div class="card-body">
800        <ul class="fa-ul">
801            <li>
802                <span class="fa-li"><?= view('icons/preferences') ?></span>
803                <a href="<?= e(route(ManageMediaPage::class)) ?>">
804                    <?= I18N::translate('Manage media') ?>
805                </a>
806            </li>
807            <li>
808                <span class="fa-li"><?= view('icons/upload') ?></span>
809                <a href="<?= e(route(UploadMediaPage::class)) ?>">
810                    <?= I18N::translate('Upload media files') ?>
811                </a>
812            </li>
813            <li>
814                <span class="fa-li"><?= view('icons/link') ?></span>
815                <a href="<?= e(route(FixLevel0MediaPage::class)) ?>">
816                    <?= I18N::translate('Link media objects to facts and events') ?>
817                </a>
818            </li>
819            <li>
820                <span class="fa-li"><?= view('icons/upload') ?></span>
821                <a href="<?= e(route(ImportThumbnailsPage::class)) ?>">
822                    <?= I18N::translate('Import custom thumbnails from webtrees version 1') ?>
823                </a>
824            </li>
825        </ul>
826    </div>
827</div>
828
829<!-- MAPS -->
830<div class="card mb-4">
831    <div class="card-header">
832        <h2 class="mb-0">
833            <?= I18N::translate('Map') ?>
834        </h2>
835    </div>
836    <div class="card-body">
837        <div class="row">
838            <div class="col-sm-12">
839                <ul class="fa-ul">
840                    <li>
841                        <span class="fa-li"><?= view('icons/location') ?></span>
842                        <a href="<?= e(route(MapDataList::class)) ?>">
843                            <?= I18N::translate('Geographic data') ?>
844                        </a>
845                    </li>
846                </ul>
847            </div>
848        </div>
849    </div>
850</div>
851
852<!-- OLD FILES -->
853<?php if (!empty($files_to_delete)) : ?>
854    <div class="card mb-4 card-outline-danger">
855        <div class="card-header">
856            <h2 class="mb-0">
857                <?= I18N::translate('Old files found') ?>
858            </h2>
859        </div>
860        <div class="card-body">
861            <p>
862                <?= I18N::translate('Files have been found from a previous version of webtrees. Old files can sometimes be a security risk. You should delete them.') ?>
863            </p>
864            <ul class="list-unstyled">
865                <?php foreach ($files_to_delete as $file_to_delete) : ?>
866                    <li dir="ltr">
867                        <code><?= e($file_to_delete) ?></code>
868                    </li>
869                <?php endforeach ?>
870            </ul>
871        </div>
872    </div>
873<?php endif ?>
874