mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-09 06:55:28 +03:00
tweaks
- add None to case selection list - allow new case creation from single cam export dialog
This commit is contained in:
parent
13e4a94065
commit
aa5934c745
@ -93,6 +93,8 @@ export default function ExportDialog({
|
||||
const { t } = useTranslation(["components/dialog"]);
|
||||
const [name, setName] = useState("");
|
||||
const [selectedCaseId, setSelectedCaseId] = useState<string | undefined>();
|
||||
const [singleNewCaseName, setSingleNewCaseName] = useState("");
|
||||
const [singleNewCaseDescription, setSingleNewCaseDescription] = useState("");
|
||||
const [activeTab, setActiveTab] = useState<ExportTab>("export");
|
||||
const [isStartingExport, setIsStartingExport] = useState(false);
|
||||
const previousModeRef = useRef<ExportMode>(mode);
|
||||
@ -137,12 +139,24 @@ export default function ExportDialog({
|
||||
setIsStartingExport(true);
|
||||
|
||||
try {
|
||||
let exportCaseId: string | undefined = selectedCaseId;
|
||||
|
||||
if (selectedCaseId === "new" && singleNewCaseName.trim().length > 0) {
|
||||
const caseResp = await axios.post("cases", {
|
||||
name: singleNewCaseName.trim(),
|
||||
description: singleNewCaseDescription.trim() || undefined,
|
||||
});
|
||||
exportCaseId = caseResp.data?.id;
|
||||
} else if (selectedCaseId === "new" || selectedCaseId === "none") {
|
||||
exportCaseId = undefined;
|
||||
}
|
||||
|
||||
await axios.post<StartExportResponse>(
|
||||
`export/${camera}/start/${Math.round(range.after)}/end/${Math.round(range.before)}`,
|
||||
{
|
||||
source: "recordings",
|
||||
name,
|
||||
export_case_id: selectedCaseId || undefined,
|
||||
export_case_id: exportCaseId,
|
||||
},
|
||||
);
|
||||
|
||||
@ -156,6 +170,8 @@ export default function ExportDialog({
|
||||
});
|
||||
setName("");
|
||||
setSelectedCaseId(undefined);
|
||||
setSingleNewCaseName("");
|
||||
setSingleNewCaseDescription("");
|
||||
setRange(undefined);
|
||||
setMode("none");
|
||||
return true;
|
||||
@ -183,6 +199,8 @@ export default function ExportDialog({
|
||||
name,
|
||||
range,
|
||||
selectedCaseId,
|
||||
singleNewCaseDescription,
|
||||
singleNewCaseName,
|
||||
setMode,
|
||||
setRange,
|
||||
t,
|
||||
@ -191,6 +209,8 @@ export default function ExportDialog({
|
||||
const handleCancel = useCallback(() => {
|
||||
setName("");
|
||||
setSelectedCaseId(undefined);
|
||||
setSingleNewCaseName("");
|
||||
setSingleNewCaseDescription("");
|
||||
setMode("none");
|
||||
setRange(undefined);
|
||||
setActiveTab("export");
|
||||
@ -272,12 +292,16 @@ export default function ExportDialog({
|
||||
range={range}
|
||||
name={name}
|
||||
selectedCaseId={selectedCaseId}
|
||||
singleNewCaseName={singleNewCaseName}
|
||||
singleNewCaseDescription={singleNewCaseDescription}
|
||||
activeTab={activeTab}
|
||||
isStartingExport={isStartingExport}
|
||||
onStartExport={onStartExport}
|
||||
setActiveTab={setActiveTab}
|
||||
setName={setName}
|
||||
setSelectedCaseId={setSelectedCaseId}
|
||||
setSingleNewCaseName={setSingleNewCaseName}
|
||||
setSingleNewCaseDescription={setSingleNewCaseDescription}
|
||||
setRange={setRange}
|
||||
setMode={setMode}
|
||||
onCancel={handleCancel}
|
||||
@ -294,12 +318,16 @@ type ExportContentProps = {
|
||||
range?: TimeRange;
|
||||
name: string;
|
||||
selectedCaseId?: string;
|
||||
singleNewCaseName: string;
|
||||
singleNewCaseDescription: string;
|
||||
activeTab: ExportTab;
|
||||
isStartingExport: boolean;
|
||||
onStartExport: () => Promise<boolean>;
|
||||
setActiveTab: (tab: ExportTab) => void;
|
||||
setName: (name: string) => void;
|
||||
setSelectedCaseId: (caseId: string | undefined) => void;
|
||||
setSingleNewCaseName: (name: string) => void;
|
||||
setSingleNewCaseDescription: (description: string) => void;
|
||||
setRange: (range: TimeRange | undefined) => void;
|
||||
setMode: (mode: ExportMode) => void;
|
||||
onCancel: () => void;
|
||||
@ -311,12 +339,16 @@ export function ExportContent({
|
||||
range,
|
||||
name,
|
||||
selectedCaseId,
|
||||
singleNewCaseName,
|
||||
singleNewCaseDescription,
|
||||
activeTab,
|
||||
isStartingExport,
|
||||
onStartExport,
|
||||
setActiveTab,
|
||||
setName,
|
||||
setSelectedCaseId,
|
||||
setSingleNewCaseName,
|
||||
setSingleNewCaseDescription,
|
||||
setRange,
|
||||
setMode,
|
||||
onCancel,
|
||||
@ -332,7 +364,7 @@ export function ExportContent({
|
||||
);
|
||||
const [selectedCameraIds, setSelectedCameraIds] = useState<string[]>([]);
|
||||
const [batchCaseSelection, setBatchCaseSelection] = useState<string>(
|
||||
selectedCaseId || "new",
|
||||
selectedCaseId || "none",
|
||||
);
|
||||
const [hasManualCameraSelection, setHasManualCameraSelection] =
|
||||
useState(false);
|
||||
@ -483,7 +515,8 @@ export function ExportContent({
|
||||
Boolean(range && range.before > range.after) &&
|
||||
selectedCameraCount > 0 &&
|
||||
!isStartingBatchExport &&
|
||||
(batchCaseSelection !== "new" || newCaseName.trim().length > 0);
|
||||
(batchCaseSelection !== "new" || newCaseName.trim().length > 0) &&
|
||||
batchCaseSelection.length > 0;
|
||||
|
||||
const onSelectTime = useCallback(
|
||||
(option: ExportOption) => {
|
||||
@ -567,7 +600,7 @@ export function ExportContent({
|
||||
})),
|
||||
};
|
||||
|
||||
if (isAdmin) {
|
||||
if (isAdmin && batchCaseSelection !== "none") {
|
||||
if (batchCaseSelection === "new") {
|
||||
payload.new_case_name = newCaseName.trim();
|
||||
payload.new_case_description = newCaseDescription.trim() || undefined;
|
||||
@ -786,8 +819,30 @@ export function ExportContent({
|
||||
{caseItem.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
<SelectSeparator />
|
||||
<SelectItem value="new">
|
||||
{t("export.case.newCaseOption")}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{selectedCaseId === "new" && (
|
||||
<div className="space-y-2 pt-1">
|
||||
<Input
|
||||
className="text-md"
|
||||
placeholder={t("export.case.newCaseNamePlaceholder")}
|
||||
value={singleNewCaseName}
|
||||
onChange={(e) => setSingleNewCaseName(e.target.value)}
|
||||
/>
|
||||
<Textarea
|
||||
className="text-md"
|
||||
placeholder={t("export.case.newCaseDescriptionPlaceholder")}
|
||||
value={singleNewCaseDescription}
|
||||
onChange={(e) =>
|
||||
setSingleNewCaseDescription(e.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</TabsContent>
|
||||
@ -947,6 +1002,9 @@ export function ExportContent({
|
||||
<SelectValue placeholder={t("export.case.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="none">
|
||||
{t("label.none", { ns: "common" })}
|
||||
</SelectItem>
|
||||
{cases
|
||||
?.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((caseItem) => (
|
||||
|
||||
@ -115,6 +115,8 @@ export default function MobileReviewSettingsDrawer({
|
||||
const [selectedCaseId, setSelectedCaseId] = useState<string | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const [singleNewCaseName, setSingleNewCaseName] = useState("");
|
||||
const [singleNewCaseDescription, setSingleNewCaseDescription] = useState("");
|
||||
const [isStartingExport, setIsStartingExport] = useState(false);
|
||||
const onStartExport = useCallback(async () => {
|
||||
if (isStartingExport) {
|
||||
@ -148,12 +150,24 @@ export default function MobileReviewSettingsDrawer({
|
||||
setIsStartingExport(true);
|
||||
|
||||
try {
|
||||
let exportCaseId: string | undefined = selectedCaseId;
|
||||
|
||||
if (selectedCaseId === "new" && singleNewCaseName.trim().length > 0) {
|
||||
const caseResp = await axios.post("cases", {
|
||||
name: singleNewCaseName.trim(),
|
||||
description: singleNewCaseDescription.trim() || undefined,
|
||||
});
|
||||
exportCaseId = caseResp.data?.id;
|
||||
} else if (selectedCaseId === "new" || selectedCaseId === "none") {
|
||||
exportCaseId = undefined;
|
||||
}
|
||||
|
||||
await axios.post<StartExportResponse>(
|
||||
`export/${camera}/start/${Math.round(range.after)}/end/${Math.round(range.before)}`,
|
||||
{
|
||||
source: "recordings",
|
||||
name,
|
||||
export_case_id: selectedCaseId || undefined,
|
||||
export_case_id: exportCaseId,
|
||||
},
|
||||
);
|
||||
|
||||
@ -169,6 +183,8 @@ export default function MobileReviewSettingsDrawer({
|
||||
});
|
||||
setName("");
|
||||
setSelectedCaseId(undefined);
|
||||
setSingleNewCaseName("");
|
||||
setSingleNewCaseDescription("");
|
||||
setRange(undefined);
|
||||
setMode("none");
|
||||
return true;
|
||||
@ -199,6 +215,8 @@ export default function MobileReviewSettingsDrawer({
|
||||
name,
|
||||
range,
|
||||
selectedCaseId,
|
||||
singleNewCaseDescription,
|
||||
singleNewCaseName,
|
||||
setRange,
|
||||
setMode,
|
||||
t,
|
||||
@ -361,12 +379,16 @@ export default function MobileReviewSettingsDrawer({
|
||||
range={range}
|
||||
name={name}
|
||||
selectedCaseId={selectedCaseId}
|
||||
singleNewCaseName={singleNewCaseName}
|
||||
singleNewCaseDescription={singleNewCaseDescription}
|
||||
activeTab={exportTab}
|
||||
isStartingExport={isStartingExport}
|
||||
onStartExport={onStartExport}
|
||||
setActiveTab={setExportTab}
|
||||
setName={setName}
|
||||
setSelectedCaseId={setSelectedCaseId}
|
||||
setSingleNewCaseName={setSingleNewCaseName}
|
||||
setSingleNewCaseDescription={setSingleNewCaseDescription}
|
||||
setRange={setRange}
|
||||
setMode={(mode) => {
|
||||
setMode(mode);
|
||||
@ -379,6 +401,8 @@ export default function MobileReviewSettingsDrawer({
|
||||
setMode("none");
|
||||
setRange(undefined);
|
||||
setSelectedCaseId(undefined);
|
||||
setSingleNewCaseName("");
|
||||
setSingleNewCaseDescription("");
|
||||
setExportTab("export");
|
||||
setDrawerMode("select");
|
||||
}}
|
||||
|
||||
@ -55,6 +55,7 @@ type MultiExportDialogProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const NONE_CASE_OPTION = "none";
|
||||
const NEW_CASE_OPTION = "new";
|
||||
|
||||
export default function MultiExportDialog({
|
||||
@ -74,10 +75,7 @@ export default function MultiExportDialog({
|
||||
const { data: cases } = useSWR<ExportCase[]>(isAdmin ? "cases" : null);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
// Single unified state: either NEW_CASE_OPTION or an existing case id.
|
||||
// Defaults to NEW_CASE_OPTION, which is also the only valid value for
|
||||
// non-admins since they can't attach to existing cases.
|
||||
const [caseSelection, setCaseSelection] = useState<string>(NEW_CASE_OPTION);
|
||||
const [caseSelection, setCaseSelection] = useState<string>(NONE_CASE_OPTION);
|
||||
const [newCaseName, setNewCaseName] = useState("");
|
||||
const [newCaseDescription, setNewCaseDescription] = useState("");
|
||||
const [isExporting, setIsExporting] = useState(false);
|
||||
@ -134,7 +132,7 @@ export default function MultiExportDialog({
|
||||
}, [t, locale]);
|
||||
|
||||
const resetState = useCallback(() => {
|
||||
setCaseSelection(NEW_CASE_OPTION);
|
||||
setCaseSelection(NONE_CASE_OPTION);
|
||||
setNewCaseName("");
|
||||
setNewCaseDescription("");
|
||||
setIsExporting(false);
|
||||
@ -146,7 +144,7 @@ export default function MultiExportDialog({
|
||||
resetState();
|
||||
} else {
|
||||
// Freshly reset each time so the default name reflects "now"
|
||||
setCaseSelection(NEW_CASE_OPTION);
|
||||
setCaseSelection(NONE_CASE_OPTION);
|
||||
setNewCaseName(defaultCaseName);
|
||||
setNewCaseDescription("");
|
||||
setIsExporting(false);
|
||||
@ -185,7 +183,7 @@ export default function MultiExportDialog({
|
||||
|
||||
const payload: BatchExportBody = { items };
|
||||
|
||||
if (isAdmin) {
|
||||
if (isAdmin && caseSelection !== NONE_CASE_OPTION) {
|
||||
if (isNewCase) {
|
||||
payload.new_case_name = newCaseName.trim();
|
||||
payload.new_case_description = newCaseDescription.trim() || undefined;
|
||||
@ -323,12 +321,15 @@ export default function MultiExportDialog({
|
||||
<SelectValue placeholder={t("export.case.placeholder")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value={NONE_CASE_OPTION}>
|
||||
{t("label.none", { ns: "common" })}
|
||||
</SelectItem>
|
||||
{existingCases.map((caseItem) => (
|
||||
<SelectItem key={caseItem.id} value={caseItem.id}>
|
||||
{caseItem.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
{existingCases.length > 0 && <SelectSeparator />}
|
||||
<SelectSeparator />
|
||||
<SelectItem value={NEW_CASE_OPTION}>
|
||||
{t("export.case.newCaseOption")}
|
||||
</SelectItem>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user