Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
a6f375ab
Unverified
Commit
a6f375ab
authored
Oct 14, 2021
by
Alex
Committed by
GitHub
Oct 14, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Release Desktop UI Repo Info Widget (#91769)
parent
ae19c8f6
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
203 additions
and
54 deletions
+203
-54
main.dart
dev/conductor/ui/lib/main.dart
+1
-1
conductor_status.dart
dev/conductor/ui/lib/widgets/conductor_status.dart
+98
-2
progression.dart
dev/conductor/ui/lib/widgets/progression.dart
+2
-1
conductor_status_test.dart
dev/conductor/ui/test/widgets/conductor_status_test.dart
+102
-50
No files found.
dev/conductor/ui/lib/main.dart
View file @
a6f375ab
...
...
@@ -55,7 +55,7 @@ class MyApp extends StatelessWidget {
const
SelectableText
(
'Desktop app for managing a release of the Flutter SDK, currently in development'
,
),
const
SizedBox
(
height:
2
0.0
),
const
SizedBox
(
height:
1
0.0
),
MainProgression
(
releaseState:
state
,
stateFilePath:
_stateFilePath
,
...
...
dev/conductor/ui/lib/widgets/conductor_status.dart
View file @
a6f375ab
...
...
@@ -28,6 +28,22 @@ class ConductorStatus extends StatefulWidget {
'Release Updated at'
,
'Dart SDK Revision'
,
];
static
final
List
<
String
>
engineRepoElements
=
<
String
>[
'Engine Candidate Branch'
,
'Engine Starting Git HEAD'
,
'Engine Current Git HEAD'
,
'Engine Path to Checkout'
,
'Engine LUCI Dashboard'
,
];
static
final
List
<
String
>
frameworkRepoElements
=
<
String
>[
'Framework Candidate Branch'
,
'Framework Starting Git HEAD'
,
'Framework Current Git HEAD'
,
'Framework Path to Checkout'
,
'Framework LUCI Dashboard'
,
];
}
class
ConductorStatusState
extends
State
<
ConductorStatus
>
{
...
...
@@ -86,7 +102,6 @@ class ConductorStatusState extends State<ConductorStatus> {
Table
(
columnWidths:
const
<
int
,
TableColumnWidth
>{
0
:
FixedColumnWidth
(
200.0
),
1
:
FixedColumnWidth
(
400.0
),
},
children:
<
TableRow
>[
for
(
String
headerElement
in
ConductorStatus
.
headerElements
)
...
...
@@ -105,19 +120,23 @@ class ConductorStatusState extends State<ConductorStatus> {
children:
<
Widget
>[
Column
(
children:
<
Widget
>[
RepoInfoExpansion
(
engineOrFramework:
'engine'
,
currentStatus:
currentStatus
),
const
SizedBox
(
height:
10.0
),
CherrypickTable
(
engineOrFramework:
'engine'
,
currentStatus:
currentStatus
),
],
),
const
SizedBox
(
width:
20.0
),
Column
(
children:
<
Widget
>[
RepoInfoExpansion
(
engineOrFramework:
'framework'
,
currentStatus:
currentStatus
),
const
SizedBox
(
height:
10.0
),
CherrypickTable
(
engineOrFramework:
'framework'
,
currentStatus:
currentStatus
),
],
),
],
)
],
)
)
,
],
);
}
...
...
@@ -208,3 +227,80 @@ class CherrypickTableState extends State<CherrypickTable> {
);
}
}
/// Widget to display repo info related to the engine and framework.
///
/// Click to show/hide the repo info in a dropdown fashion. By default the section is hidden.
class
RepoInfoExpansion
extends
StatefulWidget
{
const
RepoInfoExpansion
({
Key
?
key
,
required
this
.
engineOrFramework
,
required
this
.
currentStatus
,
})
:
super
(
key:
key
);
final
String
engineOrFramework
;
final
Map
<
String
,
Object
>
currentStatus
;
@override
RepoInfoExpansionState
createState
()
=>
RepoInfoExpansionState
();
}
class
RepoInfoExpansionState
extends
State
<
RepoInfoExpansion
>
{
bool
_isExpanded
=
false
;
/// Show/hide [ExpansionPanel].
void
showHide
()
{
setState
(()
{
_isExpanded
=
!
_isExpanded
;
});
}
@override
Widget
build
(
BuildContext
context
)
{
return
SizedBox
(
width:
500.0
,
child:
ExpansionPanelList
(
expandedHeaderPadding:
EdgeInsets
.
zero
,
expansionCallback:
(
int
index
,
bool
isExpanded
)
{
showHide
();
},
children:
<
ExpansionPanel
>[
ExpansionPanel
(
isExpanded:
_isExpanded
,
headerBuilder:
(
BuildContext
context
,
bool
isExpanded
)
{
return
ListTile
(
key:
Key
(
'
${widget.engineOrFramework}
RepoInfoDropdown'
),
title:
Text
(
'
${widget.engineOrFramework == 'engine' ? 'Engine' : 'Framework'}
Repo Info'
),
onTap:
()
{
showHide
();
});
},
body:
Padding
(
padding:
const
EdgeInsets
.
all
(
15.0
),
child:
Table
(
columnWidths:
const
<
int
,
TableColumnWidth
>{
0
:
FixedColumnWidth
(
240.0
),
},
children:
<
TableRow
>[
for
(
String
repoElement
in
widget
.
engineOrFramework
==
'engine'
?
ConductorStatus
.
engineRepoElements
:
ConductorStatus
.
frameworkRepoElements
)
TableRow
(
decoration:
const
BoxDecoration
(
border:
Border
(
top:
BorderSide
(
color:
Colors
.
grey
))),
children:
<
Widget
>[
Text
(
'
$repoElement
:'
),
SelectableText
(
(
widget
.
currentStatus
[
repoElement
]
==
null
||
widget
.
currentStatus
[
repoElement
]
==
''
)
?
'Unknown'
:
widget
.
currentStatus
[
repoElement
]!
as
String
),
],
),
],
),
),
),
],
),
);
}
}
dev/conductor/ui/lib/widgets/progression.dart
View file @
a6f375ab
...
...
@@ -37,7 +37,7 @@ class MainProgression extends StatefulWidget {
class
MainProgressionState
extends
State
<
MainProgression
>
{
int
_completedStep
=
0
;
// Move forward the stepper to the next step of the release.
//
/
Move forward the stepper to the next step of the release.
void
nextStep
()
{
if
(
_completedStep
<
MainProgression
.
_stepTitles
.
length
-
1
)
{
setState
(()
{
...
...
@@ -74,6 +74,7 @@ class MainProgressionState extends State<MainProgression> {
releaseState:
widget
.
releaseState
,
stateFilePath:
widget
.
stateFilePath
,
),
const
SizedBox
(
height:
20.0
),
Stepper
(
controlsBuilder:
(
BuildContext
context
,
ControlsDetails
details
)
=>
Row
(),
physics:
const
ScrollPhysics
(),
...
...
dev/conductor/ui/test/widgets/conductor_status_test.dart
View file @
a6f375ab
...
...
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:conductor_core/conductor_core.dart'
;
import
'package:conductor_core/proto.dart'
as
pb
;
import
'package:conductor_ui/widgets/conductor_status.dart'
;
import
'package:flutter/gestures.dart'
;
...
...
@@ -10,51 +11,32 @@ import 'package:flutter_test/flutter_test.dart';
void
main
(
)
{
group
(
'conductor_status'
,
()
{
testWidgets
(
'Conductor_status displays nothing found when there is no state file'
,
(
WidgetTester
tester
)
async
{
const
String
testPath
=
'./testPath'
;
await
tester
.
pumpWidget
(
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
MaterialApp
(
home:
Material
(
child:
Column
(
children:
const
<
Widget
>[
ConductorStatus
(
stateFilePath:
testPath
,
),
],
),
),
);
},
),
);
late
pb
.
ConductorState
state
;
expect
(
find
.
text
(
'No persistent state file found at
$testPath
'
),
findsOneWidget
);
expect
(
find
.
text
(
'Conductor version:'
),
findsNothing
);
});
const
String
testPath
=
'./testPath'
;
const
String
conductorVersion
=
'v1.0'
;
const
String
releaseChannel
=
'beta'
;
const
String
releaseVersion
=
'1.2.0-3.4.pre'
;
const
String
engineCandidateBranch
=
'flutter-1.2-candidate.3'
;
const
String
frameworkCandidateBranch
=
'flutter-1.2-candidate.4'
;
const
String
workingBranch
=
'cherrypicks-
$engineCandidateBranch
'
;
const
String
dartRevision
=
'fe9708ab688dcda9923f584ba370a66fcbc3811f'
;
const
String
engineCherrypick1
=
'a5a25cd702b062c24b2c67b8d30b5cb33e0ef6f0'
;
const
String
engineCherrypick2
=
'94d06a2e1d01a3b0c693b94d70c5e1df9d78d249'
;
const
String
frameworkCherrypick
=
'768cd702b691584b2c67b8d30b5cb33e0ef6f0'
;
const
String
engineStartingGitHead
=
'083049e6cae311910c6a6619a6681b7eba4035b4'
;
const
String
engineCurrentGitHead
=
'23otn2o3itn2o3int2oi3tno23itno2i3tn'
;
const
String
engineCheckoutPath
=
'/Users/alexchen/Desktop/flutter_conductor_checkouts/engine'
;
const
String
frameworkStartingGitHead
=
'df6981e98rh49er8h149er8h19er8h1'
;
const
String
frameworkCurrentGitHead
=
'239tnint023t09j2039tj0239tn'
;
const
String
frameworkCheckoutPath
=
'/Users/alexchen/Desktop/flutter_conductor_checkouts/framework'
;
final
String
engineLUCIDashboard
=
luciConsoleLink
(
releaseChannel
,
'engine'
);
final
String
frameworkLUCIDashboard
=
luciConsoleLink
(
releaseChannel
,
'flutter'
);
testWidgets
(
'Conductor_status displays correct status with a state file'
,
(
WidgetTester
tester
)
async
{
const
String
testPath
=
'./testPath'
;
const
String
conductorVersion
=
'v1.0'
;
const
String
releaseChannel
=
'beta'
;
const
String
releaseVersion
=
'1.2.0-3.4.pre'
;
const
String
candidateBranch
=
'flutter-1.2-candidate.3'
;
const
String
workingBranch
=
'cherrypicks-
$candidateBranch
'
;
const
String
dartRevision
=
'fe9708ab688dcda9923f584ba370a66fcbc3811f'
;
const
String
engineCherrypick1
=
'a5a25cd702b062c24b2c67b8d30b5cb33e0ef6f0'
;
const
String
engineCherrypick2
=
'94d06a2e1d01a3b0c693b94d70c5e1df9d78d249'
;
const
String
frameworkCherrypick
=
'768cd702b691584b2c67b8d30b5cb33e0ef6f0'
;
const
String
engineStartingGitHead
=
'083049e6cae311910c6a6619a6681b7eba4035b4'
;
const
String
engineCurrentGitHead
=
'083049e6cae311910c6a6619a6681b7eba4035b4'
;
const
String
engineCheckoutPath
=
'/Users/alexchen/Desktop/flutter_conductor_checkouts/engine'
;
const
String
frameworkStartingGitHead
=
'083049e6cae311910c6a6619a6681b7eba4035b4'
;
const
String
frameworkCurrentGitHead
=
'083049e6cae311910c6a6619a6681b7eba4035b4'
;
const
String
frameworkCheckoutPath
=
'/Users/alexchen/Desktop/flutter_conductor_checkouts/framework'
;
final
pb
.
ConductorState
state
=
pb
.
ConductorState
(
setUp
(()
{
state
=
pb
.
ConductorState
(
engine:
pb
.
Repository
(
candidateBranch:
c
andidateBranch
,
candidateBranch:
engineC
andidateBranch
,
cherrypicks:
<
pb
.
Cherrypick
>[
pb
.
Cherrypick
(
trunkRevision:
engineCherrypick1
),
pb
.
Cherrypick
(
trunkRevision:
engineCherrypick2
),
...
...
@@ -66,7 +48,7 @@ void main() {
checkoutPath:
engineCheckoutPath
,
),
framework:
pb
.
Repository
(
candidateBranch:
c
andidateBranch
,
candidateBranch:
frameworkC
andidateBranch
,
cherrypicks:
<
pb
.
Cherrypick
>[
pb
.
Cherrypick
(
trunkRevision:
frameworkCherrypick
),
],
...
...
@@ -79,13 +61,38 @@ void main() {
releaseChannel:
releaseChannel
,
releaseVersion:
releaseVersion
,
);
});
testWidgets
(
'Conductor_status displays nothing found when there is no state file'
,
(
WidgetTester
tester
)
async
{
const
String
testPath
=
'./testPath'
;
await
tester
.
pumpWidget
(
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ConductorStatus
(
stateFilePath:
testPath
,
),
],
),
),
);
},
),
);
expect
(
find
.
text
(
'No persistent state file found at
$testPath
'
),
findsOneWidget
);
expect
(
find
.
text
(
'Conductor version:'
),
findsNothing
);
});
testWidgets
(
'Conductor_status displays correct status with a state file'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
MaterialApp
(
home:
Material
(
child:
Column
(
child:
ListView
(
children:
<
Widget
>[
ConductorStatus
(
releaseState:
state
,
...
...
@@ -130,9 +137,7 @@ void main() {
testWidgets
(
'Conductor_status displays correct status with a null state file except a releaseChannel'
,
(
WidgetTester
tester
)
async
{
const
String
testPath
=
'./testPath'
;
const
String
releaseChannel
=
'beta'
;
final
pb
.
ConductorState
state
=
pb
.
ConductorState
(
final
pb
.
ConductorState
stateIncomplete
=
pb
.
ConductorState
(
releaseChannel:
releaseChannel
,
);
...
...
@@ -141,10 +146,10 @@ void main() {
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
MaterialApp
(
home:
Material
(
child:
Column
(
child:
ListView
(
children:
<
Widget
>[
ConductorStatus
(
releaseState:
state
,
releaseState:
state
Incomplete
,
stateFilePath:
testPath
,
),
],
...
...
@@ -160,7 +165,7 @@ void main() {
expect
(
find
.
text
(
'
$headerElement
:'
),
findsOneWidget
);
}
expect
(
find
.
text
(
releaseChannel
),
findsOneWidget
);
expect
(
find
.
text
(
'Unknown'
),
findsNWidgets
(
3
));
expect
(
find
.
text
(
'Unknown'
),
findsNWidgets
(
11
));
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
addTearDown
(
gesture
.
removePointer
);
...
...
@@ -176,5 +181,52 @@ void main() {
await
tester
.
pumpAndSettle
();
expect
(
find
.
textContaining
(
'PENDING: The cherrypick has not yet been applied.'
),
findsOneWidget
);
});
testWidgets
(
'Repo Info section displays corresponding info in a dropdown fashion'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
<
Widget
>[
ConductorStatus
(
releaseState:
state
,
stateFilePath:
testPath
,
),
],
),
),
);
},
),
);
expect
(
find
.
text
(
'No persistent state file found at
$testPath
'
),
findsNothing
);
for
(
final
String
repoElement
in
ConductorStatus
.
engineRepoElements
)
{
expect
(
find
.
text
(
'
$repoElement
:'
),
findsOneWidget
);
}
for
(
final
String
repoElement
in
ConductorStatus
.
frameworkRepoElements
)
{
expect
(
find
.
text
(
'
$repoElement
:'
),
findsOneWidget
);
}
expect
(
find
.
text
(
engineCandidateBranch
),
findsOneWidget
);
expect
(
find
.
text
(
engineStartingGitHead
),
findsOneWidget
);
expect
(
find
.
text
(
engineCurrentGitHead
),
findsOneWidget
);
expect
(
find
.
text
(
engineCheckoutPath
),
findsOneWidget
);
expect
(
find
.
text
(
engineLUCIDashboard
),
findsOneWidget
);
expect
(
find
.
text
(
frameworkCandidateBranch
),
findsOneWidget
);
expect
(
find
.
text
(
frameworkStartingGitHead
),
findsOneWidget
);
expect
(
find
.
text
(
frameworkCurrentGitHead
),
findsOneWidget
);
expect
(
find
.
text
(
frameworkCheckoutPath
),
findsOneWidget
);
expect
(
find
.
text
(
frameworkLUCIDashboard
),
findsOneWidget
);
expect
(
tester
.
widget
<
ExpansionPanelList
>(
find
.
byType
(
ExpansionPanelList
).
first
).
children
[
0
].
isExpanded
,
equals
(
false
));
await
tester
.
tap
(
find
.
byKey
(
const
Key
(
'engineRepoInfoDropdown'
)));
await
tester
.
pumpAndSettle
();
expect
(
tester
.
widget
<
ExpansionPanelList
>(
find
.
byType
(
ExpansionPanelList
).
first
).
children
[
0
].
isExpanded
,
equals
(
true
));
});
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment