fix(docs): page help buttons open the right topic + wiring guard
The Federation and Runs help buttons opened the architecture doc:
federation.md/runs.md existed as assets but had no _DocEntry, so
showFaiDoc resolved the unknown slug to _kDocs.first. Register both
(onWelcome: false, so they don't clutter the newcomer grid but are
reachable), split the Welcome grid onto the curated subset, and make
the unknown-slug fallback assert in debug instead of silently opening
the wrong topic.
Guard (no-bugfix-without-a-guard): doc_help_wiring_test.dart scans
lib/ for every showFaiDoc('slug') call and asserts each has a
registered entry AND both assets/docs/<slug>[_de].md files. Exposes
kKnownDocSlugs for the test.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
588f437395
commit
5a3f00bb2c
7 changed files with 226 additions and 6 deletions
|
|
@ -1048,14 +1048,28 @@ class _DocEntry {
|
|||
final IconData icon;
|
||||
final String Function(AppLocalizations) title;
|
||||
final String Function(AppLocalizations) blurb;
|
||||
|
||||
/// Whether this entry is shown as a card in the Welcome page's
|
||||
/// doc grid. Every entry is reachable via [showFaiDoc] regardless;
|
||||
/// `onWelcome: false` keeps advanced topics (federation, runs) out
|
||||
/// of the newcomer grid while still wiring their page help buttons.
|
||||
final bool onWelcome;
|
||||
|
||||
const _DocEntry({
|
||||
required this.slug,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.blurb,
|
||||
this.onWelcome = true,
|
||||
});
|
||||
}
|
||||
|
||||
/// Every doc topic Studio can open in-app. The slug maps to
|
||||
/// `assets/docs/<slug>[_<locale>].md`. Adding a page help button
|
||||
/// (`showFaiDoc(context, '<slug>')`) requires a matching entry here
|
||||
/// AND the asset files — `doc_help_wiring_test.dart` enforces both,
|
||||
/// so a help button can never silently fall back to the wrong topic
|
||||
/// again (federation/runs used to resolve to architecture).
|
||||
final List<_DocEntry> _kDocs = <_DocEntry>[
|
||||
_DocEntry(
|
||||
slug: 'architecture',
|
||||
|
|
@ -1087,17 +1101,47 @@ final List<_DocEntry> _kDocs = <_DocEntry>[
|
|||
title: (l) => l.welcomeDocApprovalsTitle,
|
||||
blurb: (l) => l.welcomeDocApprovalsBlurb,
|
||||
),
|
||||
_DocEntry(
|
||||
slug: 'federation',
|
||||
icon: Icons.hub_outlined,
|
||||
title: (l) => l.welcomeDocFederationTitle,
|
||||
blurb: (l) => l.welcomeDocFederationBlurb,
|
||||
onWelcome: false,
|
||||
),
|
||||
_DocEntry(
|
||||
slug: 'runs',
|
||||
icon: Icons.rocket_launch_outlined,
|
||||
title: (l) => l.welcomeDocRunsTitle,
|
||||
blurb: (l) => l.welcomeDocRunsBlurb,
|
||||
onWelcome: false,
|
||||
),
|
||||
];
|
||||
|
||||
/// The doc cards shown on the Welcome page (curated newcomer set).
|
||||
final List<_DocEntry> _kWelcomeDocs =
|
||||
_kDocs.where((d) => d.onWelcome).toList();
|
||||
|
||||
/// Slugs Studio can resolve in-app — exposed for the wiring guard
|
||||
/// test so it can assert every `showFaiDoc` call has a home.
|
||||
final Set<String> kKnownDocSlugs = _kDocs.map((d) => d.slug).toSet();
|
||||
|
||||
/// Public entry-point for the doc-reader sheet. Pass a slug
|
||||
/// ("approvals", "audit", "security", "architecture", "flows")
|
||||
/// and the bottom sheet opens with the localized markdown.
|
||||
/// Returns null when the slug isn't registered — caller can
|
||||
/// log + show a SnackBar.
|
||||
Future<void>? showFaiDoc(BuildContext context, String slug) {
|
||||
// A slug with no entry is a wiring bug (doc_help_wiring_test.dart
|
||||
// guards against it). The fallback keeps the UI alive in release,
|
||||
// but we assert in debug so the mistake surfaces during
|
||||
// development rather than silently opening the wrong topic.
|
||||
final entry = _kDocs.firstWhere(
|
||||
(d) => d.slug == slug,
|
||||
orElse: () => _kDocs.first,
|
||||
orElse: () {
|
||||
assert(false, 'showFaiDoc: unknown doc slug "$slug" — register it '
|
||||
'in _kDocs and add assets/docs/$slug[_de].md');
|
||||
return _kDocs.first;
|
||||
},
|
||||
);
|
||||
return _DocReaderSheet.show(context, entry);
|
||||
}
|
||||
|
|
@ -1130,9 +1174,9 @@ class _DocsRow extends StatelessWidget {
|
|||
if (!twoCols) {
|
||||
return Column(
|
||||
children: [
|
||||
for (var i = 0; i < _kDocs.length; i++) ...[
|
||||
for (var i = 0; i < _kWelcomeDocs.length; i++) ...[
|
||||
if (i > 0) const SizedBox(height: ChainSpace.md),
|
||||
_DocCard(entry: _kDocs[i]),
|
||||
_DocCard(entry: _kWelcomeDocs[i]),
|
||||
],
|
||||
],
|
||||
);
|
||||
|
|
@ -1144,12 +1188,12 @@ class _DocsRow extends StatelessWidget {
|
|||
// card spans the full width so it reads as intentional
|
||||
// rather than a lonely half-box with dead space beside it.
|
||||
final rows = <Widget>[];
|
||||
for (var i = 0; i < _kDocs.length; i += 2) {
|
||||
for (var i = 0; i < _kWelcomeDocs.length; i += 2) {
|
||||
if (rows.isNotEmpty) {
|
||||
rows.add(const SizedBox(height: ChainSpace.md));
|
||||
}
|
||||
final left = _kDocs[i];
|
||||
final right = i + 1 < _kDocs.length ? _kDocs[i + 1] : null;
|
||||
final left = _kWelcomeDocs[i];
|
||||
final right = i + 1 < _kWelcomeDocs.length ? _kWelcomeDocs[i + 1] : null;
|
||||
if (right == null) {
|
||||
rows.add(_DocCard(entry: left));
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue