Merge branch 'master' into price-calculation

pull/270/head
Inex Code 2023-09-01 15:38:35 +03:00
commit d64764f4a8
44 changed files with 1345 additions and 107 deletions

View File

@ -60,7 +60,7 @@
"title": "Tətbiq parametrləri", "title": "Tətbiq parametrləri",
"dark_theme_title": "Qaranlıq mövzu", "dark_theme_title": "Qaranlıq mövzu",
"reset_config_title": "Tətbiq Sıfırlayın", "reset_config_title": "Tətbiq Sıfırlayın",
"reset_config_description": "API və Super İstifadəçi Açarlarını sıfırlayın", "reset_config_description": "API və Super İstifadəçi Açarlarını sıfırlayın.",
"delete_server_title": "Serveri silin", "delete_server_title": "Serveri silin",
"dark_theme_description": "Rəng mövzusunu dəyişdirin", "dark_theme_description": "Rəng mövzusunu dəyişdirin",
"delete_server_description": "Əməliyyat serveri siləcək. Bundan sonra o, əlçatmaz olacaq.", "delete_server_description": "Əməliyyat serveri siləcək. Bundan sonra o, əlçatmaz olacaq.",

View File

@ -259,7 +259,7 @@
"privacy_policy": "Палітыка прыватнасці" "privacy_policy": "Палітыка прыватнасці"
}, },
"application_settings": { "application_settings": {
"reset_config_description": "Скінуць API ключы i суперкарыстальніка", "reset_config_description": "Скінуць API ключы i суперкарыстальніка.",
"delete_server_description": "Дзеянне прывядзе да выдалення сервера. Пасля гэтага ён будзе недаступны.", "delete_server_description": "Дзеянне прывядзе да выдалення сервера. Пасля гэтага ён будзе недаступны.",
"title": "Налады праграмы", "title": "Налады праграмы",
"dark_theme_title": "Цёмная тэма", "dark_theme_title": "Цёмная тэма",

View File

@ -60,7 +60,7 @@
"title": "Nastavení aplikace", "title": "Nastavení aplikace",
"dark_theme_title": "Tmavé téma", "dark_theme_title": "Tmavé téma",
"reset_config_title": "Obnovení konfigurace aplikace", "reset_config_title": "Obnovení konfigurace aplikace",
"reset_config_description": "Obnovení klíčů api a uživatele root", "reset_config_description": "Obnovení klíčů API a uživatele root.",
"delete_server_title": "Odstranit server", "delete_server_title": "Odstranit server",
"dark_theme_description": "Přepnutí tématu aplikace", "dark_theme_description": "Přepnutí tématu aplikace",
"delete_server_description": "Tím odstraníte svůj server. Nebude již přístupný.", "delete_server_description": "Tím odstraníte svůj server. Nebude již přístupný.",

View File

@ -64,7 +64,7 @@
"dark_theme_title": "Dunkles Thema", "dark_theme_title": "Dunkles Thema",
"dark_theme_description": "Ihr Anwendungsdesign wechseln", "dark_theme_description": "Ihr Anwendungsdesign wechseln",
"reset_config_title": "Anwendungseinstellungen zurücksetzen", "reset_config_title": "Anwendungseinstellungen zurücksetzen",
"reset_config_description": "API Sclüssel und root Benutzer zurücksetzen", "reset_config_description": "API Sclüssel und root Benutzer zurücksetzen.",
"delete_server_title": "Server löschen", "delete_server_title": "Server löschen",
"delete_server_description": "Das wird Ihren Server löschen. Es wird nicht mehr zugänglich sein.", "delete_server_description": "Das wird Ihren Server löschen. Es wird nicht mehr zugänglich sein.",
"system_dark_theme_title": "Standard-Systemthema", "system_dark_theme_title": "Standard-Systemthema",

View File

@ -68,7 +68,7 @@
"dark_theme_description": "Switch your application theme", "dark_theme_description": "Switch your application theme",
"dangerous_settings": "Dangerous settings", "dangerous_settings": "Dangerous settings",
"reset_config_title": "Reset application config", "reset_config_title": "Reset application config",
"reset_config_description": "Reset api keys and root user", "reset_config_description": "Resets API keys and root user.",
"delete_server_title": "Delete server", "delete_server_title": "Delete server",
"delete_server_description": "This removes your server. It will be no longer accessible." "delete_server_description": "This removes your server. It will be no longer accessible."
}, },
@ -204,8 +204,23 @@
"backups_encryption_key_copy": "Copy the encryption key", "backups_encryption_key_copy": "Copy the encryption key",
"backups_encryption_key_show": "Show the encryption key", "backups_encryption_key_show": "Show the encryption key",
"backups_encryption_key_description": "This key is used to encrypt your backups. If you lose it, you will not be able to restore your backups. Keep it in a safe place, as it will be useful if you ever need to restore from backups manually.", "backups_encryption_key_description": "This key is used to encrypt your backups. If you lose it, you will not be able to restore your backups. Keep it in a safe place, as it will be useful if you ever need to restore from backups manually.",
"backups_encryption_key_not_found": "Encryption key not found yet, please try again later.",
"pending_jobs": "Currently running backup jobs", "pending_jobs": "Currently running backup jobs",
"snapshots_title": "Snapshot list" "snapshots_title": "Snapshot list",
"forget_snapshot": "Forget snapshot",
"forget_snapshot_alert": "You are about to delete this snapshot. Are you sure? This action usually cannot be undone.",
"forget_snapshot_error": "Couldn't forget snapshot",
"snapshot_modal_heading": "Snapshot details",
"snapshot_service_title": "Service",
"snapshot_creation_time_title": "Creation time",
"snapshot_id_title": "Snapshot ID",
"snapshot_modal_select_strategy": "Select the restore strategy",
"snapshot_modal_download_verify_option_title": "Download, verify and then replace",
"snapshot_modal_download_verify_option_description": "Less risk, but more free space needed. Downloads entire snapshot to the temporary storage, verifies it and then replaces the current data.",
"snapshot_modal_inplace_option_title": "Replace in place",
"snapshot_modal_inplace_option_description": "Less free space needed, but more risk. Replaces current data with the snapshot data during the download.",
"snapshot_modal_service_not_found": "This is a snapshot of a service you don't have on your server anymore. Usually this shouldn't happen, and we cannot do the automatic restore. You can still download the snapshot and restore it manually. Contact SelfPrivacy support if you need help.",
"restore_started": "Restore started, check the jobs list for the current status"
}, },
"storage": { "storage": {
"card_title": "Server Storage", "card_title": "Server Storage",
@ -543,4 +558,4 @@
"reset_onboarding_description": "Reset onboarding switch to show onboarding screen again", "reset_onboarding_description": "Reset onboarding switch to show onboarding screen again",
"cubit_statuses": "Cubit loading statuses" "cubit_statuses": "Cubit loading statuses"
} }
} }

View File

@ -38,7 +38,7 @@
"application_settings": { "application_settings": {
"reset_config_title": "Restablecer la configuración de la aplicación", "reset_config_title": "Restablecer la configuración de la aplicación",
"dark_theme_description": "Cambia el tema de tu aplicación", "dark_theme_description": "Cambia el tema de tu aplicación",
"reset_config_description": "Restablecer claves api y usuario root", "reset_config_description": "Restablecer claves API y usuario root.",
"delete_server_title": "Eliminar servidor", "delete_server_title": "Eliminar servidor",
"delete_server_description": "Esto elimina su servidor. Ya no será accesible.", "delete_server_description": "Esto elimina su servidor. Ya no será accesible.",
"title": "Ajustes de la aplicación", "title": "Ajustes de la aplicación",
@ -89,4 +89,4 @@
"about_us_page": { "about_us_page": {
"title": "Sobre nosotros" "title": "Sobre nosotros"
} }
} }

View File

@ -64,7 +64,7 @@
"delete_server_title": "Supprimer le serveur", "delete_server_title": "Supprimer le serveur",
"delete_server_description": "Cela va supprimer votre serveur. Celui-ci ne sera plus accessible.", "delete_server_description": "Cela va supprimer votre serveur. Celui-ci ne sera plus accessible.",
"dark_theme_title": "Thème sombre", "dark_theme_title": "Thème sombre",
"reset_config_description": "Réinitialiser les clés API et l'utilisateur root" "reset_config_description": "Réinitialiser les clés API et l'utilisateur root."
}, },
"ssh": { "ssh": {
"title": "Clés SSH", "title": "Clés SSH",

View File

@ -66,7 +66,7 @@
"dark_theme_description": "Lietojumprogrammas dizaina pārslēgšana", "dark_theme_description": "Lietojumprogrammas dizaina pārslēgšana",
"dangerous_settings": "Bīstamie iestatījumi", "dangerous_settings": "Bīstamie iestatījumi",
"reset_config_title": "Atiestatīt lietojumprogrammas konfigurāciju", "reset_config_title": "Atiestatīt lietojumprogrammas konfigurāciju",
"reset_config_description": "Atiestatīt API atslēgas un saknes lietotāju", "reset_config_description": "Atiestatīt API atslēgas un saknes lietotāju.",
"delete_server_title": "Izdzēst serveri", "delete_server_title": "Izdzēst serveri",
"delete_server_description": "Šis izdzēš jūsu serveri. Tas vairs nebūs pieejams." "delete_server_description": "Šis izdzēš jūsu serveri. Tas vairs nebūs pieejams."
}, },
@ -215,4 +215,4 @@
"not_ready_card": { "not_ready_card": {
"in_menu": "Serveris vēl nav iestatīts. Lūdzu, pabeidziet iestatīšanu, izmantojot iestatīšanas vedni, lai turpinātu darbu." "in_menu": "Serveris vēl nav iestatīts. Lūdzu, pabeidziet iestatīšanu, izmantojot iestatīšanas vedni, lai turpinātu darbu."
} }
} }

