From c1e6964786fe1fc3e9ae06eda1a98404519b287e Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 11 Oct 2026 17:33:39 +0300 Subject: [PATCH 1/2] fix(ui): disabled primary is a grey chip, tx badge, MCP button sizes, ERD toolbar, switch row inset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - A disabled filled button uses the muted surface and label instead of a half-transparent accent. - The SQL toolbar badge reads Auto-commit / Manual commit before the first run instead of 'Transaction —'. - MCP section buttons are md like the rest of Preferences. - Switch rows no longer inset their label by 4 px. - Below 1100 px the ERD toolbar's Note, Auto layout and hidden-tables buttons are icon-only, so Export does not wrap alone. Refs #1480 --- lib/features/erd/erd_view.dart | 14 +++++++++- .../settings/preferences_controls.dart | 2 +- .../settings/preferences_mcp_section.dart | 6 ++--- .../workspace/sql_workspace_toolbar.dart | 10 +++---- lib/shared/widgets/querya_button.dart | 25 +++++++++++------- test/shared/widgets/querya_button_test.dart | 26 +++++++++++++++++++ 6 files changed, 62 insertions(+), 21 deletions(-) diff --git a/lib/features/erd/erd_view.dart b/lib/features/erd/erd_view.dart index 81965296..00fd4946 100644 --- a/lib/features/erd/erd_view.dart +++ b/lib/features/erd/erd_view.dart @@ -1598,7 +1598,13 @@ class _ErdViewState extends material.State material.Container( decoration: SqlEditorChrome.sqlToolbarDecoration(context), padding: const material.EdgeInsets.all(8), - child: QueryaControlScope( + child: material.LayoutBuilder( + builder: (context, constraints) { + // Below ~1100 px the labels of Note, Auto layout and the hidden + // tables button give way to icons (the tooltips keep the names) + // so the toolbar stays on one row. + final compact = constraints.maxWidth < 1100; + return QueryaControlScope( size: QueryaControlSize.md, child: material.Wrap( spacing: 8, @@ -1641,6 +1647,7 @@ class _ErdViewState extends material.State _viewsMenu(), QueryaButton.secondary( key: const material.ValueKey('erd_add_note'), + compact: compact, label: 'Note', icon: material.Icons.sticky_note_2_outlined, tooltip: 'Add a sticky note to the diagram', @@ -1649,6 +1656,7 @@ class _ErdViewState extends material.State if (_marked.isNotEmpty) QueryaButton.secondary( key: const material.ValueKey('erd_group_marked'), + compact: compact, label: 'Group ${_marked.length} ' '${_marked.length == 1 ? 'table' : 'tables'}', icon: material.Icons.folder_open_rounded, @@ -1658,12 +1666,14 @@ class _ErdViewState extends material.State if (_hidden.isNotEmpty) QueryaButton.secondary( key: const material.ValueKey('erd_show_all'), + compact: compact, label: 'Show ${_hidden.length} hidden', icon: material.Icons.visibility_outlined, onPressed: _showAllTables, ), QueryaButton.secondary( key: const material.ValueKey('erd_auto_layout'), + compact: compact, label: 'Auto layout', icon: material.Icons.auto_fix_high_rounded, tooltip: 'Arrange the tables again (undoes manual moves)', @@ -1684,6 +1694,8 @@ class _ErdViewState extends material.State ), ], ), + ); + }, ), ), material.Expanded(child: material.ClipRect(child: body)), diff --git a/lib/features/settings/preferences_controls.dart b/lib/features/settings/preferences_controls.dart index daf2183e..264909f5 100644 --- a/lib/features/settings/preferences_controls.dart +++ b/lib/features/settings/preferences_controls.dart @@ -129,7 +129,7 @@ class PreferencesSwitchRow extends StatelessWidget { onTap: isInteractive ? () => onChanged!(!value) : null, borderRadius: material.BorderRadius.circular(6), child: material.Padding( - padding: const material.EdgeInsets.symmetric(vertical: 6, horizontal: 4), + padding: const material.EdgeInsets.symmetric(vertical: 6), child: material.Row( crossAxisAlignment: material.CrossAxisAlignment.center, children: [ diff --git a/lib/features/settings/preferences_mcp_section.dart b/lib/features/settings/preferences_mcp_section.dart index 34df7561..65ff81e6 100644 --- a/lib/features/settings/preferences_mcp_section.dart +++ b/lib/features/settings/preferences_mcp_section.dart @@ -257,14 +257,14 @@ class PreferencesMcpSectionState key: material.ValueKey('mcp_copy_${kind.name}'), label: 'Copy ${kind.label} config', icon: material.Icons.copy_rounded, - size: QueryaControlSize.sm, + size: QueryaControlSize.md, onPressed: () => unawaited(_copy(kind)), ), QueryaButton.secondary( key: const material.ValueKey('mcp_regenerate'), label: 'Regenerate token', icon: material.Icons.key_rounded, - size: QueryaControlSize.sm, + size: QueryaControlSize.md, tooltip: 'Disconnects connected clients; they reconnect on ' 'their next start.', onPressed: _enabled && !_busy ? () => unawaited(_regenerate()) : null, @@ -286,7 +286,7 @@ class PreferencesMcpSectionState QueryaButton.secondary( key: const material.ValueKey('mcp_clear_log'), label: 'Clear', - size: QueryaControlSize.sm, + size: QueryaControlSize.md, onPressed: _activity.isEmpty ? null : () => unawaited(_clearLog()), ), ], diff --git a/lib/features/workspace/sql_workspace_toolbar.dart b/lib/features/workspace/sql_workspace_toolbar.dart index dfd03326..8de9d253 100644 --- a/lib/features/workspace/sql_workspace_toolbar.dart +++ b/lib/features/workspace/sql_workspace_toolbar.dart @@ -127,13 +127,9 @@ class SqlWorkspaceToolbar extends StatelessWidget { material.Widget _txBadge() { final open = txOpen; - if (open == null) { - return const QueryaBadge.status( - 'Transaction —', - status: QueryaBadgeStatus.neutral, - ); - } - if (open) { + // An unknown state (before the first run) reads as the commit mode, not + // as a dash. + if (open == true) { return const QueryaBadge.status( 'Transaction open', status: QueryaBadgeStatus.warning, diff --git a/lib/shared/widgets/querya_button.dart b/lib/shared/widgets/querya_button.dart index 8bbef19b..fc1b7c53 100644 --- a/lib/shared/widgets/querya_button.dart +++ b/lib/shared/widgets/querya_button.dart @@ -318,14 +318,21 @@ class _QueryaButtonState extends material.State { final base = w.variant == QueryaButtonVariant.primary ? wb.accent : wb.destructive; - foreground = w.variant == QueryaButtonVariant.primary - ? wb.onAccent - : _onColor(base); - final tint = _pressed && enabled - ? 0.22 - : (_hovered && enabled ? 0.12 : 0.0); - background = - material.Color.alphaBlend(foreground.withValues(alpha: tint), base); + if (w.onPressed == null) { + // A disabled filled button is a quiet grey chip, not a faded accent: + // the label of a half-transparent teal button was hard to read. + foreground = scheme.mutedForeground; + background = scheme.muted; + } else { + foreground = w.variant == QueryaButtonVariant.primary + ? wb.onAccent + : _onColor(base); + final tint = _pressed && enabled + ? 0.22 + : (_hovered && enabled ? 0.12 : 0.0); + background = + material.Color.alphaBlend(foreground.withValues(alpha: tint), base); + } } else { final toneColor = w.tone == QueryaButtonTone.destructive ? wb.destructive @@ -467,7 +474,7 @@ class _QueryaButtonState extends material.State { ), ); - if (w.onPressed == null) { + if (w.onPressed == null && !filled) { button = material.Opacity(opacity: 0.5, child: button); } diff --git a/test/shared/widgets/querya_button_test.dart b/test/shared/widgets/querya_button_test.dart index 19fe01aa..ff130e7b 100644 --- a/test/shared/widgets/querya_button_test.dart +++ b/test/shared/widgets/querya_button_test.dart @@ -38,6 +38,32 @@ void main() { expect(taps, 0); }); + testWidgets('a disabled primary is a grey chip, not a faded accent', + (tester) async { + await tester.pumpWidget( + _shell(const QueryaButton.primary(label: 'Save')), + ); + expect( + find.descendant( + of: find.byType(QueryaButton), + matching: find.byType(material.Opacity), + ), + findsNothing, + ); + + // Other disabled variants still fade. + await tester.pumpWidget( + _shell(const QueryaButton.secondary(label: 'Save')), + ); + expect( + find.descendant( + of: find.byType(QueryaButton), + matching: find.byType(material.Opacity), + ), + findsOneWidget, + ); + }); + testWidgets('a loading button does not fire', (tester) async { var taps = 0; await tester.pumpWidget( From 4818504dd15c3e94efbd127a93671b56dc7b1856 Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 11 Oct 2026 17:37:27 +0300 Subject: [PATCH 2/2] test(e2e): before the first run the badge reads Auto-commit --- test/e2e/02_sql_workspaces/e2e_transaction_guard_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/02_sql_workspaces/e2e_transaction_guard_test.dart b/test/e2e/02_sql_workspaces/e2e_transaction_guard_test.dart index 820a69e4..aa8b1bd6 100644 --- a/test/e2e/02_sql_workspaces/e2e_transaction_guard_test.dart +++ b/test/e2e/02_sql_workspaces/e2e_transaction_guard_test.dart @@ -56,7 +56,7 @@ void main() { await ws.pump(tester, delegate); await E2eSqlWorkspace.settle(tester); // Unknown until the first command refreshes the state. - expect(find.text('Transaction —'), findsOneWidget); + expect(find.text('Auto-commit'), findsOneWidget); await beginFromSessionMenu(tester); expect(find.text('Transaction open'), findsOneWidget);