chore: initialize repository baseline
Import the existing Electron + React + TypeScript app as the version-control baseline before the scanner rework (C# input/capture sidecar, resolution-anchored layout profiles, OCR preprocessing, eval harness, rescan-merge, GOOD interop). Housekeeping in this commit: - Remove orphaned temp_inputhelper_block.ts (duplicate of the input-helper script). - Ignore .claude/scheduled_tasks.lock local session state. - Add .gitattributes to normalize line endings (LF in repo). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
import { useCallback, useEffect, useMemo } from "react";
|
||||
import type { Dispatch, MutableRefObject, SetStateAction } from "react";
|
||||
import { runAutoReviewScan as runAutoReviewScanAction, runVisibleGridScan as runVisibleGridScanAction } from "./scanViewScanActions";
|
||||
import {
|
||||
initializeLearningState,
|
||||
loadReviewQueue as loadReviewQueueFromRepo,
|
||||
persistParsedArtifact as persistParsedArtifactHelper,
|
||||
saveReviewSample as saveReviewSampleHelper,
|
||||
} from "./scanViewReviewHelpers";
|
||||
import { createReviewContext, createScanActionContext } from "./scanViewControllerService";
|
||||
import { useScanCommandListener } from "./useScanCommandListener";
|
||||
import type { ParsedArtifactCandidate } from "../../../lib/artifactOcrParser";
|
||||
import type { ScannerLearningRules } from "../../../lib/scannerLearning";
|
||||
import type { BooleanResult, CaptureOptions, CaptureResult, ClickResult, ReviewSampleRecord } from "../../../types/global";
|
||||
import type {
|
||||
ArtifactRepositoryPort,
|
||||
ReviewSampleRepositoryPort,
|
||||
LearningRepositoryPort,
|
||||
RuntimeRepositoryPort,
|
||||
AutomationRepositoryPort,
|
||||
} from "../../../infrastructure/repositories/rendererBridgeRepositoryTypes";
|
||||
import type { AutoScanStats, ScanSummary } from "../../../lib/scannerSession";
|
||||
import type { RuntimeInfo } from "../../../types/global";
|
||||
|
||||
type BooleanSetter = Dispatch<SetStateAction<boolean>>;
|
||||
type NumberSetter = Dispatch<SetStateAction<number>>;
|
||||
type StringSetter = Dispatch<SetStateAction<string>>;
|
||||
type NumberOrNullSetter = Dispatch<SetStateAction<number | null>>;
|
||||
type ScannerRulesSetter = Dispatch<SetStateAction<ScannerLearningRules>>;
|
||||
type ReviewSamplesSetter = Dispatch<SetStateAction<ReviewSampleRecord[]>>;
|
||||
type ScanSummarySetter = Dispatch<SetStateAction<ScanSummary | null>>;
|
||||
type AutoScanStatsSetter = Dispatch<SetStateAction<AutoScanStats>>;
|
||||
|
||||
interface ScanViewActionInput {
|
||||
autoScanRunning: boolean;
|
||||
setAutoScanRunning: BooleanSetter;
|
||||
isScanning: boolean;
|
||||
stopVisibleScanRef: MutableRefObject<boolean>;
|
||||
selectedSourceId: string;
|
||||
bridgeReady: boolean;
|
||||
automationRepo?: AutomationRepositoryPort;
|
||||
runtimeInfo?: RuntimeInfo | null;
|
||||
runtimeRepo?: RuntimeRepositoryPort;
|
||||
scanLimit: number;
|
||||
skipRows: number;
|
||||
detectedInventoryCount: number;
|
||||
setScanSummary: ScanSummarySetter;
|
||||
setAutoScanStats: AutoScanStatsSetter;
|
||||
setReviewStatus: StringSetter;
|
||||
appendAutomationLog: (line: string) => void;
|
||||
appendClickDiagnostics: (result: ClickResult, prefix?: string) => void;
|
||||
parseArtifact: (capture: CaptureResult | null) => ParsedArtifactCandidate | null;
|
||||
artifactRepo?: ArtifactRepositoryPort;
|
||||
reviewSamplesRepo?: ReviewSampleRepositoryPort;
|
||||
learningRepo?: LearningRepositoryPort;
|
||||
onStoredArtifactsChanged?: (() => Promise<void>) | (() => void);
|
||||
setReviewSampleTotal: NumberSetter;
|
||||
setReviewSamples: ReviewSamplesSetter;
|
||||
setLearningRulesLoaded: BooleanSetter;
|
||||
setScannerLearningRules: ScannerRulesSetter;
|
||||
setStoredTotal: NumberOrNullSetter;
|
||||
scannerLearningRules: ScannerLearningRules;
|
||||
captureSelectedSource: (delayMs?: number, focusGenshin?: boolean, options?: CaptureOptions) => Promise<CaptureResult | null>;
|
||||
latestCapture: CaptureResult | null;
|
||||
parsedArtifact: ParsedArtifactCandidate | null;
|
||||
canCaptureSource: boolean;
|
||||
setReviewQueueOpen: BooleanSetter;
|
||||
}
|
||||
|
||||
export interface ScanViewActionResult {
|
||||
requestScanStop: (reason?: string) => void;
|
||||
saveReviewSample: (
|
||||
capture?: CaptureResult | null,
|
||||
parsed?: ParsedArtifactCandidate | null,
|
||||
reason?: string,
|
||||
) => Promise<BooleanResult | null>;
|
||||
loadReviewQueue: () => Promise<void>;
|
||||
openReviewQueue: () => Promise<void>;
|
||||
runAutoReviewScan: () => Promise<void>;
|
||||
runVisibleGridScan: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function useScanViewActions(input: ScanViewActionInput): ScanViewActionResult {
|
||||
const {
|
||||
autoScanRunning,
|
||||
setAutoScanRunning,
|
||||
isScanning,
|
||||
stopVisibleScanRef,
|
||||
selectedSourceId,
|
||||
bridgeReady,
|
||||
automationRepo,
|
||||
runtimeInfo,
|
||||
runtimeRepo,
|
||||
scanLimit,
|
||||
skipRows,
|
||||
detectedInventoryCount,
|
||||
setScanSummary,
|
||||
setAutoScanStats,
|
||||
setReviewStatus,
|
||||
appendAutomationLog,
|
||||
appendClickDiagnostics,
|
||||
parseArtifact,
|
||||
artifactRepo,
|
||||
reviewSamplesRepo,
|
||||
learningRepo,
|
||||
onStoredArtifactsChanged,
|
||||
setReviewSampleTotal,
|
||||
setReviewSamples,
|
||||
setLearningRulesLoaded,
|
||||
setScannerLearningRules,
|
||||
setStoredTotal,
|
||||
scannerLearningRules,
|
||||
captureSelectedSource,
|
||||
latestCapture,
|
||||
parsedArtifact,
|
||||
canCaptureSource,
|
||||
setReviewQueueOpen,
|
||||
} = input;
|
||||
|
||||
const requestScanStop = useCallback((reason = "Stop angefordert.") => {
|
||||
stopVisibleScanRef.current = true;
|
||||
appendAutomationLog(`stop requested: ${reason}`);
|
||||
setReviewStatus(`${reason} Der aktuelle Klick/Capture-Schritt wird noch sauber beendet.`);
|
||||
}, [appendAutomationLog, setReviewStatus, stopVisibleScanRef]);
|
||||
|
||||
const reviewContext = useMemo(
|
||||
() =>
|
||||
createReviewContext({
|
||||
artifactRepo,
|
||||
reviewSamplesRepo,
|
||||
learningRepo,
|
||||
onStoredArtifactsChanged,
|
||||
setReviewSampleTotal,
|
||||
setReviewSamples,
|
||||
setLearningRulesLoaded,
|
||||
setScannerLearningRules,
|
||||
setReviewStatus,
|
||||
setStoredTotal,
|
||||
appendAutomationLog,
|
||||
}),
|
||||
[
|
||||
artifactRepo,
|
||||
reviewSamplesRepo,
|
||||
learningRepo,
|
||||
onStoredArtifactsChanged,
|
||||
setReviewSampleTotal,
|
||||
setReviewSamples,
|
||||
setLearningRulesLoaded,
|
||||
setScannerLearningRules,
|
||||
setReviewStatus,
|
||||
setStoredTotal,
|
||||
appendAutomationLog,
|
||||
],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
void initializeLearningState(reviewContext);
|
||||
}, [reviewContext]);
|
||||
|
||||
const focusDashboard = useCallback(async () => {
|
||||
try {
|
||||
await automationRepo?.focusMainWindow?.();
|
||||
} catch {
|
||||
// Best-effort fallback; state remains in renderer.
|
||||
}
|
||||
}, [automationRepo?.focusMainWindow]);
|
||||
|
||||
const parseArtifactAndPersist = useCallback(
|
||||
async function parseArtifactAndPersist(
|
||||
capture: CaptureResult | null,
|
||||
parsed: ParsedArtifactCandidate,
|
||||
source: string,
|
||||
needsReview: boolean,
|
||||
) {
|
||||
return persistParsedArtifactHelper(capture, parsed, source, needsReview, reviewContext);
|
||||
},
|
||||
[reviewContext],
|
||||
);
|
||||
|
||||
const handleSaveReviewSample = useCallback(
|
||||
async function handleSaveReviewSample(
|
||||
capture: CaptureResult | null = latestCapture,
|
||||
parsed: ParsedArtifactCandidate | null = parsedArtifact,
|
||||
reason = "manual",
|
||||
): Promise<BooleanResult | null> {
|
||||
const result = await saveReviewSampleHelper(
|
||||
capture,
|
||||
parsed,
|
||||
reason,
|
||||
scannerLearningRules,
|
||||
reviewContext,
|
||||
);
|
||||
return result.result ? { ok: result.result.ok } : null;
|
||||
},
|
||||
[latestCapture, parsedArtifact, reviewContext, scannerLearningRules],
|
||||
);
|
||||
|
||||
const scanActionContext = useMemo(
|
||||
() =>
|
||||
createScanActionContext({
|
||||
autoScanRunning,
|
||||
setAutoScanRunning,
|
||||
isScanning,
|
||||
stopVisibleScanRef,
|
||||
selectedSourceId,
|
||||
bridgeReady,
|
||||
automationRepo,
|
||||
runtimeInfo,
|
||||
runtimeRepo,
|
||||
scanLimit,
|
||||
skipRows,
|
||||
detectedInventoryCount,
|
||||
setScanSummary,
|
||||
setAutoScanStats,
|
||||
setReviewStatus,
|
||||
appendAutomationLog,
|
||||
appendClickDiagnostics,
|
||||
parseArtifact,
|
||||
persistParsedArtifact: parseArtifactAndPersist,
|
||||
saveReviewSample: handleSaveReviewSample,
|
||||
focusDashboard,
|
||||
captureSelectedSource,
|
||||
captureFastSelectedSource: (delayMs = 0, focusGenshin = false) => captureSelectedSource(delayMs, focusGenshin, { skipOcr: true }),
|
||||
}),
|
||||
[
|
||||
autoScanRunning,
|
||||
setAutoScanRunning,
|
||||
isScanning,
|
||||
stopVisibleScanRef,
|
||||
selectedSourceId,
|
||||
bridgeReady,
|
||||
automationRepo,
|
||||
runtimeInfo,
|
||||
runtimeRepo,
|
||||
scanLimit,
|
||||
skipRows,
|
||||
detectedInventoryCount,
|
||||
setScanSummary,
|
||||
setAutoScanStats,
|
||||
setReviewStatus,
|
||||
appendAutomationLog,
|
||||
appendClickDiagnostics,
|
||||
parseArtifact,
|
||||
parseArtifactAndPersist,
|
||||
handleSaveReviewSample,
|
||||
focusDashboard,
|
||||
captureSelectedSource,
|
||||
],
|
||||
);
|
||||
|
||||
const loadReviewQueueAction = useCallback(async () => {
|
||||
await loadReviewQueueFromRepo(reviewContext);
|
||||
}, [reviewContext]);
|
||||
|
||||
const openReviewQueueModal = useCallback(async () => {
|
||||
await loadReviewQueueAction();
|
||||
setReviewQueueOpen(true);
|
||||
}, [loadReviewQueueAction, setReviewQueueOpen]);
|
||||
|
||||
const runAutoReviewScan = useCallback(async () => {
|
||||
if (autoScanRunning || !selectedSourceId || !canCaptureSource) return;
|
||||
await runAutoReviewScanAction(scanActionContext);
|
||||
}, [autoScanRunning, canCaptureSource, selectedSourceId, scanActionContext]);
|
||||
|
||||
const runVisibleGridScan = useCallback(async () => {
|
||||
if (autoScanRunning || !bridgeReady || !selectedSourceId || !automationRepo?.clickScreen || !automationRepo?.scrollScreen) {
|
||||
return;
|
||||
}
|
||||
await runVisibleGridScanAction(scanActionContext);
|
||||
}, [
|
||||
autoScanRunning,
|
||||
bridgeReady,
|
||||
selectedSourceId,
|
||||
automationRepo?.clickScreen,
|
||||
automationRepo?.scrollScreen,
|
||||
scanActionContext,
|
||||
]);
|
||||
|
||||
useScanCommandListener({
|
||||
automationRepo,
|
||||
autoScanRunning,
|
||||
isScanning,
|
||||
selectedSourceId,
|
||||
requestScanStop,
|
||||
runVisibleGridScan,
|
||||
});
|
||||
|
||||
return {
|
||||
requestScanStop,
|
||||
saveReviewSample: handleSaveReviewSample,
|
||||
loadReviewQueue: loadReviewQueueAction,
|
||||
openReviewQueue: openReviewQueueModal,
|
||||
runAutoReviewScan,
|
||||
runVisibleGridScan,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user