View File

@ -64,7 +64,7 @@
"dark_theme_title": "Ciemny motyw aplikacji", "dark_theme_title": "Ciemny motyw aplikacji",
"dark_theme_description": "Zmień kolor motywu aplikacji", "dark_theme_description": "Zmień kolor motywu aplikacji",
"reset_config_title": "Resetowanie", "reset_config_title": "Resetowanie",
"reset_config_description": "Zresetuj klucze API i użytkownika root", "reset_config_description": "Zresetuj klucze API i użytkownika root.",
"delete_server_title": "Usuń serwer", "delete_server_title": "Usuń serwer",
"delete_server_description": "Ta czynność usunie serwer. Po tym będzie niedostępny.", "delete_server_description": "Ta czynność usunie serwer. Po tym będzie niedostępny.",
"system_dark_theme_description": "Użyj jasnego lub ciemnego motywu w zależności od ustawień systemu", "system_dark_theme_description": "Użyj jasnego lub ciemnego motywu w zależności od ustawień systemu",

View File

@ -65,7 +65,7 @@
"dark_theme_title": "Тёмная тема", "dark_theme_title": "Тёмная тема",
"dark_theme_description": "Сменить цветовую тему", "dark_theme_description": "Сменить цветовую тему",
"reset_config_title": "Сброс настроек", "reset_config_title": "Сброс настроек",
"reset_config_description": "Сбросить API ключи, а также root пользователя", "reset_config_description": "Сбросить API ключи и root пользователя.",
"delete_server_title": "Удалить сервер", "delete_server_title": "Удалить сервер",
"delete_server_description": "Действие приведёт к удалению сервера. После этого он будет недоступен.", "delete_server_description": "Действие приведёт к удалению сервера. После этого он будет недоступен.",
"system_dark_theme_title": "Системная тема по-умолчанию", "system_dark_theme_title": "Системная тема по-умолчанию",
@ -201,7 +201,8 @@
"autobackup_set_period": "Установить период", "autobackup_set_period": "Установить период",
"autobackup_period_set": "Период установлен", "autobackup_period_set": "Период установлен",
"backups_encryption_key": "Ключ шифрования", "backups_encryption_key": "Ключ шифрования",
"snapshots_title": "Список снимков" "snapshots_title": "Список снимков",
"forget_snapshot_error": "Не удалось забыть снимок"
}, },
"storage": { "storage": {
"card_title": "Хранилище", "card_title": "Хранилище",

View File

@ -114,7 +114,7 @@
"dark_theme_title": "Temná téma", "dark_theme_title": "Temná téma",
"dark_theme_description": "Zmeniť tému aplikácie", "dark_theme_description": "Zmeniť tému aplikácie",
"reset_config_title": "Resetovať nastavenia aplikácie", "reset_config_title": "Resetovať nastavenia aplikácie",
"reset_config_description": "Resetovať kľúče API a užívateľa root", "reset_config_description": "Resetovať kľúče API a užívateľa root.",
"delete_server_title": "Zmazať server", "delete_server_title": "Zmazať server",
"delete_server_description": "Tým sa odstráni váš server. Už nebude prístupným.", "delete_server_description": "Tým sa odstráni váš server. Už nebude prístupným.",
"system_dark_theme_description": "Použitie svetlej alebo tmavej témy v závislosti od nastavení systému", "system_dark_theme_description": "Použitie svetlej alebo tmavej témy v závislosti od nastavení systému",

View File

@ -67,7 +67,6 @@
"dark_theme_description": "Spreminjanje barvne teme", "dark_theme_description": "Spreminjanje barvne teme",
"dangerous_settings": "Nevarne nastavitve", "dangerous_settings": "Nevarne nastavitve",
"reset_config_title": "Ponastavitev konfiguracije aplikacije", "reset_config_title": "Ponastavitev konfiguracije aplikacije",
"reset_config_description": "Сбросить API ключи, а также root пользователя",
"delete_server_title": "Brisanje strežnika", "delete_server_title": "Brisanje strežnika",
"delete_server_description": "To dejanje povzroči izbris strežnika. Nato bo nedosegljiv." "delete_server_description": "To dejanje povzroči izbris strežnika. Nato bo nedosegljiv."
}, },
@ -254,4 +253,4 @@
"title": "VPN Strežnik", "title": "VPN Strežnik",
"subtitle": "Zasebni strežnik VPN" "subtitle": "Zasebni strežnik VPN"
} }
} }

View File

@ -59,7 +59,7 @@
"title": "การตั้งค่าแอปพลิเคชัน", "title": "การตั้งค่าแอปพลิเคชัน",
"dark_theme_title": "ธีมมืด", "dark_theme_title": "ธีมมืด",
"reset_config_title": "รีเซ็ตค่าดั้งเดิมการตั้งค่าของแอปพลิเคชั่น", "reset_config_title": "รีเซ็ตค่าดั้งเดิมการตั้งค่าของแอปพลิเคชั่น",
"reset_config_description": "รีเซ็ต api key และผู้ใช้งาน root", "reset_config_description": "รีเซ็ต API key และผู้ใช้งาน root",
"delete_server_title": "ลบเซิฟเวอร์" "delete_server_title": "ลบเซิฟเวอร์"
}, },
"ssh": { "ssh": {

View File

@ -41,7 +41,7 @@
"reset_config_title": "Скинути налаштування", "reset_config_title": "Скинути налаштування",
"dark_theme_title": "Темна тема", "dark_theme_title": "Темна тема",
"dark_theme_description": "Змінити тему додатка", "dark_theme_description": "Змінити тему додатка",
"reset_config_description": "Скинути API ключі та root користувача", "reset_config_description": "Скинути API ключі та root користувача.",
"delete_server_title": "Видалити сервер", "delete_server_title": "Видалити сервер",
"delete_server_description": "Це видалить ваш сервер. Він більше не буде доступний." "delete_server_description": "Це видалить ваш сервер. Він більше не буде доступний."
}, },

View File

@ -81,13 +81,21 @@ mutation InitializeRepository($repository: InitializeRepositoryInput!) {
} }
} }
mutation RestoreBackup($snapshotId: String!) { mutation RestoreBackup($snapshotId: String!, $strategy: RestoreStrategy! = DOWNLOAD_VERIFY_OVERWRITE) {
backup { backup {
restoreBackup(snapshotId: $snapshotId) { restoreBackup(snapshotId: $snapshotId, strategy: $strategy) {
...basicMutationReturnFields ...basicMutationReturnFields
job { job {
...basicApiJobsFields ...basicApiJobsFields
} }
} }
} }
}
mutation ForgetSnapshot($snapshotId: String!) {
backup {
forgetSnapshot(snapshotId: $snapshotId) {
...basicMutationReturnFields
}
}
} }

View File

