Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions lib/core/sdui/sdui_tree_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class SduiTreeBuilderState extends material.State<SduiTreeBuilder> {
final Set<String> _expanded = {};
final Map<String, String> _expandErrors = {};

static const double _rowExtent = 36;
static const double _rowExtent = 28;

@override
void initState() {
Expand Down Expand Up @@ -180,17 +180,27 @@ class SduiTreeBuilderState extends material.State<SduiTreeBuilder> {
}

material.Widget _buildNodeRow(SduiTreeNode node, {required int depth}) {
final theme = material.Theme.of(context);
final muted = theme.colorScheme.onSurfaceVariant.withValues(alpha: 0.85);
final primary = theme.colorScheme.primary;
final canExpand = node.expandable || node.hasChildren;
final isExpanded = _expanded.contains(node.id);
final isLoading = _loading.contains(node.id);
final nodeKind = _resolveNodeKind(node);
final isBrowsable = nodeKind == 'table' || nodeKind == 'view';
final iconSize = canExpand
? QueryaIconSizes.treeGroup
: QueryaIconSizes.treeLeaf;
final iconColor = isBrowsable
? primary.withValues(alpha: 0.5)
: muted;
final rowLeft = 8.0 + depth * 16.0 + (canExpand ? 0 : 4.0);

return material.InkWell(
onTap: isBrowsable ? () => widget.onNodeSelected?.call(node) : null,
child: material.Padding(
padding: material.EdgeInsets.only(
left: 8.0 + depth * 16.0,
left: rowLeft,
right: 8,
),
child: material.Row(
Expand All @@ -201,18 +211,22 @@ class SduiTreeBuilderState extends material.State<SduiTreeBuilder> {
height: 28,
child: material.IconButton(
padding: material.EdgeInsets.zero,
iconSize: 18,
iconSize: QueryaIconSizes.treeExpand,
onPressed: () {
if (isExpanded) {
_onCollapse(node);
} else {
_onExpand(node);
}
},
icon: material.Icon(
isExpanded
? material.Icons.expand_more
: material.Icons.chevron_right,
icon: material.AnimatedRotation(
turns: isExpanded ? 0.25 : 0,
duration: const Duration(milliseconds: 160),
curve: material.Curves.easeOutCubic,
child: const material.Icon(
QueryaIcons.expandClosed,
size: QueryaIconSizes.treeExpand,
),
),
),
)
Expand All @@ -230,7 +244,8 @@ class SduiTreeBuilderState extends material.State<SduiTreeBuilder> {
node.icon,
expandable: node.expandable,
),
size: QueryaIconSizes.sduiNode,
size: iconSize,
color: iconColor,
),
const Gap(8),
material.Expanded(
Expand All @@ -239,7 +254,8 @@ class SduiTreeBuilderState extends material.State<SduiTreeBuilder> {
overflow: material.TextOverflow.ellipsis,
maxLines: 1,
style: material.TextStyle(
fontSize: 12,
fontSize: 11,
color: isBrowsable ? theme.colorScheme.onSurface : muted,
fontWeight: isBrowsable ? material.FontWeight.w600 : null,
),
),
Expand Down
4 changes: 2 additions & 2 deletions lib/core/ui/querya_icons.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ abstract final class QueryaIcons {
case 'database':
return database;
case 'table':
return tableGroup;
return expandable ? tableGroup : tableLeaf;
case 'view':
case 'eye':
return viewGroup;
return expandable ? viewGroup : viewLeaf;
case 'folder':
case 'folder-table':
return folder;
Expand Down
2 changes: 1 addition & 1 deletion lib/features/connections/connections_panel_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ class _ExtensionConnectionTileState extends State<_ExtensionConnectionTile> {
duration: context.motionDuration(QueryaMotion.fast),
curve: context.motionCurve(QueryaMotion.standardCurve),
child: material.Icon(
material.Icons.chevron_right_rounded,
QueryaIcons.expandClosed,
size: 16,
color: theme.colorScheme.mutedForeground,
),
Expand Down
2 changes: 1 addition & 1 deletion lib/features/connections/connections_panel_mysql.dart
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ class _MysqlObjectGroupState extends State<_MysqlObjectGroup> {
context: context,
itemCount: widget.items.length,
itemExtent: kConnectionTreeRowExtent,
padding: const material.EdgeInsets.only(left: 22),
padding: const material.EdgeInsets.only(left: 26),
itemBuilder: (context, index) {
final item = widget.items[index];
return _PgTreeRow(
Expand Down
2 changes: 1 addition & 1 deletion lib/features/connections/connections_panel_pg_tree.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1035,7 +1035,7 @@ class _PgObjectGroupState extends State<_PgObjectGroup> {
context: context,
itemCount: widget.items.length,
itemExtent: kConnectionTreeRowExtent,
padding: const material.EdgeInsets.only(left: 22),
padding: const material.EdgeInsets.only(left: 26),
itemBuilder: (context, index) {
final item = widget.items[index];
return _PgTreeRow(
Expand Down
146 changes: 92 additions & 54 deletions lib/features/connections/connections_panel_redis.dart
Original file line number Diff line number Diff line change
Expand Up @@ -258,22 +258,24 @@ class _RedisConnectionTileState extends State<_RedisConnectionTile> {
),
),
if (_error != null)
material.Padding(
TreeLoadError(
message: _error!,
padding: const material.EdgeInsets.only(
left: 28, top: 4, bottom: 4),
child: material.Text(
'Error',
overflow: material.TextOverflow.ellipsis,
maxLines: 1,
style: material.TextStyle(
fontSize: 11, color: theme.colorScheme.destructive),
left: 28,
top: 4,
bottom: 4,
),
onRetry: _loadDatabases,
),
for (final db in _databases)
_RedisDatabaseNode(
index: db.index,
keys: db.keys,
onTap: () => widget.onDatabaseTap?.call(db.index),
if (_databases.isNotEmpty)
_RedisDatabasesNode(
connection: widget.connection,
databases: _databases,
onRefreshDatabases: () {
setState(() => _databases = []);
_loadDatabases();
},
onDatabaseTap: widget.onDatabaseTap,
),
],
),
Expand All @@ -285,6 +287,60 @@ class _RedisConnectionTileState extends State<_RedisConnectionTile> {
}
}

class _RedisDatabasesNode extends material.StatelessWidget {
const _RedisDatabasesNode({
required this.connection,
required this.databases,
required this.onRefreshDatabases,
this.onDatabaseTap,
});

final ConnectionRow connection;
final List<({int index, int keys})> databases;
final VoidCallback onRefreshDatabases;
final void Function(int database)? onDatabaseTap;

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return material.Padding(
padding: const material.EdgeInsets.only(left: 20),
child: material.Column(
crossAxisAlignment: material.CrossAxisAlignment.start,
mainAxisSize: material.MainAxisSize.min,
children: [
_PgTreeRow(
label: 'Databases (${databases.length})',
icon: QueryaIcons.databasesFolder,
iconSize: QueryaIconSizes.treeConnection,
iconColor: theme.colorScheme.primary.withValues(alpha: 0.7),
textStyle: material.TextStyle(
fontSize: 12,
color: theme.colorScheme.foreground,
),
verticalPadding: 4,
onTap: null,
connection: connection,
onContextRefresh: onRefreshDatabases,
),
lazyConnectionTreeList(
context: context,
itemCount: databases.length,
itemBuilder: (context, index) {
final db = databases[index];
return _RedisDatabaseNode(
index: db.index,
keys: db.keys,
onTap: () => onDatabaseTap?.call(db.index),
);
},
),
],
),
);
}
}

class _RedisDatabaseNode extends StatelessWidget {
const _RedisDatabaseNode({
required this.index,
Expand All @@ -300,49 +356,31 @@ class _RedisDatabaseNode extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
return material.Padding(
padding: const material.EdgeInsets.only(left: 24),
child: material.MouseRegion(
cursor: material.SystemMouseCursors.click,
child: material.InkWell(
onTap: onTap,
borderRadius: material.BorderRadius.circular(6),
child: material.Padding(
padding:
const material.EdgeInsets.symmetric(horizontal: 8, vertical: 5),
child: material.Row(
children: [
material.Icon(
QueryaIcons.databasesFolder,
size: 14,
color: keys > 0
? theme.colorScheme.primary.withValues(alpha: 0.7)
: theme.colorScheme.mutedForeground
.withValues(alpha: 0.5),
padding: const material.EdgeInsets.only(left: 16),
child: _PgTreeRow(
label: 'db$index',
icon: QueryaIcons.database,
iconSize: QueryaIconSizes.treeConnection,
iconColor: keys > 0
? theme.colorScheme.primary.withValues(alpha: 0.7)
: theme.colorScheme.mutedForeground.withValues(alpha: 0.5),
trailing: keys > 0
? material.Text(
'$keys',
style: material.TextStyle(
fontSize: 10,
color: theme.colorScheme.mutedForeground,
),
const Gap(8),
material.Expanded(
child: material.Text(
'db$index',
overflow: material.TextOverflow.ellipsis,
maxLines: 1,
style: material.TextStyle(
fontSize: 12,
color: keys > 0
? theme.colorScheme.foreground
: theme.colorScheme.mutedForeground,
),
),
),
if (keys > 0)
material.Text(
'$keys',
style: material.TextStyle(
fontSize: 10, color: theme.colorScheme.mutedForeground),
),
],
),
),
)
: null,
textStyle: material.TextStyle(
fontSize: 12,
color: keys > 0
? theme.colorScheme.foreground
: theme.colorScheme.mutedForeground,
),
verticalPadding: 3,
onTap: onTap,
),
);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/features/connections/connections_panel_sqlite.dart
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ class _SqliteObjectGroupState extends State<_SqliteObjectGroup> {
curve: context.motionCurve(QueryaMotion.standardCurve),
child: material.Icon(
QueryaIcons.expandClosed,
size: 13,
size: QueryaIconSizes.treeExpand,
color: theme.colorScheme.mutedForeground,
),
),
Expand All @@ -387,7 +387,7 @@ class _SqliteObjectGroupState extends State<_SqliteObjectGroup> {
context: context,
itemCount: widget.items.length,
itemExtent: kConnectionTreeRowExtent,
padding: const material.EdgeInsets.only(left: 22),
padding: const material.EdgeInsets.only(left: 26),
itemBuilder: (context, index) {
final item = widget.items[index];
return _PgTreeRow(
Expand Down
3 changes: 2 additions & 1 deletion test/core/sdui/sdui_builders_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:querya_desktop/core/sdui/sdui_form_builder.dart';
import 'package:querya_desktop/core/sdui/sdui_form_schema.dart';
import 'package:querya_desktop/core/sdui/sdui_tree_builder.dart';
import 'package:querya_desktop/core/sdui/sdui_tree_schema.dart';
import 'package:querya_desktop/core/ui/querya_icons.dart';

import '../../support/querya_theme_test_shell.dart';

Expand Down Expand Up @@ -206,7 +207,7 @@ void main() {
expect(find.text('Databases'), findsOneWidget);
expect(find.text('analytics'), findsNothing);

await tester.tap(find.byIcon(material.Icons.chevron_right));
await tester.tap(find.byIcon(QueryaIcons.expandClosed));
await tester.pumpAndSettle();

expect(fetches, 1);
Expand Down
14 changes: 13 additions & 1 deletion test/core/ui/querya_icons_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,21 @@ void main() {
QueryaIcons.database,
);
expect(
QueryaIcons.sduiNodeIcon('table', expandable: false),
QueryaIcons.sduiNodeIcon('table', expandable: true),
QueryaIcons.tableGroup,
);
expect(
QueryaIcons.sduiNodeIcon('table', expandable: false),
QueryaIcons.tableLeaf,
);
expect(
QueryaIcons.sduiNodeIcon('view', expandable: true),
QueryaIcons.viewGroup,
);
expect(
QueryaIcons.sduiNodeIcon('view', expandable: false),
QueryaIcons.viewLeaf,
);
expect(
QueryaIcons.sduiNodeIcon(null, expandable: true),
QueryaIcons.folder,
Expand Down
Loading