diff --git a/assets/translations/en.json b/assets/translations/en.json index 9fb5d729..3c849eff 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -202,7 +202,7 @@ "extend_volume_button": "Extend volume", "extending_volume_title": "Extending volume", "extending_volume_description": "Resizing volume will allow you to store more data on your server without extending the server itself. Volume can only be extended: shrinking is not possible.", - "extending_volume_price_info": "Price includes VAT and is estimated from pricing data provided by Hetzner.", + "extending_volume_price_info": "Price includes VAT and is estimated from pricing data provided by Hetzner. Server will be rebooted after resizing.", "extending_volume_error": "Couldn't initialize volume extending.", "size": "Size", "euro": "Euro", @@ -490,7 +490,8 @@ "rebootServer": "Reboot server", "create_ssh_key": "Create SSH key for {}", "delete_ssh_key": "Delete SSH key for {}", - "server_jobs": "Jobs on the server" + "server_jobs": "Jobs on the server", + "resetUserPassword": "Reset password of user" }, "validations": { "required": "Required.", diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 4c92f22c..ce2d6231 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -204,7 +204,7 @@ "extend_volume_button": "Расширить хранилище", "extending_volume_title": "Расширение хранилища", "extending_volume_description": "Изменение размера хранилища позволит вам держать больше данных на вашем сервере без расширения самого сервера. Объем можно только увеличить: уменьшить нельзя.", - "extending_volume_price_info": "Цена включает НДС и рассчитана на основе данных о ценах, предоставленных Hetzner.", + "extending_volume_price_info": "Цена включает НДС и рассчитана на основе данных о ценах, предоставленных Hetzner. Сервер будет перезагружен во время процесса.", "extending_volume_error": "Не удалось начать расширение хранилища.", "size": "Размер", "euro": "Евро", diff --git a/lib/logic/cubit/provider_volumes/provider_volume_cubit.dart b/lib/logic/cubit/provider_volumes/provider_volume_cubit.dart index 65c313b1..6a1c7d16 100644 --- a/lib/logic/cubit/provider_volumes/provider_volume_cubit.dart +++ b/lib/logic/cubit/provider_volumes/provider_volume_cubit.dart @@ -17,6 +17,8 @@ class ApiProviderVolumeCubit VolumeProviderApiFactory? providerApi; + final ServerApi serverApi = ServerApi(); + @override Future load() async { if (serverInstallationCubit.state is ServerInstallationFinished) { @@ -34,23 +36,23 @@ class ApiProviderVolumeCubit providerApi!.getVolumeProvider().getPricePerGb(); Future refresh() async { - emit(const ApiProviderVolumeState([], LoadingStatus.refreshing)); + emit(const ApiProviderVolumeState([], LoadingStatus.refreshing, false)); _refetch(); } Future _refetch() async { if (providerApi == null) { - return emit(const ApiProviderVolumeState([], LoadingStatus.error)); + return emit(const ApiProviderVolumeState([], LoadingStatus.error, false)); } final List volumes = await providerApi!.getVolumeProvider().getVolumes(); if (volumes.isEmpty) { - return emit(const ApiProviderVolumeState([], LoadingStatus.error)); + return emit(const ApiProviderVolumeState([], LoadingStatus.error, false)); } - emit(ApiProviderVolumeState(volumes, LoadingStatus.success)); + emit(ApiProviderVolumeState(volumes, LoadingStatus.success, false)); } Future attachVolume(final DiskVolume volume) async { @@ -71,7 +73,12 @@ class ApiProviderVolumeCubit Future resizeVolume( final DiskVolume volume, final int newSizeGb, + final Function() callback, ) async { + getIt().showSnackBar( + 'Starting resize', + ); + emit(state.copyWith(isResizing: true)); final bool resized = await providerApi!.getVolumeProvider().resizeVolume( volume.providerVolume!.id, newSizeGb, @@ -81,13 +88,29 @@ class ApiProviderVolumeCubit getIt().showSnackBar( 'providers.storage.extending_volume_error'.tr(), ); + emit(state.copyWith(isResizing: false)); return false; } + getIt().showSnackBar( + 'Hetzner resized, waiting 10 seconds', + ); await Future.delayed(const Duration(seconds: 10)); await ServerApi().resizeVolume(volume.name); - refresh(); + getIt().showSnackBar( + 'Server api resized, waiting 20 seconds', + ); + + await Future.delayed(const Duration(seconds: 20)); + getIt().showSnackBar( + 'Restarting server', + ); + + await refresh(); + emit(state.copyWith(isResizing: false)); + await callback(); + await serverApi.reboot(); return true; } diff --git a/lib/logic/cubit/provider_volumes/provider_volume_state.dart b/lib/logic/cubit/provider_volumes/provider_volume_state.dart index 16a3f177..406eaaad 100644 --- a/lib/logic/cubit/provider_volumes/provider_volume_state.dart +++ b/lib/logic/cubit/provider_volumes/provider_volume_state.dart @@ -1,22 +1,25 @@ part of 'provider_volume_cubit.dart'; class ApiProviderVolumeState extends ServerInstallationDependendState { - const ApiProviderVolumeState(this._volumes, this.status); + const ApiProviderVolumeState(this._volumes, this.status, this.isResizing); const ApiProviderVolumeState.initial() - : this(const [], LoadingStatus.uninitialized); + : this(const [], LoadingStatus.uninitialized, false); final List _volumes; final LoadingStatus status; + final bool isResizing; List get volumes => _volumes; ApiProviderVolumeState copyWith({ final List? volumes, final LoadingStatus? status, + final bool? isResizing, }) => ApiProviderVolumeState( volumes ?? _volumes, status ?? this.status, + isResizing ?? this.isResizing, ); @override diff --git a/lib/logic/cubit/server_volumes/server_volume_cubit.dart b/lib/logic/cubit/server_volumes/server_volume_cubit.dart index ca6dbb6e..e48a809e 100644 --- a/lib/logic/cubit/server_volumes/server_volume_cubit.dart +++ b/lib/logic/cubit/server_volumes/server_volume_cubit.dart @@ -24,7 +24,7 @@ class ApiServerVolumeCubit @override Future load() async { if (serverInstallationCubit.state is ServerInstallationFinished) { - _refetch(); + reload(); } } @@ -43,7 +43,7 @@ class ApiServerVolumeCubit return; } - Future _refetch() async { + Future reload() async { final volumes = await serverApi.getServerDiskVolumes(); final usesBinds = await serverApi.isUsingBinds(); var status = LoadingStatus.error; diff --git a/lib/ui/components/jobs_content/server_job_card.dart b/lib/ui/components/jobs_content/server_job_card.dart index 1dadb687..46e21166 100644 --- a/lib/ui/components/jobs_content/server_job_card.dart +++ b/lib/ui/components/jobs_content/server_job_card.dart @@ -46,21 +46,23 @@ class ServerJobCard extends StatelessWidget { children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - serverJob.name, - style: Theme.of(context).textTheme.bodyMedium, - ), - Text( - serverJob.description, - style: Theme.of(context).textTheme.bodySmall, - ), - ], + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + serverJob.name, + style: Theme.of(context).textTheme.bodyMedium, + ), + Text( + serverJob.description, + style: Theme.of(context).textTheme.bodySmall, + ), + ], + ), ), - const Spacer(), Icon( icon, color: color, diff --git a/lib/ui/pages/server_storage/binds_migration/data_to_binds_migration.dart b/lib/ui/pages/server_storage/binds_migration/data_to_binds_migration.dart index a88b70cb..c984dd5b 100644 --- a/lib/ui/pages/server_storage/binds_migration/data_to_binds_migration.dart +++ b/lib/ui/pages/server_storage/binds_migration/data_to_binds_migration.dart @@ -3,13 +3,16 @@ import 'package:flutter/material.dart'; import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_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'; import 'package:selfprivacy/ui/components/brand_button/filled_button.dart'; import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; import 'package:selfprivacy/ui/components/info_box/info_box.dart'; import 'package:selfprivacy/logic/models/disk_status.dart'; +import 'package:selfprivacy/ui/components/jobs_content/jobs_content.dart'; import 'package:selfprivacy/ui/components/storage_list_items/server_storage_list_item.dart'; import 'package:selfprivacy/ui/components/storage_list_items/service_migration_list_item.dart'; -import 'package:selfprivacy/ui/pages/server_storage/binds_migration/migration_process_page.dart'; +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 { @@ -162,8 +165,17 @@ class _DataToBindsMigrationPageState extends State { title: 'providers.storage.start_migration_button'.tr(), onPressed: () { context.read().migrateToBinds(serviceToDisk); - Navigator.of(context).push( - materialRoute(const MigrationProcessPage()), + Navigator.of(context).pushAndRemoveUntil( + materialRoute(const RootPage()), + (final predicate) => false, + ); + showBrandBottomSheet( + context: context, + builder: (final BuildContext context) => + const BrandBottomSheet( + isExpended: true, + child: JobsContent(), + ), ); }, ), diff --git a/lib/ui/pages/server_storage/extending_volume.dart b/lib/ui/pages/server_storage/extending_volume.dart index 38aed993..1c8980e2 100644 --- a/lib/ui/pages/server_storage/extending_volume.dart +++ b/lib/ui/pages/server_storage/extending_volume.dart @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart'; import 'package:selfprivacy/logic/cubit/provider_volumes/provider_volume_cubit.dart'; +import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart'; import 'package:selfprivacy/logic/models/disk_size.dart'; import 'package:selfprivacy/ui/components/brand_button/filled_button.dart'; import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart'; @@ -26,7 +27,7 @@ class ExtendingVolumePage extends StatefulWidget { class _ExtendingVolumePageState extends State { @override void initState() { - minSize = widget.diskVolumeToResize.sizeTotal + DiskSize.fromGibibyte(2); + minSize = widget.diskVolumeToResize.sizeTotal + DiskSize.fromGibibyte(3); _currentSliderGbValue = minSize.gibibyte; super.initState(); } @@ -73,11 +74,14 @@ class _ExtendingVolumePageState extends State { (_euroPerGb * double.parse(_sizeController.text)) .toStringAsFixed(2); minSize = - widget.diskVolumeToResize.sizeTotal + DiskSize.fromGibibyte(2); + widget.diskVolumeToResize.sizeTotal + DiskSize.fromGibibyte(3); if (_currentSliderGbValue < 0) { _currentSliderGbValue = minSize.gibibyte; } + final isAlreadyResizing = + context.watch().state.isResizing; + return BrandHeroScreen( hasBackButton: true, heroTitle: 'providers.storage.extending_volume_title'.tr(), @@ -143,13 +147,14 @@ class _ExtendingVolumePageState extends State { context.read().resizeVolume( widget.diskVolumeToResize, _currentSliderGbValue.round(), + context.read().reload, ); Navigator.of(context).pushAndRemoveUntil( materialRoute(const RootPage()), (final predicate) => false, ); }, - disabled: _isError, + disabled: _isError || isAlreadyResizing, ), const SizedBox(height: 16), const Divider(