mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-28 19:56:50 +00:00
Allow removing completed and failed server jobs
This commit is contained in:
parent
19aab4b57f
commit
e330878e6d
|
@ -482,7 +482,8 @@
|
||||||
"upgradeServer": "Обновить сервер",
|
"upgradeServer": "Обновить сервер",
|
||||||
"rebootServer": "Перезагрузить сервер",
|
"rebootServer": "Перезагрузить сервер",
|
||||||
"create_ssh_key": "Создать SSH ключ для {}",
|
"create_ssh_key": "Создать SSH ключ для {}",
|
||||||
"delete_ssh_key": "Удалить SSH ключ для {}"
|
"delete_ssh_key": "Удалить SSH ключ для {}",
|
||||||
|
"server_jobs": "Задачи на сервере"
|
||||||
},
|
},
|
||||||
"validations": {
|
"validations": {
|
||||||
"required": "Обязательное поле.",
|
"required": "Обязательное поле.",
|
||||||
|
|
|
@ -22,14 +22,24 @@ mixin JobsApi on ApiMap {
|
||||||
return jobsList;
|
return jobsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> removeApiJob(final String uid) async {
|
Future<GenericMutationResult> removeApiJob(final String uid) async {
|
||||||
try {
|
try {
|
||||||
final GraphQLClient client = await getClient();
|
final GraphQLClient client = await getClient();
|
||||||
final variables = Variables$Mutation$RemoveJob(jobId: uid);
|
final variables = Variables$Mutation$RemoveJob(jobId: uid);
|
||||||
final mutation = Options$Mutation$RemoveJob(variables: variables);
|
final mutation = Options$Mutation$RemoveJob(variables: variables);
|
||||||
await client.mutate$RemoveJob(mutation);
|
final response = await client.mutate$RemoveJob(mutation);
|
||||||
|
return GenericMutationResult(
|
||||||
|
success: response.parsedData?.removeJob.success ?? false,
|
||||||
|
code: response.parsedData?.removeJob.code ?? 0,
|
||||||
|
message: response.parsedData?.removeJob.message,
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
|
return GenericMutationResult(
|
||||||
|
success: false,
|
||||||
|
code: 0,
|
||||||
|
message: e.toString(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ class ServerJobsCubit
|
||||||
ServerJobsCubit(final ServerInstallationCubit serverInstallationCubit)
|
ServerJobsCubit(final ServerInstallationCubit serverInstallationCubit)
|
||||||
: super(
|
: super(
|
||||||
serverInstallationCubit,
|
serverInstallationCubit,
|
||||||
const ServerJobsState(),
|
ServerJobsState(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Timer? timer;
|
Timer? timer;
|
||||||
|
@ -23,7 +23,7 @@ class ServerJobsCubit
|
||||||
@override
|
@override
|
||||||
void clear() async {
|
void clear() async {
|
||||||
emit(
|
emit(
|
||||||
const ServerJobsState(),
|
ServerJobsState(),
|
||||||
);
|
);
|
||||||
if (timer != null && timer!.isActive) {
|
if (timer != null && timer!.isActive) {
|
||||||
timer!.cancel();
|
timer!.cancel();
|
||||||
|
@ -40,7 +40,7 @@ class ServerJobsCubit
|
||||||
serverJobList: jobs,
|
serverJobList: jobs,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
timer = Timer(const Duration(seconds: 10), () => reload(useTimer: true));
|
timer = Timer(const Duration(seconds: 5), () => reload(useTimer: true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +72,44 @@ class ServerJobsCubit
|
||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the job object and change its isHidden to true.
|
||||||
|
/// Emit the new state.
|
||||||
|
/// Call the api to remove the job.
|
||||||
|
/// If the api call fails, change the isHidden to false and emit the new state.
|
||||||
|
/// If the api call succeeds, remove the job from the list and emit the new state.
|
||||||
|
Future<void> removeServerJob(final String uid) async {
|
||||||
|
final ServerJob? job = getServerJobByUid(uid);
|
||||||
|
if (job == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
job.isHidden = true;
|
||||||
|
emit(
|
||||||
|
ServerJobsState(
|
||||||
|
serverJobList: state.serverJobList,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await api.removeApiJob(uid);
|
||||||
|
if (!result.success) {
|
||||||
|
job.isHidden = false;
|
||||||
|
emit(
|
||||||
|
ServerJobsState(
|
||||||
|
serverJobList: state.serverJobList,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
getIt<NavigationService>().showSnackBar(result.message!);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.serverJobList.remove(job);
|
||||||
|
emit(
|
||||||
|
ServerJobsState(
|
||||||
|
serverJobList: state.serverJobList,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> reload({final bool useTimer = false}) async {
|
Future<void> reload({final bool useTimer = false}) async {
|
||||||
final List<ServerJob> jobs = await api.getServerJobs();
|
final List<ServerJob> jobs = await api.getServerJobs();
|
||||||
emit(
|
emit(
|
||||||
|
@ -80,7 +118,7 @@ class ServerJobsCubit
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (useTimer) {
|
if (useTimer) {
|
||||||
timer = Timer(const Duration(seconds: 10), () => reload(useTimer: true));
|
timer = Timer(const Duration(seconds: 5), () => reload(useTimer: true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,28 @@
|
||||||
part of 'server_jobs_cubit.dart';
|
part of 'server_jobs_cubit.dart';
|
||||||
|
|
||||||
class ServerJobsState extends ServerInstallationDependendState {
|
class ServerJobsState extends ServerInstallationDependendState {
|
||||||
const ServerJobsState({
|
ServerJobsState({
|
||||||
this.serverJobList = const [],
|
final serverJobList = const <ServerJob>[],
|
||||||
this.migrationJobUid,
|
this.migrationJobUid,
|
||||||
});
|
}) {
|
||||||
final List<ServerJob> serverJobList;
|
_serverJobList = serverJobList;
|
||||||
|
}
|
||||||
|
|
||||||
|
late final List<ServerJob> _serverJobList;
|
||||||
final String? migrationJobUid;
|
final String? migrationJobUid;
|
||||||
|
|
||||||
|
List<ServerJob> get serverJobList =>
|
||||||
|
_serverJobList.where((final ServerJob job) => !job.isHidden).toList();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [migrationJobUid, ...serverJobList];
|
List<Object?> get props => [migrationJobUid, ..._serverJobList];
|
||||||
|
|
||||||
ServerJobsState copyWith({
|
ServerJobsState copyWith({
|
||||||
final List<ServerJob>? serverJobList,
|
final List<ServerJob>? serverJobList,
|
||||||
final String? migrationJobUid,
|
final String? migrationJobUid,
|
||||||
}) =>
|
}) =>
|
||||||
ServerJobsState(
|
ServerJobsState(
|
||||||
serverJobList: serverJobList ?? this.serverJobList,
|
serverJobList: serverJobList ?? _serverJobList,
|
||||||
migrationJobUid: migrationJobUid ?? this.migrationJobUid,
|
migrationJobUid: migrationJobUid ?? this.migrationJobUid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ class ServerJob {
|
||||||
final String? result;
|
final String? result;
|
||||||
final String? statusText;
|
final String? statusText;
|
||||||
final DateTime? finishedAt;
|
final DateTime? finishedAt;
|
||||||
|
bool isHidden = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum JobStatusEnum {
|
enum JobStatusEnum {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.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/server_jobs/server_jobs_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
||||||
import 'package:selfprivacy/ui/components/action_button/action_button.dart';
|
import 'package:selfprivacy/ui/components/action_button/action_button.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_alert/brand_alert.dart';
|
import 'package:selfprivacy/ui/components/brand_alert/brand_alert.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
||||||
|
@ -18,7 +19,11 @@ class JobsContent extends StatelessWidget {
|
||||||
const JobsContent({final super.key});
|
const JobsContent({final super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(final BuildContext context) => BlocBuilder<JobsCubit, JobsState>(
|
Widget build(final BuildContext context) {
|
||||||
|
final List<ServerJob> serverJobs =
|
||||||
|
context.watch<ServerJobsCubit>().state.serverJobList;
|
||||||
|
|
||||||
|
return BlocBuilder<JobsCubit, JobsState>(
|
||||||
builder: (final context, final state) {
|
builder: (final context, final state) {
|
||||||
late List<Widget> widgets;
|
late List<Widget> widgets;
|
||||||
final ServerInstallationState installationState =
|
final ServerInstallationState installationState =
|
||||||
|
@ -81,8 +86,7 @@ class JobsContent extends StatelessWidget {
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
primary:
|
primary: Theme.of(context).colorScheme.errorContainer,
|
||||||
Theme.of(context).colorScheme.errorContainer,
|
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
),
|
),
|
||||||
|
@ -92,9 +96,8 @@ class JobsContent extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
'basis.remove'.tr(),
|
'basis.remove'.tr(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context)
|
color:
|
||||||
.colorScheme
|
Theme.of(context).colorScheme.onErrorContainer,
|
||||||
.onErrorContainer,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -121,15 +124,34 @@ class JobsContent extends StatelessWidget {
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
...widgets,
|
...widgets,
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const Divider(),
|
const Divider(height: 0),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
...context.read<ServerJobsCubit>().state.serverJobList.map(
|
Padding(
|
||||||
(final job) => ServerJobCard(
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'jobs.server_jobs'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...serverJobs.map(
|
||||||
|
(final job) => Dismissible(
|
||||||
|
key: ValueKey(job.uid),
|
||||||
|
direction: job.status == JobStatusEnum.finished ||
|
||||||
|
job.status == JobStatusEnum.error
|
||||||
|
? DismissDirection.horizontal
|
||||||
|
: DismissDirection.none,
|
||||||
|
child: ServerJobCard(
|
||||||
serverJob: job,
|
serverJob: job,
|
||||||
),
|
),
|
||||||
|
onDismissed: (final direction) {
|
||||||
|
context.read<ServerJobsCubit>().removeServerJob(job.uid);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue