Merge pull request 'fix: Return the binds migration interface' (#467) from inex/binds-migration into master
continuous-integration/drone/push Build is passing Details

Reviewed-on: #467
pull/469/head
Inex Code 2024-02-23 18:51:52 +02:00
commit 212c60c613
8 changed files with 103 additions and 60 deletions

View File

@ -60,17 +60,18 @@ mixin VolumeApi on GraphQLApiMap {
Future<GenericResult<String?>> migrateToBinds(
final Map<String, String> serviceToDisk,
final String fallbackDrive,
) async {
GenericResult<String?>? mutation;
try {
final GraphQLClient client = await getClient();
final input = Input$MigrateToBindsInput(
bitwardenBlockDevice: serviceToDisk['bitwarden']!,
emailBlockDevice: serviceToDisk['mailserver']!,
giteaBlockDevice: serviceToDisk['gitea']!,
nextcloudBlockDevice: serviceToDisk['nextcloud']!,
pleromaBlockDevice: serviceToDisk['pleroma']!,
bitwardenBlockDevice: serviceToDisk['bitwarden'] ?? fallbackDrive,
emailBlockDevice: serviceToDisk['email'] ?? fallbackDrive,
giteaBlockDevice: serviceToDisk['gitea'] ?? fallbackDrive,
nextcloudBlockDevice: serviceToDisk['nextcloud'] ?? fallbackDrive,
pleromaBlockDevice: serviceToDisk['pleroma'] ?? fallbackDrive,
);
final variables = Variables$Mutation$MigrateToBinds(input: input);
final migrateMutation =

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/models/json/server_job.dart';
@ -68,6 +69,25 @@ class ServerJobsBloc extends Bloc<ServerJobsEvent, ServerJobsState> {
await getIt<ApiConnectionRepository>().removeAllFinishedServerJobs();
}
Future<void> migrateToBinds(final Map<String, String> serviceToDisk) async {
final fallbackDrive = getIt<ApiConnectionRepository>()
.apiData
.volumes
.data
?.where((final drive) => drive.root)
.first
.name ??
'sda1';
final result = await getIt<ApiConnectionRepository>()
.api
.migrateToBinds(serviceToDisk, fallbackDrive);
if (result.data == null) {
getIt<NavigationService>()
.showSnackBar(result.message!, behavior: SnackBarBehavior.floating);
return;
}
}
@override
void onChange(final Change<ServerJobsState> change) {
super.onChange(change);

View File

@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
class SectionTitle extends StatelessWidget {
const SectionTitle({
required this.title,
super.key,
});
final String title;
@override
Widget build(final BuildContext context) => Padding(
padding: const EdgeInsets.all(16),
child: Text(
title,
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
);
}

View File

@ -5,6 +5,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:package_info/package_info.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/ui/components/list_tiles/section_title.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/utils/breakpoints.dart';
import 'package:selfprivacy/utils/platform_adapter.dart';
@ -220,26 +221,6 @@ class AboutApplicationPage extends StatelessWidget {
}
}
class SectionTitle extends StatelessWidget {
const SectionTitle({
required this.title,
super.key,
});
final String title;
@override
Widget build(final BuildContext context) => Padding(
padding: const EdgeInsets.all(16),
child: Text(
title,
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
);
}
class LinkListTile extends StatelessWidget {
const LinkListTile({
required this.title,

View File

@ -3,8 +3,12 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/tls_options.dart';
import 'package:selfprivacy/logic/bloc/services/services_bloc.dart';
import 'package:selfprivacy/logic/bloc/volumes/volumes_bloc.dart';
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
import 'package:selfprivacy/ui/components/list_tiles/section_title.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/router/router.dart';
@RoutePage()
class DeveloperSettingsPage extends StatefulWidget {
@ -23,15 +27,7 @@ class _DeveloperSettingsPageState extends State<DeveloperSettingsPage> {
heroTitle: 'developer_settings.title'.tr(),
heroSubtitle: 'developer_settings.subtitle'.tr(),
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Text(
'developer_settings.server_setup'.tr(),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
),
SectionTitle(title: 'developer_settings.server_setup'.tr()),
SwitchListTile(
title: Text('developer_settings.use_staging_acme'.tr()),
subtitle:
@ -59,15 +55,7 @@ class _DeveloperSettingsPageState extends State<DeveloperSettingsPage> {
() => TlsOptions.allowCustomSshKeyDuringSetup = value,
),
),
Padding(
padding: const EdgeInsets.all(16),
child: Text(
'developer_settings.routing'.tr(),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
),
SectionTitle(title: 'developer_settings.routing'.tr()),
ListTile(
title: Text('developer_settings.reset_onboarding'.tr()),
subtitle:
@ -78,15 +66,32 @@ class _DeveloperSettingsPageState extends State<DeveloperSettingsPage> {
.read<AppSettingsCubit>()
.turnOffOnboarding(isOnboardingShowing: true),
),
Padding(
padding: const EdgeInsets.all(16),
child: Text(
'developer_settings.cubit_statuses'.tr(),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
ListTile(
title: Text('storage.start_migration_button'.tr()),
subtitle: Text('storage.data_migration_notice'.tr()),
enabled:
!context.watch<AppSettingsCubit>().state.isOnboardingShowing,
onTap: () => context.pushRoute(
ServicesMigrationRoute(
diskStatus: context.read<VolumesBloc>().state.diskStatus,
services: context
.read<ServicesBloc>()
.state
.services
.where(
(final service) =>
service.id == 'bitwarden' ||
service.id == 'gitea' ||
service.id == 'pleroma' ||
service.id == 'email' ||
service.id == 'nextcloud',
)
.toList(),
isMigration: true,
),
),
),
SectionTitle(title: 'developer_settings.cubit_statuses'.tr()),
ListTile(
title: const Text('ApiConnectionRepository status'),
subtitle: Text(

View File

@ -18,11 +18,13 @@ class ServicesMigrationPage extends StatefulWidget {
const ServicesMigrationPage({
required this.services,
required this.diskStatus,
required this.isMigration,
super.key,
});
final DiskStatus diskStatus;
final List<Service> services;
final bool isMigration;
@override
State<ServicesMigrationPage> createState() => _ServicesMigrationPageState();
@ -169,18 +171,24 @@ class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
),
),
const SizedBox(height: 16),
if (isVolumePicked)
if (widget.isMigration || (!widget.isMigration && isVolumePicked))
BrandButton.filled(
child: Text('storage.start_migration_button'.tr()),
onPressed: () {
for (final service in widget.services) {
if (serviceToDisk[service.id] != null) {
context.read<ServicesBloc>().add(
ServiceMove(
service,
serviceToDisk[service.id]!,
),
);
if (widget.isMigration) {
context.read<ServerJobsBloc>().migrateToBinds(
serviceToDisk,
);
} else {
for (final service in widget.services) {
if (serviceToDisk[service.id] != null) {
context.read<ServicesBloc>().add(
ServiceMove(
service,
serviceToDisk[service.id]!,
),
);
}
}
}
context.router.popUntilRoot();

View File

@ -114,6 +114,7 @@ class _ServicePageState extends State<ServicePage> {
ServicesMigrationRoute(
services: [service],
diskStatus: context.read<VolumesBloc>().state.diskStatus,
isMigration: false,
),
),
leading: const Icon(Icons.drive_file_move_outlined),

View File

@ -159,6 +159,7 @@ abstract class _$RootRouter extends RootStackRouter {
child: ServicesMigrationPage(
services: args.services,
diskStatus: args.diskStatus,
isMigration: args.isMigration,
key: args.key,
),
);
@ -575,6 +576,7 @@ class ServicesMigrationRoute extends PageRouteInfo<ServicesMigrationRouteArgs> {
ServicesMigrationRoute({
required List<Service> services,
required DiskStatus diskStatus,
required bool isMigration,
Key? key,
List<PageRouteInfo>? children,
}) : super(
@ -582,6 +584,7 @@ class ServicesMigrationRoute extends PageRouteInfo<ServicesMigrationRouteArgs> {
args: ServicesMigrationRouteArgs(
services: services,
diskStatus: diskStatus,
isMigration: isMigration,
key: key,
),
initialChildren: children,
@ -597,6 +600,7 @@ class ServicesMigrationRouteArgs {
const ServicesMigrationRouteArgs({
required this.services,
required this.diskStatus,
required this.isMigration,
this.key,
});
@ -604,11 +608,13 @@ class ServicesMigrationRouteArgs {
final DiskStatus diskStatus;
final bool isMigration;
final Key? key;
@override
String toString() {
return 'ServicesMigrationRouteArgs{services: $services, diskStatus: $diskStatus, key: $key}';
return 'ServicesMigrationRouteArgs{services: $services, diskStatus: $diskStatus, isMigration: $isMigration, key: $key}';
}
}