feat: guided setup — clickable next steps, signature relaxation, fresh-install auto-open
Post-apply the wizard now renders real Studio actions instead of CLI
text: a start-hub button that polls until the daemon answers,
per-module install buttons (capability-name install via the hub's
store index) with done/progress states, and an open-the-starter-flow
button that navigates to the Flows page. Regulated plans explain in
plain language that modules come from a signed source; the preview
offers 'allow installing from the public store' as one deliberate,
reversible switch that re-assembles the plan (allow_unsigned_modules).
Fresh installs (no config, no setup-plan.yaml) auto-open the wizard
once per run — the wizard IS the onboarding — and it steps back once
a setup exists. The welcome CTA is framed honestly ('get started in
3 questions'), and after the wizard closes the onboarding checklist
remounts, re-probes, and says what the assistant already covered
(profile line from setup-plan.yaml) instead of acting as a second,
disconnected onboarding surface.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
140408d26a
commit
1f1e050b42
8 changed files with 704 additions and 51 deletions
|
|
@ -26,6 +26,41 @@ Widget _host() => MaterialApp(
|
|||
),
|
||||
);
|
||||
|
||||
/// Host that opens the dialog pre-seeded on the review / applied
|
||||
/// step with [plan] (the parsed `--plan-json` shape), bypassing the
|
||||
/// CLI subprocess.
|
||||
Widget _seededHost(Map<String, dynamic> plan, {bool applied = false}) =>
|
||||
MaterialApp(
|
||||
locale: const Locale('de'),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: Builder(
|
||||
builder: (context) => Scaffold(
|
||||
body: Center(
|
||||
child: ElevatedButton(
|
||||
onPressed: () => showDialog<void>(
|
||||
context: context,
|
||||
builder: (_) =>
|
||||
GuidedSetupDialog(debugPlan: plan, debugApplied: applied),
|
||||
),
|
||||
child: const Text('open'),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _regulatedPlan({bool signed = true}) => {
|
||||
'profile': 'enterprise',
|
||||
'modules': ['text.extract', 'text.summarize'],
|
||||
'starter_flow': 'extract-summarize',
|
||||
'runbook': 'service',
|
||||
'curated_docs': <String>[],
|
||||
'require_signatures': signed,
|
||||
'worm_audit': false,
|
||||
'approval_step': true,
|
||||
};
|
||||
|
||||
void main() {
|
||||
testWidgets('step 1 shows scenario options in German with explanations', (
|
||||
tester,
|
||||
|
|
@ -75,4 +110,70 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
expect(find.text('Schritt 2 von 3'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'review of a regulated plan explains the signature dead end and offers the relaxation switch',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(_seededHost(_regulatedPlan()));
|
||||
await tester.tap(find.text('open'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// The plain-language notice + the deliberate one-click switch.
|
||||
expect(
|
||||
find.textContaining('Der öffentliche Store liefert zurzeit unsignierte Pakete'),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(
|
||||
find.text('Installation aus dem öffentlichen Store erlauben'),
|
||||
findsOneWidget,
|
||||
);
|
||||
// No raw CLI prose anywhere.
|
||||
expect(find.textContaining('chain install'), findsNothing);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'applied state renders clickable next steps — start hub, per-module install, open flow',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(
|
||||
_seededHost(_regulatedPlan(signed: false), applied: true),
|
||||
);
|
||||
await tester.tap(find.text('open'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Fertig — Ch∆In ist eingerichtet.'), findsOneWidget);
|
||||
// Hub not probed up in tests → the start action + the
|
||||
// install-needs-hub hint show, and install buttons exist
|
||||
// (disabled) for each plan module.
|
||||
expect(find.text('Hub starten'), findsOneWidget);
|
||||
expect(
|
||||
find.textContaining('Starten Sie zuerst den Hub'),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.text('text.extract installieren'), findsOneWidget);
|
||||
expect(find.text('text.summarize installieren'), findsOneWidget);
|
||||
expect(
|
||||
find.text('Beispiel-Flow „extract-summarize“ öffnen'),
|
||||
findsOneWidget,
|
||||
);
|
||||
// No CLI text in the GUI path.
|
||||
expect(find.textContaining('chain serve'), findsNothing);
|
||||
expect(find.textContaining('chain install'), findsNothing);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'applied regulated (signed) state guides to the signed source instead of dead-end install buttons',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(_seededHost(_regulatedPlan(), applied: true));
|
||||
await tester.tap(find.text('open'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
find.textContaining('signierten Quelle'),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.text('text.extract installieren'), findsNothing);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue