Compare commits

..

No commits in common. "4ceb5bb56725f324327da12417dfb1a3b9386a82" and "ea975b3bcbacfe71af07487c51631067b717e48d" have entirely different histories.

3 changed files with 2 additions and 58 deletions

View file

@ -1,22 +0,0 @@
# fai_chain_studio — Ch∆In Studio (Flutter GUI)
Die grafische Oberfläche der Ch∆In-Plattform (Studio). Gehört dem `chain`-Agenten
(siehe `../../shared/AGENTS.md`). Plattform-/Naming-Konventionen und die
Zero-Learning-Curve-Regeln stammen aus dem Haupt-Repo `fai_chain` (dort `CLAUDE.md`).
## Design
Basis: `../../shared/DESIGN.md`. Studio-Abweichung: Zero-Learning-Curve führend
(Klartext, Inline-Hilfe, kopierbare Fehler); **Akzent bleibt Blau** (Wiedererkennung der
bestehenden Studio-Identität), nicht Petrol. Dark + Light sind Release-Gate.
## UI-Verifikations-Gate (PFLICHT)
Keine „fertig"-Meldung zu UI-Arbeit ohne:
1. **Frischen eigenen Screenshot-Beleg** der geänderten Screens — **hell UND dunkel**
(wie in `fai_chain` gefordert). Nicht aus dem Gedächtnis, nicht „sollte so aussehen".
2. **Durchgespielten Klick-Flow:** die betroffene Interaktion real im laufenden Studio
klicken/bedienen — nicht nur statisch gerendert prüfen. Sonst wiederkehrendes Muster:
„fertig gemeldet, aber der Klick tut nichts".
3. Bewertung gegen `shared/DESIGN.md` + die Studio-Abweichung oben; Fehlermeldungen
kopierbar; Theme-Umschaltung schaltet wirklich alles um.
Testzustände danach zurücksetzen. Stefan nutzt meist Safari — Web-Ansichten dort mitdenken.

View file

@ -641,18 +641,6 @@ class _OnboardingChecklistState extends State<_OnboardingChecklist> {
setState(() => _dismissed = true); setState(() => _dismissed = true);
} }
/// Open Settings (where System-AI + MCP are configured) and
/// re-probe when it closes. The Settings dialog overlays the
/// welcome page rather than navigating, so without this the
/// checklist kept showing the pre-config state (e.g. "connect
/// System-AI" stayed unchecked right after saving a working
/// config). Navigation-based rows self-heal on return; these
/// dialog-based ones did not.
Future<void> _openSettingsThenRefresh() async {
await ChainSettingsDialog.show(context);
if (mounted) await _refresh();
}
/// Localized plain-language label for the applied setup profile. /// Localized plain-language label for the applied setup profile.
String _profileLabel(AppLocalizations l) => switch (_setupProfile) { String _profileLabel(AppLocalizations l) => switch (_setupProfile) {
'enterprise' => l.setupProfileEnterprise, 'enterprise' => l.setupProfileEnterprise,
@ -676,13 +664,13 @@ class _OnboardingChecklistState extends State<_OnboardingChecklist> {
_aiOk, _aiOk,
l.welcomeChecklistAi, l.welcomeChecklistAi,
l.welcomeChecklistAiHint, l.welcomeChecklistAiHint,
_openSettingsThenRefresh, () => ChainSettingsDialog.show(context),
), ),
( (
_mcpOk, _mcpOk,
l.welcomeChecklistMcp, l.welcomeChecklistMcp,
l.welcomeChecklistMcpHint, l.welcomeChecklistMcpHint,
_openSettingsThenRefresh, () => ChainSettingsDialog.show(context),
), ),
( (
_moduleOk, _moduleOk,

View file

@ -144,7 +144,6 @@ class _FaiSystemAiEditorState extends State<ChainSystemAiEditor> {
String? _modelsError; String? _modelsError;
AskAiResult? _testResult; AskAiResult? _testResult;
String? _error; String? _error;
final _scrollController = ScrollController();
HardwareSnapshot? _hw; HardwareSnapshot? _hw;
CuratedSnapshot? _curated; CuratedSnapshot? _curated;
Map<String, CuratedModelInfo> _curatedById = const {}; Map<String, CuratedModelInfo> _curatedById = const {};
@ -201,26 +200,9 @@ class _FaiSystemAiEditorState extends State<ChainSystemAiEditor> {
_endpoint.dispose(); _endpoint.dispose();
_model.dispose(); _model.dispose();
_apiKeyEnv.dispose(); _apiKeyEnv.dispose();
_scrollController.dispose();
super.dispose(); super.dispose();
} }
/// Reveal the test-result / error panel. It renders at the bottom
/// of a scrollable, height-capped form, so on a tall dialog it
/// lands below the fold the operator taps "Test connection",
/// the footer button flickers, and nothing *visible* changes.
/// Scroll it into view so the outcome is never missed.
void _revealBottom() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!_scrollController.hasClients) return;
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 250),
curve: Curves.easeOut,
);
});
}
void _onProviderChanged(_ProviderPreset p) { void _onProviderChanged(_ProviderPreset p) {
setState(() { setState(() {
_preset = p; _preset = p;
@ -273,7 +255,6 @@ class _FaiSystemAiEditorState extends State<ChainSystemAiEditor> {
_saving = false; _saving = false;
_error = e.toString(); _error = e.toString();
}); });
_revealBottom();
} }
} }
@ -316,13 +297,11 @@ class _FaiSystemAiEditorState extends State<ChainSystemAiEditor> {
_testing = false; _testing = false;
_testResult = r; _testResult = r;
}); });
_revealBottom();
} catch (e) { } catch (e) {
setState(() { setState(() {
_testing = false; _testing = false;
_error = e.toString(); _error = e.toString();
}); });
_revealBottom();
} }
} }
@ -396,7 +375,6 @@ class _FaiSystemAiEditorState extends State<ChainSystemAiEditor> {
content: ConstrainedBox( content: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 520, maxHeight: 600), constraints: const BoxConstraints(maxWidth: 520, maxHeight: 600),
child: SingleChildScrollView( child: SingleChildScrollView(
controller: _scrollController,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,