@ -4982,9 +4982,13 @@ class _CopyWithStubImpl$Mutation$InitializeRepository$backup<TRes>
} }
class Variables$Mutation$RestoreBackup { class Variables$Mutation$RestoreBackup {
factory Variables$Mutation$RestoreBackup({required String snapshotId}) => factory Variables$Mutation$RestoreBackup({
required String snapshotId,
required Enum$RestoreStrategy strategy,
}) =>
Variables$Mutation$RestoreBackup._({ Variables$Mutation$RestoreBackup._({
r'snapshotId': snapshotId, r'snapshotId': snapshotId,
r'strategy': strategy,
}); });
Variables$Mutation$RestoreBackup._(this._$data); Variables$Mutation$RestoreBackup._(this._$data);
@ -4993,16 +4997,23 @@ class Variables$Mutation$RestoreBackup {
final result$data = <String, dynamic>{}; final result$data = <String, dynamic>{};
final l$snapshotId = data['snapshotId']; final l$snapshotId = data['snapshotId'];
result$data['snapshotId'] = (l$snapshotId as String); result$data['snapshotId'] = (l$snapshotId as String);
final l$strategy = data['strategy'];
result$data['strategy'] =
fromJson$Enum$RestoreStrategy((l$strategy as String));
return Variables$Mutation$RestoreBackup._(result$data); return Variables$Mutation$RestoreBackup._(result$data);
} }
Map<String, dynamic> _$data; Map<String, dynamic> _$data;
String get snapshotId => (_$data['snapshotId'] as String); String get snapshotId => (_$data['snapshotId'] as String);
Enum$RestoreStrategy get strategy =>
(_$data['strategy'] as Enum$RestoreStrategy);
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final result$data = <String, dynamic>{}; final result$data = <String, dynamic>{};
final l$snapshotId = snapshotId; final l$snapshotId = snapshotId;
result$data['snapshotId'] = l$snapshotId; result$data['snapshotId'] = l$snapshotId;
final l$strategy = strategy;
result$data['strategy'] = toJson$Enum$RestoreStrategy(l$strategy);
return result$data; return result$data;
} }
@ -5025,13 +5036,22 @@ class Variables$Mutation$RestoreBackup {
if (l$snapshotId != lOther$snapshotId) { if (l$snapshotId != lOther$snapshotId) {
return false; return false;
} }
final l$strategy = strategy;
final lOther$strategy = other.strategy;
if (l$strategy != lOther$strategy) {
return false;
}
return true; return true;
} }
@override @override
int get hashCode { int get hashCode {
final l$snapshotId = snapshotId; final l$snapshotId = snapshotId;
return Object.hashAll([l$snapshotId]); final l$strategy = strategy;
return Object.hashAll([
l$snapshotId,
l$strategy,
]);
} }
} }
@ -5044,7 +5064,10 @@ abstract class CopyWith$Variables$Mutation$RestoreBackup<TRes> {
factory CopyWith$Variables$Mutation$RestoreBackup.stub(TRes res) = factory CopyWith$Variables$Mutation$RestoreBackup.stub(TRes res) =
_CopyWithStubImpl$Variables$Mutation$RestoreBackup; _CopyWithStubImpl$Variables$Mutation$RestoreBackup;
TRes call({String? snapshotId}); TRes call({
String? snapshotId,
Enum$RestoreStrategy? strategy,
});
} }
class _CopyWithImpl$Variables$Mutation$RestoreBackup<TRes> class _CopyWithImpl$Variables$Mutation$RestoreBackup<TRes>
@ -5060,11 +5083,16 @@ class _CopyWithImpl$Variables$Mutation$RestoreBackup<TRes>
static const _undefined = <dynamic, dynamic>{}; static const _undefined = <dynamic, dynamic>{};
TRes call({Object? snapshotId = _undefined}) => TRes call({
Object? snapshotId = _undefined,
Object? strategy = _undefined,
}) =>
_then(Variables$Mutation$RestoreBackup._({ _then(Variables$Mutation$RestoreBackup._({
..._instance._$data, ..._instance._$data,
if (snapshotId != _undefined && snapshotId != null) if (snapshotId != _undefined && snapshotId != null)
'snapshotId': (snapshotId as String), 'snapshotId': (snapshotId as String),
if (strategy != _undefined && strategy != null)
'strategy': (strategy as Enum$RestoreStrategy),
})); }));
} }
@ -5074,7 +5102,11 @@ class _CopyWithStubImpl$Variables$Mutation$RestoreBackup<TRes>
TRes _res; TRes _res;
call({String? snapshotId}) => _res; call({
String? snapshotId,
Enum$RestoreStrategy? strategy,
}) =>
_res;
} }
class Mutation$RestoreBackup { class Mutation$RestoreBackup {
@ -5223,7 +5255,18 @@ const documentNodeMutationRestoreBackup = DocumentNode(definitions: [
), ),
defaultValue: DefaultValueNode(value: null), defaultValue: DefaultValueNode(value: null),
directives: [], directives: [],
) ),
VariableDefinitionNode(
variable: VariableNode(name: NameNode(value: 'strategy')),
type: NamedTypeNode(
name: NameNode(value: 'RestoreStrategy'),
isNonNull: true,
),
defaultValue: DefaultValueNode(
value: EnumValueNode(
name: NameNode(value: 'DOWNLOAD_VERIFY_OVERWRITE'))),
directives: [],
),
], ],
directives: [], directives: [],
selectionSet: SelectionSetNode(selections: [ selectionSet: SelectionSetNode(selections: [
@ -5240,7 +5283,11 @@ const documentNodeMutationRestoreBackup = DocumentNode(definitions: [
ArgumentNode( ArgumentNode(
name: NameNode(value: 'snapshotId'), name: NameNode(value: 'snapshotId'),
value: VariableNode(name: NameNode(value: 'snapshotId')), value: VariableNode(name: NameNode(value: 'snapshotId')),
) ),
ArgumentNode(
name: NameNode(value: 'strategy'),
value: VariableNode(name: NameNode(value: 'strategy')),
),
], ],
directives: [], directives: [],
selectionSet: SelectionSetNode(selections: [ selectionSet: SelectionSetNode(selections: [
@ -5727,3 +5774,702 @@ class _CopyWithStubImpl$Mutation$RestoreBackup$backup$restoreBackup<TRes>
CopyWith$Fragment$basicApiJobsFields<TRes> get job => CopyWith$Fragment$basicApiJobsFields<TRes> get job =>
CopyWith$Fragment$basicApiJobsFields.stub(_res); CopyWith$Fragment$basicApiJobsFields.stub(_res);
} }
class Variables$Mutation$ForgetSnapshot {
factory Variables$Mutation$ForgetSnapshot({required String snapshotId}) =>
Variables$Mutation$ForgetSnapshot._({
r'snapshotId': snapshotId,
});
Variables$Mutation$ForgetSnapshot._(this._$data);
factory Variables$Mutation$ForgetSnapshot.fromJson(
Map<String, dynamic> data) {
final result$data = <String, dynamic>{};
final l$snapshotId = data['snapshotId'];
result$data['snapshotId'] = (l$snapshotId as String);
return Variables$Mutation$ForgetSnapshot._(result$data);
}
Map<String, dynamic> _$data;
String get snapshotId => (_$data['snapshotId'] as String);
Map<String, dynamic> toJson() {
final result$data = <String, dynamic>{};
final l$snapshotId = snapshotId;
result$data['snapshotId'] = l$snapshotId;
return result$data;
}
CopyWith$Variables$Mutation$ForgetSnapshot<Variables$Mutation$ForgetSnapshot>
get copyWith => CopyWith$Variables$Mutation$ForgetSnapshot(
this,
(i) => i,
);
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (!(other is Variables$Mutation$ForgetSnapshot) ||
runtimeType != other.runtimeType) {
return false;
}
final l$snapshotId = snapshotId;
final lOther$snapshotId = other.snapshotId;
if (l$snapshotId != lOther$snapshotId) {
return false;
}
return true;
}
@override
int get hashCode {
final l$snapshotId = snapshotId;
return Object.hashAll([l$snapshotId]);
}
}
abstract class CopyWith$Variables$Mutation$ForgetSnapshot<TRes> {
factory CopyWith$Variables$Mutation$ForgetSnapshot(
Variables$Mutation$ForgetSnapshot instance,
TRes Function(Variables$Mutation$ForgetSnapshot) then,
) = _CopyWithImpl$Variables$Mutation$ForgetSnapshot;
factory CopyWith$Variables$Mutation$ForgetSnapshot.stub(TRes res) =
_CopyWithStubImpl$Variables$Mutation$ForgetSnapshot;
TRes call({String? snapshotId});
}
class _CopyWithImpl$Variables$Mutation$ForgetSnapshot<TRes>
implements CopyWith$Variables$Mutation$ForgetSnapshot<TRes> {
_CopyWithImpl$Variables$Mutation$ForgetSnapshot(
this._instance,
this._then,
);
final Variables$Mutation$ForgetSnapshot _instance;
final TRes Function(Variables$Mutation$ForgetSnapshot) _then;
static const _undefined = <dynamic, dynamic>{};
TRes call({Object? snapshotId = _undefined}) =>
_then(Variables$Mutation$ForgetSnapshot._({
..._instance._$data,
if (snapshotId != _undefined && snapshotId != null)
'snapshotId': (snapshotId as String),
}));
}
class _CopyWithStubImpl$Variables$Mutation$ForgetSnapshot<TRes>
implements CopyWith$Variables$Mutation$ForgetSnapshot<TRes> {
_CopyWithStubImpl$Variables$Mutation$ForgetSnapshot(this._res);
TRes _res;
call({String? snapshotId}) => _res;
}
class Mutation$ForgetSnapshot {
Mutation$ForgetSnapshot({
required this.backup,
this.$__typename = 'Mutation',
});
factory Mutation$ForgetSnapshot.fromJson(Map<String, dynamic> json) {
final l$backup = json['backup'];
final l$$__typename = json['__typename'];
return Mutation$ForgetSnapshot(
backup: Mutation$ForgetSnapshot$backup.fromJson(
(l$backup as Map<String, dynamic>)),
$__typename: (l$$__typename as String),
);
}
final Mutation$ForgetSnapshot$backup backup;
final String $__typename;
Map<String, dynamic> toJson() {
final _resultData = <String, dynamic>{};
final l$backup = backup;
_resultData['backup'] = l$backup.toJson();
final l$$__typename = $__typename;
_resultData['__typename'] = l$$__typename;
return _resultData;
}
@override
int get hashCode {
final l$backup = backup;
final l$$__typename = $__typename;
return Object.hashAll([
l$backup,
l$$__typename,
]);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (!(other is Mutation$ForgetSnapshot) ||
runtimeType != other.runtimeType) {
return false;
}
final l$backup = backup;
final lOther$backup = other.backup;
if (l$backup != lOther$backup) {
return false;
}
final l$$__typename = $__typename;
final lOther$$__typename = other.$__typename;
if (l$$__typename != lOther$$__typename) {
return false;
}
return true;
}
}
extension UtilityExtension$Mutation$ForgetSnapshot on Mutation$ForgetSnapshot {
CopyWith$Mutation$ForgetSnapshot<Mutation$ForgetSnapshot> get copyWith =>
CopyWith$Mutation$ForgetSnapshot(
this,
(i) => i,
);
}
abstract class CopyWith$Mutation$ForgetSnapshot<TRes> {
factory CopyWith$Mutation$ForgetSnapshot(
Mutation$ForgetSnapshot instance,
TRes Function(Mutation$ForgetSnapshot) then,
) = _CopyWithImpl$Mutation$ForgetSnapshot;
factory CopyWith$Mutation$ForgetSnapshot.stub(TRes res) =
_CopyWithStubImpl$Mutation$ForgetSnapshot;
TRes call({
Mutation$ForgetSnapshot$backup? backup,
String? $__typename,
});
CopyWith$Mutation$ForgetSnapshot$backup<TRes> get backup;
}
class _CopyWithImpl$Mutation$ForgetSnapshot<TRes>
implements CopyWith$Mutation$ForgetSnapshot<TRes> {
_CopyWithImpl$Mutation$ForgetSnapshot(
this._instance,
this._then,
);
final Mutation$ForgetSnapshot _instance;
final TRes Function(Mutation$ForgetSnapshot) _then;
static const _undefined = <dynamic, dynamic>{};
TRes call({
Object? backup = _undefined,
Object? $__typename = _undefined,
}) =>
_then(Mutation$ForgetSnapshot(
backup: backup == _undefined || backup == null
? _instance.backup
: (backup as Mutation$ForgetSnapshot$backup),
$__typename: $__typename == _undefined || $__typename == null
? _instance.$__typename
: ($__typename as String),
));
CopyWith$Mutation$ForgetSnapshot$backup<TRes> get backup {
final local$backup = _instance.backup;
return CopyWith$Mutation$ForgetSnapshot$backup(
local$backup, (e) => call(backup: e));
}
}
class _CopyWithStubImpl$Mutation$ForgetSnapshot<TRes>
implements CopyWith$Mutation$ForgetSnapshot<TRes> {
_CopyWithStubImpl$Mutation$ForgetSnapshot(this._res);
TRes _res;
call({
Mutation$ForgetSnapshot$backup? backup,
String? $__typename,
}) =>
_res;
CopyWith$Mutation$ForgetSnapshot$backup<TRes> get backup =>
CopyWith$Mutation$ForgetSnapshot$backup.stub(_res);
}
const documentNodeMutationForgetSnapshot = DocumentNode(definitions: [
OperationDefinitionNode(
type: OperationType.mutation,
name: NameNode(value: 'ForgetSnapshot'),
variableDefinitions: [
VariableDefinitionNode(
variable: VariableNode(name: NameNode(value: 'snapshotId')),
type: NamedTypeNode(
name: NameNode(value: 'String'),
isNonNull: true,
),
defaultValue: DefaultValueNode(value: null),
directives: [],
)
],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'backup'),
alias: null,
arguments: [],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'forgetSnapshot'),
alias: null,
arguments: [
ArgumentNode(
name: NameNode(value: 'snapshotId'),
value: VariableNode(name: NameNode(value: 'snapshotId')),
)
],
directives: [],
selectionSet: SelectionSetNode(selections: [
FragmentSpreadNode(
name: NameNode(value: 'basicMutationReturnFields'),
directives: [],
),
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,
),
]),
),
fragmentDefinitionbasicMutationReturnFields,
]);
Mutation$ForgetSnapshot _parserFn$Mutation$ForgetSnapshot(
Map<String, dynamic> data) =>
Mutation$ForgetSnapshot.fromJson(data);
typedef OnMutationCompleted$Mutation$ForgetSnapshot = FutureOr<void> Function(
Map<String, dynamic>?,
Mutation$ForgetSnapshot?,
);
class Options$Mutation$ForgetSnapshot
extends graphql.MutationOptions<Mutation$ForgetSnapshot> {
Options$Mutation$ForgetSnapshot({
String? operationName,
required Variables$Mutation$ForgetSnapshot variables,
graphql.FetchPolicy? fetchPolicy,
graphql.ErrorPolicy? errorPolicy,
graphql.CacheRereadPolicy? cacheRereadPolicy,
Object? optimisticResult,
Mutation$ForgetSnapshot? typedOptimisticResult,
graphql.Context? context,
OnMutationCompleted$Mutation$ForgetSnapshot? onCompleted,
graphql.OnMutationUpdate<Mutation$ForgetSnapshot>? update,
graphql.OnError? onError,
}) : onCompletedWithParsed = onCompleted,
super(
variables: variables.toJson(),
operationName: operationName,
fetchPolicy: fetchPolicy,
errorPolicy: errorPolicy,
cacheRereadPolicy: cacheRereadPolicy,
optimisticResult: optimisticResult ?? typedOptimisticResult?.toJson(),
context: context,
onCompleted: onCompleted == null
? null
: (data) => onCompleted(
data,
data == null
? null
: _parserFn$Mutation$ForgetSnapshot(data),
),
update: update,
onError: onError,
document: documentNodeMutationForgetSnapshot,
parserFn: _parserFn$Mutation$ForgetSnapshot,
);
final OnMutationCompleted$Mutation$ForgetSnapshot? onCompletedWithParsed;
@override
List<Object?> get properties => [
...super.onCompleted == null
? super.properties
: super.properties.where((property) => property != onCompleted),
onCompletedWithParsed,
];
}
class WatchOptions$Mutation$ForgetSnapshot
extends graphql.WatchQueryOptions<Mutation$ForgetSnapshot> {
WatchOptions$Mutation$ForgetSnapshot({
String? operationName,
required Variables$Mutation$ForgetSnapshot variables,
graphql.FetchPolicy? fetchPolicy,
graphql.ErrorPolicy? errorPolicy,
graphql.CacheRereadPolicy? cacheRereadPolicy,
Object? optimisticResult,
Mutation$ForgetSnapshot? typedOptimisticResult,
graphql.Context? context,
Duration? pollInterval,
bool? eagerlyFetchResults,
bool carryForwardDataOnException = true,
bool fetchResults = false,
}) : super(
variables: variables.toJson(),
operationName: operationName,
fetchPolicy: fetchPolicy,
errorPolicy: errorPolicy,
cacheRereadPolicy: cacheRereadPolicy,
optimisticResult: optimisticResult ?? typedOptimisticResult?.toJson(),
context: context,
document: documentNodeMutationForgetSnapshot,
pollInterval: pollInterval,
eagerlyFetchResults: eagerlyFetchResults,
carryForwardDataOnException: carryForwardDataOnException,
fetchResults: fetchResults,
parserFn: _parserFn$Mutation$ForgetSnapshot,
);
}
extension ClientExtension$Mutation$ForgetSnapshot on graphql.GraphQLClient {
Future<graphql.QueryResult<Mutation$ForgetSnapshot>> mutate$ForgetSnapshot(
Options$Mutation$ForgetSnapshot options) async =>
await this.mutate(options);
graphql.ObservableQuery<Mutation$ForgetSnapshot> watchMutation$ForgetSnapshot(
WatchOptions$Mutation$ForgetSnapshot options) =>
this.watchMutation(options);
}
class Mutation$ForgetSnapshot$backup {
Mutation$ForgetSnapshot$backup({
required this.forgetSnapshot,
this.$__typename = 'BackupMutations',
});
factory Mutation$ForgetSnapshot$backup.fromJson(Map<String, dynamic> json) {
final l$forgetSnapshot = json['forgetSnapshot'];
final l$$__typename = json['__typename'];
return Mutation$ForgetSnapshot$backup(
forgetSnapshot: Mutation$ForgetSnapshot$backup$forgetSnapshot.fromJson(
(l$forgetSnapshot as Map<String, dynamic>)),
$__typename: (l$$__typename as String),
);
}
final Mutation$ForgetSnapshot$backup$forgetSnapshot forgetSnapshot;
final String $__typename;
Map<String, dynamic> toJson() {
final _resultData = <String, dynamic>{};
final l$forgetSnapshot = forgetSnapshot;
_resultData['forgetSnapshot'] = l$forgetSnapshot.toJson();
final l$$__typename = $__typename;
_resultData['__typename'] = l$$__typename;
return _resultData;
}
@override
int get hashCode {
final l$forgetSnapshot = forgetSnapshot;
final l$$__typename = $__typename;
return Object.hashAll([
l$forgetSnapshot,
l$$__typename,
]);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (!(other is Mutation$ForgetSnapshot$backup) ||
runtimeType != other.runtimeType) {
return false;
}
final l$forgetSnapshot = forgetSnapshot;
final lOther$forgetSnapshot = other.forgetSnapshot;
if (l$forgetSnapshot != lOther$forgetSnapshot) {
return false;
}
final l$$__typename = $__typename;
final lOther$$__typename = other.$__typename;
if (l$$__typename != lOther$$__typename) {
return false;
}
return true;
}
}
extension UtilityExtension$Mutation$ForgetSnapshot$backup
on Mutation$ForgetSnapshot$backup {
CopyWith$Mutation$ForgetSnapshot$backup<Mutation$ForgetSnapshot$backup>
get copyWith => CopyWith$Mutation$ForgetSnapshot$backup(
this,
(i) => i,
);
}
abstract class CopyWith$Mutation$ForgetSnapshot$backup<TRes> {
factory CopyWith$Mutation$ForgetSnapshot$backup(
Mutation$ForgetSnapshot$backup instance,
TRes Function(Mutation$ForgetSnapshot$backup) then,
) = _CopyWithImpl$Mutation$ForgetSnapshot$backup;
factory CopyWith$Mutation$ForgetSnapshot$backup.stub(TRes res) =
_CopyWithStubImpl$Mutation$ForgetSnapshot$backup;
TRes call({
Mutation$ForgetSnapshot$backup$forgetSnapshot? forgetSnapshot,
String? $__typename,
});
CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot<TRes>
get forgetSnapshot;
}
class _CopyWithImpl$Mutation$ForgetSnapshot$backup<TRes>
implements CopyWith$Mutation$ForgetSnapshot$backup<TRes> {
_CopyWithImpl$Mutation$ForgetSnapshot$backup(
this._instance,
this._then,
);
final Mutation$ForgetSnapshot$backup _instance;
final TRes Function(Mutation$ForgetSnapshot$backup) _then;
static const _undefined = <dynamic, dynamic>{};
TRes call({
Object? forgetSnapshot = _undefined,
Object? $__typename = _undefined,
}) =>
_then(Mutation$ForgetSnapshot$backup(
forgetSnapshot: forgetSnapshot == _undefined || forgetSnapshot == null
? _instance.forgetSnapshot
: (forgetSnapshot as Mutation$ForgetSnapshot$backup$forgetSnapshot),
$__typename: $__typename == _undefined || $__typename == null
? _instance.$__typename
: ($__typename as String),
));
CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot<TRes>
get forgetSnapshot {
final local$forgetSnapshot = _instance.forgetSnapshot;
return CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot(
local$forgetSnapshot, (e) => call(forgetSnapshot: e));
}
}
class _CopyWithStubImpl$Mutation$ForgetSnapshot$backup<TRes>
implements CopyWith$Mutation$ForgetSnapshot$backup<TRes> {
_CopyWithStubImpl$Mutation$ForgetSnapshot$backup(this._res);
TRes _res;
call({
Mutation$ForgetSnapshot$backup$forgetSnapshot? forgetSnapshot,
String? $__typename,
}) =>
_res;
CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot<TRes>
get forgetSnapshot =>
CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot.stub(_res);
}
class Mutation$ForgetSnapshot$backup$forgetSnapshot
implements Fragment$basicMutationReturnFields$$GenericMutationReturn {
Mutation$ForgetSnapshot$backup$forgetSnapshot({
required this.code,
required this.message,
required this.success,
this.$__typename = 'GenericMutationReturn',
});
factory Mutation$ForgetSnapshot$backup$forgetSnapshot.fromJson(
Map<String, dynamic> json) {
final l$code = json['code'];
final l$message = json['message'];
final l$success = json['success'];
final l$$__typename = json['__typename'];
return Mutation$ForgetSnapshot$backup$forgetSnapshot(
code: (l$code as int),
message: (l$message as String),
success: (l$success as bool),
$__typename: (l$$__typename as String),
);
}
final int code;
final String message;
final bool success;
final String $__typename;
Map<String, dynamic> toJson() {
final _resultData = <String, dynamic>{};
final l$code = code;
_resultData['code'] = l$code;
final l$message = message;
_resultData['message'] = l$message;
final l$success = success;
_resultData['success'] = l$success;
final l$$__typename = $__typename;
_resultData['__typename'] = l$$__typename;
return _resultData;
}
@override
int get hashCode {
final l$code = code;
final l$message = message;
final l$success = success;
final l$$__typename = $__typename;
return Object.hashAll([
l$code,
l$message,
l$success,
l$$__typename,
]);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (!(other is Mutation$ForgetSnapshot$backup$forgetSnapshot) ||
runtimeType != other.runtimeType) {
return false;
}
final l$code = code;
final lOther$code = other.code;
if (l$code != lOther$code) {
return false;
}
final l$message = message;
final lOther$message = other.message;
if (l$message != lOther$message) {
return false;
}
final l$success = success;
final lOther$success = other.success;
if (l$success != lOther$success) {
return false;
}
final l$$__typename = $__typename;
final lOther$$__typename = other.$__typename;
if (l$$__typename != lOther$$__typename) {
return false;
}
return true;
}
}
extension UtilityExtension$Mutation$ForgetSnapshot$backup$forgetSnapshot
on Mutation$ForgetSnapshot$backup$forgetSnapshot {
CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot<
Mutation$ForgetSnapshot$backup$forgetSnapshot>
get copyWith => CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot(
this,
(i) => i,
);
}
abstract class CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot<TRes> {
factory CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot(
Mutation$ForgetSnapshot$backup$forgetSnapshot instance,
TRes Function(Mutation$ForgetSnapshot$backup$forgetSnapshot) then,
) = _CopyWithImpl$Mutation$ForgetSnapshot$backup$forgetSnapshot;
factory CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot.stub(
TRes res) =
_CopyWithStubImpl$Mutation$ForgetSnapshot$backup$forgetSnapshot;
TRes call({
int? code,
String? message,
bool? success,
String? $__typename,
});
}
class _CopyWithImpl$Mutation$ForgetSnapshot$backup$forgetSnapshot<TRes>
implements CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot<TRes> {
_CopyWithImpl$Mutation$ForgetSnapshot$backup$forgetSnapshot(
this._instance,
this._then,
);
final Mutation$ForgetSnapshot$backup$forgetSnapshot _instance;
final TRes Function(Mutation$ForgetSnapshot$backup$forgetSnapshot) _then;
static const _undefined = <dynamic, dynamic>{};
TRes call({
Object? code = _undefined,
Object? message = _undefined,
Object? success = _undefined,
Object? $__typename = _undefined,
}) =>
_then(Mutation$ForgetSnapshot$backup$forgetSnapshot(
code:
code == _undefined || code == null ? _instance.code : (code as int),
message: message == _undefined || message == null
? _instance.message
: (message as String),
success: success == _undefined || success == null
? _instance.success
: (success as bool),
$__typename: $__typename == _undefined || $__typename == null
? _instance.$__typename
: ($__typename as String),
));
}
class _CopyWithStubImpl$Mutation$ForgetSnapshot$backup$forgetSnapshot<TRes>
implements CopyWith$Mutation$ForgetSnapshot$backup$forgetSnapshot<TRes> {
_CopyWithStubImpl$Mutation$ForgetSnapshot$backup$forgetSnapshot(this._res);
TRes _res;
call({
int? code,
String? message,
bool? success,
String? $__typename,
}) =>
_res;
}

View File

@ -94,7 +94,8 @@ type BackupMutations {
removeRepository: GenericBackupConfigReturn! removeRepository: GenericBackupConfigReturn!
setAutobackupPeriod(period: Int = null): GenericBackupConfigReturn! setAutobackupPeriod(period: Int = null): GenericBackupConfigReturn!
startBackup(serviceId: String!): GenericJobMutationReturn! startBackup(serviceId: String!): GenericJobMutationReturn!
restoreBackup(snapshotId: String!): GenericJobMutationReturn! restoreBackup(snapshotId: String!, strategy: RestoreStrategy! = DOWNLOAD_VERIFY_OVERWRITE): GenericJobMutationReturn!
forgetSnapshot(snapshotId: String!): GenericMutationReturn!
forceSnapshotsReload: GenericMutationReturn! forceSnapshotsReload: GenericMutationReturn!
} }
@ -241,6 +242,11 @@ input RecoveryKeyLimitsInput {
uses: Int = null uses: Int = null
} }
enum RestoreStrategy {
INPLACE
DOWNLOAD_VERIFY_OVERWRITE
}
enum ServerProvider { enum ServerProvider {
HETZNER HETZNER
DIGITALOCEAN DIGITALOCEAN

View File

@ -1338,6 +1338,30 @@ Enum$DnsProvider fromJson$Enum$DnsProvider(String value) {
} }
} }
enum Enum$RestoreStrategy { INPLACE, DOWNLOAD_VERIFY_OVERWRITE, $unknown }
String toJson$Enum$RestoreStrategy(Enum$RestoreStrategy e) {
switch (e) {
case Enum$RestoreStrategy.INPLACE:
return r'INPLACE';
case Enum$RestoreStrategy.DOWNLOAD_VERIFY_OVERWRITE:
return r'DOWNLOAD_VERIFY_OVERWRITE';
case Enum$RestoreStrategy.$unknown:
return r'$unknown';
}
}
Enum$RestoreStrategy fromJson$Enum$RestoreStrategy(String value) {
switch (value) {
case r'INPLACE':
return Enum$RestoreStrategy.INPLACE;
case r'DOWNLOAD_VERIFY_OVERWRITE':
return Enum$RestoreStrategy.DOWNLOAD_VERIFY_OVERWRITE;
default:
return Enum$RestoreStrategy.$unknown;
}
}
enum Enum$ServerProvider { HETZNER, DIGITALOCEAN, $unknown } enum Enum$ServerProvider { HETZNER, DIGITALOCEAN, $unknown }
String toJson$Enum$ServerProvider(Enum$ServerProvider e) { String toJson$Enum$ServerProvider(Enum$ServerProvider e) {

View File

@ -209,14 +209,17 @@ mixin BackupsApi on GraphQLApiMap {
Future<GenericResult<ServerJob?>> restoreBackup( Future<GenericResult<ServerJob?>> restoreBackup(
final String snapshotId, final String snapshotId,
final BackupRestoreStrategy strategy,
) async { ) async {
QueryResult<Mutation$RestoreBackup> response; QueryResult<Mutation$RestoreBackup> response;
GenericResult<ServerJob?>? result; GenericResult<ServerJob?>? result;
try { try {
final GraphQLClient client = await getClient(); final GraphQLClient client = await getClient();
final variables = final variables = Variables$Mutation$RestoreBackup(
Variables$Mutation$RestoreBackup(snapshotId: snapshotId); snapshotId: snapshotId,
strategy: strategy.toGraphQL,
);
final options = Options$Mutation$RestoreBackup(variables: variables); final options = Options$Mutation$RestoreBackup(variables: variables);
response = await client.mutate$RestoreBackup(options); response = await client.mutate$RestoreBackup(options);
if (response.hasException) { if (response.hasException) {
@ -245,4 +248,42 @@ mixin BackupsApi on GraphQLApiMap {
return result; return result;
} }
Future<GenericResult<bool?>> forgetSnapshot(
final String snapshotId,
) async {
QueryResult<Mutation$ForgetSnapshot> response;
GenericResult<bool?>? result;
try {
final GraphQLClient client = await getClient();
final variables = Variables$Mutation$ForgetSnapshot(
snapshotId: snapshotId,
);
final options = Options$Mutation$ForgetSnapshot(variables: variables);
response = await client.mutate$ForgetSnapshot(options);
if (response.hasException) {
final message = response.exception.toString();
print(message);
result = GenericResult(
success: false,
data: null,
message: message,
);
}
result = GenericResult(
success: true,
data: response.parsedData!.backup.forgetSnapshot.success,
);
} catch (e) {
print(e);
result = GenericResult(
success: false,
data: null,
message: e.toString(),
);
}
return result;
}
} }

View File

@ -20,15 +20,23 @@ mixin ServerActionsApi on GraphQLApiMap {
return result; return result;
} }
Future<bool> reboot() async { Future<GenericResult<DateTime?>> reboot() async {
DateTime? time;
try { try {
final GraphQLClient client = await getClient(); final GraphQLClient client = await getClient();
return await _commonBoolRequest( final response = await client.mutate$RebootSystem();
() async => client.mutate$RebootSystem(), if (response.hasException) {
); print(response.exception.toString());
}
if (response.parsedData!.rebootSystem.success) {
time = DateTime.now();
}
} catch (e) { } catch (e) {
return false; print(e);
return GenericResult(data: time, success: false);
} }
return GenericResult(data: time, success: true);
} }
Future<bool> pullConfigurationUpdate() async { Future<bool> pullConfigurationUpdate() async {

View File

@ -41,7 +41,6 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
refreshing: false, refreshing: false,
), ),
); );
print(state);
} }
} }
@ -113,9 +112,7 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
final BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket; final BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket;
if (bucket == null) { if (bucket == null) {
emit(state.copyWith(isInitialized: false)); emit(state.copyWith(isInitialized: false));
print('bucket is null');
} else { } else {
print('bucket is not null');
final GenericResult result = await api.initializeRepository( final GenericResult result = await api.initializeRepository(
InitializeRepositoryInput( InitializeRepositoryInput(
provider: BackupsProviderType.backblaze, provider: BackupsProviderType.backblaze,
@ -125,7 +122,6 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
password: bucket.applicationKey, password: bucket.applicationKey,
), ),
); );
print('result is $result');
if (result.success == false) { if (result.success == false) {
getIt<NavigationService>() getIt<NavigationService>()
.showSnackBar(result.message ?? 'Unknown error'); .showSnackBar(result.message ?? 'Unknown error');
@ -185,9 +181,12 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
emit(state.copyWith(preventActions: false)); emit(state.copyWith(preventActions: false));
} }
Future<void> restoreBackup(final String backupId) async { Future<void> restoreBackup(
final String backupId,
final BackupRestoreStrategy strategy,
) async {
emit(state.copyWith(preventActions: true)); emit(state.copyWith(preventActions: true));
await api.restoreBackup(backupId); await api.restoreBackup(backupId, strategy);
emit(state.copyWith(preventActions: false)); emit(state.copyWith(preventActions: false));
} }
@ -211,6 +210,30 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
await updateBackups(); await updateBackups();
} }
Future<void> forgetSnapshot(final String snapshotId) async {
final result = await api.forgetSnapshot(snapshotId);
if (!result.success) {
getIt<NavigationService>().showSnackBar('jobs.generic_error'.tr());
return;
}
if (result.data == false) {
getIt<NavigationService>()
.showSnackBar('backup.forget_snapshot_error'.tr());
}
// Optimistic update
final backups = state.backups;
final index =
backups.indexWhere((final snapshot) => snapshot.id == snapshotId);
if (index != -1) {
backups.removeAt(index);
emit(state.copyWith(backups: backups));
}
await updateBackups();
}
@override @override
void clear() async { void clear() async {
emit(const BackupsState()); emit(const BackupsState());

View File

@ -54,8 +54,8 @@ class JobsCubit extends Cubit<JobsState> {
Future<void> rebootServer() async { Future<void> rebootServer() async {
emit(JobsStateLoading()); emit(JobsStateLoading());
final bool isSuccessful = await api.reboot(); final rebootResult = await api.reboot();
if (isSuccessful) { if (rebootResult.success && rebootResult.data != null) {
getIt<NavigationService>().showSnackBar('jobs.reboot_success'.tr()); getIt<NavigationService>().showSnackBar('jobs.reboot_success'.tr());
} else { } else {
getIt<NavigationService>().showSnackBar('jobs.reboot_failed'.tr()); getIt<NavigationService>().showSnackBar('jobs.reboot_failed'.tr());

View File

@ -21,7 +21,7 @@ class SshFormCubit extends FormCubit {
ValidationModel( ValidationModel(
(final String newKey) => (final String newKey) =>
user.sshKeys.any((final String key) => key == newKey), user.sshKeys.any((final String key) => key == newKey),
'validations.already_exists'.tr(), 'validations.already_exist'.tr(),
), ),
RequiredStringValidation('validations.required'.tr()), RequiredStringValidation('validations.required'.tr()),
ValidationModel<String>( ValidationModel<String>(

View File

@ -260,12 +260,12 @@ class ServerInstallationRepository {
Future<ServerHostingDetails> restart() async { Future<ServerHostingDetails> restart() async {
final server = getIt<ApiConfigModel>().serverDetails!; final server = getIt<ApiConfigModel>().serverDetails!;
final result = await ProvidersController.currentServerProvider!.restart( final result = await ServerApi().reboot();
server.id,
);
if (result.success && result.data != null) { if (result.success && result.data != null) {
server.copyWith(startTime: result.data); server.copyWith(startTime: result.data);
} else {
getIt<NavigationService>().showSnackBar('jobs.reboot_failed'.tr());
} }
return server; return server;

View File

@ -1,5 +1,6 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/backups.graphql.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/backups.graphql.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/schema.graphql.dart';
import 'package:selfprivacy/logic/models/hive/backups_credential.dart'; import 'package:selfprivacy/logic/models/hive/backups_credential.dart';
class Backup { class Backup {
@ -58,3 +59,26 @@ class BackupConfiguration {
final String? locationName; final String? locationName;
final BackupsProviderType provider; final BackupsProviderType provider;
} }
enum BackupRestoreStrategy {
inplace,
downloadVerifyOverwrite,
unknown;
factory BackupRestoreStrategy.fromGraphQL(
final Enum$RestoreStrategy strategy,
) =>
switch (strategy) {
Enum$RestoreStrategy.INPLACE => inplace,
Enum$RestoreStrategy.DOWNLOAD_VERIFY_OVERWRITE =>
downloadVerifyOverwrite,
Enum$RestoreStrategy.$unknown => unknown,
};
Enum$RestoreStrategy get toGraphQL => switch (this) {
inplace => Enum$RestoreStrategy.INPLACE,
downloadVerifyOverwrite =>
Enum$RestoreStrategy.DOWNLOAD_VERIFY_OVERWRITE,
unknown => Enum$RestoreStrategy.$unknown,
};
}

View File

@ -3,17 +3,22 @@ import 'package:flutter/material.dart';
class OutlinedCard extends StatelessWidget { class OutlinedCard extends StatelessWidget {
const OutlinedCard({ const OutlinedCard({
required this.child, required this.child,
this.borderColor,
this.borderWidth,
super.key, super.key,
}); });
final Widget child; final Widget child;
final Color? borderColor;
final double? borderWidth;
@override @override
Widget build(final BuildContext context) => Card( Widget build(final BuildContext context) => Card(
elevation: 0.0, elevation: 0.0,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(12)), borderRadius: const BorderRadius.all(Radius.circular(12)),
side: BorderSide( side: BorderSide(
color: Theme.of(context).colorScheme.outline, color: borderColor ?? Theme.of(context).colorScheme.outline,
width: borderWidth ?? 1.0,
), ),
), ),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,

View File

@ -18,6 +18,7 @@ import 'package:selfprivacy/ui/helpers/modals.dart';
import 'package:selfprivacy/ui/pages/backups/change_period_modal.dart'; import 'package:selfprivacy/ui/pages/backups/change_period_modal.dart';
import 'package:selfprivacy/ui/pages/backups/copy_encryption_key_modal.dart'; import 'package:selfprivacy/ui/pages/backups/copy_encryption_key_modal.dart';
import 'package:selfprivacy/ui/pages/backups/create_backups_modal.dart'; import 'package:selfprivacy/ui/pages/backups/create_backups_modal.dart';
import 'package:selfprivacy/ui/pages/backups/snapshot_modal.dart';
import 'package:selfprivacy/ui/router/router.dart'; import 'package:selfprivacy/ui/router/router.dart';
import 'package:selfprivacy/utils/extensions/duration.dart'; import 'package:selfprivacy/utils/extensions/duration.dart';
@ -62,14 +63,22 @@ class BackupDetailsPage extends StatelessWidget {
heroTitle: 'backup.card_title'.tr(), heroTitle: 'backup.card_title'.tr(),
heroSubtitle: 'backup.description'.tr(), heroSubtitle: 'backup.description'.tr(),
children: [ children: [
BrandButton.rised( if (preventActions)
onPressed: preventActions const Center(
? null child: Padding(
: () async { padding: EdgeInsets.all(16.0),
await context.read<BackupsCubit>().initializeBackups(); child: CircularProgressIndicator(),
}, ),
text: 'backup.initialize'.tr(), ),
), if (!preventActions)
BrandButton.rised(
onPressed: preventActions
? null
: () async {
await context.read<BackupsCubit>().initializeBackups();
},
text: 'backup.initialize'.tr(),
),
], ],
); );
} }
@ -176,7 +185,9 @@ class BackupDetailsPage extends StatelessWidget {
'backup.backups_encryption_key_subtitle'.tr(), 'backup.backups_encryption_key_subtitle'.tr(),
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 8),
const Divider(),
const SizedBox(height: 8),
if (backupJobs.isNotEmpty) if (backupJobs.isNotEmpty)
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -233,16 +244,40 @@ class BackupDetailsPage extends StatelessWidget {
onTap: preventActions onTap: preventActions
? null ? null
: () { : () {
showPopUpAlert( showModalBottomSheet(
alertTitle: 'backup.restoring'.tr(), useRootNavigator: true,
description: 'backup.restore_alert'.tr( context: context,
args: [backup.time.toString()], isScrollControlled: true,
builder: (final BuildContext context) =>
DraggableScrollableSheet(
expand: false,
maxChildSize: 0.9,
minChildSize: 0.5,
initialChildSize: 0.7,
builder: (
final context,
final scrollController,
) =>
SnapshotModal(
snapshot: backup,
scrollController: scrollController,
),
), ),
actionButtonTitle: 'modals.yes'.tr(), );
},
onLongPress: preventActions
? null
: () {
showPopUpAlert(
alertTitle: 'backup.forget_snapshot'.tr(),
description:
'backup.forget_snapshot_alert'.tr(),
actionButtonTitle:
'backup.forget_snapshot'.tr(),
actionButtonOnPressed: () => { actionButtonOnPressed: () => {
context context.read<BackupsCubit>().forgetSnapshot(
.read<BackupsCubit>() backup.id,
.restoreBackup(backup.id) )
}, },
); );
}, },

View File

@ -9,6 +9,7 @@ import 'package:selfprivacy/logic/models/backup.dart';
import 'package:selfprivacy/logic/models/service.dart'; import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/ui/helpers/modals.dart'; import 'package:selfprivacy/ui/helpers/modals.dart';
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
import 'package:selfprivacy/ui/pages/backups/snapshot_modal.dart';
@RoutePage() @RoutePage()
class BackupsListPage extends StatelessWidget { class BackupsListPage extends StatelessWidget {
@ -47,14 +48,35 @@ class BackupsListPage extends StatelessWidget {
onTap: preventActions onTap: preventActions
? null ? null
: () { : () {
showPopUpAlert( showModalBottomSheet(
alertTitle: 'backup.restoring'.tr(), useRootNavigator: true,
description: 'backup.restore_alert'.tr( context: context,
args: [backup.time.toString()], isScrollControlled: true,
builder: (final BuildContext context) =>
DraggableScrollableSheet(
expand: false,
maxChildSize: 0.9,
minChildSize: 0.5,
initialChildSize: 0.7,
builder: (final context, final scrollController) =>
SnapshotModal(
snapshot: backup,
scrollController: scrollController,
),
), ),
actionButtonTitle: 'modals.yes'.tr(), );
},
onLongPress: preventActions
? null
: () {
showPopUpAlert(
alertTitle: 'backup.forget_snapshot'.tr(),
description: 'backup.forget_snapshot_alert'.tr(),
actionButtonTitle: 'backup.forget_snapshot'.tr(),
actionButtonOnPressed: () => { actionButtonOnPressed: () => {
context.read<BackupsCubit>().restoreBackup(backup.id) context.read<BackupsCubit>().forgetSnapshot(
backup.id,
)
}, },
); );
}, },

View File

@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart'; import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart'; import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart';
import 'package:selfprivacy/ui/components/info_box/info_box.dart';
class CopyEncryptionKeyModal extends StatefulWidget { class CopyEncryptionKeyModal extends StatefulWidget {
const CopyEncryptionKeyModal({ const CopyEncryptionKeyModal({
@ -32,8 +33,27 @@ class _CopyEncryptionKeyModalState extends State<CopyEncryptionKeyModal> {
@override @override
Widget build(final BuildContext context) { Widget build(final BuildContext context) {
final String encryptionKey = final String? encryptionKey =
context.watch<BackupsCubit>().state.backblazeBucket!.encryptionKey; context.watch<BackupsCubit>().state.backblazeBucket?.encryptionKey;
if (encryptionKey == null) {
return ListView(
controller: widget.scrollController,
padding: const EdgeInsets.all(16),
children: [
const SizedBox(height: 16),
Text(
'backup.backups_encryption_key'.tr(),
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
InfoBox(
text: 'backup.backups_encryption_key_not_found'.tr(),
isWarning: true,
),
],
);
}
return ListView( return ListView(
controller: widget.scrollController, controller: widget.scrollController,
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),

View File

@ -0,0 +1,232 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.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/backup.dart';
import 'package:selfprivacy/logic/models/json/server_job.dart';
import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
import 'package:selfprivacy/ui/components/cards/outlined_card.dart';
import 'package:selfprivacy/ui/components/info_box/info_box.dart';
class SnapshotModal extends StatefulWidget {
const SnapshotModal({
required this.snapshot,
required this.scrollController,
super.key,
});
final Backup snapshot;
final ScrollController scrollController;
@override
State<SnapshotModal> createState() => _SnapshotModalState();
}
class _SnapshotModalState extends State<SnapshotModal> {
BackupRestoreStrategy selectedStrategy =
BackupRestoreStrategy.downloadVerifyOverwrite;
@override
Widget build(final BuildContext context) {
final List<String> busyServices = context
.watch<ServerJobsCubit>()
.state
.backupJobList
.where(
(final ServerJob job) =>
job.status == JobStatusEnum.running ||
job.status == JobStatusEnum.created,
)
.map((final ServerJob job) => job.typeId.split('.')[1])
.toList();
final bool isServiceBusy = busyServices.contains(widget.snapshot.serviceId);
final Service? service = context
.read<ServicesCubit>()
.state
.getServiceById(widget.snapshot.serviceId);
return ListView(
controller: widget.scrollController,
padding: const EdgeInsets.all(16),
children: [
const SizedBox(height: 16),
Text(
'backup.snapshot_modal_heading'.tr(),
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
ListTile(
leading: service != null
? SvgPicture.string(
service.svgIcon,
height: 24,
width: 24,
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.onSurface,
BlendMode.srcIn,
),
)
: const Icon(
Icons.question_mark_outlined,
),
title: Text(
'backup.snapshot_service_title'.tr(),
),
subtitle: Text(
service?.displayName ?? widget.snapshot.fallbackServiceName,
),
),
ListTile(
leading: Icon(
Icons.access_time_outlined,
color: Theme.of(context).colorScheme.onSurface,
),
title: Text(
'backup.snapshot_creation_time_title'.tr(),
),
subtitle: Text(
'${MaterialLocalizations.of(context).formatShortDate(widget.snapshot.time)} ${TimeOfDay.fromDateTime(widget.snapshot.time).format(context)}',
),
),
ListTile(
leading: Icon(
Icons.numbers_outlined,
color: Theme.of(context).colorScheme.onSurface,
),
title: Text(
'backup.snapshot_id_title'.tr(),
),
subtitle: Text(
widget.snapshot.id,
),
),
if (service != null)
Column(
children: [
const SizedBox(height: 8),
Text(
'backup.snapshot_modal_select_strategy'.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
_BackupStrategySelectionCard(
isSelected: selectedStrategy ==
BackupRestoreStrategy.downloadVerifyOverwrite,
onTap: () {
setState(() {
selectedStrategy =
BackupRestoreStrategy.downloadVerifyOverwrite;
});
},
title:
'backup.snapshot_modal_download_verify_option_title'.tr(),
subtitle:
'backup.snapshot_modal_download_verify_option_description'
.tr(),
),
const SizedBox(height: 8),
_BackupStrategySelectionCard(
isSelected: selectedStrategy == BackupRestoreStrategy.inplace,
onTap: () {
setState(() {
selectedStrategy = BackupRestoreStrategy.inplace;
});
},
title: 'backup.snapshot_modal_inplace_option_title'.tr(),
subtitle:
'backup.snapshot_modal_inplace_option_description'.tr(),
),
const SizedBox(height: 8),
// Restore backup button
BrandButton.filled(
onPressed: isServiceBusy
? null
: () {
context.read<BackupsCubit>().restoreBackup(
widget.snapshot.id,
selectedStrategy,
);
Navigator.of(context).pop();
getIt<NavigationService>()
.showSnackBar('backup.restore_started'.tr());
},
text: 'backup.restore'.tr(),
),
],
)
else
Padding(
padding: const EdgeInsets.all(16.0),
child: InfoBox(
isWarning: true,
text: 'backup.snapshot_modal_service_not_found'.tr(),
),
)
],
);
}
}
class _BackupStrategySelectionCard extends StatelessWidget {
const _BackupStrategySelectionCard({
required this.isSelected,
required this.title,
required this.subtitle,
required this.onTap,
});
final bool isSelected;
final String title;
final String subtitle;
final void Function() onTap;
@override
Widget build(final BuildContext context) => OutlinedCard(
borderColor: isSelected ? Theme.of(context).colorScheme.primary : null,
borderWidth: isSelected ? 3 : 1,
child: InkResponse(
highlightShape: BoxShape.rectangle,
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
if (isSelected)
Icon(
Icons.radio_button_on_outlined,
color: Theme.of(context).colorScheme.primary,
)
else
Icon(
Icons.radio_button_off_outlined,
color: Theme.of(context).colorScheme.outline,
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: Theme.of(context).textTheme.bodyLarge,
),
Text(
subtitle,
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
),
],
),
),
),
);
}

View File

@ -55,6 +55,20 @@ class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
}); });
} }
bool get isVolumePicked {
bool isChangeFound = false;
for (final Service service in widget.services) {
for (final String serviceId in serviceToDisk.keys) {
if (serviceId == service.id &&
serviceToDisk[serviceId] != service.storageUsage.volume!) {
isChangeFound = true;
}
}
}
return isChangeFound;
}
/// Check the services and if a service is moved (in a serviceToDisk entry) /// Check the services and if a service is moved (in a serviceToDisk entry)
/// subtract the used storage from the old volume and add it to the new volume. /// subtract the used storage from the old volume and add it to the new volume.
/// The old volume is the volume the service is currently on, shown in services list. /// The old volume is the volume the service is currently on, shown in services list.
@ -157,40 +171,41 @@ class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
BrandButton.filled( if (widget.isMigration || (!widget.isMigration && isVolumePicked))
child: Text('storage.start_migration_button'.tr()), BrandButton.filled(
onPressed: () { child: Text('storage.start_migration_button'.tr()),
if (widget.isMigration) { onPressed: () {
context.read<ServerJobsCubit>().migrateToBinds( if (widget.isMigration) {
serviceToDisk, context.read<ServerJobsCubit>().migrateToBinds(
); serviceToDisk,
} else { );
for (final service in widget.services) { } else {
if (serviceToDisk[service.id] != null) { for (final service in widget.services) {
context.read<ServicesCubit>().moveService( if (serviceToDisk[service.id] != null) {
service.id, context.read<ServicesCubit>().moveService(
serviceToDisk[service.id]!, service.id,
); serviceToDisk[service.id]!,
);
}
} }
} }
} context.router.popUntilRoot();
context.router.popUntilRoot(); showModalBottomSheet(
showModalBottomSheet( context: context,
context: context, useRootNavigator: true,
useRootNavigator: true, isScrollControlled: true,
isScrollControlled: true, builder: (final BuildContext context) =>
builder: (final BuildContext context) => DraggableScrollableSheet(
DraggableScrollableSheet( expand: false,
expand: false, maxChildSize: 0.9,
maxChildSize: 0.9, minChildSize: 0.4,
minChildSize: 0.4, initialChildSize: 0.6,
initialChildSize: 0.6, builder: (final context, final scrollController) =>
builder: (final context, final scrollController) => JobsContent(controller: scrollController),
JobsContent(controller: scrollController), ),
), );
); },
}, ),
),
const SizedBox(height: 32), const SizedBox(height: 32),
], ],
), ),

View File

@ -109,6 +109,7 @@ class ProviderInputDataPage extends StatelessWidget {
), ),
const SizedBox(height: 32), const SizedBox(height: 32),
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: providerCubit.apiKey, formFieldCubit: providerCubit.apiKey,
textAlign: TextAlign.center, textAlign: TextAlign.center,
scrollPadding: const EdgeInsets.only(bottom: 70), scrollPadding: const EdgeInsets.only(bottom: 70),

View File

@ -273,6 +273,7 @@ class InitializingPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: context.read<BackblazeFormCubit>().keyId, formFieldCubit: context.read<BackblazeFormCubit>().keyId,
textAlign: TextAlign.center, textAlign: TextAlign.center,
scrollPadding: const EdgeInsets.only(bottom: 70), scrollPadding: const EdgeInsets.only(bottom: 70),
@ -448,6 +449,7 @@ class InitializingPage extends StatelessWidget {
), ),
const SizedBox(height: 32), const SizedBox(height: 32),
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: context.read<RootUserFormCubit>().userName, formFieldCubit: context.read<RootUserFormCubit>().userName,
textAlign: TextAlign.center, textAlign: TextAlign.center,
scrollPadding: const EdgeInsets.only(bottom: 70), scrollPadding: const EdgeInsets.only(bottom: 70),

View File

@ -116,6 +116,7 @@ class ProviderInputDataPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: providerCubit.apiKey, formFieldCubit: providerCubit.apiKey,
textAlign: TextAlign.center, textAlign: TextAlign.center,
scrollPadding: const EdgeInsets.only(bottom: 70), scrollPadding: const EdgeInsets.only(bottom: 70),

View File

@ -65,6 +65,7 @@ class RecoverByNewDeviceKeyInput extends StatelessWidget {
ignoreBreakpoints: true, ignoreBreakpoints: true,
children: [ children: [
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: formFieldCubit:
context.read<RecoveryDeviceFormCubit>().tokenField, context.read<RecoveryDeviceFormCubit>().tokenField,
decoration: InputDecoration( decoration: InputDecoration(

View File

@ -76,6 +76,7 @@ class RecoverByOldToken extends StatelessWidget {
ignoreBreakpoints: true, ignoreBreakpoints: true,
children: [ children: [
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: formFieldCubit:
context.read<RecoveryDeviceFormCubit>().tokenField, context.read<RecoveryDeviceFormCubit>().tokenField,
decoration: InputDecoration( decoration: InputDecoration(

View File

@ -36,6 +36,7 @@ class RecoverByRecoveryKey extends StatelessWidget {
context.read<ServerInstallationCubit>().revertRecoveryStep, context.read<ServerInstallationCubit>().revertRecoveryStep,
children: [ children: [
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: formFieldCubit:
context.read<RecoveryDeviceFormCubit>().tokenField, context.read<RecoveryDeviceFormCubit>().tokenField,
decoration: InputDecoration( decoration: InputDecoration(

View File

@ -36,6 +36,7 @@ class RecoveryConfirmBackblaze extends StatelessWidget {
hasFlashButton: false, hasFlashButton: false,
children: [ children: [
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: context.read<BackblazeFormCubit>().keyId, formFieldCubit: context.read<BackblazeFormCubit>().keyId,
decoration: const InputDecoration( decoration: const InputDecoration(
border: OutlineInputBorder(), border: OutlineInputBorder(),

View File

@ -39,6 +39,7 @@ class RecoveryConfirmDns extends StatelessWidget {
context.read<ServerInstallationCubit>().revertRecoveryStep, context.read<ServerInstallationCubit>().revertRecoveryStep,
children: [ children: [
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: context.read<DnsProviderFormCubit>().apiKey, formFieldCubit: context.read<DnsProviderFormCubit>().apiKey,
decoration: InputDecoration( decoration: InputDecoration(
border: const OutlineInputBorder(), border: const OutlineInputBorder(),

View File

@ -121,6 +121,7 @@ class SelectDomainToRecover extends StatelessWidget {
}, },
children: [ children: [
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: formFieldCubit:
context.read<RecoveryDomainFormCubit>().serverDomainField, context.read<RecoveryDomainFormCubit>().serverDomainField,
decoration: InputDecoration( decoration: InputDecoration(

View File

@ -38,6 +38,7 @@ class RecoveryServerProviderConnected extends StatelessWidget {
}, },
children: [ children: [
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: context.read<ServerProviderFormCubit>().apiKey, formFieldCubit: context.read<ServerProviderFormCubit>().apiKey,
decoration: InputDecoration( decoration: InputDecoration(
border: const OutlineInputBorder(), border: const OutlineInputBorder(),

View File

@ -55,6 +55,7 @@ class NewUserPage extends StatelessWidget {
const SizedBox(width: 14), const SizedBox(width: 14),
IntrinsicHeight( IntrinsicHeight(
child: CubitFormTextField( child: CubitFormTextField(
autofocus: true,
formFieldCubit: context.read<UserFormCubit>().login, formFieldCubit: context.read<UserFormCubit>().login,
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'users.login'.tr(), labelText: 'users.login'.tr(),

View File

@ -41,6 +41,7 @@ class ResetPassword extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
CubitFormTextField( CubitFormTextField(
autofocus: true,
formFieldCubit: formFieldCubit:
context.read<UserFormCubit>().password, context.read<UserFormCubit>().password,
decoration: InputDecoration( decoration: InputDecoration(

View File

@ -296,6 +296,7 @@ class NewSshKey extends StatelessWidget {
children: [ children: [
IntrinsicHeight( IntrinsicHeight(
child: CubitFormTextField( child: CubitFormTextField(
autofocus: true,
formFieldCubit: context.read<SshFormCubit>().key, formFieldCubit: context.read<SshFormCubit>().key,
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'ssh.input_label'.tr(), labelText: 'ssh.input_label'.tr(),