feat(recovery): Implement access recovery routing for server providers

pull/140/head
NaiJi ✨ 2022-11-17 11:14:34 +04:00
parent 0234278c2c
commit 51dc4c67b2
15 changed files with 536 additions and 14 deletions

View File

@ -300,6 +300,7 @@
"checks": "Checks have been completed \n{} out of {}"
},
"recovering": {
"generic_error": "Operation failed, please try again.",
"recovery_main_header": "Connect to an existing server",
"domain_recovery_description": "Enter a server domain you want to get access for:",
"domain_recover_placeholder": "Your domain",
@ -319,9 +320,9 @@
"fallback_select_provider_console": "Access to the server console of my prodiver.",
"authorization_failed": "Couldn't log in with this key",
"fallback_select_provider_console_hint": "For example: Hetzner.",
"hetzner_connected": "Connect to Hetzner",
"hetzner_connected_description": "Communication established. Enter Hetzner token with access to {}:",
"hetzner_connected_placeholder": "Hetzner token",
"server_provider_connected": "Connect to your Server Provider",
"server_provider_connected_description": "Communication established. Enter you token with access to {}:",
"server_provider_connected_placeholder": "Server Provider token",
"confirm_server": "Confirm server",
"confirm_server_description": "Found your server! Confirm it is the right one:",
"confirm_server_accept": "Yes! That's it",

View File

@ -299,6 +299,7 @@
"checks": "Проверок выполнено: \n{} / {}"
},
"recovering": {
"generic_error": "Ошибка проведения операции, попробуйте ещё раз.",
"recovery_main_header": "Подключиться к существующему серверу",
"domain_recovery_description": "Введите домен, по которому вы хотите получить доступ к серверу:",
"domain_recover_placeholder": "Домен",

View File

@ -4,7 +4,7 @@ import 'package:graphql/client.dart' as graphql;
import 'package:json_annotation/json_annotation.dart';
import 'package:selfprivacy/utils/scalars.dart';
import 'schema.graphql.dart';
import 'services.graphql.dart';
import 'server_api.graphql.dart';
part 'disk_volumes.graphql.g.dart';
@JsonSerializable(explicitToJson: true)

View File

@ -173,6 +173,7 @@ input RecoveryKeyLimitsInput {
enum ServerProvider {
HETZNER
DIGITALOCEAN
}
type Service {

View File

@ -693,6 +693,8 @@ enum Enum$DnsProvider {
enum Enum$ServerProvider {
@JsonValue('HETZNER')
HETZNER,
@JsonValue('DIGITALOCEAN')
DIGITALOCEAN,
$unknown
}

View File

@ -64,6 +64,14 @@ mutation RebootSystem {
}
}
query SystemServerProvider {
system {
provider {
provider
}
}
}
query GetApiTokens {
api {
devices {

View File

@ -4,7 +4,6 @@ import 'package:graphql/client.dart' as graphql;
import 'package:json_annotation/json_annotation.dart';
import 'package:selfprivacy/utils/scalars.dart';
import 'schema.graphql.dart';
import 'services.graphql.dart';
part 'server_api.graphql.g.dart';
@JsonSerializable(explicitToJson: true)
@ -3178,6 +3177,425 @@ class _CopyWithStubImpl$Mutation$RebootSystem$rebootSystem<TRes>
_res;
}
@JsonSerializable(explicitToJson: true)
class Query$SystemServerProvider {
Query$SystemServerProvider({required this.system, required this.$__typename});
@override
factory Query$SystemServerProvider.fromJson(Map<String, dynamic> json) =>
_$Query$SystemServerProviderFromJson(json);
final Query$SystemServerProvider$system system;
@JsonKey(name: '__typename')
final String $__typename;
Map<String, dynamic> toJson() => _$Query$SystemServerProviderToJson(this);
int get hashCode {
final l$system = system;
final l$$__typename = $__typename;
return Object.hashAll([l$system, l$$__typename]);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (!(other is Query$SystemServerProvider) ||
runtimeType != other.runtimeType) return false;
final l$system = system;
final lOther$system = other.system;
if (l$system != lOther$system) return false;
final l$$__typename = $__typename;
final lOther$$__typename = other.$__typename;
if (l$$__typename != lOther$$__typename) return false;
return true;
}
}
extension UtilityExtension$Query$SystemServerProvider
on Query$SystemServerProvider {
CopyWith$Query$SystemServerProvider<Query$SystemServerProvider>
get copyWith => CopyWith$Query$SystemServerProvider(this, (i) => i);
}
abstract class CopyWith$Query$SystemServerProvider<TRes> {
factory CopyWith$Query$SystemServerProvider(
Query$SystemServerProvider instance,
TRes Function(Query$SystemServerProvider) then) =
_CopyWithImpl$Query$SystemServerProvider;
factory CopyWith$Query$SystemServerProvider.stub(TRes res) =
_CopyWithStubImpl$Query$SystemServerProvider;
TRes call({Query$SystemServerProvider$system? system, String? $__typename});
CopyWith$Query$SystemServerProvider$system<TRes> get system;
}
class _CopyWithImpl$Query$SystemServerProvider<TRes>
implements CopyWith$Query$SystemServerProvider<TRes> {
_CopyWithImpl$Query$SystemServerProvider(this._instance, this._then);
final Query$SystemServerProvider _instance;
final TRes Function(Query$SystemServerProvider) _then;
static const _undefined = {};
TRes call({Object? system = _undefined, Object? $__typename = _undefined}) =>
_then(Query$SystemServerProvider(
system: system == _undefined || system == null
? _instance.system
: (system as Query$SystemServerProvider$system),
$__typename: $__typename == _undefined || $__typename == null
? _instance.$__typename
: ($__typename as String)));
CopyWith$Query$SystemServerProvider$system<TRes> get system {
final local$system = _instance.system;
return CopyWith$Query$SystemServerProvider$system(
local$system, (e) => call(system: e));
}
}
class _CopyWithStubImpl$Query$SystemServerProvider<TRes>
implements CopyWith$Query$SystemServerProvider<TRes> {
_CopyWithStubImpl$Query$SystemServerProvider(this._res);
TRes _res;
call({Query$SystemServerProvider$system? system, String? $__typename}) =>
_res;
CopyWith$Query$SystemServerProvider$system<TRes> get system =>
CopyWith$Query$SystemServerProvider$system.stub(_res);
}
const documentNodeQuerySystemServerProvider = DocumentNode(definitions: [
OperationDefinitionNode(
type: OperationType.query,
name: NameNode(value: 'SystemServerProvider'),
variableDefinitions: [],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'system'),
alias: null,
arguments: [],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'provider'),
alias: null,
arguments: [],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'provider'),
alias: null,
arguments: [],
directives: [],
selectionSet: null),
FieldNode(
name: NameNode(value: '__typename'),
alias: null,
arguments: [],
directives: [],
selectionSet: null)
])),
FieldNode(
name: NameNode(value: '__typename'),
alias: null,
arguments: [],
directives: [],
selectionSet: null)
])),
FieldNode(
name: NameNode(value: '__typename'),
alias: null,
arguments: [],
directives: [],
selectionSet: null)
])),
]);
Query$SystemServerProvider _parserFn$Query$SystemServerProvider(
Map<String, dynamic> data) =>
Query$SystemServerProvider.fromJson(data);
class Options$Query$SystemServerProvider
extends graphql.QueryOptions<Query$SystemServerProvider> {
Options$Query$SystemServerProvider(
{String? operationName,
graphql.FetchPolicy? fetchPolicy,
graphql.ErrorPolicy? errorPolicy,
graphql.CacheRereadPolicy? cacheRereadPolicy,
Object? optimisticResult,
Duration? pollInterval,
graphql.Context? context})
: super(
operationName: operationName,
fetchPolicy: fetchPolicy,
errorPolicy: errorPolicy,
cacheRereadPolicy: cacheRereadPolicy,
optimisticResult: optimisticResult,
pollInterval: pollInterval,
context: context,
document: documentNodeQuerySystemServerProvider,
parserFn: _parserFn$Query$SystemServerProvider);
}
class WatchOptions$Query$SystemServerProvider
extends graphql.WatchQueryOptions<Query$SystemServerProvider> {
WatchOptions$Query$SystemServerProvider(
{String? operationName,
graphql.FetchPolicy? fetchPolicy,
graphql.ErrorPolicy? errorPolicy,
graphql.CacheRereadPolicy? cacheRereadPolicy,
Object? optimisticResult,
graphql.Context? context,
Duration? pollInterval,
bool? eagerlyFetchResults,
bool carryForwardDataOnException = true,
bool fetchResults = false})
: super(
operationName: operationName,
fetchPolicy: fetchPolicy,
errorPolicy: errorPolicy,
cacheRereadPolicy: cacheRereadPolicy,
optimisticResult: optimisticResult,
context: context,
document: documentNodeQuerySystemServerProvider,
pollInterval: pollInterval,
eagerlyFetchResults: eagerlyFetchResults,
carryForwardDataOnException: carryForwardDataOnException,
fetchResults: fetchResults,
parserFn: _parserFn$Query$SystemServerProvider);
}
class FetchMoreOptions$Query$SystemServerProvider
extends graphql.FetchMoreOptions {
FetchMoreOptions$Query$SystemServerProvider(
{required graphql.UpdateQuery updateQuery})
: super(
updateQuery: updateQuery,
document: documentNodeQuerySystemServerProvider);
}
extension ClientExtension$Query$SystemServerProvider on graphql.GraphQLClient {
Future<graphql.QueryResult<Query$SystemServerProvider>>
query$SystemServerProvider(
[Options$Query$SystemServerProvider? options]) async =>
await this.query(options ?? Options$Query$SystemServerProvider());
graphql.ObservableQuery<Query$SystemServerProvider>
watchQuery$SystemServerProvider(
[WatchOptions$Query$SystemServerProvider? options]) =>
this.watchQuery(options ?? WatchOptions$Query$SystemServerProvider());
void writeQuery$SystemServerProvider(
{required Query$SystemServerProvider data, bool broadcast = true}) =>
this.writeQuery(
graphql.Request(
operation: graphql.Operation(
document: documentNodeQuerySystemServerProvider)),
data: data.toJson(),
broadcast: broadcast);
Query$SystemServerProvider? readQuery$SystemServerProvider(
{bool optimistic = true}) {
final result = this.readQuery(
graphql.Request(
operation: graphql.Operation(
document: documentNodeQuerySystemServerProvider)),
optimistic: optimistic);
return result == null ? null : Query$SystemServerProvider.fromJson(result);
}
}
@JsonSerializable(explicitToJson: true)
class Query$SystemServerProvider$system {
Query$SystemServerProvider$system(
{required this.provider, required this.$__typename});
@override
factory Query$SystemServerProvider$system.fromJson(
Map<String, dynamic> json) =>
_$Query$SystemServerProvider$systemFromJson(json);
final Query$SystemServerProvider$system$provider provider;
@JsonKey(name: '__typename')
final String $__typename;
Map<String, dynamic> toJson() =>
_$Query$SystemServerProvider$systemToJson(this);
int get hashCode {
final l$provider = provider;
final l$$__typename = $__typename;
return Object.hashAll([l$provider, l$$__typename]);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (!(other is Query$SystemServerProvider$system) ||
runtimeType != other.runtimeType) return false;
final l$provider = provider;
final lOther$provider = other.provider;
if (l$provider != lOther$provider) return false;
final l$$__typename = $__typename;
final lOther$$__typename = other.$__typename;
if (l$$__typename != lOther$$__typename) return false;
return true;
}
}
extension UtilityExtension$Query$SystemServerProvider$system
on Query$SystemServerProvider$system {
CopyWith$Query$SystemServerProvider$system<Query$SystemServerProvider$system>
get copyWith =>
CopyWith$Query$SystemServerProvider$system(this, (i) => i);
}
abstract class CopyWith$Query$SystemServerProvider$system<TRes> {
factory CopyWith$Query$SystemServerProvider$system(
Query$SystemServerProvider$system instance,
TRes Function(Query$SystemServerProvider$system) then) =
_CopyWithImpl$Query$SystemServerProvider$system;
factory CopyWith$Query$SystemServerProvider$system.stub(TRes res) =
_CopyWithStubImpl$Query$SystemServerProvider$system;
TRes call(
{Query$SystemServerProvider$system$provider? provider,
String? $__typename});
CopyWith$Query$SystemServerProvider$system$provider<TRes> get provider;
}
class _CopyWithImpl$Query$SystemServerProvider$system<TRes>
implements CopyWith$Query$SystemServerProvider$system<TRes> {
_CopyWithImpl$Query$SystemServerProvider$system(this._instance, this._then);
final Query$SystemServerProvider$system _instance;
final TRes Function(Query$SystemServerProvider$system) _then;
static const _undefined = {};
TRes call(
{Object? provider = _undefined, Object? $__typename = _undefined}) =>
_then(Query$SystemServerProvider$system(
provider: provider == _undefined || provider == null
? _instance.provider
: (provider as Query$SystemServerProvider$system$provider),
$__typename: $__typename == _undefined || $__typename == null
? _instance.$__typename
: ($__typename as String)));
CopyWith$Query$SystemServerProvider$system$provider<TRes> get provider {
final local$provider = _instance.provider;
return CopyWith$Query$SystemServerProvider$system$provider(
local$provider, (e) => call(provider: e));
}
}
class _CopyWithStubImpl$Query$SystemServerProvider$system<TRes>
implements CopyWith$Query$SystemServerProvider$system<TRes> {
_CopyWithStubImpl$Query$SystemServerProvider$system(this._res);
TRes _res;
call(
{Query$SystemServerProvider$system$provider? provider,
String? $__typename}) =>
_res;
CopyWith$Query$SystemServerProvider$system$provider<TRes> get provider =>
CopyWith$Query$SystemServerProvider$system$provider.stub(_res);
}
@JsonSerializable(explicitToJson: true)
class Query$SystemServerProvider$system$provider {
Query$SystemServerProvider$system$provider(
{required this.provider, required this.$__typename});
@override
factory Query$SystemServerProvider$system$provider.fromJson(
Map<String, dynamic> json) =>
_$Query$SystemServerProvider$system$providerFromJson(json);
@JsonKey(unknownEnumValue: Enum$ServerProvider.$unknown)
final Enum$ServerProvider provider;
@JsonKey(name: '__typename')
final String $__typename;
Map<String, dynamic> toJson() =>
_$Query$SystemServerProvider$system$providerToJson(this);
int get hashCode {
final l$provider = provider;
final l$$__typename = $__typename;
return Object.hashAll([l$provider, l$$__typename]);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (!(other is Query$SystemServerProvider$system$provider) ||
runtimeType != other.runtimeType) return false;
final l$provider = provider;
final lOther$provider = other.provider;
if (l$provider != lOther$provider) return false;
final l$$__typename = $__typename;
final lOther$$__typename = other.$__typename;
if (l$$__typename != lOther$$__typename) return false;
return true;
}
}
extension UtilityExtension$Query$SystemServerProvider$system$provider
on Query$SystemServerProvider$system$provider {
CopyWith$Query$SystemServerProvider$system$provider<
Query$SystemServerProvider$system$provider>
get copyWith =>
CopyWith$Query$SystemServerProvider$system$provider(this, (i) => i);
}
abstract class CopyWith$Query$SystemServerProvider$system$provider<TRes> {
factory CopyWith$Query$SystemServerProvider$system$provider(
Query$SystemServerProvider$system$provider instance,
TRes Function(Query$SystemServerProvider$system$provider) then) =
_CopyWithImpl$Query$SystemServerProvider$system$provider;
factory CopyWith$Query$SystemServerProvider$system$provider.stub(TRes res) =
_CopyWithStubImpl$Query$SystemServerProvider$system$provider;
TRes call({Enum$ServerProvider? provider, String? $__typename});
}
class _CopyWithImpl$Query$SystemServerProvider$system$provider<TRes>
implements CopyWith$Query$SystemServerProvider$system$provider<TRes> {
_CopyWithImpl$Query$SystemServerProvider$system$provider(
this._instance, this._then);
final Query$SystemServerProvider$system$provider _instance;
final TRes Function(Query$SystemServerProvider$system$provider) _then;
static const _undefined = {};
TRes call(
{Object? provider = _undefined, Object? $__typename = _undefined}) =>
_then(Query$SystemServerProvider$system$provider(
provider: provider == _undefined || provider == null
? _instance.provider
: (provider as Enum$ServerProvider),
$__typename: $__typename == _undefined || $__typename == null
? _instance.$__typename
: ($__typename as String)));
}
class _CopyWithStubImpl$Query$SystemServerProvider$system$provider<TRes>
implements CopyWith$Query$SystemServerProvider$system$provider<TRes> {
_CopyWithStubImpl$Query$SystemServerProvider$system$provider(this._res);
TRes _res;
call({Enum$ServerProvider? provider, String? $__typename}) => _res;
}
@JsonSerializable(explicitToJson: true)
class Query$GetApiTokens {
Query$GetApiTokens({required this.api, required this.$__typename});

View File

@ -330,6 +330,58 @@ Map<String, dynamic> _$Mutation$RebootSystem$rebootSystemToJson(
'__typename': instance.$__typename,
};
Query$SystemServerProvider _$Query$SystemServerProviderFromJson(
Map<String, dynamic> json) =>
Query$SystemServerProvider(
system: Query$SystemServerProvider$system.fromJson(
json['system'] as Map<String, dynamic>),
$__typename: json['__typename'] as String,
);
Map<String, dynamic> _$Query$SystemServerProviderToJson(
Query$SystemServerProvider instance) =>
<String, dynamic>{
'system': instance.system.toJson(),
'__typename': instance.$__typename,
};
Query$SystemServerProvider$system _$Query$SystemServerProvider$systemFromJson(
Map<String, dynamic> json) =>
Query$SystemServerProvider$system(
provider: Query$SystemServerProvider$system$provider.fromJson(
json['provider'] as Map<String, dynamic>),
$__typename: json['__typename'] as String,
);
Map<String, dynamic> _$Query$SystemServerProvider$systemToJson(
Query$SystemServerProvider$system instance) =>
<String, dynamic>{
'provider': instance.provider.toJson(),
'__typename': instance.$__typename,
};
Query$SystemServerProvider$system$provider
_$Query$SystemServerProvider$system$providerFromJson(
Map<String, dynamic> json) =>
Query$SystemServerProvider$system$provider(
provider: $enumDecode(_$Enum$ServerProviderEnumMap, json['provider'],
unknownValue: Enum$ServerProvider.$unknown),
$__typename: json['__typename'] as String,
);
Map<String, dynamic> _$Query$SystemServerProvider$system$providerToJson(
Query$SystemServerProvider$system$provider instance) =>
<String, dynamic>{
'provider': _$Enum$ServerProviderEnumMap[instance.provider]!,
'__typename': instance.$__typename,
};
const _$Enum$ServerProviderEnumMap = {
Enum$ServerProvider.HETZNER: 'HETZNER',
Enum$ServerProvider.DIGITALOCEAN: 'DIGITALOCEAN',
Enum$ServerProvider.$unknown: r'$unknown',
};
Query$GetApiTokens _$Query$GetApiTokensFromJson(Map<String, dynamic> json) =>
Query$GetApiTokens(
api: Query$GetApiTokens$api.fromJson(json['api'] as Map<String, dynamic>),

View File

@ -3,7 +3,7 @@ import 'package:gql/ast.dart';
import 'package:graphql/client.dart' as graphql;
import 'package:json_annotation/json_annotation.dart';
import 'schema.graphql.dart';
import 'services.graphql.dart';
import 'server_api.graphql.dart';
part 'server_settings.graphql.g.dart';
@JsonSerializable(explicitToJson: true)

View File

@ -4,6 +4,7 @@ import 'package:graphql/client.dart' as graphql;
import 'package:json_annotation/json_annotation.dart';
import 'package:selfprivacy/utils/scalars.dart';
import 'schema.graphql.dart';
import 'server_api.graphql.dart';
part 'services.graphql.g.dart';
@JsonSerializable(explicitToJson: true)

View File

@ -3,7 +3,7 @@ import 'package:gql/ast.dart';
import 'package:graphql/client.dart' as graphql;
import 'package:json_annotation/json_annotation.dart';
import 'schema.graphql.dart';
import 'services.graphql.dart';
import 'server_api.graphql.dart';
part 'users.graphql.g.dart';
@JsonSerializable(explicitToJson: true)

View File

@ -9,6 +9,7 @@ import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/services.graphql.
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/users.graphql.dart';
import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart';
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
import 'package:selfprivacy/logic/models/hive/server_details.dart';
import 'package:selfprivacy/logic/models/hive/user.dart';
import 'package:selfprivacy/logic/models/json/api_token.dart';
import 'package:selfprivacy/logic/models/json/backup.dart';
@ -88,6 +89,31 @@ class ServerApi extends ApiMap
return apiVersion;
}
Future<ServerProvider> getServerProviderType() async {
QueryResult response;
ServerProvider providerType = ServerProvider.unknown;
try {
final GraphQLClient client = await getClient();
response = await client.query$SystemServerProvider();
if (response.hasException) {
print(response.exception.toString());
}
final rawProviderValue = response.data!['system']['provider']['provider'];
switch (rawProviderValue) {
case 'HETZNER':
providerType = ServerProvider.hetzner;
break;
case 'DIGITALOCEAN':
providerType = ServerProvider.digitalOcean;
break;
}
} catch (e) {
print(e);
}
return providerType;
}
Future<bool> isUsingBinds() async {
QueryResult response;
bool usesBinds = false;

View File

@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:equatable/equatable.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_factory_creator.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_factory_settings.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/dns_provider_api_settings.dart';
@ -478,6 +479,16 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
token,
dataState.recoveryCapabilities,
);
final ServerProvider provider = await ServerApi(
customToken: token,
isWithToken: true,
).getServerProviderType();
if (provider == ServerProvider.unknown) {
getIt<NavigationService>()
.showSnackBar('recovering.generic_error'.tr());
return;
}
setServerProviderType(provider);
await repository.saveServerDetails(serverDetails);
emit(
dataState.copyWith(

View File

@ -13,7 +13,7 @@ import 'package:selfprivacy/ui/pages/setup/recovering/recover_by_new_device_key.
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_confirm_backblaze.dart';
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_confirm_cloudflare.dart';
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_confirm_server.dart';
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_hentzner_connected.dart';
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_server_provider_connected.dart';
import 'package:selfprivacy/ui/pages/setup/recovering/recovery_method_select.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
@ -48,7 +48,7 @@ class RecoveryRouting extends StatelessWidget {
currentPage = const RecoverByOldToken();
break;
case RecoveryStep.serverProviderToken:
currentPage = const RecoveryHetznerConnected();
currentPage = const RecoveryServerProviderConnected();
break;
case RecoveryStep.serverSelection:
currentPage = const RecoveryConfirmServer();

View File

@ -10,8 +10,8 @@ import 'package:cubit_form/cubit_form.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
class RecoveryHetznerConnected extends StatelessWidget {
const RecoveryHetznerConnected({super.key});
class RecoveryServerProviderConnected extends StatelessWidget {
const RecoveryServerProviderConnected({super.key});
@override
Widget build(final BuildContext context) {
@ -26,8 +26,8 @@ class RecoveryHetznerConnected extends StatelessWidget {
context.watch<ProviderFormCubit>().state;
return BrandHeroScreen(
heroTitle: 'recovering.hetzner_connected'.tr(),
heroSubtitle: 'recovering.hetzner_connected_description'.tr(
heroTitle: 'recovering.server_provider_connected'.tr(),
heroSubtitle: 'recovering.server_provider_connected_description'.tr(
args: [appConfig.state.serverDomain?.domainName ?? 'your domain'],
),
hasBackButton: true,
@ -40,7 +40,8 @@ class RecoveryHetznerConnected extends StatelessWidget {
formFieldCubit: context.read<ProviderFormCubit>().apiKey,
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: 'recovering.hetzner_connected_placeholder'.tr(),
labelText:
'recovering.server_provider_connected_placeholder'.tr(),
),
),
const SizedBox(height: 16),