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( Future<GenericResult<String?>> migrateToBinds(
final Map<String, String> serviceToDisk, final Map<String, String> serviceToDisk,
final String fallbackDrive,
) async { ) async {
GenericResult<String?>? mutation; GenericResult<String?>? mutation;
try { try {
final GraphQLClient client = await getClient(); final GraphQLClient client = await getClient();
final input = Input$MigrateToBindsInput( final input = Input$MigrateToBindsInput(
bitwardenBlockDevice: serviceToDisk['bitwarden']!, bitwardenBlockDevice: serviceToDisk['bitwarden'] ?? fallbackDrive,
emailBlockDevice: serviceToDisk['mailserver']!, emailBlockDevice: serviceToDisk['email'] ?? fallbackDrive,
giteaBlockDevice: serviceToDisk['gitea']!, giteaBlockDevice: serviceToDisk['gitea'] ?? fallbackDrive,
nextcloudBlockDevice: serviceToDisk['nextcloud']!, nextcloudBlockDevice: serviceToDisk['nextcloud'] ?? fallbackDrive,
pleromaBlockDevice: serviceToDisk['pleroma']!, pleromaBlockDevice: serviceToDisk['pleroma'] ?? fallbackDrive,
); );
final variables = Variables$Mutation$MigrateToBinds(input: input); final variables = Variables$Mutation$MigrateToBinds(input: input);
final migrateMutation = final migrateMutation =

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:bloc_concurrency/bloc_concurrency.dart'; import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/models/json/server_job.dart'; import 'package:selfprivacy/logic/models/json/server_job.dart';
@ -68,6 +69,25 @@ class ServerJobsBloc extends Bloc<ServerJobsEvent, ServerJobsState> {
await getIt<ApiConnectionRepository>().removeAllFinishedServerJobs(); 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 @override
void onChange(final Change<ServerJobsState> change) { void onChange(final Change<ServerJobsState> change) {
super.onChange(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:flutter/material.dart';
import 'package:package_info/package_info.dart'; import 'package:package_info/package_info.dart';
import 'package:selfprivacy/config/get_it_config.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/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/utils/breakpoints.dart'; import 'package:selfprivacy/utils/breakpoints.dart';
import 'package:selfprivacy/utils/platform_adapter.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 { class LinkListTile extends StatelessWidget {
const LinkListTile({ const LinkListTile({
required this.title, required this.title,

View File

@ -3,8 +3,12 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/tls_options.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/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/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/router/router.dart';
@RoutePage() @RoutePage()
class DeveloperSettingsPage extends StatefulWidget { class DeveloperSettingsPage extends StatefulWidget {
@ -23,15 +27,7 @@ class _DeveloperSettingsPageState extends State<DeveloperSettingsPage> {
heroTitle: 'developer_settings.title'.tr(), heroTitle: 'developer_settings.title'.tr(),
heroSubtitle: 'developer_settings.subtitle'.tr(), heroSubtitle: 'developer_settings.subtitle'.tr(),
children: [ children: [
Padding( SectionTitle(title: 'developer_settings.server_setup'.tr()),
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,
),
),
),
SwitchListTile( SwitchListTile(
title: Text('developer_settings.use_staging_acme'.tr()), title: Text('developer_settings.use_staging_acme'.tr()),
subtitle: subtitle:
@ -59,15 +55,7 @@ class _DeveloperSettingsPageState extends State<DeveloperSettingsPage> {
() => TlsOptions.allowCustomSshKeyDuringSetup = value, () => TlsOptions.allowCustomSshKeyDuringSetup = value,
), ),
), ),
Padding( SectionTitle(title: 'developer_settings.routing'.tr()),
padding: const EdgeInsets.all(16),
child: Text(
'developer_settings.routing'.tr(),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
),
ListTile( ListTile(
title: Text('developer_settings.reset_onboarding'.tr()), title: Text('developer_settings.reset_onboarding'.tr()),
subtitle: subtitle:
@ -78,15 +66,32 @@ class _DeveloperSettingsPageState extends State<DeveloperSettingsPage> {
.read<AppSettingsCubit>() .read<AppSettingsCubit>()
.turnOffOnboarding(isOnboardingShowing: true), .turnOffOnboarding(isOnboardingShowing: true),
), ),
Padding( ListTile(
padding: const EdgeInsets.all(16), title: Text('storage.start_migration_button'.tr()),
child: Text( subtitle: Text('storage.data_migration_notice'.tr()),
'developer_settings.cubit_statuses'.tr(), enabled:
style: Theme.of(context).textTheme.labelLarge!.copyWith( !context.watch<AppSettingsCubit>().state.isOnboardingShowing,
color: Theme.of(context).colorScheme.secondary, 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( ListTile(
title: const Text('ApiConnectionRepository status'), title: const Text('ApiConnectionRepository status'),
subtitle: Text( subtitle: Text(

View File

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

View File

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

View File

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