feat(backups): Add descriptions for backups

pull/228/head
Inex Code 2023-07-02 14:41:31 +03:00
parent b3b7c83461
commit 62b7a0ee7e
13 changed files with 121 additions and 55 deletions

View File

@ -1,10 +1,10 @@
import 'dart:async';
import 'disk_volumes.graphql.dart';
import 'package:gql/ast.dart';
import 'package:graphql/client.dart' as graphql;
import 'package:selfprivacy/utils/scalars.dart';
import 'schema.graphql.dart';
import 'server_api.graphql.dart';
import 'services.graphql.dart';
class Fragment$genericBackupConfigReturn {
Fragment$genericBackupConfigReturn({

View File

@ -3,7 +3,6 @@ import 'package:gql/ast.dart';
import 'package:graphql/client.dart' as graphql;
import 'schema.graphql.dart';
import 'server_api.graphql.dart';
import 'services.graphql.dart';
class Fragment$basicMutationReturnFields {
Fragment$basicMutationReturnFields({

View File

@ -255,6 +255,7 @@ type Service {
isRequired: Boolean!
isEnabled: Boolean!
canBeBackedUp: Boolean!
backupDescription: String!
status: ServiceStatusEnum!
url: String
dnsRecords: [DnsRecord!]

View File

@ -1,9 +1,9 @@
import 'dart:async';
import 'disk_volumes.graphql.dart';
import 'package:gql/ast.dart';
import 'package:graphql/client.dart' as graphql;
import 'package:selfprivacy/utils/scalars.dart';
import 'schema.graphql.dart';
import 'services.graphql.dart';
class Fragment$basicMutationReturnFields {
Fragment$basicMutationReturnFields({

View File

@ -1,8 +1,8 @@
import 'dart:async';
import 'disk_volumes.graphql.dart';
import 'package:gql/ast.dart';
import 'package:graphql/client.dart' as graphql;
import 'schema.graphql.dart';
import 'services.graphql.dart';
class Fragment$basicMutationReturnFields {
Fragment$basicMutationReturnFields({

View File

@ -17,6 +17,7 @@ query AllServices {
isMovable
isRequired
canBeBackedUp
backupDescription
status
storageUsage {
title

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'disk_volumes.graphql.dart';
import 'package:gql/ast.dart';
import 'package:graphql/client.dart' as graphql;
import 'schema.graphql.dart';
@ -2502,6 +2503,13 @@ const documentNodeQueryAllServices = DocumentNode(definitions: [
directives: [],
selectionSet: null,
),
FieldNode(
name: NameNode(value: 'backupDescription'),
alias: null,
arguments: [],
directives: [],
selectionSet: null,
),
FieldNode(
name: NameNode(value: 'status'),
alias: null,
@ -2884,6 +2892,7 @@ class Query$AllServices$services$allServices {
required this.isMovable,
required this.isRequired,
required this.canBeBackedUp,
required this.backupDescription,
required this.status,
required this.storageUsage,
required this.svgIcon,
@ -2901,6 +2910,7 @@ class Query$AllServices$services$allServices {
final l$isMovable = json['isMovable'];
final l$isRequired = json['isRequired'];
final l$canBeBackedUp = json['canBeBackedUp'];
final l$backupDescription = json['backupDescription'];
final l$status = json['status'];
final l$storageUsage = json['storageUsage'];
final l$svgIcon = json['svgIcon'];
@ -2918,6 +2928,7 @@ class Query$AllServices$services$allServices {
isMovable: (l$isMovable as bool),
isRequired: (l$isRequired as bool),
canBeBackedUp: (l$canBeBackedUp as bool),
backupDescription: (l$backupDescription as String),
status: fromJson$Enum$ServiceStatusEnum((l$status as String)),
storageUsage:
Query$AllServices$services$allServices$storageUsage.fromJson(
@ -2944,6 +2955,8 @@ class Query$AllServices$services$allServices {
final bool canBeBackedUp;
final String backupDescription;
final Enum$ServiceStatusEnum status;
final Query$AllServices$services$allServices$storageUsage storageUsage;
@ -2972,6 +2985,8 @@ class Query$AllServices$services$allServices {
_resultData['isRequired'] = l$isRequired;
final l$canBeBackedUp = canBeBackedUp;
_resultData['canBeBackedUp'] = l$canBeBackedUp;
final l$backupDescription = backupDescription;
_resultData['backupDescription'] = l$backupDescription;
final l$status = status;
_resultData['status'] = toJson$Enum$ServiceStatusEnum(l$status);
final l$storageUsage = storageUsage;
@ -2995,6 +3010,7 @@ class Query$AllServices$services$allServices {
final l$isMovable = isMovable;
final l$isRequired = isRequired;
final l$canBeBackedUp = canBeBackedUp;
final l$backupDescription = backupDescription;
final l$status = status;
final l$storageUsage = storageUsage;
final l$svgIcon = svgIcon;
@ -3009,6 +3025,7 @@ class Query$AllServices$services$allServices {
l$isMovable,
l$isRequired,
l$canBeBackedUp,
l$backupDescription,
l$status,
l$storageUsage,
l$svgIcon,
@ -3077,6 +3094,11 @@ class Query$AllServices$services$allServices {
if (l$canBeBackedUp != lOther$canBeBackedUp) {
return false;
}
final l$backupDescription = backupDescription;
final lOther$backupDescription = other.backupDescription;
if (l$backupDescription != lOther$backupDescription) {
return false;
}
final l$status = status;
final lOther$status = other.status;
if (l$status != lOther$status) {
@ -3134,6 +3156,7 @@ abstract class CopyWith$Query$AllServices$services$allServices<TRes> {
bool? isMovable,
bool? isRequired,
bool? canBeBackedUp,
String? backupDescription,
Enum$ServiceStatusEnum? status,
Query$AllServices$services$allServices$storageUsage? storageUsage,
String? svgIcon,
@ -3172,6 +3195,7 @@ class _CopyWithImpl$Query$AllServices$services$allServices<TRes>
Object? isMovable = _undefined,
Object? isRequired = _undefined,
Object? canBeBackedUp = _undefined,
Object? backupDescription = _undefined,
Object? status = _undefined,
Object? storageUsage = _undefined,
Object? svgIcon = _undefined,
@ -3201,6 +3225,10 @@ class _CopyWithImpl$Query$AllServices$services$allServices<TRes>
canBeBackedUp: canBeBackedUp == _undefined || canBeBackedUp == null
? _instance.canBeBackedUp
: (canBeBackedUp as bool),
backupDescription:
backupDescription == _undefined || backupDescription == null
? _instance.backupDescription
: (backupDescription as String),
status: status == _undefined || status == null
? _instance.status
: (status as Enum$ServiceStatusEnum),
@ -3251,6 +3279,7 @@ class _CopyWithStubImpl$Query$AllServices$services$allServices<TRes>
bool? isMovable,
bool? isRequired,
bool? canBeBackedUp,
String? backupDescription,
Enum$ServiceStatusEnum? status,
Query$AllServices$services$allServices$storageUsage? storageUsage,
String? svgIcon,

View File

@ -1,8 +1,8 @@
import 'dart:async';
import 'disk_volumes.graphql.dart';
import 'package:gql/ast.dart';
import 'package:graphql/client.dart' as graphql;
import 'schema.graphql.dart';
import 'services.graphql.dart';
class Fragment$basicMutationReturnFields {
Fragment$basicMutationReturnFields({

View File

@ -30,6 +30,7 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
final BackupConfiguration? backupConfig =
await api.getBackupsConfiguration();
final List<Backup> backups = await api.getBackups();
backups.sort((final a, final b) => b.time.compareTo(a.time));
emit(
state.copyWith(
backblazeBucket: bucket,
@ -144,6 +145,7 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
Future<void> updateBackups({final bool useTimer = false}) async {
emit(state.copyWith(refreshing: true));
final backups = await api.getBackups();
backups.sort((final a, final b) => b.time.compareTo(a.time));
final backupConfig = await api.getBackupsConfiguration();
emit(

View File

@ -25,7 +25,7 @@ class BackupsState extends ServerInstallationDependendState {
backups,
preventActions,
refreshTimer,
refreshing
refreshing,
];
BackupsState copyWith({

View File

@ -18,6 +18,7 @@ class Service {
isRequired: service.isRequired,
isMovable: service.isMovable,
canBeBackedUp: service.canBeBackedUp,
backupDescription: service.backupDescription,
status: ServiceStatus.fromGraphQL(service.status),
storageUsage: ServiceStorageUsage(
used: DiskSize(byte: int.parse(service.storageUsage.usedSpace)),
@ -44,6 +45,7 @@ class Service {
required this.isRequired,
required this.isMovable,
required this.canBeBackedUp,
required this.backupDescription,
required this.status,
required this.storageUsage,
required this.svgIcon,
@ -78,6 +80,7 @@ class Service {
isRequired: false,
isMovable: false,
canBeBackedUp: false,
backupDescription: '',
status: ServiceStatus.off,
storageUsage: ServiceStorageUsage(
used: const DiskSize(byte: 0),
@ -95,6 +98,7 @@ class Service {
final bool isRequired;
final bool isMovable;
final bool canBeBackedUp;
final String backupDescription;
final ServiceStatus status;
final ServiceStorageUsage storageUsage;
final String svgIcon;

View File

@ -147,7 +147,8 @@ class _HeroSliverAppBarState extends State<HeroSliverAppBar> {
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (final BuildContext context) => DraggableScrollableSheet(
builder: (final BuildContext context) =>
DraggableScrollableSheet(
expand: false,
maxChildSize: 0.9,
minChildSize: 0.4,

View File

@ -93,59 +93,88 @@ class _BackupDetailsPageState extends State<BackupDetailsPage>
// Each list item has a date
// When clicked, starts the restore action
if (isBackupInitialized)
OutlinedCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
title: Text(
'backups.latest_snapshots'.tr(),
style: Theme.of(context).textTheme.headlineSmall!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
subtitle: Text(
'backups.latest_snapshots_subtitle'.tr(),
style: Theme.of(context).textTheme.labelMedium,
),
),
if (backups.isEmpty)
ListTile(
leading: const Icon(
Icons.refresh,
),
title: Text(
'backup.restore'.tr(),
style: Theme.of(context).textTheme.titleLarge,
Icons.error_outline,
),
title: Text('backup.no_backups'.tr()),
),
const Divider(
height: 1.0,
),
if (backups.isEmpty)
ListTile(
leading: const Icon(
Icons.error_outline,
),
title: Text('backup.no_backups'.tr()),
),
if (backups.isNotEmpty)
Column(
children: backups
.map(
(final Backup backup) => ListTile(
onTap: preventActions
? null
: () {
showPopUpAlert(
alertTitle: 'backup.restoring'.tr(),
description: 'backup.restore_alert'.tr(
args: [backup.time.toString()],
),
actionButtonTitle: 'modals.yes'.tr(),
actionButtonOnPressed: () => {
context
.read<BackupsCubit>()
.restoreBackup(backup.id)
},
);
if (backups.isNotEmpty)
Column(
children: backups.take(20).map(
(final Backup backup) {
final service = context
.read<ServicesCubit>()
.state
.getServiceById(backup.serviceId);
return ListTile(
onTap: preventActions
? null
: () {
showPopUpAlert(
alertTitle: 'backup.restoring'.tr(),
description: 'backup.restore_alert'.tr(
args: [backup.time.toString()],
),
actionButtonTitle: 'modals.yes'.tr(),
actionButtonOnPressed: () => {
context
.read<BackupsCubit>()
.restoreBackup(backup.id)
},
title: Text(
'${MaterialLocalizations.of(context).formatShortDate(backup.time)} ${TimeOfDay.fromDateTime(backup.time).format(context)}',
),
),
)
.toList(),
);
},
title: Text(
'${MaterialLocalizations.of(context).formatShortDate(backup.time)} ${TimeOfDay.fromDateTime(backup.time).format(context)}',
),
subtitle: Text(
service?.displayName ?? backup.fallbackServiceName,
),
leading: service != null
? SvgPicture.string(
service.svgIcon,
height: 24,
width: 24,
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.onBackground,
BlendMode.srcIn,
),
)
: const Icon(
Icons.question_mark_outlined,
),
);
},
).toList(),
),
if (backups.isNotEmpty && backups.length > 20)
ListTile(
title: Text(
'backups.show_more'.tr(),
style: Theme.of(context).textTheme.labelMedium,
),
],
),
leading: const Icon(
Icons.arrow_drop_down,
),
onTap: null,
)
],
),
const SizedBox(height: 16),
OutlinedCard(
@ -317,7 +346,7 @@ class _CreateBackupsModalState extends State<CreateBackupsModal> {
service.displayName,
),
subtitle: Text(
busy ? 'backup.service_busy'.tr() : service.description,
busy ? 'backup.service_busy'.tr() : service.backupDescription,
),
secondary: SvgPicture.string(
service.svgIcon,