mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-05 22:02:39 +02:00
merge upstream/dev into feat/migrate-electric-to-zero
Resolve 8 conflicts: - Accept upstream deletion of 3 composio_*_connector.py (unified Google connectors) - Accept our deletion of ElectricProvider.tsx, use-connectors-electric.ts, use-messages-electric.ts (replaced by Zero equivalents) - Keep both new deps in package.json (@rocicorp/zero + @slate-serializers/html) - Regenerate pnpm-lock.yaml
This commit is contained in:
commit
5d8a62a4a6
207 changed files with 28023 additions and 12247 deletions
|
|
@ -126,6 +126,10 @@ export function useGooglePicker({ connectorId, onPicked }: UseGooglePickerOption
|
|||
builder.setDeveloperKey(picker_api_key);
|
||||
}
|
||||
|
||||
if (window.innerWidth < 640) {
|
||||
builder.setSize(window.innerWidth - 32, window.innerHeight * 0.75);
|
||||
}
|
||||
|
||||
const picker = builder
|
||||
.setCallback((data: google.picker.ResponseObject) => {
|
||||
const action = data[google.picker.Response.ACTION];
|
||||
|
|
|
|||
62
surfsense_web/hooks/use-hitl-phase.ts
Normal file
62
surfsense_web/hooks/use-hitl-phase.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
export type HitlPhase = "pending" | "processing" | "complete" | "rejected";
|
||||
|
||||
interface HitlInterruptLike {
|
||||
__decided__?: string | null;
|
||||
__completed__?: boolean;
|
||||
}
|
||||
|
||||
const MINIMUM_SHIMMER_MS = 500;
|
||||
const FALLBACK_TIMEOUT_MS = 30_000;
|
||||
|
||||
/**
|
||||
* State machine for HITL approval card phases.
|
||||
*
|
||||
* Phases:
|
||||
* pending – waiting for user decision (show buttons)
|
||||
* processing – user approved/edited, waiting for backend (shimmer)
|
||||
* complete – backend responded with __completed__ (done text)
|
||||
* rejected – user rejected (cancelled text)
|
||||
*/
|
||||
export function useHitlPhase(interruptData: HitlInterruptLike): {
|
||||
phase: HitlPhase;
|
||||
setProcessing: () => void;
|
||||
setRejected: () => void;
|
||||
} {
|
||||
const [phase, setPhase] = useState<HitlPhase>(() => {
|
||||
if (interruptData.__decided__ === "reject") return "rejected";
|
||||
if (interruptData.__decided__) return "complete";
|
||||
return "pending";
|
||||
});
|
||||
|
||||
const shimmerStartRef = useRef<number | null>(null);
|
||||
|
||||
// processing → complete when __completed__ arrives (with min shimmer duration)
|
||||
useEffect(() => {
|
||||
if (phase !== "processing") return;
|
||||
if (!interruptData.__completed__) return;
|
||||
|
||||
const elapsed = shimmerStartRef.current ? Date.now() - shimmerStartRef.current : Infinity;
|
||||
const remaining = Math.max(0, MINIMUM_SHIMMER_MS - elapsed);
|
||||
|
||||
const timer = setTimeout(() => setPhase("complete"), remaining);
|
||||
return () => clearTimeout(timer);
|
||||
}, [phase, interruptData.__completed__]);
|
||||
|
||||
// Fallback: processing → complete after 30s even if __completed__ never arrives
|
||||
useEffect(() => {
|
||||
if (phase !== "processing") return;
|
||||
const fallback = setTimeout(() => setPhase("complete"), FALLBACK_TIMEOUT_MS);
|
||||
return () => clearTimeout(fallback);
|
||||
}, [phase]);
|
||||
|
||||
return {
|
||||
phase,
|
||||
setProcessing: () => {
|
||||
shimmerStartRef.current = Date.now();
|
||||
setPhase("processing");
|
||||
},
|
||||
setRejected: () => setPhase("rejected"),
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue