Add Get started, a guided walk through what is left to set up after installing (cron, email, backups, billing, support, the team, starter content - each pack or picked item by item - and a first client), each step a short form of its own with Skip for now and ticked off from the settings themselves, shown to the first admin to sign in on a new install and as a Finish setting up card on the dashboard until done, skipped or dismissed, and in Admin > Get started any time; database 3.4.7 adds settings.config_getting_started (on for a new install, off for an updated one), config_getting_started_skipped and config_getting_started_opened_at; the starter content loaders take the items to load, the mail server check moves to settingsMailServerCheck() for Admin > Mail and the Email step, app.js only starts DataTables where it is loaded, and setup's finish step points at Get started

This commit is contained in:
johnnyq
2026-10-25 14:46:02 -04:00
parent 58e502ad38
commit 6d29583cef
6 changed files with 305 additions and 52 deletions

View File

@@ -3,8 +3,11 @@
/*
* Get started - Starter content: the packs Maintenance > Starter Content has,
* each with how much it would add, ticked to add (getting_started_content).
* Only what isn't here already is added, so ticking one that is changes
* nothing.
* Pick which, under each, lists what it would add - every item ticked, so the
* whole pack goes in unless some are unticked (picked[pack] says the list was
* there, items[pack][] what is ticked in it; js/getting_started.js keeps the
* pack's tick and count in step). Only what isn't here already is listed or
* added.
*/
defined('FROM_GETTING_STARTED') || die("Direct file access is not allowed");
@@ -13,7 +16,6 @@ defined('FROM_STARTER_CONTENT') || define('FROM_STARTER_CONTENT', true);
require_once dirname(__DIR__) . '/post/starter_content_model.php';
$gs_packs = starterContentPacks();
$gs_pack_status = starterContentStatus($mysqli);
?>
<form action="post.php" method="post" data-gs-form>
@@ -21,19 +23,54 @@ $gs_pack_status = starterContentStatus($mysqli);
<div class="list-group mb-3 itflow-gs-packs" data-gs-packs>
<?php foreach ($gs_packs as $gs_key => $gs_pack) {
$gs_status = $gs_pack_status[$gs_key];
$gs_all_here = $gs_status['missing'] === 0; ?>
<label class="list-group-item d-flex gap-3 align-items-start<?= $gs_all_here ? ' is-here' : '' ?>" data-gs-pack="<?= $gs_key ?>">
<input class="form-check-input flex-shrink-0 mt-1" type="checkbox" name="packs[]" value="<?= $gs_key ?>"<?= $gs_all_here ? ' disabled' : ' checked' ?>>
<span class="itflow-gs-pack-icon" aria-hidden="true"><i class="fas fa-fw <?= escapeHtml($gs_pack['icon']) ?>"></i></span>
<span class="min-w-0 flex-grow-1">
<span class="d-flex flex-wrap align-items-baseline gap-2">
<span class="fw-semibold"><?= escapeHtml($gs_pack['label']) ?></span>
<span class="small text-body-secondary"><?= $gs_all_here ? '<i class="fas fa-check text-success me-1"></i>All ' . $gs_status['total'] . ' here' : ($gs_status['present'] ? $gs_status['missing'] . ' more to add' : $gs_status['total'] . ' to add') ?></span>
</span>
<span class="small text-body-secondary itflow-gs-pack-about" title="<?= escapeHtml($gs_pack['description']) ?>"><?= escapeHtml($gs_pack['description']) ?></span>
</span>
</label>
$gs_items = starterContentItems($mysqli, $gs_key);
$gs_total = starterContentTotal($gs_key);
$gs_missing = count($gs_items);
$gs_all_here = $gs_missing === 0;
$gs_count = $gs_all_here ? '' : ($gs_missing < $gs_total ? "$gs_missing more to add" : "$gs_missing to add"); ?>
<div class="list-group-item<?= $gs_all_here ? ' is-here' : '' ?>" data-gs-pack="<?= $gs_key ?>">
<div class="d-flex gap-3 align-items-start">
<input class="form-check-input flex-shrink-0 mt-1" type="checkbox" name="packs[]" value="<?= $gs_key ?>" id="gsPack_<?= $gs_key ?>"<?= $gs_all_here ? ' disabled' : ' checked' ?> data-gs-pack-check>
<span class="itflow-gs-pack-icon" aria-hidden="true"><i class="fas fa-fw <?= escapeHtml($gs_pack['icon']) ?>"></i></span>
<div class="min-w-0 flex-grow-1">
<label class="d-flex flex-wrap align-items-baseline gap-2 mb-0" for="gsPack_<?= $gs_key ?>">
<span class="fw-semibold"><?= escapeHtml($gs_pack['label']) ?></span>
<?php if ($gs_all_here) { ?>
<span class="small text-body-secondary"><i class="fas fa-check text-success me-1"></i>All <?= $gs_total ?> here</span>
<?php } else { ?>
<span class="small text-body-secondary" data-gs-pack-count data-gs-of="<?= $gs_missing ?>" data-gs-more="<?= $gs_missing < $gs_total ? 1 : 0 ?>"><?= $gs_count ?></span>
<?php } ?>
</label>
<div class="small text-body-secondary itflow-gs-pack-about" title="<?= escapeHtml($gs_pack['description']) ?>"><?= escapeHtml($gs_pack['description']) ?></div>
<?php if (!$gs_all_here) { ?>
<details class="itflow-gs-pick mt-1" data-gs-pick>
<summary class="small">Pick which</summary>
<input type="hidden" name="picked[<?= $gs_key ?>]" value="1">
<div class="itflow-gs-pick-tools small mt-2">
<button type="button" class="btn btn-link btn-sm p-0 align-baseline" data-gs-pick-all>All</button>
<span class="text-body-secondary" aria-hidden="true">·</span>
<button type="button" class="btn btn-link btn-sm p-0 align-baseline" data-gs-pick-none>None</button>
</div>
<div class="itflow-gs-pick-list mt-2">
<div class="itflow-gs-pick-cols">
<?php $gs_group = null;
foreach ($gs_items as $gs_n => $gs_item) {
if ($gs_item['group'] !== '' && $gs_item['group'] !== $gs_group) {
$gs_group = $gs_item['group']; ?>
<div class="itflow-gs-pick-group"><?= escapeHtml($gs_group) ?></div>
<?php } ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="items[<?= $gs_key ?>][]" value="<?= escapeHtml($gs_item['key']) ?>" id="gsItem_<?= $gs_key ?>_<?= $gs_n ?>" checked data-gs-item>
<label class="form-check-label" for="gsItem_<?= $gs_key ?>_<?= $gs_n ?>"><?= escapeHtml($gs_item['name']) ?></label>
</div>
<?php } ?>
</div>
</div>
</details>
<?php } ?>
</div>
</div>
</div>
<?php } ?>
</div>
<p class="small text-body-secondary">Nothing you already have is changed. Each pack can be added later, or brought up to date, in Maintenance &gt; Starter Content.</p>