| // Copyright 2019 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/material.dart'; |
| |
| import 'package:cocoon_service/protos.dart' show Agent; |
| |
| import '../logic/agent_health_details.dart'; |
| import '../state/agent.dart'; |
| import 'agent_health_details_bar.dart'; |
| import 'now.dart'; |
| |
| /// Values to be used in [PopupMenu] to know what action to execute. |
| enum _AgentTileAction { details, authorize, reserve } |
| |
| /// A card for showing the information from an [Agent]. |
| /// |
| /// Summarizes [Agent.healthDetails] into a row of icons. |
| /// |
| /// Offers the ability to view the agent raw health details, re-authorize the |
| /// agent, and attempt to reserve a task for the agent. |
| class AgentTile extends StatelessWidget { |
| const AgentTile({ |
| Key key, |
| this.agentHealthDetails, |
| this.agentState, |
| }) : super(key: key); |
| |
| final AgentState agentState; |
| |
| final AgentHealthDetails agentHealthDetails; |
| |
| @visibleForTesting |
| static const Duration authorizeAgentSnackbarDuration = Duration(seconds: 5); |
| |
| @visibleForTesting |
| static const Duration reserveTaskSnackbarDuration = Duration(seconds: 5); |
| |
| @override |
| Widget build(BuildContext context) { |
| final ThemeData theme = Theme.of(context); |
| final DateTime now = Now.of(context); |
| |
| final Agent agent = agentHealthDetails.agent; |
| |
| return Card( |
| child: ListTile( |
| leading: CircleAvatar( |
| backgroundColor: agentHealthDetails.isHealthy(now) ? Colors.green : theme.errorColor, |
| foregroundColor: Colors.white, |
| child: _getIconFromId(agent.agentId), |
| ), |
| title: Text(agent.agentId), |
| subtitle: AgentHealthDetailsBar(agentHealthDetails), |
| trailing: PopupMenuButton<_AgentTileAction>( |
| itemBuilder: (BuildContext context) => <PopupMenuEntry<_AgentTileAction>>[ |
| const PopupMenuItem<_AgentTileAction>( |
| child: Text('Raw health details'), |
| value: _AgentTileAction.details, |
| ), |
| const PopupMenuItem<_AgentTileAction>( |
| child: Text('Authorize agent'), |
| value: _AgentTileAction.authorize, |
| ), |
| const PopupMenuItem<_AgentTileAction>( |
| child: Text('Reserve task'), |
| value: _AgentTileAction.reserve, |
| ), |
| ], |
| icon: const Icon(Icons.more_vert), |
| onSelected: (_AgentTileAction value) { |
| switch (value) { |
| case _AgentTileAction.details: |
| _showHealthDetailsDialog(context, agent.healthDetails); |
| break; |
| case _AgentTileAction.authorize: |
| _authorizeAgent(context, agent); |
| break; |
| case _AgentTileAction.reserve: |
| _reserveTask(context, agent); |
| break; |
| default: |
| throw Exception('$value is not a valid operation on AgentTile popup menu'); |
| } |
| }, |
| ), |
| ), |
| ); |
| } |
| |
| /// A lookup function for showing the leading icon based on [agentId]. |
| Icon _getIconFromId(String agentId) { |
| if (agentId.contains('vm')) { |
| return const Icon(Icons.dns); |
| } else if (agentId.contains('linux')) { |
| return const Icon(Icons.android); |
| } else if (agentId.contains('mac')) { |
| return const Icon(Icons.phone_iphone); |
| } else if (agentId.contains('windows')) { |
| return const Icon(Icons.desktop_windows); |
| } |
| |
| return const Icon(Icons.device_unknown); |
| } |
| |
| void _showHealthDetailsDialog(BuildContext context, String rawHealthDetails) { |
| // TODO(chillers): Add copy button when web has support. https://github.com/flutter/flutter/issues/46020 |
| debugPrint('health details: $rawHealthDetails'); |
| |
| showDialog<SimpleDialog>( |
| context: context, |
| builder: (BuildContext context) => SimpleDialog( |
| children: <Widget>[ |
| Text(rawHealthDetails), |
| ], |
| ), |
| ); |
| } |
| |
| /// Call [authorizeAgent] to Cocoon for [agent] and show the new access token. |
| /// |
| /// On success, displays a [SnackBar] telling the user the access token can |
| /// be found in their console. |
| /// |
| /// If the request fails, [AgentDashboardPage] will handle the error and show |
| /// a [SnackBar]. |
| Future<void> _authorizeAgent(BuildContext context, Agent agent) async { |
| final String token = await agentState.authorizeAgent(agent); |
| if (token != null) { |
| // TODO(chillers): Copy the token to clipboard when web has support. https://github.com/flutter/flutter/issues/46020 |
| debugPrint('token: $token'); |
| |
| Scaffold.of(context).showSnackBar(const SnackBar( |
| content: Text('Check console for token'), |
| duration: authorizeAgentSnackbarDuration, |
| )); |
| } |
| } |
| |
| /// Call [reserveTask] to Cocoon for [agent] and show the information for |
| /// the [Task] that was reserved. |
| /// |
| /// On success, displays a [SnackBar] telling the user the information can |
| /// be found in their console. The data is just the ids and names for the |
| /// task its commit. |
| /// |
| /// If the request fails, [AgentDashboardPage] will handle the error and show |
| /// a [SnackBar]. |
| Future<void> _reserveTask(BuildContext context, Agent agent) async { |
| await agentState.reserveTask(agent); |
| Scaffold.of(context).showSnackBar(const SnackBar( |
| content: Text('Check console for reserve task info'), |
| duration: authorizeAgentSnackbarDuration, |
| )); |
| } |
| } |