From 88040f563f0c0cbbd5fbeaf86d0fd7a510d4192e Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Fri, 10 Jul 2026 19:23:34 +0300 Subject: [PATCH 1/2] fix(ui): route File menu SQL intents through global fallback Ensures New/Open/Save work from the title bar and non-SQL views by opening the SQL workspace or showing a hint when no SQL connection is active. Fixes #268 --- lib/core/actions/sql_connection_types.dart | 6 + .../actions/sql_editor_command_bridge.dart | 95 +++++++++++ .../actions/sql_editor_global_actions.dart | 102 ++++++++++++ lib/features/main_screen/main_screen.dart | 80 +++++---- lib/features/mysql/mysql_sql_workspace.dart | 14 ++ .../postgresql/postgres_sql_workspace.dart | 14 ++ lib/features/sqlite/sqlite_sql_workspace.dart | 14 ++ .../sql_editor_command_bridge_test.dart | 53 ++++++ .../sql_editor_global_actions_test.dart | 156 ++++++++++++++++++ 9 files changed, 502 insertions(+), 32 deletions(-) create mode 100644 lib/core/actions/sql_connection_types.dart create mode 100644 lib/core/actions/sql_editor_command_bridge.dart create mode 100644 lib/core/actions/sql_editor_global_actions.dart create mode 100644 test/core/actions/sql_editor_command_bridge_test.dart create mode 100644 test/core/actions/sql_editor_global_actions_test.dart diff --git a/lib/core/actions/sql_connection_types.dart b/lib/core/actions/sql_connection_types.dart new file mode 100644 index 00000000..e7c5f422 --- /dev/null +++ b/lib/core/actions/sql_connection_types.dart @@ -0,0 +1,6 @@ +import 'package:querya_desktop/core/storage/local_db.dart'; + +const kSqlCapableConnectionTypes = {'postgresql', 'mysql', 'sqlite'}; + +bool isSqlCapableConnection(ConnectionRow? connection) => + connection != null && kSqlCapableConnectionTypes.contains(connection.type); diff --git a/lib/core/actions/sql_editor_command_bridge.dart b/lib/core/actions/sql_editor_command_bridge.dart new file mode 100644 index 00000000..adb9a739 --- /dev/null +++ b/lib/core/actions/sql_editor_command_bridge.dart @@ -0,0 +1,95 @@ +import 'package:flutter/foundation.dart'; + +enum SqlEditorPendingAction { none, newQuery, openFile, saveFile } + +/// Lets the active SQL workspace handle File menu commands when menu focus is +/// outside the editor subtree (e.g. title bar). +class SqlEditorCommandBridge { + SqlEditorCommandBridge._(); + + static final SqlEditorCommandBridge instance = SqlEditorCommandBridge._(); + + int? _ownerConnectionId; + VoidCallback? _onNew; + VoidCallback? _onOpen; + VoidCallback? _onSave; + + SqlEditorPendingAction pendingAction = SqlEditorPendingAction.none; + + bool get isActive => _onNew != null; + + void register({ + required int? connectionId, + required VoidCallback onNew, + required VoidCallback onOpen, + required VoidCallback onSave, + }) { + _ownerConnectionId = connectionId; + _onNew = onNew; + _onOpen = onOpen; + _onSave = onSave; + _flushPending(); + } + + void unregister({required int? connectionId}) { + if (_ownerConnectionId != connectionId) return; + _ownerConnectionId = null; + _onNew = null; + _onOpen = null; + _onSave = null; + } + + void queuePending(SqlEditorPendingAction action) { + pendingAction = action; + } + + void invokeNew() { + if (_onNew != null) { + _onNew!(); + return; + } + pendingAction = SqlEditorPendingAction.newQuery; + } + + void invokeOpen() { + if (_onOpen != null) { + _onOpen!(); + return; + } + pendingAction = SqlEditorPendingAction.openFile; + } + + void invokeSave() { + if (_onSave != null) { + _onSave!(); + return; + } + pendingAction = SqlEditorPendingAction.saveFile; + } + + void _flushPending() { + final action = pendingAction; + if (action == SqlEditorPendingAction.none) return; + pendingAction = SqlEditorPendingAction.none; + + switch (action) { + case SqlEditorPendingAction.none: + break; + case SqlEditorPendingAction.newQuery: + _onNew?.call(); + case SqlEditorPendingAction.openFile: + _onOpen?.call(); + case SqlEditorPendingAction.saveFile: + _onSave?.call(); + } + } + + @visibleForTesting + void resetForTest() { + _ownerConnectionId = null; + _onNew = null; + _onOpen = null; + _onSave = null; + pendingAction = SqlEditorPendingAction.none; + } +} diff --git a/lib/core/actions/sql_editor_global_actions.dart b/lib/core/actions/sql_editor_global_actions.dart new file mode 100644 index 00000000..39760d49 --- /dev/null +++ b/lib/core/actions/sql_editor_global_actions.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart' as material; +import 'package:flutter/widgets.dart'; +import 'package:querya_desktop/core/actions/sql_connection_types.dart'; +import 'package:querya_desktop/core/actions/sql_editor_actions.dart'; +import 'package:querya_desktop/core/actions/sql_editor_command_bridge.dart'; +import 'package:querya_desktop/core/storage/local_db.dart'; + +/// Fallback [Actions] for File → New/Open/Save when focus is outside a SQL +/// workspace (title bar, table view, MongoDB/Redis, empty workspace). +class SqlEditorGlobalActions extends StatelessWidget { + const SqlEditorGlobalActions({ + super.key, + required this.activeConnection, + required this.onOpenSqlWorkspace, + required this.child, + }); + + final ConnectionRow? activeConnection; + final void Function(ConnectionRow connection) onOpenSqlWorkspace; + final Widget child; + + static const _noSqlConnectionMessage = + 'Select a PostgreSQL, MySQL, or SQLite connection to edit SQL files.'; + + @override + Widget build(BuildContext context) { + return Actions( + actions: >{ + NewSqlIntent: CallbackAction( + onInvoke: (_) { + _handleNew(context); + return null; + }, + ), + OpenSqlIntent: CallbackAction( + onInvoke: (_) { + _handleOpen(context); + return null; + }, + ), + SaveSqlIntent: CallbackAction( + onInvoke: (_) { + _handleSave(context); + return null; + }, + ), + }, + child: child, + ); + } + + void _handleNew(material.BuildContext context) { + final bridge = SqlEditorCommandBridge.instance; + if (bridge.isActive) { + bridge.invokeNew(); + return; + } + final connection = activeConnection; + if (!isSqlCapableConnection(connection)) { + _showHint(context, _noSqlConnectionMessage); + return; + } + bridge.queuePending(SqlEditorPendingAction.newQuery); + onOpenSqlWorkspace(connection!); + } + + void _handleOpen(material.BuildContext context) { + final bridge = SqlEditorCommandBridge.instance; + if (bridge.isActive) { + bridge.invokeOpen(); + return; + } + final connection = activeConnection; + if (!isSqlCapableConnection(connection)) { + _showHint(context, _noSqlConnectionMessage); + return; + } + bridge.queuePending(SqlEditorPendingAction.openFile); + onOpenSqlWorkspace(connection!); + } + + void _handleSave(material.BuildContext context) { + final bridge = SqlEditorCommandBridge.instance; + if (bridge.isActive) { + bridge.invokeSave(); + return; + } + final connection = activeConnection; + if (!isSqlCapableConnection(connection)) { + _showHint(context, _noSqlConnectionMessage); + return; + } + bridge.queuePending(SqlEditorPendingAction.saveFile); + onOpenSqlWorkspace(connection!); + } + + static void _showHint(material.BuildContext context, String message) { + material.ScaffoldMessenger.of(context).showSnackBar( + material.SnackBar(content: material.Text(message)), + ); + } +} diff --git a/lib/features/main_screen/main_screen.dart b/lib/features/main_screen/main_screen.dart index e34ed870..6c9b4616 100644 --- a/lib/features/main_screen/main_screen.dart +++ b/lib/features/main_screen/main_screen.dart @@ -12,6 +12,7 @@ import 'package:flutter/material.dart' as material BuildContext, Widget, RepaintBoundary; +import 'package:querya_desktop/core/actions/sql_editor_global_actions.dart'; import 'package:querya_desktop/core/storage/local_db.dart'; import 'package:querya_desktop/core/theme/querya_theme_scope.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; @@ -123,6 +124,17 @@ class _MainScreenState extends State { _workspace.value = _workspace.value.openSqliteSqlWorkspace(connection); } + void _openSqlWorkspaceForConnection(ConnectionRow connection) { + switch (connection.type) { + case 'postgresql': + _onPostgresOpenSqlWorkspace(connection); + case 'mysql': + _onMysqlOpenSqlWorkspace(connection); + case 'sqlite': + _onSqliteOpenSqlWorkspace(connection); + } + } + Future _openNewConnectionFromHero() async { final row = await promptCreateConnection(context); if (!mounted || row == null) return; @@ -152,17 +164,20 @@ class _MainScreenState extends State { @override material.Widget build(material.BuildContext context) { final wb = context.workbench; - return material.Scaffold( - backgroundColor: wb.canvas, - body: WindowBorder( - color: wb.borderSubtle.withValues(alpha: 0.35), - width: 1, - child: Column( - children: [ - ValueListenableBuilder( - valueListenable: _workspace, - builder: (context, workspace, _) { - return QueryaWindowTitleBar( + return ValueListenableBuilder( + valueListenable: _workspace, + builder: (context, workspace, _) { + return SqlEditorGlobalActions( + activeConnection: workspace.activeConnection, + onOpenSqlWorkspace: _openSqlWorkspaceForConnection, + child: material.Scaffold( + backgroundColor: wb.canvas, + body: WindowBorder( + color: wb.borderSubtle.withValues(alpha: 0.35), + width: 1, + child: Column( + children: [ + QueryaWindowTitleBar( onNewDatabaseConnection: _onNewDatabaseConnectionFromMenu, onNewDatabaseConnectionFromUrl: _onNewDatabaseConnectionFromUrl, activeConnection: workspace.activeConnection, @@ -197,29 +212,30 @@ class _MainScreenState extends State { _connectionsPanelKey.currentState?.disconnectOthers(active); } }, - ); - }, - ), - Divider(height: 1, color: wb.borderSubtle.withValues(alpha: 0.22)), - Expanded( - child: _MainContentSplit( - connectionsPanelKey: _connectionsPanelKey, - workspace: _workspace, - onConnectionSelected: _onConnectionSelected, - onPostgresObjectSelected: _onPostgresObjectSelected, - onMysqlObjectSelected: _onMysqlObjectSelected, - onSqliteObjectSelected: _onSqliteObjectSelected, - onRedisDatabaseSelected: _onRedisDatabaseSelected, - onMongoDBDatabaseSelected: _onMongoDBDatabaseSelected, - onPostgresOpenSqlWorkspace: _onPostgresOpenSqlWorkspace, - onMysqlOpenSqlWorkspace: _onMysqlOpenSqlWorkspace, - onSqliteOpenSqlWorkspace: _onSqliteOpenSqlWorkspace, - onRequestNewConnection: _openNewConnectionFromHero, + ), + Divider(height: 1, color: wb.borderSubtle.withValues(alpha: 0.22)), + Expanded( + child: _MainContentSplit( + connectionsPanelKey: _connectionsPanelKey, + workspace: _workspace, + onConnectionSelected: _onConnectionSelected, + onPostgresObjectSelected: _onPostgresObjectSelected, + onMysqlObjectSelected: _onMysqlObjectSelected, + onSqliteObjectSelected: _onSqliteObjectSelected, + onRedisDatabaseSelected: _onRedisDatabaseSelected, + onMongoDBDatabaseSelected: _onMongoDBDatabaseSelected, + onPostgresOpenSqlWorkspace: _onPostgresOpenSqlWorkspace, + onMysqlOpenSqlWorkspace: _onMysqlOpenSqlWorkspace, + onSqliteOpenSqlWorkspace: _onSqliteOpenSqlWorkspace, + onRequestNewConnection: _openNewConnectionFromHero, + ), + ), + ], ), ), - ], - ), - ), + ), + ); + }, ); } } diff --git a/lib/features/mysql/mysql_sql_workspace.dart b/lib/features/mysql/mysql_sql_workspace.dart index 42c0aac1..49878c7a 100644 --- a/lib/features/mysql/mysql_sql_workspace.dart +++ b/lib/features/mysql/mysql_sql_workspace.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart' as material; import 'package:flutter/services.dart' show LogicalKeyboardKey; import 'package:file_selector/file_selector.dart'; import 'package:querya_desktop/core/actions/sql_editor_actions.dart'; +import 'package:querya_desktop/core/actions/sql_editor_command_bridge.dart'; import 'package:querya_desktop/core/database/mysql_service.dart'; import 'package:querya_desktop/core/layout/vertical_split_pane.dart'; import 'package:querya_desktop/core/storage/app_settings.dart'; @@ -65,9 +66,20 @@ class _MysqlSqlWorkspaceState extends material.State { SqlWorkspaceSettingsRevision.listenable.addListener(_appSettingsListener); material.WidgetsBinding.instance.addPostFrameCallback((_) { unawaited(_loadWorkspaceSettings()); + _registerSqlEditorCommands(); }); } + void _registerSqlEditorCommands() { + if (!mounted) return; + SqlEditorCommandBridge.instance.register( + connectionId: widget.connectionRow.id, + onNew: () => _sqlController.clear(), + onOpen: () => unawaited(_openSqlFile()), + onSave: () => unawaited(_saveSqlFile()), + ); + } + @override void didUpdateWidget(covariant MysqlSqlWorkspace oldWidget) { super.didUpdateWidget(oldWidget); @@ -120,6 +132,8 @@ class _MysqlSqlWorkspaceState extends material.State { @override void dispose() { + SqlEditorCommandBridge.instance + .unregister(connectionId: widget.connectionRow.id); SqlWorkspaceSettingsRevision.listenable .removeListener(_appSettingsListener); _topFraction.dispose(); diff --git a/lib/features/postgresql/postgres_sql_workspace.dart b/lib/features/postgresql/postgres_sql_workspace.dart index 22bc209f..26e579f1 100644 --- a/lib/features/postgresql/postgres_sql_workspace.dart +++ b/lib/features/postgresql/postgres_sql_workspace.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart' as material; import 'package:flutter/services.dart' show LogicalKeyboardKey; import 'package:file_selector/file_selector.dart'; import 'package:querya_desktop/core/actions/sql_editor_actions.dart'; +import 'package:querya_desktop/core/actions/sql_editor_command_bridge.dart'; import 'package:postgres/postgres.dart' as pg; import 'package:querya_desktop/core/database/postgres_service.dart'; import 'package:querya_desktop/core/database/postgres_sql.dart'; @@ -106,9 +107,20 @@ class _PostgresSqlWorkspaceState extends material.State { material.WidgetsBinding.instance.addPostFrameCallback((_) { _syncPostgresSqlTreeContext(); unawaited(_loadWorkspaceSettings()); + _registerSqlEditorCommands(); }); } + void _registerSqlEditorCommands() { + if (!mounted) return; + SqlEditorCommandBridge.instance.register( + connectionId: widget.connectionRow.id, + onNew: () => _sqlController.clear(), + onOpen: () => unawaited(_openSqlFile()), + onSave: () => unawaited(_saveSqlFile()), + ); + } + @override void didUpdateWidget(covariant PostgresSqlWorkspace oldWidget) { super.didUpdateWidget(oldWidget); @@ -257,6 +269,8 @@ class _PostgresSqlWorkspaceState extends material.State { @override void dispose() { + SqlEditorCommandBridge.instance + .unregister(connectionId: widget.connectionRow.id); SqlWorkspaceSettingsRevision.listenable .removeListener(_appSettingsListener); _topFraction.dispose(); diff --git a/lib/features/sqlite/sqlite_sql_workspace.dart b/lib/features/sqlite/sqlite_sql_workspace.dart index 2f34b117..c34c62fa 100644 --- a/lib/features/sqlite/sqlite_sql_workspace.dart +++ b/lib/features/sqlite/sqlite_sql_workspace.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart' as material; import 'package:flutter/services.dart' show LogicalKeyboardKey; import 'package:file_selector/file_selector.dart'; import 'package:querya_desktop/core/actions/sql_editor_actions.dart'; +import 'package:querya_desktop/core/actions/sql_editor_command_bridge.dart'; import 'package:querya_desktop/core/database/sqlite_service.dart'; import 'package:querya_desktop/core/layout/vertical_split_pane.dart'; import 'package:querya_desktop/core/storage/app_settings.dart'; @@ -59,9 +60,20 @@ class _SqliteSqlWorkspaceState extends material.State { SqlWorkspaceSettingsRevision.listenable.addListener(_appSettingsListener); material.WidgetsBinding.instance.addPostFrameCallback((_) { unawaited(_loadWorkspaceSettings()); + _registerSqlEditorCommands(); }); } + void _registerSqlEditorCommands() { + if (!mounted) return; + SqlEditorCommandBridge.instance.register( + connectionId: widget.connectionRow.id, + onNew: () => _sqlController.clear(), + onOpen: () => unawaited(_openSqlFile()), + onSave: () => unawaited(_saveSqlFile()), + ); + } + @override void didUpdateWidget(covariant SqliteSqlWorkspace oldWidget) { super.didUpdateWidget(oldWidget); @@ -100,6 +112,8 @@ class _SqliteSqlWorkspaceState extends material.State { @override void dispose() { + SqlEditorCommandBridge.instance + .unregister(connectionId: widget.connectionRow.id); SqlWorkspaceSettingsRevision.listenable .removeListener(_appSettingsListener); _topFraction.dispose(); diff --git a/test/core/actions/sql_editor_command_bridge_test.dart b/test/core/actions/sql_editor_command_bridge_test.dart new file mode 100644 index 00000000..7b1630bc --- /dev/null +++ b/test/core/actions/sql_editor_command_bridge_test.dart @@ -0,0 +1,53 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:querya_desktop/core/actions/sql_editor_command_bridge.dart'; + +void main() { + tearDown(SqlEditorCommandBridge.instance.resetForTest); + + test('register invokes pending new query after mount', () { + final bridge = SqlEditorCommandBridge.instance; + bridge.queuePending(SqlEditorPendingAction.newQuery); + + var newCount = 0; + bridge.register( + connectionId: 1, + onNew: () => newCount++, + onOpen: () {}, + onSave: () {}, + ); + + expect(newCount, 1); + expect(bridge.pendingAction, SqlEditorPendingAction.none); + }); + + test('invokeOpen uses active handler when registered', () { + final bridge = SqlEditorCommandBridge.instance; + var openCount = 0; + bridge.register( + connectionId: 2, + onNew: () {}, + onOpen: () => openCount++, + onSave: () {}, + ); + + bridge.invokeOpen(); + expect(openCount, 1); + }); + + test('unregister ignores stale connection id', () { + final bridge = SqlEditorCommandBridge.instance; + var newCount = 0; + bridge.register( + connectionId: 3, + onNew: () => newCount++, + onOpen: () {}, + onSave: () {}, + ); + + bridge.unregister(connectionId: 99); + expect(bridge.isActive, isTrue); + + bridge.unregister(connectionId: 3); + expect(bridge.isActive, isFalse); + }); +} diff --git a/test/core/actions/sql_editor_global_actions_test.dart b/test/core/actions/sql_editor_global_actions_test.dart new file mode 100644 index 00000000..49ba7d37 --- /dev/null +++ b/test/core/actions/sql_editor_global_actions_test.dart @@ -0,0 +1,156 @@ +import 'package:flutter/material.dart' as material; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:querya_desktop/core/actions/sql_connection_types.dart'; +import 'package:querya_desktop/core/actions/sql_editor_actions.dart'; +import 'package:querya_desktop/core/actions/sql_editor_command_bridge.dart'; +import 'package:querya_desktop/core/actions/sql_editor_global_actions.dart'; +import 'package:querya_desktop/core/storage/local_db.dart'; + +import '../../support/querya_theme_test_shell.dart'; + +ConnectionRow _postgresConnection() => ConnectionRow( + id: 1, + type: 'postgresql', + name: 'Local PG', + createdAt: '2026-01-01T00:00:00.000Z', + ); + +void main() { + tearDown(SqlEditorCommandBridge.instance.resetForTest); + + group('isSqlCapableConnection', () { + test('accepts postgres mysql sqlite', () { + expect(isSqlCapableConnection(_postgresConnection()), isTrue); + expect( + isSqlCapableConnection( + ConnectionRow( + id: 2, + type: 'redis', + name: 'Redis', + createdAt: '2026-01-01T00:00:00.000Z', + ), + ), + isFalse, + ); + }); + }); + + testWidgets('NewSqlIntent opens sql workspace for sql-capable connection', + (tester) async { + ConnectionRow? opened; + + await tester.pumpWidget( + queryaThemeTestShell( + child: material.ScaffoldMessenger( + child: material.Scaffold( + body: SqlEditorGlobalActions( + activeConnection: _postgresConnection(), + onOpenSqlWorkspace: (connection) => opened = connection, + child: material.Builder( + builder: (context) { + return material.ElevatedButton( + onPressed: () { + Actions.invoke(context, const NewSqlIntent()); + }, + child: const material.Text('invoke'), + ); + }, + ), + ), + ), + ), + ), + ); + + await tester.tap(find.text('invoke')); + await tester.pump(); + + expect(opened?.type, 'postgresql'); + expect( + SqlEditorCommandBridge.instance.pendingAction, + SqlEditorPendingAction.newQuery, + ); + }); + + testWidgets('NewSqlIntent shows hint when connection is not sql-capable', + (tester) async { + await tester.pumpWidget( + queryaThemeTestShell( + child: material.ScaffoldMessenger( + child: material.Scaffold( + body: SqlEditorGlobalActions( + activeConnection: ConnectionRow( + id: 3, + type: 'mongodb', + name: 'Mongo', + createdAt: '2026-01-01T00:00:00.000Z', + ), + onOpenSqlWorkspace: (_) {}, + child: material.Builder( + builder: (context) { + return material.ElevatedButton( + onPressed: () { + Actions.invoke(context, const NewSqlIntent()); + }, + child: const material.Text('invoke'), + ); + }, + ), + ), + ), + ), + ), + ); + + await tester.tap(find.text('invoke')); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 300)); + + expect( + find.text( + 'Select a PostgreSQL, MySQL, or SQLite connection to edit SQL files.', + ), + findsOneWidget, + ); + }); + + testWidgets('OpenSqlIntent delegates to active sql editor bridge', + (tester) async { + var openCount = 0; + SqlEditorCommandBridge.instance.register( + connectionId: 1, + onNew: () {}, + onOpen: () => openCount++, + onSave: () {}, + ); + + await tester.pumpWidget( + queryaThemeTestShell( + child: material.ScaffoldMessenger( + child: material.Scaffold( + body: SqlEditorGlobalActions( + activeConnection: _postgresConnection(), + onOpenSqlWorkspace: (_) => fail('should not open workspace'), + child: material.Builder( + builder: (context) { + return material.ElevatedButton( + onPressed: () { + Actions.invoke(context, const OpenSqlIntent()); + }, + child: const material.Text('invoke'), + ); + }, + ), + ), + ), + ), + ), + ); + + await tester.tap(find.text('invoke')); + await tester.pump(); + + expect(openCount, 1); + }); +} From 3b87d96d6b2d645d4c250a740c01355722068036 Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Fri, 10 Jul 2026 19:27:57 +0300 Subject: [PATCH 2/2] test: add const to ConnectionRow in global actions tests Fixes prefer_const_constructors analyzer warnings in CI. --- test/core/actions/sql_editor_global_actions_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/core/actions/sql_editor_global_actions_test.dart b/test/core/actions/sql_editor_global_actions_test.dart index 49ba7d37..1a8b6b71 100644 --- a/test/core/actions/sql_editor_global_actions_test.dart +++ b/test/core/actions/sql_editor_global_actions_test.dart @@ -9,7 +9,7 @@ import 'package:querya_desktop/core/storage/local_db.dart'; import '../../support/querya_theme_test_shell.dart'; -ConnectionRow _postgresConnection() => ConnectionRow( +ConnectionRow _postgresConnection() => const ConnectionRow( id: 1, type: 'postgresql', name: 'Local PG', @@ -24,7 +24,7 @@ void main() { expect(isSqlCapableConnection(_postgresConnection()), isTrue); expect( isSqlCapableConnection( - ConnectionRow( + const ConnectionRow( id: 2, type: 'redis', name: 'Redis', @@ -80,7 +80,7 @@ void main() { child: material.ScaffoldMessenger( child: material.Scaffold( body: SqlEditorGlobalActions( - activeConnection: ConnectionRow( + activeConnection: const ConnectionRow( id: 3, type: 'mongodb', name: 'Mongo',