Merge pull request #530 from getmaxun/retrain-robot
feat: retrain robot
This commit is contained in:
@@ -54,6 +54,7 @@
|
|||||||
"label": "URL",
|
"label": "URL",
|
||||||
"button": "Aufnahme starten"
|
"button": "Aufnahme starten"
|
||||||
},
|
},
|
||||||
|
"retrain": "Neu trainieren",
|
||||||
"edit": "Bearbeiten",
|
"edit": "Bearbeiten",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
"duplicate": "Duplizieren",
|
"duplicate": "Duplizieren",
|
||||||
@@ -237,7 +238,9 @@
|
|||||||
"confirm": "Bestätigen"
|
"confirm": "Bestätigen"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"save_success": "Roboter erfolgreich gespeichert"
|
"save_success": "Roboter erfolgreich gespeichert",
|
||||||
|
"retrain_success": "Roboter erfolgreich neu trainiert",
|
||||||
|
"save_error": "Fehler beim Speichern des Roboters"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"user_not_logged": "Benutzer nicht angemeldet. Aufnahme kann nicht gespeichert werden.",
|
"user_not_logged": "Benutzer nicht angemeldet. Aufnahme kann nicht gespeichert werden.",
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
"discard_and_create":"Discard & Create New",
|
"discard_and_create":"Discard & Create New",
|
||||||
"cancel":"Cancel"
|
"cancel":"Cancel"
|
||||||
},
|
},
|
||||||
|
"retrain": "Retrain",
|
||||||
"edit":"Edit",
|
"edit":"Edit",
|
||||||
"delete":"Delete",
|
"delete":"Delete",
|
||||||
"duplicate":"Duplicate",
|
"duplicate":"Duplicate",
|
||||||
@@ -245,7 +246,9 @@
|
|||||||
"confirm": "Confirm"
|
"confirm": "Confirm"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"save_success": "Robot saved successfully"
|
"save_success": "Robot saved successfully",
|
||||||
|
"retrain_success": "Robot retrained successfully",
|
||||||
|
"save_error": "Error saving robot"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"user_not_logged": "User not logged in. Cannot save recording.",
|
"user_not_logged": "User not logged in. Cannot save recording.",
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
"label": "URL",
|
"label": "URL",
|
||||||
"button": "Comenzar grabación"
|
"button": "Comenzar grabación"
|
||||||
},
|
},
|
||||||
|
"retrain": "Reentrenar",
|
||||||
"edit": "Editar",
|
"edit": "Editar",
|
||||||
"delete": "Eliminar",
|
"delete": "Eliminar",
|
||||||
"duplicate": "Duplicar",
|
"duplicate": "Duplicar",
|
||||||
@@ -238,7 +239,9 @@
|
|||||||
"confirm": "Confirmar"
|
"confirm": "Confirmar"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"save_success": "Robot guardado exitosamente"
|
"save_success": "Robot guardado correctamente",
|
||||||
|
"retrain_success": "Robot reentrenado correctamente",
|
||||||
|
"save_error": "Error al guardar el robot"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"user_not_logged": "Usuario no conectado. No se puede guardar la grabación.",
|
"user_not_logged": "Usuario no conectado. No se puede guardar la grabación.",
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
"label": "URL",
|
"label": "URL",
|
||||||
"button": "録画を開始"
|
"button": "録画を開始"
|
||||||
},
|
},
|
||||||
|
"retrain": "再学習",
|
||||||
"edit": "編集",
|
"edit": "編集",
|
||||||
"delete": "削除",
|
"delete": "削除",
|
||||||
"duplicate": "複製",
|
"duplicate": "複製",
|
||||||
@@ -238,7 +239,9 @@
|
|||||||
"confirm": "確認"
|
"confirm": "確認"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"save_success": "ロボットが正常に保存されました"
|
"save_success": "ロボットの保存に成功しました",
|
||||||
|
"retrain_success": "ロボットの再トレーニングに成功しました",
|
||||||
|
"save_error": "ロボットの保存中にエラーが発生しました"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"user_not_logged": "ユーザーがログインしていません。録画を保存できません。",
|
"user_not_logged": "ユーザーがログインしていません。録画を保存できません。",
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
"label": "URL",
|
"label": "URL",
|
||||||
"button": "开始录制"
|
"button": "开始录制"
|
||||||
},
|
},
|
||||||
|
"retrain": "重新训练",
|
||||||
"edit": "编辑",
|
"edit": "编辑",
|
||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
"duplicate": "复制",
|
"duplicate": "复制",
|
||||||
@@ -238,7 +239,9 @@
|
|||||||
"confirm": "确认"
|
"confirm": "确认"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"save_success": "机器人保存成功"
|
"save_success": "机器人保存成功",
|
||||||
|
"retrain_success": "机器人重新训练成功",
|
||||||
|
"save_error": "保存机器人时出错"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"user_not_logged": "用户未登录。无法保存录制。",
|
"user_not_logged": "用户未登录。无法保存录制。",
|
||||||
|
|||||||
@@ -139,12 +139,14 @@ export class WorkflowGenerator {
|
|||||||
*/
|
*/
|
||||||
private registerEventHandlers = (socket: Socket) => {
|
private registerEventHandlers = (socket: Socket) => {
|
||||||
socket.on('save', (data) => {
|
socket.on('save', (data) => {
|
||||||
const { fileName, userId, isLogin } = data;
|
const { fileName, userId, isLogin, robotId } = data;
|
||||||
logger.log('debug', `Saving workflow ${fileName} for user ID ${userId}`);
|
logger.log('debug', `Saving workflow ${fileName} for user ID ${userId}`);
|
||||||
this.saveNewWorkflow(fileName, userId, isLogin);
|
this.saveNewWorkflow(fileName, userId, isLogin, robotId);
|
||||||
});
|
});
|
||||||
socket.on('new-recording', () => this.workflowRecord = {
|
socket.on('new-recording', (data) => {
|
||||||
workflow: [],
|
this.workflowRecord = {
|
||||||
|
workflow: [],
|
||||||
|
};
|
||||||
});
|
});
|
||||||
socket.on('activeIndex', (data) => this.generatedData.lastIndex = parseInt(data));
|
socket.on('activeIndex', (data) => this.generatedData.lastIndex = parseInt(data));
|
||||||
socket.on('decision', async ({ pair, actionType, decision, userId }) => {
|
socket.on('decision', async ({ pair, actionType, decision, userId }) => {
|
||||||
@@ -764,38 +766,62 @@ export class WorkflowGenerator {
|
|||||||
* @param fileName The name of the file.
|
* @param fileName The name of the file.
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public saveNewWorkflow = async (fileName: string, userId: number, isLogin: boolean) => {
|
public saveNewWorkflow = async (fileName: string, userId: number, isLogin: boolean, robotId?: string) => {
|
||||||
const recording = this.optimizeWorkflow(this.workflowRecord);
|
const recording = this.optimizeWorkflow(this.workflowRecord);
|
||||||
|
let actionType = 'saved';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.recordingMeta = {
|
if (robotId) {
|
||||||
name: fileName,
|
const robot = await Robot.findOne({ where: { 'recording_meta.id': robotId }});
|
||||||
id: uuid(),
|
|
||||||
createdAt: this.recordingMeta.createdAt || new Date().toLocaleString(),
|
|
||||||
pairs: recording.workflow.length,
|
|
||||||
updatedAt: new Date().toLocaleString(),
|
|
||||||
params: this.getParams() || [],
|
|
||||||
isLogin: isLogin,
|
|
||||||
}
|
|
||||||
const robot = await Robot.create({
|
|
||||||
userId,
|
|
||||||
recording_meta: this.recordingMeta,
|
|
||||||
recording: recording,
|
|
||||||
});
|
|
||||||
capture(
|
|
||||||
'maxun-oss-robot-created',
|
|
||||||
{
|
|
||||||
robot_meta: robot.recording_meta,
|
|
||||||
recording: robot.recording,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.log('info', `Robot saved with id: ${robot.id}`);
|
if (robot) {
|
||||||
|
await robot.update({
|
||||||
|
recording: recording,
|
||||||
|
recording_meta: {
|
||||||
|
...robot.recording_meta,
|
||||||
|
pairs: recording.workflow.length,
|
||||||
|
params: this.getParams() || [],
|
||||||
|
updatedAt: new Date().toLocaleString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
actionType = 'retrained';
|
||||||
|
logger.log('info', `Robot retrained with id: ${robot.id}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.recordingMeta = {
|
||||||
|
name: fileName,
|
||||||
|
id: uuid(),
|
||||||
|
createdAt: this.recordingMeta.createdAt || new Date().toLocaleString(),
|
||||||
|
pairs: recording.workflow.length,
|
||||||
|
updatedAt: new Date().toLocaleString(),
|
||||||
|
params: this.getParams() || [],
|
||||||
|
isLogin: isLogin,
|
||||||
|
}
|
||||||
|
const robot = await Robot.create({
|
||||||
|
userId,
|
||||||
|
recording_meta: this.recordingMeta,
|
||||||
|
recording: recording,
|
||||||
|
});
|
||||||
|
capture(
|
||||||
|
'maxun-oss-robot-created',
|
||||||
|
{
|
||||||
|
robot_meta: robot.recording_meta,
|
||||||
|
recording: robot.recording,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
actionType = 'saved';
|
||||||
|
logger.log('info', `Robot saved with id: ${robot.id}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
const { message } = e as Error;
|
const { message } = e as Error;
|
||||||
logger.log('warn', `Cannot save the file to the local file system ${e}`)
|
logger.log('warn', `Cannot save the file to the local file system ${e}`)
|
||||||
|
actionType = 'error';
|
||||||
}
|
}
|
||||||
this.socket.emit('fileSaved');
|
|
||||||
|
this.socket.emit('fileSaved', { actionType });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -55,6 +55,11 @@ const BrowserRecordingSave = () => {
|
|||||||
type: 'recording-notification',
|
type: 'recording-notification',
|
||||||
notification: notificationData
|
notification: notificationData
|
||||||
}, '*');
|
}, '*');
|
||||||
|
|
||||||
|
window.opener.postMessage({
|
||||||
|
type: 'session-data-clear',
|
||||||
|
timestamp: Date.now()
|
||||||
|
}, '*');
|
||||||
}
|
}
|
||||||
|
|
||||||
setBrowserId(null);
|
setBrowserId(null);
|
||||||
|
|||||||
@@ -19,26 +19,32 @@ export const SaveRecording = ({ fileName }: SaveRecordingProps) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [openModal, setOpenModal] = useState<boolean>(false);
|
const [openModal, setOpenModal] = useState<boolean>(false);
|
||||||
const [needConfirm, setNeedConfirm] = useState<boolean>(false);
|
const [needConfirm, setNeedConfirm] = useState<boolean>(false);
|
||||||
const [recordingName, setRecordingName] = useState<string>(fileName);
|
const [saveRecordingName, setSaveRecordingName] = useState<string>(fileName);
|
||||||
const [waitingForSave, setWaitingForSave] = useState<boolean>(false);
|
const [waitingForSave, setWaitingForSave] = useState<boolean>(false);
|
||||||
|
|
||||||
const { browserId, setBrowserId, notify, recordings, isLogin } = useGlobalInfoStore();
|
const { browserId, setBrowserId, notify, recordings, isLogin, recordingName, retrainRobotId } = useGlobalInfoStore();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { state, dispatch } = useContext(AuthContext);
|
const { state, dispatch } = useContext(AuthContext);
|
||||||
const { user } = state;
|
const { user } = state;
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (recordingName) {
|
||||||
|
setSaveRecordingName(recordingName);
|
||||||
|
}
|
||||||
|
}, [recordingName]);
|
||||||
|
|
||||||
const handleChangeOfTitle = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChangeOfTitle = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { value } = event.target;
|
const { value } = event.target;
|
||||||
if (needConfirm) {
|
if (needConfirm) {
|
||||||
setNeedConfirm(false);
|
setNeedConfirm(false);
|
||||||
}
|
}
|
||||||
setRecordingName(value);
|
setSaveRecordingName(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSaveRecording = async (event: React.SyntheticEvent) => {
|
const handleSaveRecording = async (event: React.SyntheticEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (recordings.includes(recordingName)) {
|
if (recordings.includes(saveRecordingName)) {
|
||||||
if (needConfirm) { return; }
|
if (needConfirm) { return; }
|
||||||
setNeedConfirm(true);
|
setNeedConfirm(true);
|
||||||
} else {
|
} else {
|
||||||
@@ -46,19 +52,43 @@ export const SaveRecording = ({ fileName }: SaveRecordingProps) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const exitRecording = useCallback(async () => {
|
const handleFinishClick = () => {
|
||||||
|
if (recordingName && !recordings.includes(recordingName)) {
|
||||||
|
saveRecording();
|
||||||
|
} else {
|
||||||
|
setOpenModal(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const exitRecording = useCallback(async (data?: { actionType: string }) => {
|
||||||
|
let successMessage = t('save_recording.notifications.save_success');
|
||||||
|
|
||||||
|
if (data && data.actionType) {
|
||||||
|
if (data.actionType === 'retrained') {
|
||||||
|
successMessage = t('save_recording.notifications.retrain_success');
|
||||||
|
} else if (data.actionType === 'saved') {
|
||||||
|
successMessage = t('save_recording.notifications.save_success');
|
||||||
|
} else if (data.actionType === 'error') {
|
||||||
|
successMessage = t('save_recording.notifications.save_error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const notificationData = {
|
const notificationData = {
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: t('save_recording.notifications.save_success'),
|
message: successMessage,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
};
|
};
|
||||||
window.sessionStorage.setItem('pendingNotification', JSON.stringify(notificationData));
|
|
||||||
|
|
||||||
if (window.opener) {
|
if (window.opener) {
|
||||||
window.opener.postMessage({
|
window.opener.postMessage({
|
||||||
type: 'recording-notification',
|
type: 'recording-notification',
|
||||||
notification: notificationData
|
notification: notificationData
|
||||||
}, '*');
|
}, '*');
|
||||||
|
|
||||||
|
window.opener.postMessage({
|
||||||
|
type: 'session-data-clear',
|
||||||
|
timestamp: Date.now()
|
||||||
|
}, '*');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (browserId) {
|
if (browserId) {
|
||||||
@@ -67,16 +97,21 @@ export const SaveRecording = ({ fileName }: SaveRecordingProps) => {
|
|||||||
setBrowserId(null);
|
setBrowserId(null);
|
||||||
|
|
||||||
window.close();
|
window.close();
|
||||||
}, [setBrowserId, browserId]);
|
}, [setBrowserId, browserId, t]);
|
||||||
|
|
||||||
// notifies backed to save the recording in progress,
|
// notifies backed to save the recording in progress,
|
||||||
// releases resources and changes the view for main page by clearing the global browserId
|
// releases resources and changes the view for main page by clearing the global browserId
|
||||||
const saveRecording = async () => {
|
const saveRecording = async () => {
|
||||||
if (user) {
|
if (user) {
|
||||||
const payload = { fileName: recordingName, userId: user.id, isLogin: isLogin };
|
const payload = {
|
||||||
|
fileName: saveRecordingName || recordingName,
|
||||||
|
userId: user.id,
|
||||||
|
isLogin: isLogin,
|
||||||
|
robotId: retrainRobotId,
|
||||||
|
};
|
||||||
socket?.emit('save', payload);
|
socket?.emit('save', payload);
|
||||||
setWaitingForSave(true);
|
setWaitingForSave(true);
|
||||||
console.log(`Saving the recording as ${recordingName} for userId ${user.id}`);
|
console.log(`Saving the recording as ${saveRecordingName || recordingName} for userId ${user.id}`);
|
||||||
} else {
|
} else {
|
||||||
console.error(t('save_recording.notifications.user_not_logged'));
|
console.error(t('save_recording.notifications.user_not_logged'));
|
||||||
}
|
}
|
||||||
@@ -92,7 +127,7 @@ export const SaveRecording = ({ fileName }: SaveRecordingProps) => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setOpenModal(true)}
|
onClick={handleFinishClick}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="success"
|
color="success"
|
||||||
sx={{
|
sx={{
|
||||||
@@ -116,7 +151,7 @@ export const SaveRecording = ({ fileName }: SaveRecordingProps) => {
|
|||||||
id="title"
|
id="title"
|
||||||
label={t('save_recording.robot_name')}
|
label={t('save_recording.robot_name')}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
defaultValue={recordingName ? recordingName : null}
|
value={saveRecordingName}
|
||||||
/>
|
/>
|
||||||
{needConfirm
|
{needConfirm
|
||||||
?
|
?
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ import {
|
|||||||
Settings,
|
Settings,
|
||||||
Power,
|
Power,
|
||||||
ContentCopy,
|
ContentCopy,
|
||||||
MoreHoriz
|
MoreHoriz,
|
||||||
|
Refresh
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { useGlobalInfoStore } from "../../context/globalInfo";
|
import { useGlobalInfoStore } from "../../context/globalInfo";
|
||||||
import { checkRunsForRecording, deleteRecordingFromStorage, getStoredRecordings } from "../../api/storage";
|
import { checkRunsForRecording, deleteRecordingFromStorage, getStoredRecordings } from "../../api/storage";
|
||||||
@@ -117,6 +118,7 @@ const TableRowMemoized = memo(({ row, columns, handlers }: any) => {
|
|||||||
return (
|
return (
|
||||||
<MemoizedTableCell key={column.id} align={column.align}>
|
<MemoizedTableCell key={column.id} align={column.align}>
|
||||||
<MemoizedOptionsButton
|
<MemoizedOptionsButton
|
||||||
|
handleRetrain={() =>handlers.handleRetrainRobot(row.id, row.name)}
|
||||||
handleEdit={() => handlers.handleEditRobot(row.id, row.name, row.params || [])}
|
handleEdit={() => handlers.handleEditRobot(row.id, row.name, row.params || [])}
|
||||||
handleDuplicate={() => handlers.handleDuplicateRobot(row.id, row.name, row.params || [])}
|
handleDuplicate={() => handlers.handleDuplicateRobot(row.id, row.name, row.params || [])}
|
||||||
handleDelete={() => handlers.handleDelete(row.id)}
|
handleDelete={() => handlers.handleDelete(row.id)}
|
||||||
@@ -185,7 +187,7 @@ export const RecordingsTable = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleMessage = (event: any) => {
|
const handleMessage = (event: any) => {
|
||||||
if (event.data && event.data.type === 'recording-notification') {
|
if (event.origin === window.location.origin && event.data && event.data.type === 'recording-notification') {
|
||||||
const notificationData = event.data.notification;
|
const notificationData = event.data.notification;
|
||||||
if (notificationData) {
|
if (notificationData) {
|
||||||
notify(notificationData.type, notificationData.message);
|
notify(notificationData.type, notificationData.message);
|
||||||
@@ -198,6 +200,17 @@ export const RecordingsTable = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.origin === window.location.origin && event.data && event.data.type === 'session-data-clear') {
|
||||||
|
window.sessionStorage.removeItem('browserId');
|
||||||
|
window.sessionStorage.removeItem('robotToRetrain');
|
||||||
|
window.sessionStorage.removeItem('robotName');
|
||||||
|
window.sessionStorage.removeItem('recordingUrl');
|
||||||
|
window.sessionStorage.removeItem('recordingSessionId');
|
||||||
|
window.sessionStorage.removeItem('pendingSessionData');
|
||||||
|
window.sessionStorage.removeItem('nextTabIsRecording');
|
||||||
|
window.sessionStorage.removeItem('initialUrl');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('message', handleMessage);
|
window.addEventListener('message', handleMessage);
|
||||||
@@ -303,6 +316,60 @@ export const RecordingsTable = ({
|
|||||||
setModalOpen(true);
|
setModalOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRetrainRobot = useCallback(async (id: string, name: string) => {
|
||||||
|
const activeBrowserId = await getActiveBrowserId();
|
||||||
|
const robot = rows.find(row => row.id === id);
|
||||||
|
let targetUrl;
|
||||||
|
|
||||||
|
if (robot?.content?.workflow && robot.content.workflow.length > 0) {
|
||||||
|
const lastPair = robot.content.workflow[robot.content.workflow.length - 1];
|
||||||
|
|
||||||
|
if (lastPair?.what) {
|
||||||
|
if (Array.isArray(lastPair.what)) {
|
||||||
|
const gotoAction = lastPair.what.find(action =>
|
||||||
|
action && typeof action === 'object' && 'action' in action && action.action === "goto"
|
||||||
|
) as any;
|
||||||
|
|
||||||
|
if (gotoAction?.args?.[0]) {
|
||||||
|
targetUrl = gotoAction.args[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetUrl) {
|
||||||
|
setInitialUrl(targetUrl);
|
||||||
|
setRecordingUrl(targetUrl);
|
||||||
|
window.sessionStorage.setItem('initialUrl', targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeBrowserId) {
|
||||||
|
setActiveBrowserId(activeBrowserId);
|
||||||
|
setWarningModalOpen(true);
|
||||||
|
} else {
|
||||||
|
startRetrainRecording(id, name, targetUrl);
|
||||||
|
}
|
||||||
|
}, [rows, setInitialUrl, setRecordingUrl]);
|
||||||
|
|
||||||
|
const startRetrainRecording = (id: string, name: string, url?: string) => {
|
||||||
|
setBrowserId('new-recording');
|
||||||
|
setRecordingName(name);
|
||||||
|
setRecordingId(id);
|
||||||
|
|
||||||
|
window.sessionStorage.setItem('browserId', 'new-recording');
|
||||||
|
window.sessionStorage.setItem('robotToRetrain', id);
|
||||||
|
window.sessionStorage.setItem('robotName', name);
|
||||||
|
|
||||||
|
window.sessionStorage.setItem('recordingUrl', url || recordingUrl);
|
||||||
|
|
||||||
|
const sessionId = Date.now().toString();
|
||||||
|
window.sessionStorage.setItem('recordingSessionId', sessionId);
|
||||||
|
|
||||||
|
window.openedRecordingWindow = window.open(`/recording-setup?session=${sessionId}`, '_blank');
|
||||||
|
|
||||||
|
window.sessionStorage.setItem('nextTabIsRecording', 'true');
|
||||||
|
};
|
||||||
|
|
||||||
const startRecording = () => {
|
const startRecording = () => {
|
||||||
setModalOpen(false);
|
setModalOpen(false);
|
||||||
|
|
||||||
@@ -381,6 +448,7 @@ export const RecordingsTable = ({
|
|||||||
handleSettingsRecording,
|
handleSettingsRecording,
|
||||||
handleEditRobot,
|
handleEditRobot,
|
||||||
handleDuplicateRobot,
|
handleDuplicateRobot,
|
||||||
|
handleRetrainRobot,
|
||||||
handleDelete: async (id: string) => {
|
handleDelete: async (id: string) => {
|
||||||
const hasRuns = await checkRunsForRecording(id);
|
const hasRuns = await checkRunsForRecording(id);
|
||||||
if (hasRuns) {
|
if (hasRuns) {
|
||||||
@@ -395,7 +463,7 @@ export const RecordingsTable = ({
|
|||||||
fetchRecordings();
|
fetchRecordings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}), [handleRunRecording, handleScheduleRecording, handleIntegrateRecording, handleSettingsRecording, handleEditRobot, handleDuplicateRobot, notify, t]);
|
}), [handleRunRecording, handleScheduleRecording, handleIntegrateRecording, handleSettingsRecording, handleEditRobot, handleDuplicateRobot, handleRetrainRobot, notify, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
@@ -597,12 +665,13 @@ const SettingsButton = ({ handleSettings }: SettingsButtonProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface OptionsButtonProps {
|
interface OptionsButtonProps {
|
||||||
|
handleRetrain: () => void;
|
||||||
handleEdit: () => void;
|
handleEdit: () => void;
|
||||||
handleDelete: () => void;
|
handleDelete: () => void;
|
||||||
handleDuplicate: () => void;
|
handleDuplicate: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const OptionsButton = ({ handleEdit, handleDelete, handleDuplicate }: OptionsButtonProps) => {
|
const OptionsButton = ({ handleRetrain, handleEdit, handleDelete, handleDuplicate }: OptionsButtonProps) => {
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
|
|
||||||
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
@@ -629,6 +698,13 @@ const OptionsButton = ({ handleEdit, handleDelete, handleDuplicate }: OptionsBut
|
|||||||
open={Boolean(anchorEl)}
|
open={Boolean(anchorEl)}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
>
|
>
|
||||||
|
<MenuItem onClick={() => { handleRetrain(); handleClose(); }}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<Refresh fontSize="small" />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>{t('recordingtable.retrain')}</ListItemText>
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
<MenuItem onClick={() => { handleEdit(); handleClose(); }}>
|
<MenuItem onClick={() => { handleEdit(); handleClose(); }}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Edit fontSize="small" />
|
<Edit fontSize="small" />
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ interface GlobalInfo {
|
|||||||
setRecordingLength: (recordingLength: number) => void;
|
setRecordingLength: (recordingLength: number) => void;
|
||||||
recordingId: string | null;
|
recordingId: string | null;
|
||||||
setRecordingId: (newId: string | null) => void;
|
setRecordingId: (newId: string | null) => void;
|
||||||
|
retrainRobotId: string | null;
|
||||||
|
setRetrainRobotId: (newId: string | null) => void;
|
||||||
recordingName: string;
|
recordingName: string;
|
||||||
setRecordingName: (recordingName: string) => void;
|
setRecordingName: (recordingName: string) => void;
|
||||||
initialUrl: string;
|
initialUrl: string;
|
||||||
@@ -90,6 +92,7 @@ class GlobalInfoStore implements Partial<GlobalInfo> {
|
|||||||
isOpen: false,
|
isOpen: false,
|
||||||
};
|
};
|
||||||
recordingId = null;
|
recordingId = null;
|
||||||
|
retrainRobotId = null;
|
||||||
recordings: string[] = [];
|
recordings: string[] = [];
|
||||||
rerenderRuns = false;
|
rerenderRuns = false;
|
||||||
rerenderRobots = false;
|
rerenderRobots = false;
|
||||||
@@ -119,6 +122,7 @@ export const GlobalInfoProvider = ({ children }: { children: JSX.Element }) => {
|
|||||||
const [rerenderRobots, setRerenderRobots] = useState<boolean>(globalInfoStore.rerenderRobots);
|
const [rerenderRobots, setRerenderRobots] = useState<boolean>(globalInfoStore.rerenderRobots);
|
||||||
const [recordingLength, setRecordingLength] = useState<number>(globalInfoStore.recordingLength);
|
const [recordingLength, setRecordingLength] = useState<number>(globalInfoStore.recordingLength);
|
||||||
const [recordingId, setRecordingId] = useState<string | null>(globalInfoStore.recordingId);
|
const [recordingId, setRecordingId] = useState<string | null>(globalInfoStore.recordingId);
|
||||||
|
const [retrainRobotId, setRetrainRobotId] = useState<string | null>(globalInfoStore.retrainRobotId);
|
||||||
const [recordingName, setRecordingName] = useState<string>(globalInfoStore.recordingName);
|
const [recordingName, setRecordingName] = useState<string>(globalInfoStore.recordingName);
|
||||||
const [isLogin, setIsLogin] = useState<boolean>(globalInfoStore.isLogin);
|
const [isLogin, setIsLogin] = useState<boolean>(globalInfoStore.isLogin);
|
||||||
const [initialUrl, setInitialUrl] = useState<string>(globalInfoStore.initialUrl);
|
const [initialUrl, setInitialUrl] = useState<string>(globalInfoStore.initialUrl);
|
||||||
@@ -169,6 +173,8 @@ export const GlobalInfoProvider = ({ children }: { children: JSX.Element }) => {
|
|||||||
setRecordingLength,
|
setRecordingLength,
|
||||||
recordingId,
|
recordingId,
|
||||||
setRecordingId,
|
setRecordingId,
|
||||||
|
retrainRobotId,
|
||||||
|
setRetrainRobotId,
|
||||||
recordingName,
|
recordingName,
|
||||||
setRecordingName,
|
setRecordingName,
|
||||||
initialUrl,
|
initialUrl,
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export const RecordingPage = ({ recordingName }: RecordingPageProps) => {
|
|||||||
|
|
||||||
const { setId, socket } = useSocketStore();
|
const { setId, socket } = useSocketStore();
|
||||||
const { setWidth } = useBrowserDimensionsStore();
|
const { setWidth } = useBrowserDimensionsStore();
|
||||||
const { browserId, setBrowserId, recordingId, recordingUrl, setRecordingUrl } = useGlobalInfoStore();
|
const { browserId, setBrowserId, recordingId, recordingUrl, setRecordingUrl, setRecordingName, setRetrainRobotId } = useGlobalInfoStore();
|
||||||
|
|
||||||
const handleShowOutputData = useCallback(() => {
|
const handleShowOutputData = useCallback(() => {
|
||||||
setShowOutputData(true);
|
setShowOutputData(true);
|
||||||
@@ -80,6 +80,19 @@ export const RecordingPage = ({ recordingName }: RecordingPageProps) => {
|
|||||||
const storedUrl = window.sessionStorage.getItem('recordingUrl');
|
const storedUrl = window.sessionStorage.getItem('recordingUrl');
|
||||||
if (storedUrl && !recordingUrl) {
|
if (storedUrl && !recordingUrl) {
|
||||||
setRecordingUrl(storedUrl);
|
setRecordingUrl(storedUrl);
|
||||||
|
window.sessionStorage.removeItem('recordingUrl');
|
||||||
|
}
|
||||||
|
|
||||||
|
const robotName = window.sessionStorage.getItem('robotName');
|
||||||
|
if (robotName) {
|
||||||
|
setRecordingName(robotName);
|
||||||
|
window.sessionStorage.removeItem('robotName');
|
||||||
|
}
|
||||||
|
|
||||||
|
const recordingId = window.sessionStorage.getItem('robotToRetrain');
|
||||||
|
if (recordingId) {
|
||||||
|
setRetrainRobotId(recordingId);
|
||||||
|
window.sessionStorage.removeItem('robotToRetrain');
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = await getActiveBrowserId();
|
const id = await getActiveBrowserId();
|
||||||
@@ -101,7 +114,7 @@ export const RecordingPage = ({ recordingName }: RecordingPageProps) => {
|
|||||||
return () => {
|
return () => {
|
||||||
isCancelled = true;
|
isCancelled = true;
|
||||||
}
|
}
|
||||||
}, [setId, recordingUrl, setRecordingUrl]);
|
}, [setId, recordingUrl, setRecordingUrl, setRecordingName, setRetrainRobotId]);
|
||||||
|
|
||||||
const changeBrowserDimensions = useCallback(() => {
|
const changeBrowserDimensions = useCallback(() => {
|
||||||
if (browserContentRef.current) {
|
if (browserContentRef.current) {
|
||||||
@@ -126,7 +139,7 @@ export const RecordingPage = ({ recordingName }: RecordingPageProps) => {
|
|||||||
}
|
}
|
||||||
setIsLoaded(true);
|
setIsLoaded(true);
|
||||||
}
|
}
|
||||||
}, [socket, browserId, recordingName, recordingId, isLoaded])
|
}, [socket, browserId, recordingName, recordingId, isLoaded]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
socket?.on('loaded', handleLoaded);
|
socket?.on('loaded', handleLoaded);
|
||||||
|
|||||||
Reference in New Issue
Block a user