Add job status to maintenance menu

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/25/head
trivernis 2 years ago
parent 6dfefe01c2
commit 5dd8eefdcc
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -1,6 +1,6 @@
[package]
name = "mediarepo-api"
version = "0.32.0"
version = "0.32.1"
edition = "2018"
license = "gpl-3"

@ -34,4 +34,10 @@ impl JobApi {
Ok(())
}
/// Checks if a particular job is already running
#[tracing::instrument(level = "debug", skip(self))]
pub async fn is_job_running(&self, job_type: JobType) -> ApiResult<bool> {
self.emit_and_get("is_job_running", job_type, None).await
}
}

@ -9,3 +9,11 @@ pub async fn run_job(api_state: ApiAccess<'_>, job_type: JobType, sync: bool) ->
Ok(())
}
#[tauri::command]
pub async fn is_job_running(api_state: ApiAccess<'_>, job_type: JobType) -> PluginResult<bool> {
let api = api_state.api().await?;
let running = api.job.is_job_running(job_type).await?;
Ok(running)
}

@ -75,7 +75,8 @@ impl<R: Runtime> MediarepoPlugin<R> {
get_file_tag_map,
all_sorting_presets,
add_sorting_preset,
delete_sorting_preset
delete_sorting_preset,
is_job_running
]),
}
}

@ -20,8 +20,9 @@ impl NamespaceProvider for JobsNamespace {
fn register(handler: &mut EventHandler) {
events!(handler,
"run_job" => Self::run_job
)
"run_job" => Self::run_job,
"is_job_running" => Self::is_job_running
);
}
}
@ -59,6 +60,26 @@ impl JobsNamespace {
Ok(Response::empty())
}
#[tracing::instrument(skip_all)]
pub async fn is_job_running(ctx: &Context, event: Event) -> IPCResult<Response> {
let job_type = event.payload::<JobType>()?;
let dispatcher = get_job_dispatcher_from_context(ctx).await;
let running = match job_type {
JobType::MigrateContentDescriptors => {
is_job_running::<MigrateCDsJob>(&dispatcher).await
}
JobType::CalculateSizes => is_job_running::<CalculateSizesJob>(&dispatcher).await,
JobType::GenerateThumbnails => {
is_job_running::<GenerateMissingThumbsJob>(&dispatcher).await
}
JobType::CheckIntegrity => is_job_running::<CheckIntegrityJob>(&dispatcher).await,
JobType::Vacuum => is_job_running::<VacuumJob>(&dispatcher).await,
};
Response::payload(&ctx, running)
}
}
async fn dispatch_job<J: 'static + Job>(
@ -107,3 +128,12 @@ async fn calculate_all_sizes(ctx: &Context) -> RepoResult<()> {
Ok(())
}
async fn is_job_running<T: 'static + Job>(dispatcher: &JobDispatcher) -> bool {
if let Some(handle) = dispatcher.get_handle::<T>().await {
let state = handle.state().await;
state == JobState::Running
} else {
false
}
}

