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