mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-02-02 14:16:58 +00:00
fix: Return the binds migration interface
Turns out, there are still servers that didn't perform the binds migration. The can't perform it anymore because email changed the id. I'm getting back the option to perform the binds migration, with some fallback defaults.
This commit is contained in:
parent
490e5f92f3
commit
a9a7b04ad5
|
@ -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 =
|
||||||
|
|
|
@ -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);
|
||||||
|
|
21
lib/ui/components/list_tiles/section_title.dart
Normal file
21
lib/ui/components/list_tiles/section_title.dart
Normal 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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
|
@ -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,
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue