From 7ea241112c6e1fc450e7f2df4fb9e52ada77ec48 Mon Sep 17 00:00:00 2001 From: lukas-heiligenbrunner Date: Fri, 16 Feb 2024 17:37:26 +0100 Subject: [PATCH] add side panel and more build log controls --- frontend/lib/components/api/APIBuilder.dart | 3 +- frontend/lib/components/build_output.dart | 12 +- .../lib/components/dashboard/chart_card.dart | 45 ++-- .../lib/components/dashboard/side_panel.dart | 6 +- frontend/lib/screens/build_screen.dart | 228 +++++++++++++++--- 5 files changed, 226 insertions(+), 68 deletions(-) diff --git a/frontend/lib/components/api/APIBuilder.dart b/frontend/lib/components/api/APIBuilder.dart index e69e701..0375bc1 100644 --- a/frontend/lib/components/api/APIBuilder.dart +++ b/frontend/lib/components/api/APIBuilder.dart @@ -42,8 +42,7 @@ class _APIBuilderState if (widget.interval != null) { timer = Timer.periodic(widget.interval!, (Timer t) { - Provider.of(context, listen: false) - .refresh(context); + Provider.of(context, listen: false).refresh(context); }); } } diff --git a/frontend/lib/components/build_output.dart b/frontend/lib/components/build_output.dart index 6263cff..237de48 100644 --- a/frontend/lib/components/build_output.dart +++ b/frontend/lib/components/build_output.dart @@ -31,11 +31,13 @@ class _BuildOutputState extends State { scrollDirection: Axis.vertical, //.horizontal child: Padding( padding: const EdgeInsets.only(left: 30, right: 15), - child: Text( - output, - style: const TextStyle( - fontSize: 16.0, - color: Colors.white, + child: SelectionArea( + child: Text( + output, + style: const TextStyle( + fontSize: 16.0, + color: Colors.white, + ), ), ), ), diff --git a/frontend/lib/components/dashboard/chart_card.dart b/frontend/lib/components/dashboard/chart_card.dart index 72205dc..199b135 100644 --- a/frontend/lib/components/dashboard/chart_card.dart +++ b/frontend/lib/components/dashboard/chart_card.dart @@ -2,17 +2,18 @@ import 'package:flutter/material.dart'; import '../../constants/color_constants.dart'; -class ChartCard extends StatelessWidget { - const ChartCard({ - Key? key, +class SideCard extends StatelessWidget { + const SideCard({ + super.key, required this.title, - required this.color, + this.color, required this.textRight, - required this.subtitle, - }) : super(key: key); + this.subtitle, + }); - final Color color; - final String title, textRight, subtitle; + final Color? color; + final String title, textRight; + final String? subtitle; @override Widget build(BuildContext context) { @@ -27,12 +28,13 @@ class ChartCard extends StatelessWidget { ), child: Row( children: [ - SizedBox( - height: 20, - width: 20, - child: Container( - color: color, - )), + if (color != null) + SizedBox( + height: 20, + width: 20, + child: Container( + color: color, + )), Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: defaultPadding), @@ -44,13 +46,14 @@ class ChartCard extends StatelessWidget { maxLines: 1, overflow: TextOverflow.ellipsis, ), - Text( - subtitle, - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: Colors.white70), - ), + if (subtitle != null) + Text( + subtitle!, + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(color: Colors.white70), + ), ], ), ), diff --git a/frontend/lib/components/dashboard/side_panel.dart b/frontend/lib/components/dashboard/side_panel.dart index bdaa6a9..f9359a3 100644 --- a/frontend/lib/components/dashboard/side_panel.dart +++ b/frontend/lib/components/dashboard/side_panel.dart @@ -39,21 +39,21 @@ class SidePanel extends StatelessWidget { nrbuilds: nrbuilds, nrfailedbuilds: nrfailedbuilds, nrActiveBuilds: nrActiveBuilds), - ChartCard( + SideCard( color: const Color(0xff0a7005), title: "Successful Builds", textRight: "${((nrbuilds - nrfailedbuilds) * 100 / nrbuilds).toStringAsFixed(2)}%", subtitle: (nrbuilds - nrfailedbuilds).toString(), ), - ChartCard( + SideCard( color: const Color(0xff760707), title: "Failed Builds", textRight: "${(nrfailedbuilds * 100 / nrbuilds).toStringAsFixed(2)}%", subtitle: nrfailedbuilds.toString(), ), - ChartCard( + SideCard( color: const Color(0xff9d8d00), title: "Active Builds", textRight: diff --git a/frontend/lib/screens/build_screen.dart b/frontend/lib/screens/build_screen.dart index f23008f..6750a8b 100644 --- a/frontend/lib/screens/build_screen.dart +++ b/frontend/lib/screens/build_screen.dart @@ -7,7 +7,10 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; +import '../components/confirm_popup.dart'; +import '../components/dashboard/chart_card.dart'; import '../components/dashboard/your_packages.dart'; +import '../constants/color_constants.dart'; class BuildScreen extends StatefulWidget { const BuildScreen({super.key, required this.buildID}); @@ -32,50 +35,201 @@ class _BuildScreenState extends State { interval: const Duration(seconds: 10), onLoad: () => const Text("loading"), onData: (buildData) { - final start_time = DateTime.fromMillisecondsSinceEpoch( - (buildData.start_time ?? 0) * 1000); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - const SizedBox( - width: 10, - ), - IconButton( - icon: Icon( - switchSuccessIcon(buildData.status), - color: switchSuccessColor(buildData.status), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + _buildTopBar(buildData), + const SizedBox( + height: 15, ), - onPressed: () { - context.replace("/build/${buildData.id}"); - }, - ), - const SizedBox( - width: 10, - ), - Text( - buildData.pkg_name, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox( - width: 10, - ), - Text("triggered ${start_time.readableDuration()}") - ], + _buildPage(buildData) + ], + ), ), - const SizedBox( - height: 15, - ), - _buildPage(buildData) + _buildSideBar(), ], ); }), ), - appBar: AppBar(), + ); + } + + Widget _buildTopBar(Build buildData) { + final start_time = + DateTime.fromMillisecondsSinceEpoch((buildData.start_time ?? 0) * 1000); + + return Container( + color: secondaryColor, + child: Padding( + padding: const EdgeInsets.only(top: 10, bottom: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const SizedBox( + width: 10, + ), + IconButton( + icon: const Icon( + Icons.arrow_back, + size: 28, + ), + onPressed: () { + context.pop(); + }, + ), + const SizedBox( + width: 10, + ), + IconButton( + icon: Icon( + switchSuccessIcon(buildData.status), + color: switchSuccessColor(buildData.status), + ), + onPressed: () { + context.replace("/build/${buildData.id}"); + }, + ), + const SizedBox( + width: 10, + ), + Text( + buildData.pkg_name, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + const SizedBox( + width: 10, + ), + Text("triggered ${start_time.readableDuration()}") + ], + ), + Row( + children: [ + IconButton( + onPressed: () {}, + icon: const Icon(Icons.read_more), + tooltip: "Follow log", + ), + IconButton( + onPressed: () {}, + icon: const Icon(Icons.vertical_align_top_rounded), + tooltip: "Go to Top", + ), + IconButton( + onPressed: () {}, + icon: Icon(Icons.vertical_align_bottom_rounded), + tooltip: "Go to Bottom", + ), + const SizedBox( + width: 15, + ), + ], + ) + ], + ), + ), + ); + } + + Widget _buildSideBar() { + return SizedBox( + width: 300, + child: Container( + color: secondaryColor, + padding: const EdgeInsets.all(defaultPadding), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 45, + ), + Divider(), + const Text( + "Actions:", + style: TextStyle(fontSize: 18), + textAlign: TextAlign.start, + ), + const SizedBox( + height: 15, + ), + Row( + children: [ + ElevatedButton( + onPressed: () async { + final confirmResult = await showConfirmationDialog( + context, + "Delete Build", + "Are you sure to delete this Package?", + () async {}, + () {}, + ); + }, + child: const Text( + "Delete", + style: TextStyle(color: Colors.redAccent), + ), + ), + const SizedBox( + width: 10, + ), + ElevatedButton( + onPressed: () async { + final confirmResult = await showConfirmationDialog( + context, + "Delete Build", + "Are you sure to delete this Package?", + () async {}, + () {}, + ); + }, + child: const Text( + "Retry", + style: TextStyle(color: Colors.orangeAccent), + ), + ), + ], + ), + const SizedBox( + height: 15, + ), + Divider(), + const SizedBox( + height: 15, + ), + Text( + "Build Information:", + style: TextStyle(fontSize: 18), + textAlign: TextAlign.start, + ), + SizedBox( + height: 20, + ), + SideCard( + title: "Build Number", + textRight: "7", + ), + SideCard( + title: "Finished", + textRight: "7", + ), + SideCard( + title: "Queued", + textRight: "7", + ), + SideCard( + title: "Duration", + textRight: "7", + ), + ], + ), + ), ); }