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