@ -19,6 +19,7 @@ import {
GetSizeRequest,
GetTagsForFilesRequest,
InitRepositoryRequest,
IsJobRunningRequest,
ReadFileRequest,
RemoveRepositoryRequest,
ResolvePathsToFilesRequest,
@ -187,6 +188,10 @@ export class MediarepoApi {
return this.invokePlugin(ApiFunction.RunJob, request);
}
public static async isJobRunning(request: IsJobRunningRequest): Promise<boolean> {
return this.invokePlugin(ApiFunction.IsJobRunning, request);
}
public static async getAllSortingPresets(): Promise<SortingPresetData[]> {
return ShortCache.cached("sorting-presets", () => this.invokePlugin(ApiFunction.GetAllSortingPresets), 1000);
}

@ -40,6 +40,7 @@ export enum ApiFunction {
SetFrontendState = "set_frontend_state",
// jobs
RunJob = "run_job",
IsJobRunning = "is_job_running",
// presets
GetAllSortingPresets = "all_sorting_presets",
AddSortingPreset = "add_sorting_preset",

@ -117,3 +117,7 @@ export type AddSortingPresetRequest = {
export type DeleteSortingPresetRequest = {
id: number
};
export type IsJobRunningRequest = {
jobType: JobType,
}

@ -17,7 +17,7 @@ import {MatSelectModule} from "@angular/material/select";
import {MatCheckboxModule} from "@angular/material/checkbox";
import {MatDividerModule} from "@angular/material/divider";
import {NgIconsModule} from "@ng-icons/core";
import {MatPlus} from "@ng-icons/material-icons/baseline";
import {MatMoreVert, MatPlus} from "@ng-icons/material-icons/baseline";
import {MatMenuModule} from "@angular/material/menu";
import {InputModule} from "../shared/input/input.module";
import {SidebarModule} from "../shared/sidebar/sidebar.module";
@ -72,7 +72,7 @@ import {AboutDialogComponent} from "./repositories-tab/repository-overview/about
MatProgressBarModule,
MatCheckboxModule,
ScrollingModule,
NgIconsModule.withIcons({ MatPlus }),
NgIconsModule.withIcons({ MatPlus, MatMoreVert }),
FlexModule,
MatButtonModule,
MatMenuModule,

@ -1,4 +1,4 @@
import {ChangeDetectionStrategy, ChangeDetectorRef, Component} from "@angular/core";
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit} from "@angular/core";
import {JobService} from "../../../../services/job/job.service";
import {JobType} from "../../../../../api/api-types/job";
import {MatDialog} from "@angular/material/dialog";
@ -13,12 +13,12 @@ import {BehaviorSubject} from "rxjs";
styleUrls: ["./repository-maintenance.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class RepositoryMaintenanceComponent {
export class RepositoryMaintenanceComponent implements OnInit, OnDestroy {
public jobState: { [Property in JobType]?: boolean } = {
CalculateSizes: false,
GenerateThumbnails: false,
};
private jobStatusInterval: any;
constructor(
private changeDetector: ChangeDetectorRef,
@ -28,14 +28,23 @@ export class RepositoryMaintenanceComponent {
) {
}
public ngOnDestroy(): void {
clearInterval(this.jobStatusInterval);
}
public async ngOnInit() {
await this.updateJobStatus();
this.jobStatusInterval = setInterval(() => this.updateJobStatus(), 10000);
}
public async runJob(jobType: JobType, runAsync: boolean) {
if (runAsync) {
this.jobState[jobType] = true;
this.jobService.runJob(jobType).then(() => this.delay(1000)).catch(this.logger.error).finally(() => {
this.jobState[jobType] = false;
this.changeDetector.detectChanges();
this.changeDetector.markForCheck();
});
this.changeDetector.detectChanges();
this.changeDetector.markForCheck();
} else {
const dialog = this.dialog.open<BusyDialogComponent, BusyDialogData>(BusyDialogComponent, {
disableClose: true,
@ -48,13 +57,13 @@ export class RepositoryMaintenanceComponent {
}
});
try {
this.changeDetector.detectChanges();
this.changeDetector.markForCheck();
await this.jobService.runJob(jobType);
} catch (err: any) {
this.logger.error(err);
} finally {
dialog.close();
this.changeDetector.detectChanges();
this.changeDetector.markForCheck();
}
}
}
@ -65,4 +74,12 @@ export class RepositoryMaintenanceComponent {
ms
));
}
private async updateJobStatus() {
const indexedTypes: JobType[] = ["CalculateSizes", "GenerateThumbnails"];
for (const jobType of indexedTypes) {
this.jobState[jobType] = await this.jobService.isJobRunning(jobType);
}
this.changeDetector.markForCheck();
}
}

@ -13,4 +13,8 @@ export class JobService {
public async runJob(jobType: JobType, sync: boolean = true): Promise<void> {
return MediarepoApi.runJob({ jobType, sync });
}
public async isJobRunning(jobType: JobType): Promise<boolean> {
return MediarepoApi.isJobRunning({ jobType });
}
}

Loading…
Cancel
Save