import React, { useState, useEffect } from "react"; import { Button, Form, ProgressBar } from "react-bootstrap"; import { Link } from "react-router-dom"; import { StashService } from "src/core/StashService"; import { useToast } from "src/hooks"; import { Modal } from "src/components/Shared"; import { GenerateButton } from "./GenerateButton"; export const SettingsTasksPanel: React.FC = () => { const Toast = useToast(); const [isImportAlertOpen, setIsImportAlertOpen] = useState(false); const [isCleanAlertOpen, setIsCleanAlertOpen] = useState(false); const [useFileMetadata, setUseFileMetadata] = useState(false); const [status, setStatus] = useState(""); const [progress, setProgress] = useState(0); const [autoTagPerformers, setAutoTagPerformers] = useState(true); const [autoTagStudios, setAutoTagStudios] = useState(true); const [autoTagTags, setAutoTagTags] = useState(true); const jobStatus = StashService.useJobStatus(); const metadataUpdate = StashService.useMetadataUpdate(); function statusToText(s: string) { switch (s) { case "Idle": return "Idle"; case "Scan": return "Scanning for new content"; case "Generate": return "Generating supporting files"; case "Clean": return "Cleaning the database"; case "Export": return "Exporting to JSON"; case "Import": return "Importing from JSON"; case "Auto Tag": return "Auto tagging scenes"; default: return "Idle"; } } useEffect(() => { if (jobStatus?.data?.jobStatus) { setStatus(statusToText(jobStatus.data.jobStatus.status)); const newProgress = jobStatus.data.jobStatus.progress; if (newProgress < 0) { setProgress(0); } else { setProgress(newProgress * 100); } } }, [jobStatus]); useEffect(() => { if (metadataUpdate?.data?.metadataUpdate) { setStatus(statusToText(metadataUpdate.data.metadataUpdate.status)); const newProgress = metadataUpdate.data.metadataUpdate.progress; if (newProgress < 0) { setProgress(0); } else { setProgress(newProgress * 100); } } }, [metadataUpdate]); function onImport() { setIsImportAlertOpen(false); StashService.mutateMetadataImport().then(() => { jobStatus.refetch(); }); } function renderImportAlert() { return ( setIsImportAlertOpen(false) }} >

Are you sure you want to import? This will delete the database and re-import from your exported metadata.

); } function onClean() { setIsCleanAlertOpen(false); StashService.mutateMetadataClean().then(() => { jobStatus.refetch(); }); } function renderCleanAlert() { return ( setIsCleanAlertOpen(false) }} >

Are you sure you want to Clean? This will delete database information and generated content for all scenes and galleries that are no longer found in the filesystem.

); } async function onScan() { try { await StashService.mutateMetadataScan({ useFileMetadata }); Toast.success({ content: "Started scan" }); jobStatus.refetch(); } catch (e) { Toast.error(e); } } function getAutoTagInput() { const wildcard = ["*"]; return { performers: autoTagPerformers ? wildcard : [], studios: autoTagStudios ? wildcard : [], tags: autoTagTags ? wildcard : [], }; } async function onAutoTag() { try { await StashService.mutateMetadataAutoTag(getAutoTagInput()); Toast.success({ content: "Started auto tagging" }); jobStatus.refetch(); } catch (e) { Toast.error(e); } } function maybeRenderStop() { if (!status || status === "Idle") { return undefined; } return ( ); } function renderJobStatus() { return ( <>
Status: {status}
{!!status && status !== "Idle" ? ( ) : ( "" )}
{maybeRenderStop()} ); } return ( <> {renderImportAlert()} {renderCleanAlert()}

Running Jobs

{renderJobStatus()}
Library
setUseFileMetadata(!useFileMetadata)} /> Scan for new content and add it to the database.
Auto Tagging
setAutoTagPerformers(!autoTagPerformers)} /> setAutoTagStudios(!autoTagStudios)} /> setAutoTagTags(!autoTagTags)} /> Auto-tag content based on filenames.
Generated Content
Check for missing files and remove them from the database. This is a destructive action.
Metadata
Export the database content into JSON format. Import from exported JSON. This is a destructive action. ); };