mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-11 10:29:39 +00:00
Service migrations
This commit is contained in:
parent
d6d7a0dcb6
commit
10891881ae
|
@ -11,8 +11,11 @@ class ServerJobsState extends ServerInstallationDependendState {
|
|||
late final List<ServerJob> _serverJobList;
|
||||
final String? migrationJobUid;
|
||||
|
||||
List<ServerJob> get serverJobList =>
|
||||
_serverJobList.where((final ServerJob job) => !job.isHidden).toList();
|
||||
List<ServerJob> get serverJobList {
|
||||
final List<ServerJob> list = _serverJobList;
|
||||
list.sort((final a, final b) => b.createdAt.compareTo(a.createdAt));
|
||||
return list;
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [migrationJobUid, ..._serverJobList];
|
||||
|
|
|
@ -19,6 +19,7 @@ class ServicesCubit extends ServerInstallationDependendCubit<ServicesState> {
|
|||
emit(
|
||||
ServicesState(
|
||||
services: services,
|
||||
lockedServices: const [],
|
||||
),
|
||||
);
|
||||
timer = Timer(const Duration(seconds: 10), () => reload(useTimer: true));
|
||||
|
@ -28,7 +29,7 @@ class ServicesCubit extends ServerInstallationDependendCubit<ServicesState> {
|
|||
Future<void> reload({final bool useTimer = false}) async {
|
||||
final List<Service> services = await api.getAllServices();
|
||||
emit(
|
||||
ServicesState(
|
||||
state.copyWith(
|
||||
services: services,
|
||||
),
|
||||
);
|
||||
|
@ -38,7 +39,26 @@ class ServicesCubit extends ServerInstallationDependendCubit<ServicesState> {
|
|||
}
|
||||
|
||||
Future<void> restart(final String serviceId) async {
|
||||
emit(state.copyWith(lockedServices: [...state.lockedServices, serviceId]));
|
||||
await api.restartService(serviceId);
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
reload();
|
||||
await Future.delayed(const Duration(seconds: 10));
|
||||
emit(
|
||||
state.copyWith(
|
||||
lockedServices: state.lockedServices
|
||||
.where((final element) => element != serviceId)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
reload();
|
||||
}
|
||||
|
||||
Future<void> moveService(
|
||||
final String serviceId,
|
||||
final String destination,
|
||||
) async {
|
||||
await api.moveService(serviceId, destination);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -3,11 +3,18 @@ part of 'services_cubit.dart';
|
|||
class ServicesState extends ServerInstallationDependendState {
|
||||
const ServicesState({
|
||||
required this.services,
|
||||
required this.lockedServices,
|
||||
});
|
||||
|
||||
const ServicesState.empty() : this(services: const []);
|
||||
const ServicesState.empty()
|
||||
: this(services: const [], lockedServices: const []);
|
||||
|
||||
final List<Service> services;
|
||||
final List<String> lockedServices;
|
||||
|
||||
bool isServiceLocked(final String serviceId) =>
|
||||
lockedServices.contains(serviceId);
|
||||
|
||||
bool get isPasswordManagerEnable => services
|
||||
.firstWhere(
|
||||
(final service) => service.id == 'bitwarden',
|
||||
|
@ -53,6 +60,7 @@ class ServicesState extends ServerInstallationDependendState {
|
|||
@override
|
||||
List<Object> get props => [
|
||||
services,
|
||||
lockedServices,
|
||||
];
|
||||
|
||||
bool isEnableByType(final ServiceTypes type) {
|
||||
|
@ -71,4 +79,13 @@ class ServicesState extends ServerInstallationDependendState {
|
|||
throw Exception('wrong state');
|
||||
}
|
||||
}
|
||||
|
||||
ServicesState copyWith({
|
||||
final List<Service>? services,
|
||||
final List<String>? lockedServices,
|
||||
}) =>
|
||||
ServicesState(
|
||||
services: services ?? this.services,
|
||||
lockedServices: lockedServices ?? this.lockedServices,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -126,13 +126,14 @@ class JobsContent extends StatelessWidget {
|
|||
const SizedBox(height: 8),
|
||||
const Divider(height: 0),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'jobs.server_jobs'.tr(),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
if (serverJobs.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'jobs.server_jobs'.tr(),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
...serverJobs.map(
|
||||
(final job) => Dismissible(
|
||||
key: ValueKey(job.uid),
|
||||
|
|
|
@ -10,7 +10,7 @@ import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
|
|||
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
|
||||
import 'package:selfprivacy/ui/pages/devices/devices.dart';
|
||||
import 'package:selfprivacy/ui/pages/recovery_key/recovery_key.dart';
|
||||
import 'package:selfprivacy/ui/pages/server_storage/binds_migration/data_to_binds_migration.dart';
|
||||
import 'package:selfprivacy/ui/pages/server_storage/binds_migration/services_migration.dart';
|
||||
import 'package:selfprivacy/ui/pages/setup/initializing.dart';
|
||||
import 'package:selfprivacy/ui/pages/onboarding/onboarding.dart';
|
||||
import 'package:selfprivacy/ui/pages/root_route.dart';
|
||||
|
@ -50,7 +50,7 @@ class MorePage extends StatelessWidget {
|
|||
_MoreMenuItem(
|
||||
title: 'providers.storage.start_migration_button'.tr(),
|
||||
iconData: Icons.drive_file_move_outline,
|
||||
goTo: DataToBindsMigrationPage(
|
||||
goTo: ServicesMigrationPage(
|
||||
diskStatus: context
|
||||
.watch<ApiServerVolumeCubit>()
|
||||
.state
|
||||
|
@ -68,6 +68,7 @@ class MorePage extends StatelessWidget {
|
|||
service.id == 'nextcloud',
|
||||
)
|
||||
.toList(),
|
||||
isMigration: true,
|
||||
),
|
||||
subtitle: 'not_ready_card.in_menu'.tr(),
|
||||
accent: true,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/disk_size.dart';
|
||||
import 'package:selfprivacy/logic/models/service.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
|
||||
|
@ -15,22 +16,23 @@ import 'package:selfprivacy/ui/helpers/modals.dart';
|
|||
import 'package:selfprivacy/ui/pages/root_route.dart';
|
||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||
|
||||
class DataToBindsMigrationPage extends StatefulWidget {
|
||||
const DataToBindsMigrationPage({
|
||||
class ServicesMigrationPage extends StatefulWidget {
|
||||
const ServicesMigrationPage({
|
||||
required this.services,
|
||||
required this.diskStatus,
|
||||
required this.isMigration,
|
||||
final super.key,
|
||||
});
|
||||
|
||||
final DiskStatus diskStatus;
|
||||
final List<Service> services;
|
||||
final bool isMigration;
|
||||
|
||||
@override
|
||||
State<DataToBindsMigrationPage> createState() =>
|
||||
_DataToBindsMigrationPageState();
|
||||
State<ServicesMigrationPage> createState() => _ServicesMigrationPageState();
|
||||
}
|
||||
|
||||
class _DataToBindsMigrationPageState extends State<DataToBindsMigrationPage> {
|
||||
class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
|
||||
/// Service id to target migration disk name
|
||||
final Map<String, String> serviceToDisk = {};
|
||||
|
||||
|
@ -164,7 +166,20 @@ class _DataToBindsMigrationPageState extends State<DataToBindsMigrationPage> {
|
|||
FilledButton(
|
||||
title: 'providers.storage.start_migration_button'.tr(),
|
||||
onPressed: () {
|
||||
context.read<ServerJobsCubit>().migrateToBinds(serviceToDisk);
|
||||
if (widget.isMigration) {
|
||||
context.read<ServerJobsCubit>().migrateToBinds(
|
||||
serviceToDisk,
|
||||
);
|
||||
} else {
|
||||
for (final service in widget.services) {
|
||||
if (serviceToDisk[service.id] != null) {
|
||||
context.read<ServicesCubit>().moveService(
|
||||
service.id,
|
||||
serviceToDisk[service.id]!,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
materialRoute(const RootPage()),
|
||||
(final predicate) => false,
|
|
@ -9,6 +9,8 @@ import 'package:selfprivacy/logic/models/job.dart';
|
|||
import 'package:selfprivacy/logic/models/service.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_cards/filled_card.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
|
||||
import 'package:selfprivacy/ui/pages/server_storage/binds_migration/services_migration.dart';
|
||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class ServicePage extends StatefulWidget {
|
||||
|
@ -40,6 +42,9 @@ class _ServicePageState extends State<ServicePage> {
|
|||
final bool serviceDisabled = service.status == ServiceStatus.inactive ||
|
||||
service.status == ServiceStatus.off;
|
||||
|
||||
final bool serviceLocked =
|
||||
context.watch<ServicesCubit>().state.isServiceLocked(service.id);
|
||||
|
||||
return BrandHeroScreen(
|
||||
hasBackButton: true,
|
||||
children: [
|
||||
|
@ -90,6 +95,7 @@ class _ServicePageState extends State<ServicePage> {
|
|||
'services.service_page.restart'.tr(),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
enabled: !serviceDisabled && !serviceLocked,
|
||||
),
|
||||
ListTile(
|
||||
iconColor: Theme.of(context).colorScheme.onBackground,
|
||||
|
@ -108,11 +114,22 @@ class _ServicePageState extends State<ServicePage> {
|
|||
: 'services.service_page.disable'.tr(),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
enabled: !serviceLocked,
|
||||
),
|
||||
if (service.isMovable)
|
||||
ListTile(
|
||||
iconColor: Theme.of(context).colorScheme.onBackground,
|
||||
onTap: () => {},
|
||||
// Open page ServicesMigrationPage
|
||||
onTap: () => Navigator.of(context).push(
|
||||
materialRoute(
|
||||
ServicesMigrationPage(
|
||||
services: [service],
|
||||
diskStatus:
|
||||
context.read<ApiServerVolumeCubit>().state.diskStatus,
|
||||
isMigration: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
leading: const Icon(Icons.drive_file_move_outlined),
|
||||
title: Text(
|
||||
'services.service_page.move'.tr(),
|
||||
|
@ -131,6 +148,7 @@ class _ServicePageState extends State<ServicePage> {
|
|||
),
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
enabled: !serviceDisabled && !serviceLocked,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue