Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test execution search and query params #141

Merged
merged 11 commits into from
Mar 21, 2024
6 changes: 3 additions & 3 deletions frontend/integration_test/find_shortcut_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'package:testcase_dashboard/models/artefact.dart';
import 'package:testcase_dashboard/models/family_name.dart';
import 'package:testcase_dashboard/providers/api.dart';
import 'package:testcase_dashboard/repositories/api_repository.dart';
import 'package:testcase_dashboard/ui/dashboard/artefact_search_bar.dart';
import 'package:testcase_dashboard/ui/page_filters/page_search_bar.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
Expand All @@ -31,8 +31,8 @@ void main() {

await tester.pumpAndSettle();

expect(find.byKey(artefactSearchBarKey), findsOneWidget);
expect(artefactSearchBarKey.currentState?.focusNode.hasFocus, isTrue);
expect(find.byKey(pageSearchBarKey), findsOneWidget);
expect(pageSearchBarKey.currentState?.focusNode.hasFocus, isTrue);
});
}

Expand Down
35 changes: 0 additions & 35 deletions frontend/lib/providers/artefact_filters.dart

This file was deleted.

23 changes: 20 additions & 3 deletions frontend/lib/providers/filtered_test_execution_ids.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,42 @@
import 'package:dartx/dartx.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../models/filters.dart';
import '../models/test_execution.dart';
import 'artefact_builds.dart';
import 'test_execution_filters.dart';

part 'filtered_test_execution_ids.g.dart';

@riverpod
Set<int> filteredTestExecutionIds(
FilteredTestExecutionIdsRef ref,
int artefactId,
Uri pageUri,
) {
final builds = ref.watch(artefactBuildsProvider(artefactId)).requireValue;
final testExecutions = [
for (final build in builds)
for (final testExecution in build.testExecutions) testExecution,
];
final filters = ref.watch(testExecutionFiltersProvider(artefactId));
final filters =
emptyTestExecutionFilters.copyWithQueryParams(pageUri.queryParametersAll);
final searchValue = pageUri.queryParameters['q'] ?? '';
nadzyah marked this conversation as resolved.
Show resolved Hide resolved

return testExecutions
.filter((testExecution) => filters.doesObjectPassFilters(testExecution))
.filter(
(testExecution) =>
_testExecutionPassesSearch(testExecution, searchValue) &&
filters.doesObjectPassFilters(testExecution),
)
.map((te) => te.id)
.toSet();
}

bool _testExecutionPassesSearch(
TestExecution testExecution,
String searchValue,
) {
return testExecution.environment.name
.toLowerCase()
.contains(searchValue.toLowerCase());
}
54 changes: 54 additions & 0 deletions frontend/lib/providers/page_filters.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../models/filters.dart';
import '../routing.dart';
import 'artefact_builds.dart';
import 'family_artefacts.dart';

part 'page_filters.g.dart';

