Skip to content

Commit 00da6cf

Browse files
authored
[Product Quality] Fix copy-to-clipboard behavior in the console (#9204)
1 parent 2e5f834 commit 00da6cf

File tree

5 files changed

+151
-13
lines changed

5 files changed

+151
-13
lines changed

packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,33 @@ class DartObjectNode extends TreeNode<DartObjectNode> {
373373
if (text != null) return text!;
374374

375375
final instanceRef = ref!.instanceRef;
376-
final value = instanceRef is InstanceRef
377-
? instanceRef.valueAsString
378-
: instanceRef;
379-
return '$name - $value';
376+
if (instanceRef != null && !name.isNullOrEmpty) {
377+
final length = instanceRef.length;
378+
// Show the variable name, kind, and length for instance kinds that have a
379+
// length (maps, lists, sets, etc).
380+
if (instanceRef.length != null) {
381+
return '$name - ${instanceRef.kind} ($length)';
382+
}
383+
384+
// Show the variable name and value for instance kinds without a length
385+
//(e.g. strings, booleans, ints).
386+
return '$name - ${instanceRef.valueAsString}';
387+
}
388+
389+
// Use the diagnostics node (if it exists). This is only provided for
390+
// Inspector nodes.
391+
final diagnostic = ref?.diagnostic;
392+
final description = diagnostic?.description;
393+
if (description != null) {
394+
final separator = diagnostic!.separator;
395+
final textPreview = diagnostic.json['textPreview'];
396+
return textPreview != null
397+
? '$description$separator $textPreview'
398+
: description;
399+
}
400+
401+
// Fallback to returning the runtime type as a catch-all.
402+
return ref.runtimeType.toString();
380403
}
381404

382405
/// Selects the object in the Flutter Widget inspector.

packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ To learn more about DevTools, check out the
1919
DevTools. - [#9125](https://github.com/flutter/devtools/pull/9125)
2020
- Dismiss stale banner messages when the connected app state changes. - [#9148](https://github.com/flutter/devtools/pull/9148)
2121
- Fix a focus traversal issue with search fields. [#9166](https://github.com/flutter/devtools/pull/9166)
22+
- Fix an issue where copying all logs in the console would show `null` for any inspected widgets. - [#9204](https://github.com/flutter/devtools/pull/9204)
2223

2324
## Inspector updates
2425

packages/devtools_app/test/screens/debugger/debugger_screen_variables_test.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,18 +114,18 @@ void main() {
114114
await pumpDebuggerScreen(tester, debuggerController);
115115
expect(find.text('Variables'), findsOneWidget);
116116

117-
final listFinder = find.text('Root 1: List (2 items)');
117+
final listFinder = find.text('root1: List (2 items)');
118118

119119
expect(listFinder, findsOneWidget);
120120

121-
final mapFinder = find.textContaining('Root 2: Map (2 items)');
121+
final mapFinder = find.textContaining('root2: Map (2 items)');
122122
final mapElement1Finder = find.textContaining("['key1']: 1.0");
123123
final mapElement2Finder = find.textContaining("['key2']: 2.0");
124124

125125
expect(listFinder, findsOneWidget);
126126
expect(mapFinder, findsOneWidget);
127-
expect(find.textContaining("Root 3: 'test str...'"), findsOneWidget);
128-
expect(find.textContaining('Root 4: true'), findsOneWidget);
127+
expect(find.textContaining("root3: 'test str...'"), findsOneWidget);
128+
expect(find.textContaining('root4: true'), findsOneWidget);
129129

130130
// Initially list is not expanded.
131131
expect(find.textContaining('0: 3'), findsNothing);
@@ -148,7 +148,7 @@ void main() {
148148
expect(mapElement2Finder, findsOneWidget);
149149

150150
// Expect a tooltip for the set instance.
151-
final setFinder = find.text('Root 5: Set (2 items)');
151+
final setFinder = find.text('root5: Set (2 items)');
152152
expect(setFinder, findsOneWidget);
153153

154154
// Initially set is not expanded.
@@ -174,7 +174,7 @@ void main() {
174174

175175
await pumpDebuggerScreen(tester, debuggerController);
176176

177-
final listFinder = find.text('Root 1: List (243,621 items)');
177+
final listFinder = find.text('root1: List (243,621 items)');
178178
await verifyGroupings(tester, parentFinder: listFinder);
179179
},
180180
);
@@ -191,7 +191,7 @@ void main() {
191191

192192
await pumpDebuggerScreen(tester, debuggerController);
193193

194-
final mapFinder = find.text('Root 1: Map (243,621 items)');
194+
final mapFinder = find.text('root1: Map (243,621 items)');
195195
await verifyGroupings(tester, parentFinder: mapFinder);
196196
},
197197
);
@@ -208,7 +208,7 @@ void main() {
208208

209209
await pumpDebuggerScreen(tester, debuggerController);
210210

211-
final setFinder = find.text('Root 1: Set (243,621 items)');
211+
final setFinder = find.text('root1: Set (243,621 items)');
212212
await verifyGroupings(tester, parentFinder: setFinder);
213213
},
214214
);

packages/devtools_app/test/shared/diagnostics/dart_object_node_test.dart

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,41 @@ void main() {
105105
expect(str.childCount, equals(0));
106106
expect(str.isPartialObject, isFalse);
107107
});
108+
109+
group('toString', () {
110+
test('string variable', () {
111+
final str = buildStringVariable('Hello there!');
112+
expect(str.toString(), equals('root1 - Hello there!'));
113+
});
114+
115+
test('boolean variable', () {
116+
final boolean = buildBooleanVariable(true);
117+
expect(boolean.toString(), equals('root1 - true'));
118+
});
119+
120+
test('set variable', () {
121+
final set = buildSetVariable(length: 3);
122+
expect(set.toString(), equals('root1 - Set (3)'));
123+
});
124+
125+
test('map variable', () {
126+
final map = buildMapVariable(length: 3);
127+
expect(map.toString(), equals('root1 - Map (3)'));
128+
});
129+
130+
test('string variable', () {
131+
final list = buildListVariable(length: 3);
132+
expect(list.toString(), equals('root1 - List (3)'));
133+
});
134+
135+
testWidgets('Text widget', (WidgetTester tester) async {
136+
final textWidget = buildTextWidgetVariable();
137+
expect(textWidget.toString(), equals('Text: Hello world!'));
138+
});
139+
140+
testWidgets('Row widget', (WidgetTester tester) async {
141+
final rowWidget = buildRowWidgetVariable();
142+
expect(rowWidget.toString(), equals('Row'));
143+
});
144+
});
108145
}

packages/devtools_app/test/test_infra/utils/variable_utils.dart

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
44

5+
import 'dart:convert';
6+
57
import 'package:devtools_app/src/shared/diagnostics/dart_object_node.dart';
8+
import 'package:devtools_app/src/shared/diagnostics/diagnostics_node.dart';
69
import 'package:devtools_app/src/shared/diagnostics/generic_instance_reference.dart';
710

811
import 'package:vm_service/vm_service.dart';
@@ -213,6 +216,22 @@ DartObjectNode buildBooleanVariable(bool value) {
213216
);
214217
}
215218

219+
DartObjectNode buildTextWidgetVariable() {
220+
return DartObjectNode.fromValue(
221+
value: null,
222+
isolateRef: _isolateRef,
223+
diagnostic: _textWidgetDiagnosticNode,
224+
);
225+
}
226+
227+
DartObjectNode buildRowWidgetVariable() {
228+
return DartObjectNode.fromValue(
229+
value: null,
230+
isolateRef: _isolateRef,
231+
diagnostic: _rowWidgetDiagnosticNode,
232+
);
233+
}
234+
216235
InstanceRef _buildInstanceRefForMap({required int length}) => InstanceRef(
217236
id: _incrementRef(),
218237
kind: InstanceKind.kMap,
@@ -266,5 +285,63 @@ int _rootNumber = 0;
266285

267286
String _incrementRoot() {
268287
_rootNumber++;
269-
return 'Root $_rootNumber';
288+
return 'root$_rootNumber';
289+
}
290+
291+
final _textWidgetDiagnosticNode = RemoteDiagnosticsNode(
292+
jsonDecode(_textWidgetDiagnosticJson),
293+
null,
294+
false,
295+
null,
296+
);
297+
298+
final _rowWidgetDiagnosticNode = RemoteDiagnosticsNode(
299+
jsonDecode(_rowWidgetDiagnosticJson),
300+
null,
301+
false,
302+
null,
303+
);
304+
305+
const _textWidgetDiagnosticJson = '''
306+
{
307+
"description": "Text",
308+
"type": "_ElementDiagnosticableTreeNode",
309+
"style": "dense",
310+
"hasChildren": true,
311+
"allowWrap": false,
312+
"summaryTree": true,
313+
"locationId": 0,
314+
"creationLocation": {
315+
"file": "file:///Users/prismo/flutter_app/main.dart",
316+
"line": 109,
317+
"column": 23,
318+
"name": "Text"
319+
},
320+
"createdByLocalProject": true,
321+
"textPreview": "Hello world!",
322+
"children": [],
323+
"widgetRuntimeType": "Text",
324+
"stateful": false
325+
}
326+
''';
327+
328+
const _rowWidgetDiagnosticJson = '''
329+
{
330+
"description": "Row",
331+
"type": "_ElementDiagnosticableTreeNode",
332+
"hasChildren": true,
333+
"allowWrap": false,
334+
"summaryTree": true,
335+
"locationId": 0,
336+
"creationLocation": {
337+
"file": "file:///Users/prismo/flutter_app/main.dart",
338+
"line": 109,
339+
"column": 23,
340+
"name": "Row"
341+
},
342+
"createdByLocalProject": true,
343+
"children": [],
344+
"widgetRuntimeType": "Row",
345+
"stateful": false
270346
}
347+
''';

0 commit comments

Comments
 (0)