From 8eedca1b1e7591db3cdcbc1ee25c59f929c68c0d Mon Sep 17 00:00:00 2001 From: AmitChauhan63390 Date: Fri, 15 Nov 2024 16:16:01 +0530 Subject: [PATCH] Recording deletion warning while runs are active --- server/src/api/record.ts | 3 +- src/api/storage.ts | 44 +++++++++++++++++++- src/components/molecules/RecordingsTable.tsx | 16 ++++++- src/components/organisms/ApiKey.tsx | 3 ++ src/components/organisms/BrowserWindow.tsx | 3 +- 5 files changed, 64 insertions(+), 5 deletions(-) diff --git a/server/src/api/record.ts b/server/src/api/record.ts index b55f06bc..573a8edb 100644 --- a/server/src/api/record.ts +++ b/server/src/api/record.ts @@ -289,7 +289,7 @@ router.get("/robots/:id", requireAPIKey, async (req: Request, res: Response) => * type: string * example: "Failed to retrieve runs" */ -router.get("/robots/:id/runs", requireAPIKey, async (req: Request, res: Response) => { +router.get("/robots/:id/runs",requireAPIKey, async (req: Request, res: Response) => { try { const runs = await Run.findAll({ where: { @@ -321,6 +321,7 @@ router.get("/robots/:id/runs", requireAPIKey, async (req: Request, res: Response } ); + function formatRunResponse(run: any) { const formattedRun = { id: run.id, diff --git a/src/api/storage.ts b/src/api/storage.ts index 9b4b06b2..22cd9a28 100644 --- a/src/api/storage.ts +++ b/src/api/storage.ts @@ -5,6 +5,10 @@ import { ScheduleSettings } from "../components/molecules/ScheduleSettings"; import { CreateRunResponse, ScheduleRunResponse } from "../pages/MainPage"; import { apiUrl } from "../apiConfig"; + + + + export const getStoredRecordings = async (): Promise => { try { const response = await axios.get(`${apiUrl}/storage/recordings`); @@ -47,16 +51,52 @@ export const getStoredRecording = async (id: string) => { } } + +export const checkRunsForRecording = async (id: string): Promise => { + const apiKey = localStorage.getItem('x-api-key'); + + // Check if the API key exists + if (!apiKey) { + console.error('API key is missing.'); + return false; + } + + try { + const response = await axios.get(`${apiUrl}/api/robots/${id}/runs`, { + headers: { + 'x-api-key': apiKey, // Pass the valid API key in the header + }, + withCredentials: true, + }); + + const runs = response.data; + return runs.runs.totalCount > 0; + } catch (error) { + console.error('Error checking runs for recording:', error); + return false; + } +}; + export const deleteRecordingFromStorage = async (id: string): Promise => { + + const hasRuns = await checkRunsForRecording(id); + + if (hasRuns) { + + return false; + } + try { const response = await axios.delete(`${apiUrl}/storage/recordings/${id}`); if (response.status === 200) { - return response.data; + + return true; } else { throw new Error(`Couldn't delete stored recording ${id}`); } } catch (error: any) { console.log(error); + return false; } }; @@ -93,7 +133,7 @@ export const createRunForStoredRecording = async (id: string, settings: RunSetti try { const response = await axios.put( `${apiUrl}/storage/runs/${id}`, - { ...settings }); + { ...settings }); if (response.status === 200) { return response.data; } else { diff --git a/src/components/molecules/RecordingsTable.tsx b/src/components/molecules/RecordingsTable.tsx index c5895193..557b0b70 100644 --- a/src/components/molecules/RecordingsTable.tsx +++ b/src/components/molecules/RecordingsTable.tsx @@ -13,7 +13,7 @@ import { IconButton, Button, Box, Typography, TextField } from "@mui/material"; import { Schedule, DeleteForever, Edit, PlayCircle, Settings, Power } from "@mui/icons-material"; import LinkIcon from '@mui/icons-material/Link'; import { useGlobalInfoStore } from "../../context/globalInfo"; -import { deleteRecordingFromStorage, getStoredRecordings } from "../../api/storage"; +import { checkRunsForRecording, deleteRecordingFromStorage, getStoredRecordings } from "../../api/storage"; import { Add } from "@mui/icons-material"; import { useNavigate } from 'react-router-dom'; import { stopRecording } from "../../api/recording"; @@ -159,6 +159,13 @@ export const RecordingsTable = ({ handleEditRecording, handleRunRecording, handl } }, []); + const hasAssociatedRuns = async (robotId: string): Promise => { + + const associatedRuns = await fetch(`/api/robot/${robotId}/runs`); + const data = await associatedRuns.json(); + return data.length > 0; + }; + return ( @@ -252,6 +259,13 @@ export const RecordingsTable = ({ handleEditRecording, handleRunRecording, handl return ( { + checkRunsForRecording(row.id).then((result: boolean) => { + if (result) { + notify('warning', 'Recording has associated runs, please delete them first'); + } + + }) + deleteRecordingFromStorage(row.id).then((result: boolean) => { if (result) { setRows([]); diff --git a/src/components/organisms/ApiKey.tsx b/src/components/organisms/ApiKey.tsx index d9f4c6fe..49675538 100644 --- a/src/components/organisms/ApiKey.tsx +++ b/src/components/organisms/ApiKey.tsx @@ -36,6 +36,8 @@ const ApiKeyManager = () => { const [copySuccess, setCopySuccess] = useState(false); const { notify } = useGlobalInfoStore(); + + useEffect(() => { const fetchApiKey = async () => { try { @@ -56,6 +58,7 @@ const ApiKeyManager = () => { try { const { data } = await axios.post(`${apiUrl}/auth/generate-api-key`); setApiKey(data.api_key); + localStorage.setItem('x-api-key', data.api_key); notify('success', `Generated API Key successfully`); } catch (error: any) { notify('error', `Failed to generate API Key - ${error.message}`); diff --git a/src/components/organisms/BrowserWindow.tsx b/src/components/organisms/BrowserWindow.tsx index cbc46731..697b4adb 100644 --- a/src/components/organisms/BrowserWindow.tsx +++ b/src/components/organisms/BrowserWindow.tsx @@ -8,6 +8,7 @@ import { useActionContext } from '../../context/browserActions'; import { useBrowserSteps, TextStep } from '../../context/browserSteps'; import { useGlobalInfoStore } from '../../context/globalInfo'; + interface ElementInfo { tagName: string; hasOnlyText?: boolean; @@ -316,7 +317,7 @@ export const BrowserWindow = () => { } }, [paginationMode, resetPaginationSelector]); - + return (
{