@riverpod
class PageFilters extends _$PageFilters {
@override
Filters build(Uri pageUri) {
if (AppRoutes.isDashboardPage(pageUri)) {
final family = AppRoutes.familyFromUri(pageUri);
final artefacts = ref
.watch(familyArtefactsProvider(family))
.requireValue
.values
.toList();

return emptyArtefactFilters
.copyWithOptionsExtracted(artefacts)
.copyWithQueryParams(pageUri.queryParametersAll);
}

if (AppRoutes.isArtefactPage(pageUri)) {
final artefactId = AppRoutes.artefactIdFromUri(pageUri);
final builds = ref.watch(artefactBuildsProvider(artefactId)).requireValue;
final testExecutions = [
for (final build in builds)
for (final testExecution in build.testExecutions) testExecution,
];

return emptyTestExecutionFilters
.copyWithOptionsExtracted(testExecutions)
.copyWithQueryParams(pageUri.queryParametersAll);
}

throw Exception('Called pageFiltersProvider in unknown page $pageUri');
}

void handleFilterOptionChange(
String filterName,
String optionName,
bool optionValue,
) {
state = state.copyWithFilterOptionValue(
filterName,
optionName,
optionValue,
);
}
}
4 changes: 2 additions & 2 deletions frontend/lib/providers/search_value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ part 'search_value.g.dart';
@riverpod
class SearchValue extends _$SearchValue {
@override
String build() {
return '';
String build(String? initialQuery) {
return initialQuery ?? '';
}

void onChanged(String newValue) {
Expand Down
33 changes: 0 additions & 33 deletions frontend/lib/providers/test_execution_filters.dart

This file was deleted.

37 changes: 16 additions & 21 deletions frontend/lib/routing.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:dartx/dartx.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

Expand Down Expand Up @@ -54,34 +55,28 @@ class AppRoutes {
static const snaps = '/snaps';
static const debs = '/debs';

static FamilyName familyFromContext(BuildContext context) {
return familyFromUri(GoRouterState.of(context).uri);
}
static Uri uriFromContext(BuildContext context) =>
GoRouterState.of(context).uri;

static FamilyName familyFromUri(Uri uri) {
final path = uri.path;

if (path.startsWith(snaps)) {
return FamilyName.snap;
} else if (path.startsWith(debs)) {
return FamilyName.deb;
} else {
throw Exception('Unknown route: $path');
}
if (path.startsWith(snaps)) return FamilyName.snap;
if (path.startsWith(debs)) return FamilyName.deb;

throw Exception('Unknown route: $path');
}

static int artefactIdFromContext(BuildContext context) {
final Map<String, String> pathParameters =
GoRouterState.of(context).pathParameters;
static int artefactIdFromUri(Uri uri) {
if (isArtefactPage(uri)) return uri.pathSegments[1].toInt();

if (!pathParameters.containsKey('artefactId')) {
throw Exception('Artefact ID not found in path');
}
return int.parse(pathParameters['artefactId']!);
throw Exception('$uri isn\'t an artefact page');
}

static bool isAtDashboardPage(BuildContext context) {
final route = GoRouterState.of(context).fullPath!;
return {snaps, debs}.contains(route);
}
static bool isDashboardPage(Uri uri) => {snaps, debs}.contains(uri.path);

static bool isArtefactPage(Uri uri) =>
(uri.path.contains(AppRoutes.snaps) ||
uri.path.contains(AppRoutes.debs)) &&
uri.pathSegments.length == 2;
}
4 changes: 3 additions & 1 deletion frontend/lib/ui/artefact_page/artefact_build_expandable.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intersperse/intersperse.dart';

import '../../models/artefact_build.dart';
Expand All @@ -19,10 +20,11 @@ class ArtefactBuildExpandable extends ConsumerWidget {

@override
Widget build(BuildContext context, WidgetRef ref) {
final pageUri = GoRouterState.of(context).uri;
final revisionText =
artefactBuild.revision == null ? '' : ' (${artefactBuild.revision})';
final filteredTestExecutionIds =
ref.watch(filteredTestExecutionIdsProvider(artefactId));
ref.watch(filteredTestExecutionIdsProvider(artefactId, pageUri));
final filteredTestExecutions = [
for (final te in artefactBuild.testExecutions)
if (filteredTestExecutionIds.contains(te.id)) te,
Expand Down
2 changes: 1 addition & 1 deletion frontend/lib/ui/artefact_page/artefact_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class ArtefactPage extends ConsumerWidget {

@override
Widget build(BuildContext context, WidgetRef ref) {
final family = AppRoutes.familyFromContext(context);
final family = AppRoutes.familyFromUri(AppRoutes.uriFromContext(context));
final artefacts = ref.watch(familyArtefactsProvider(family));
return Padding(
padding: const EdgeInsets.only(
Expand Down
4 changes: 2 additions & 2 deletions frontend/lib/ui/artefact_page/artefact_page_body.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import 'package:yaru_widgets/yaru_widgets.dart';

import '../../models/artefact.dart';
import '../../providers/artefact_builds.dart';
import '../page_filters/page_filters.dart';
import '../spacing.dart';
import 'artefact_build_expandable.dart';
import 'test_executions_side_filters.dart';

class ArtefactPageBody extends ConsumerWidget {
const ArtefactPageBody({super.key, required this.artefact});
Expand All @@ -21,7 +21,7 @@ class ArtefactPageBody extends ConsumerWidget {
data: (artefactBuilds) => Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TestExecutionsSideFilters(artefactId: artefact.id),
const PageFiltersView(searchHint: 'Search by environment name'),
const SizedBox(width: Spacing.level5),
Expanded(
child: Column(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class _StagesRow extends ConsumerWidget {

@override
Widget build(BuildContext context, WidgetRef ref) {
final family = AppRoutes.familyFromContext(context);
final family = AppRoutes.familyFromUri(AppRoutes.uriFromContext(context));
final stages = familyStages(family);

final stageNamesWidgets = <Widget>[];
Expand Down
2 changes: 1 addition & 1 deletion frontend/lib/ui/artefact_page/artefact_signoff_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ArtefactSignoffButton extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final fontStyle = Theme.of(context).textTheme.titleMedium;
final family = AppRoutes.familyFromContext(context);
final family = AppRoutes.familyFromUri(AppRoutes.uriFromContext(context));

return YaruPopupMenuButton(
child: Text(
Expand Down
3 changes: 2 additions & 1 deletion frontend/lib/ui/artefact_page/test_execution_review.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ class TestExecutionReviewButton extends StatelessWidget {

@override
Widget build(BuildContext context) {
final artefactId = AppRoutes.artefactIdFromContext(context);
final artefactId =
AppRoutes.artefactIdFromUri(AppRoutes.uriFromContext(context));
return GestureDetector(
onTap: () {
showPopover(
Expand Down
23 changes: 0 additions & 23 deletions frontend/lib/ui/artefact_page/test_executions_side_filters.dart

This file was deleted.

Loading
Loading