From 037b939d89112484797ce89ba8d4da738f0e9f13 Mon Sep 17 00:00:00 2001 From: Omar Abou Selo Date: Wed, 11 Sep 2024 15:01:21 +0300 Subject: [PATCH] Fetch single artefact on artefact page (#210) * Fetch single artefact on artefact page * Fix bug where review ratio doesn't get updated on artefact page --- frontend/lib/providers/artefact.dart | 29 +++++++++++++++ frontend/lib/providers/family_artefacts.dart | 37 +++---------------- .../lib/providers/review_test_execution.dart | 11 ++---- frontend/lib/repositories/api_repository.dart | 5 +++ .../lib/ui/artefact_page/artefact_page.dart | 27 ++------------ .../artefact_signoff_button.dart | 6 +-- .../test_execution_pop_over.dart | 4 -- .../artefact_page/test_execution_review.dart | 2 - 8 files changed, 49 insertions(+), 72 deletions(-) create mode 100644 frontend/lib/providers/artefact.dart diff --git a/frontend/lib/providers/artefact.dart b/frontend/lib/providers/artefact.dart new file mode 100644 index 00000000..6b1ec1a3 --- /dev/null +++ b/frontend/lib/providers/artefact.dart @@ -0,0 +1,29 @@ +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +import '../models/artefact.dart' as artefact_model; +import 'api.dart'; + +part 'artefact.g.dart'; + +@riverpod +class Artefact extends _$Artefact { + @override + Future build(int artefactId) { + final api = ref.watch(apiProvider); + return api.getArtefact(artefactId); + } + + Future changeArtefactStatus( + id, + artefact_model.ArtefactStatus status, + ) async { + final api = ref.read(apiProvider); + final artefact = await api.changeArtefactStatus(artefactId, status); + state = AsyncData(artefact); + } + + Future updateCompletedTestExecutionsCount(int count) async { + final artefact = await future; + state = AsyncData(artefact.copyWith(completedTestExecutionsCount: count)); + } +} diff --git a/frontend/lib/providers/family_artefacts.dart b/frontend/lib/providers/family_artefacts.dart index d407c16e..31da2c53 100644 --- a/frontend/lib/providers/family_artefacts.dart +++ b/frontend/lib/providers/family_artefacts.dart @@ -7,35 +7,10 @@ import 'api.dart'; part 'family_artefacts.g.dart'; @riverpod -class FamilyArtefacts extends _$FamilyArtefacts { - @override - Future> build(FamilyName family) async { - final api = ref.watch(apiProvider); - return api.getFamilyArtefacts(family); - } - - Future changeArtefactStatus( - int artefactId, - ArtefactStatus newStatus, - ) async { - final api = ref.read(apiProvider); - final artefact = await api.changeArtefactStatus(artefactId, newStatus); - - final previousState = await future; - state = AsyncData({...previousState, artefact.id: artefact}); - } - - Future updateCompletedTestExecutionsCount( - int artefactId, - int count, - ) async { - final previousState = await future; - final artefact = previousState[artefactId]; - if (artefact != null) { - state = AsyncData({ - ...previousState, - artefactId: artefact.copyWith(completedTestExecutionsCount: count), - }); - } - } +Future> familyArtefacts( + FamilyArtefactsRef ref, + FamilyName family, +) { + final api = ref.watch(apiProvider); + return api.getFamilyArtefacts(family); } diff --git a/frontend/lib/providers/review_test_execution.dart b/frontend/lib/providers/review_test_execution.dart index 26c0f14f..5c0d88c5 100644 --- a/frontend/lib/providers/review_test_execution.dart +++ b/frontend/lib/providers/review_test_execution.dart @@ -1,9 +1,8 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; -import '../models/family_name.dart'; import '../models/test_execution.dart'; +import 'artefact.dart'; import 'artefact_builds.dart'; -import 'family_artefacts.dart'; part 'review_test_execution.g.dart'; @@ -18,7 +17,6 @@ class ReviewTestExecution extends _$ReviewTestExecution { int testExecutionId, String reviewComment, List reviewDecision, - FamilyName familyName, int artefactId, ) async { await ref @@ -41,10 +39,7 @@ class ReviewTestExecution extends _$ReviewTestExecution { .fold(0, (a, b) => a + b); await ref - .read(familyArtefactsProvider(familyName).notifier) - .updateCompletedTestExecutionsCount( - artefactId, - newCompletedTestExecutionsCount, - ); + .read(artefactProvider(artefactId).notifier) + .updateCompletedTestExecutionsCount(newCompletedTestExecutionsCount); } } diff --git a/frontend/lib/repositories/api_repository.dart b/frontend/lib/repositories/api_repository.dart index 5cfad9c4..7888e0dd 100644 --- a/frontend/lib/repositories/api_repository.dart +++ b/frontend/lib/repositories/api_repository.dart @@ -125,4 +125,9 @@ class ApiRepository { Future deleteTestIssue(int issueId) async { await dio.delete('/v1/test-cases/reported-issues/$issueId'); } + + Future getArtefact(int artefactId) async { + final response = await dio.get('/v1/artefacts/$artefactId'); + return Artefact.fromJson(response.data); + } } diff --git a/frontend/lib/ui/artefact_page/artefact_page.dart b/frontend/lib/ui/artefact_page/artefact_page.dart index d184741b..445c560b 100644 --- a/frontend/lib/ui/artefact_page/artefact_page.dart +++ b/frontend/lib/ui/artefact_page/artefact_page.dart @@ -2,9 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:yaru/widgets.dart'; -import '../../providers/family_artefacts.dart'; -import '../../routing.dart'; -import '../dialog_header.dart'; +import '../../providers/artefact.dart'; import '../spacing.dart'; import 'artefact_page_body.dart'; import 'artefact_page_header.dart'; @@ -15,34 +13,17 @@ class ArtefactPage extends ConsumerWidget { final int artefactId; - Column get _invalidArtefactErrorMessage { - return const Column( - children: [ - DialogHeader(), - Expanded( - child: Center( - child: Text('Artefact not found. It may be that a' - ' newer version has been released already'), - ), - ), - ], - ); - } - @override Widget build(BuildContext context, WidgetRef ref) { - final family = AppRoutes.familyFromUri(AppRoutes.uriFromContext(context)); - final artefacts = ref.watch(familyArtefactsProvider(family)); + final artefact = ref.watch(artefactProvider(artefactId)); return Padding( padding: const EdgeInsets.only( left: Spacing.pageHorizontalPadding, right: Spacing.pageHorizontalPadding, top: Spacing.level5, ), - child: artefacts.when( - data: (artefacts) { - final artefact = artefacts[artefactId]; - if (artefact == null) return _invalidArtefactErrorMessage; + child: artefact.when( + data: (artefact) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/frontend/lib/ui/artefact_page/artefact_signoff_button.dart b/frontend/lib/ui/artefact_page/artefact_signoff_button.dart index e1932124..a648b534 100644 --- a/frontend/lib/ui/artefact_page/artefact_signoff_button.dart +++ b/frontend/lib/ui/artefact_page/artefact_signoff_button.dart @@ -3,8 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:yaru/widgets.dart'; import '../../models/artefact.dart'; -import '../../providers/family_artefacts.dart'; -import '../../routing.dart'; +import '../../providers/artefact.dart' hide Artefact; class ArtefactSignoffButton extends ConsumerWidget { const ArtefactSignoffButton({super.key, required this.artefact}); @@ -14,7 +13,6 @@ class ArtefactSignoffButton extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final fontStyle = Theme.of(context).textTheme.titleMedium; - final family = AppRoutes.familyFromUri(AppRoutes.uriFromContext(context)); return YaruPopupMenuButton( child: Text( @@ -26,7 +24,7 @@ class ArtefactSignoffButton extends ConsumerWidget { (status) => PopupMenuItem( value: status, onTap: () => ref - .read(familyArtefactsProvider(family).notifier) + .read(artefactProvider(artefact.id).notifier) .changeArtefactStatus(artefact.id, status), child: Text( status.name, diff --git a/frontend/lib/ui/artefact_page/test_execution_pop_over.dart b/frontend/lib/ui/artefact_page/test_execution_pop_over.dart index 8d5712fd..573fcd44 100644 --- a/frontend/lib/ui/artefact_page/test_execution_pop_over.dart +++ b/frontend/lib/ui/artefact_page/test_execution_pop_over.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:yaru/widgets.dart'; -import '../../models/family_name.dart'; import '../../models/test_execution.dart'; import '../../providers/review_test_execution.dart'; import '../spacing.dart'; @@ -13,12 +12,10 @@ class TestExecutionPopOver extends ConsumerStatefulWidget { super.key, required this.testExecution, required this.artefactId, - required this.family, }); final TestExecution testExecution; final int artefactId; - final FamilyName family; @override TestExecutionPopOverState createState() => TestExecutionPopOverState(); @@ -117,7 +114,6 @@ class TestExecutionPopOverState extends ConsumerState { widget.testExecution.id, reviewCommentController.text, reviewDecisions, - widget.family, widget.artefactId, ); Navigator.pop(context); diff --git a/frontend/lib/ui/artefact_page/test_execution_review.dart b/frontend/lib/ui/artefact_page/test_execution_review.dart index e578bed8..ad039caf 100644 --- a/frontend/lib/ui/artefact_page/test_execution_review.dart +++ b/frontend/lib/ui/artefact_page/test_execution_review.dart @@ -37,7 +37,6 @@ class TestExecutionReviewButton extends StatelessWidget { @override Widget build(BuildContext context) { - final family = AppRoutes.familyFromUri(AppRoutes.uriFromContext(context)); final artefactId = AppRoutes.artefactIdFromUri(AppRoutes.uriFromContext(context)); return GestureDetector( @@ -47,7 +46,6 @@ class TestExecutionReviewButton extends StatelessWidget { bodyBuilder: (context) => TestExecutionPopOver( testExecution: testExecution, artefactId: artefactId, - family: family, ), direction: PopoverDirection.bottom, width: 500,