Enabled users to rename or update the titles of all recorded actions
This commit is contained in:
@@ -81,7 +81,7 @@
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"typedoc": "^0.23.8",
|
||||
"typescript": "^4.6.3",
|
||||
"typescript": "^5.0.0",
|
||||
"uuid": "^8.3.2",
|
||||
"uuidv4": "^6.2.12",
|
||||
"web-vitals": "^2.1.4",
|
||||
|
||||
@@ -254,7 +254,7 @@ function handleWorkflowActions(workflow: any[], credentials: Credentials) {
|
||||
router.put('/recordings/:id', requireSignIn, async (req: AuthenticatedRequest, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { name, limits, credentials, targetUrl } = req.body;
|
||||
const { name, limits, credentials, targetUrl, workflow: incomingWorkflow } = req.body;
|
||||
|
||||
// Validate input
|
||||
if (!name && !limits && !credentials && !targetUrl) {
|
||||
@@ -298,7 +298,10 @@ router.put('/recordings/:id', requireSignIn, async (req: AuthenticatedRequest, r
|
||||
|
||||
await robot.save();
|
||||
|
||||
let workflow = [...robot.recording.workflow]; // Create a copy of the workflow
|
||||
// Start with existing workflow or allow client to supply a full workflow replacement
|
||||
let workflow = incomingWorkflow && Array.isArray(incomingWorkflow)
|
||||
? JSON.parse(JSON.stringify(incomingWorkflow))
|
||||
: [...robot.recording.workflow]; // Create a copy of the workflow
|
||||
|
||||
if (credentials) {
|
||||
workflow = handleWorkflowActions(workflow, credentials);
|
||||
|
||||
@@ -32,7 +32,9 @@ export const updateRecording = async (id: string, data: {
|
||||
name?: string;
|
||||
limits?: Array<{pairIndex: number, actionIndex: number, argIndex: number, limit: number}>;
|
||||
credentials?: Credentials;
|
||||
targetUrl?: string
|
||||
targetUrl?: string;
|
||||
// optional full workflow replacement (useful for action renames)
|
||||
workflow?: any[];
|
||||
}): Promise<boolean> => {
|
||||
try {
|
||||
const response = await axios.put(`${apiUrl}/storage/recordings/${id}`, data);
|
||||
|
||||
@@ -417,6 +417,43 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleActionNameChange = (
|
||||
pairIndex: number,
|
||||
actionIndex: number,
|
||||
newName: string
|
||||
) => {
|
||||
setRobot((prev) => {
|
||||
if (!prev) return prev;
|
||||
|
||||
const updatedWorkflow = [...prev.recording.workflow];
|
||||
if (
|
||||
updatedWorkflow.length > pairIndex &&
|
||||
updatedWorkflow[pairIndex]?.what &&
|
||||
updatedWorkflow[pairIndex].what.length > actionIndex
|
||||
) {
|
||||
const action = { ...updatedWorkflow[pairIndex].what[actionIndex] };
|
||||
// update the standard name field
|
||||
action.name = newName;
|
||||
|
||||
// also update legacy __name location if present (args[0].__name)
|
||||
if (action.args && action.args.length > 0 && typeof action.args[0] === 'object' && action.args[0] !== null && '__name' in action.args[0]) {
|
||||
try {
|
||||
action.args[0] = { ...action.args[0], __name: newName };
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
updatedWorkflow[pairIndex].what[actionIndex] = action;
|
||||
}
|
||||
|
||||
return {
|
||||
...prev,
|
||||
recording: { ...prev.recording, workflow: updatedWorkflow },
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleTargetUrlChange = (newUrl: string) => {
|
||||
setRobot((prev) => {
|
||||
if (!prev) return prev;
|
||||
@@ -497,6 +534,51 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const renderActionNameFields = () => {
|
||||
if (!robot || !robot.recording || !robot.recording.workflow) return null;
|
||||
|
||||
const editableActions = new Set(['screenshot', 'scrapeList', 'scrapeSchema']);
|
||||
const inputs: JSX.Element[] = [];
|
||||
|
||||
robot.recording.workflow.forEach((pair, pairIndex) => {
|
||||
if (!pair.what) return;
|
||||
|
||||
pair.what.forEach((action, actionIndex) => {
|
||||
// Only show editable name inputs for meaningful action types
|
||||
if (!editableActions.has(String(action.action))) return;
|
||||
|
||||
// derive current name from possible fields
|
||||
const currentName =
|
||||
action.name ||
|
||||
(action.args && action.args[0] && typeof action.args[0] === 'object' && action.args[0].__name) ||
|
||||
'';
|
||||
|
||||
inputs.push(
|
||||
<TextField
|
||||
key={`action-name-${pairIndex}-${actionIndex}`}
|
||||
label={`${t('Action')} ${pairIndex}:${actionIndex} - ${String(action.action)}`}
|
||||
type="text"
|
||||
value={currentName}
|
||||
onChange={(e) => handleActionNameChange(pairIndex, actionIndex, e.target.value)}
|
||||
style={{ marginBottom: '12px' }}
|
||||
fullWidth
|
||||
/>
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
if (inputs.length === 0) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="body1" style={{ marginBottom: '10px' }}>
|
||||
{t('Action Names')}
|
||||
</Typography>
|
||||
{inputs}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const renderCredentialFields = (
|
||||
selectors: string[],
|
||||
headerText: string,
|
||||
@@ -574,7 +656,7 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => {
|
||||
|
||||
const targetUrl = getTargetUrl();
|
||||
|
||||
const payload = {
|
||||
const payload: any = {
|
||||
name: robot.recording_meta.name,
|
||||
limits: scrapeListLimits.map((limit) => ({
|
||||
pairIndex: limit.pairIndex,
|
||||
@@ -584,6 +666,8 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => {
|
||||
})),
|
||||
credentials: credentialsForPayload,
|
||||
targetUrl: targetUrl,
|
||||
// send the (possibly edited) workflow so backend can persist action name changes
|
||||
workflow: robot.recording.workflow,
|
||||
};
|
||||
|
||||
const success = await updateRecording(robot.recording_meta.id, payload);
|
||||
@@ -647,6 +731,7 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => {
|
||||
/>
|
||||
|
||||
{renderScrapeListLimitFields()}
|
||||
{renderActionNameFields()}
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user