Merge pull request #602 from getmaxun/single-discard

feat: discard only current active action
This commit is contained in:
Karishma Shukla
2025-05-29 00:21:20 +05:30
committed by GitHub
4 changed files with 125 additions and 37 deletions

View File

@@ -85,7 +85,7 @@ export const BrowserWindow = () => {
const [paginationSelector, setPaginationSelector] = useState<string>('');
const { socket } = useSocketStore();
const { notify } = useGlobalInfoStore();
const { notify, currentTextActionId, currentListActionId } = useGlobalInfoStore();
const { getText, getList, paginationMode, paginationType, limitMode, captureStage } = useActionContext();
const { addTextStep, addListStep, updateListStepData } = useBrowserSteps();
@@ -326,8 +326,8 @@ export const BrowserWindow = () => {
selector: highlighterData.selector,
tag: highlighterData.elementInfo?.tagName,
shadow: highlighterData.elementInfo?.isShadowRoot,
attribute
});
attribute,
}, currentTextActionId || `text-${crypto.randomUUID()}`);
} else {
// Show the modal if there are multiple options
setAttributeOptions(options);
@@ -344,7 +344,7 @@ export const BrowserWindow = () => {
if (paginationType !== '' && paginationType !== 'scrollDown' && paginationType !== 'scrollUp' && paginationType !== 'none') {
setPaginationSelector(highlighterData.selector);
notify(`info`, t('browser_window.attribute_modal.notifications.pagination_select_success'));
addListStep(listSelector!, fields, currentListId || 0, { type: paginationType, selector: highlighterData.selector });
addListStep(listSelector!, fields, currentListId || 0, currentListActionId || `list-${crypto.randomUUID()}`, { type: paginationType, selector: highlighterData.selector });
socket?.emit('setPaginationMode', { pagination: false });
}
return;
@@ -412,6 +412,7 @@ export const BrowserWindow = () => {
listSelector,
updatedFields,
currentListId,
currentListActionId || `list-${crypto.randomUUID()}`,
{ type: '', selector: paginationSelector }
);
}
@@ -449,7 +450,7 @@ export const BrowserWindow = () => {
tag: selectedElement.info?.tagName,
shadow: selectedElement.info?.isShadowRoot,
attribute: attribute
});
}, currentTextActionId || `text-${crypto.randomUUID()}`);
}
if (getList === true && listSelector && currentListId) {
const newField: TextStep = {
@@ -484,6 +485,7 @@ export const BrowserWindow = () => {
listSelector,
updatedFields,
currentListId,
currentListActionId || `list-${crypto.randomUUID()}`,
{ type: '', selector: paginationSelector }
);
}

View File

@@ -52,7 +52,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
const [isCaptureListConfirmed, setIsCaptureListConfirmed] = useState(false);
const { panelHeight } = useBrowserDimensionsStore();
const { lastAction, notify, currentWorkflowActionsState, setCurrentWorkflowActionsState, resetInterpretationLog } = useGlobalInfoStore();
const { lastAction, notify, currentWorkflowActionsState, setCurrentWorkflowActionsState, resetInterpretationLog, currentListActionId, setCurrentListActionId, currentTextActionId, setCurrentTextActionId, currentScreenshotActionId, setCurrentScreenshotActionId } = useGlobalInfoStore();
const {
getText, startGetText, stopGetText,
getList, startGetList, stopGetList,
@@ -69,7 +69,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
startAction, finishAction
} = useActionContext();
const { browserSteps, updateBrowserTextStepLabel, deleteBrowserStep, addScreenshotStep, updateListTextFieldLabel, removeListTextField, updateListStepLimit } = useBrowserSteps();
const { browserSteps, updateBrowserTextStepLabel, deleteBrowserStep, addScreenshotStep, updateListTextFieldLabel, removeListTextField, updateListStepLimit, deleteStepsByActionId } = useBrowserSteps();
const { id, socket } = useSocketStore();
const { t } = useTranslation();
@@ -139,15 +139,21 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
const handleStartGetText = () => {
setIsCaptureTextConfirmed(false);
const newActionId = `text-${crypto.randomUUID()}`;
setCurrentTextActionId(newActionId);
startGetText();
}
const handleStartGetList = () => {
setIsCaptureListConfirmed(false);
const newActionId = `list-${crypto.randomUUID()}`;
setCurrentListActionId(newActionId);
startGetList();
}
const handleStartGetScreenshot = () => {
const newActionId = `screenshot-${crypto.randomUUID()}`;
setCurrentScreenshotActionId(newActionId);
startGetScreenshot();
};
@@ -277,6 +283,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
socket?.emit('action', { action: 'scrapeSchema', settings });
}
setIsCaptureTextConfirmed(true);
setCurrentTextActionId('');
resetInterpretationLog();
finishAction('text');
onFinishCapture();
@@ -337,6 +344,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
notify('error', t('right_panel.errors.unable_create_settings'));
}
handleStopGetList();
setCurrentListActionId('');
resetInterpretationLog();
finishAction('list');
onFinishCapture();
@@ -434,35 +442,73 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
const discardGetText = useCallback(() => {
stopGetText();
browserSteps.forEach(step => {
if (step.type === 'text') {
deleteBrowserStep(step.id);
}
if (currentTextActionId) {
const stepsToDelete = browserSteps
.filter(step => step.type === 'text' && step.actionId === currentTextActionId)
.map(step => step.id);
deleteStepsByActionId(currentTextActionId);
setTextLabels(prevLabels => {
const newLabels = { ...prevLabels };
stepsToDelete.forEach(id => {
delete newLabels[id];
});
setTextLabels({});
setErrors({});
setConfirmedTextSteps({});
return newLabels;
});
setErrors(prevErrors => {
const newErrors = { ...prevErrors };
stepsToDelete.forEach(id => {
delete newErrors[id];
});
return newErrors;
});
setConfirmedTextSteps(prev => {
const newConfirmed = { ...prev };
stepsToDelete.forEach(id => {
delete newConfirmed[id];
});
return newConfirmed;
});
}
setCurrentTextActionId('');
setIsCaptureTextConfirmed(false);
notify('error', t('right_panel.errors.capture_text_discarded'));
}, [browserSteps, stopGetText, deleteBrowserStep, notify, t]);
}, [currentTextActionId, browserSteps, stopGetText, deleteStepsByActionId, notify, t]);
const discardGetList = useCallback(() => {
stopGetList();
browserSteps.forEach(step => {
if (step.type === 'list') {
deleteBrowserStep(step.id);
}
if (currentListActionId) {
const listStepsToDelete = browserSteps
.filter(step => step.type === 'list' && step.actionId === currentListActionId)
.map(step => step.id);
deleteStepsByActionId(currentListActionId);
setConfirmedListTextFields(prev => {
const newConfirmed = { ...prev };
listStepsToDelete.forEach(id => {
delete newConfirmed[id];
});
return newConfirmed;
});
}
resetListState();
stopPaginationMode();
stopLimitMode();
setShowPaginationOptions(false);
setShowLimitOptions(false);
setCaptureStage('initial');
setConfirmedListTextFields({});
setCurrentListActionId('');
setIsCaptureListConfirmed(false);
notify('error', t('right_panel.errors.capture_list_discarded'));
}, [browserSteps, stopGetList, deleteBrowserStep, resetListState, setShowPaginationOptions, setShowLimitOptions, setCaptureStage, notify, t]);
}, [currentListActionId, browserSteps, stopGetList, deleteStepsByActionId, resetListState, setShowPaginationOptions, setShowLimitOptions, setCaptureStage, notify, t]);
const captureScreenshot = (fullPage: boolean) => {
const screenshotSettings: ScreenshotSettings = {
@@ -474,7 +520,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
scale: 'device',
};
socket?.emit('action', { action: 'screenshot', settings: screenshotSettings });
addScreenshotStep(fullPage);
addScreenshotStep(fullPage, currentScreenshotActionId);
stopGetScreenshot();
resetInterpretationLog();
finishAction('screenshot');

View File

@@ -6,12 +6,14 @@ export interface TextStep {
label: string;
data: string;
selectorObj: SelectorObject;
actionId?: string; // Add actionId to track which action created this step
}
interface ScreenshotStep {
id: number;
type: 'screenshot';
fullPage: boolean;
actionId?: string; // Add actionId to track which action created this step
}
export interface ListStep {
@@ -24,6 +26,7 @@ export interface ListStep {
selector: string;
};
limit?: number;
actionId?: string; // Add actionId to track which action created this step
}
export type BrowserStep = TextStep | ScreenshotStep | ListStep;
@@ -38,15 +41,16 @@ export interface SelectorObject {
interface BrowserStepsContextType {
browserSteps: BrowserStep[];
addTextStep: (label: string, data: string, selectorObj: SelectorObject) => void;
addListStep: (listSelector: string, fields: { [key: string]: TextStep }, listId: number, pagination?: { type: string; selector: string }, limit?: number) => void
addScreenshotStep: (fullPage: boolean) => void;
addTextStep: (label: string, data: string, selectorObj: SelectorObject, actionId: string) => void;
addListStep: (listSelector: string, fields: { [key: string]: TextStep }, listId: number, actionId: string, pagination?: { type: string; selector: string }, limit?: number) => void
addScreenshotStep: (fullPage: boolean, actionId: string) => void;
deleteBrowserStep: (id: number) => void;
updateBrowserTextStepLabel: (id: number, newLabel: string) => void;
updateListTextFieldLabel: (listId: number, fieldKey: string, newLabel: string) => void;
updateListStepLimit: (listId: number, limit: number) => void;
updateListStepData: (listId: number, extractedData: any[]) => void;
removeListTextField: (listId: number, fieldKey: string) => void;
deleteStepsByActionId: (actionId: string) => void; // New function to delete steps by actionId
}
const BrowserStepsContext = createContext<BrowserStepsContextType | undefined>(undefined);
@@ -55,14 +59,14 @@ export const BrowserStepsProvider: React.FC<{ children: React.ReactNode }> = ({
const [browserSteps, setBrowserSteps] = useState<BrowserStep[]>([]);
const [discardedFields, setDiscardedFields] = useState<Set<string>>(new Set());
const addTextStep = (label: string, data: string, selectorObj: SelectorObject) => {
const addTextStep = (label: string, data: string, selectorObj: SelectorObject, actionId: string) => {
setBrowserSteps(prevSteps => [
...prevSteps,
{ id: Date.now(), type: 'text', label, data, selectorObj }
{ id: Date.now(), type: 'text', label, data, selectorObj, actionId }
]);
};
const addListStep = (listSelector: string, newFields: { [key: string]: TextStep }, listId: number, pagination?: { type: string; selector: string }, limit?: number) => {
const addListStep = (listSelector: string, newFields: { [key: string]: TextStep }, listId: number, actionId: string, pagination?: { type: string; selector: string }, limit?: number) => {
setBrowserSteps(prevSteps => {
const existingListStepIndex = prevSteps.findIndex(step => step.type === 'list' && step.id === listId);
@@ -77,10 +81,14 @@ export const BrowserStepsProvider: React.FC<{ children: React.ReactNode }> = ({
if (existingListStep.fields[key]) {
acc[key] = {
...field,
label: existingListStep.fields[key].label
label: existingListStep.fields[key].label,
actionId
};
} else {
acc[key] = field;
acc[key] = {
...field,
actionId
};
}
}
return acc;
@@ -90,22 +98,31 @@ export const BrowserStepsProvider: React.FC<{ children: React.ReactNode }> = ({
...existingListStep,
fields: mergedFields,
pagination: pagination || existingListStep.pagination,
limit: limit
limit: limit,
actionId
};
return updatedSteps;
} else {
const fieldsWithActionId = Object.entries(newFields).reduce((acc, [key, field]) => {
acc[key] = {
...field,
actionId
};
return acc;
}, {} as { [key: string]: TextStep });
return [
...prevSteps,
{ id: listId, type: 'list', listSelector, fields: newFields, pagination, limit }
{ id: listId, type: 'list', listSelector, fields: fieldsWithActionId, pagination, limit, actionId }
];
}
});
};
const addScreenshotStep = (fullPage: boolean) => {
const addScreenshotStep = (fullPage: boolean, actionId: string) => {
setBrowserSteps(prevSteps => [
...prevSteps,
{ id: Date.now(), type: 'screenshot', fullPage }
{ id: Date.now(), type: 'screenshot', fullPage, actionId }
]);
};
@@ -113,6 +130,10 @@ export const BrowserStepsProvider: React.FC<{ children: React.ReactNode }> = ({
setBrowserSteps(prevSteps => prevSteps.filter(step => step.id !== id));
};
const deleteStepsByActionId = (actionId: string) => {
setBrowserSteps(prevSteps => prevSteps.filter(step => step.actionId !== actionId));
};
const updateBrowserTextStepLabel = (id: number, newLabel: string) => {
setBrowserSteps(prevSteps =>
prevSteps.map(step =>
@@ -199,6 +220,7 @@ export const BrowserStepsProvider: React.FC<{ children: React.ReactNode }> = ({
updateListStepLimit,
updateListStepData,
removeListTextField,
deleteStepsByActionId, // Export the new function
}}>
{children}
</BrowserStepsContext.Provider>

View File

@@ -80,6 +80,12 @@ interface GlobalInfo {
}) => void;
shouldResetInterpretationLog: boolean;
resetInterpretationLog: () => void;
currentTextActionId: string;
setCurrentTextActionId: (actionId: string) => void;
currentListActionId: string;
setCurrentListActionId: (actionId: string) => void;
currentScreenshotActionId: string;
setCurrentScreenshotActionId: (actionId: string) => void;
};
class GlobalInfoStore implements Partial<GlobalInfo> {
@@ -106,6 +112,9 @@ class GlobalInfoStore implements Partial<GlobalInfo> {
hasScrapeSchemaAction: false,
};
shouldResetInterpretationLog = false;
currentTextActionId = '';
currentListActionId = '';
currentScreenshotActionId = '';
};
const globalInfoStore = new GlobalInfoStore();
@@ -129,6 +138,9 @@ export const GlobalInfoProvider = ({ children }: { children: JSX.Element }) => {
const [recordingUrl, setRecordingUrl] = useState<string>(globalInfoStore.recordingUrl);
const [currentWorkflowActionsState, setCurrentWorkflowActionsState] = useState(globalInfoStore.currentWorkflowActionsState);
const [shouldResetInterpretationLog, setShouldResetInterpretationLog] = useState<boolean>(globalInfoStore.shouldResetInterpretationLog);
const [currentTextActionId, setCurrentTextActionId] = useState<string>('');
const [currentListActionId, setCurrentListActionId] = useState<string>('');
const [currentScreenshotActionId, setCurrentScreenshotActionId] = useState<string>('');
const notify = (severity: 'error' | 'warning' | 'info' | 'success', message: string) => {
setNotification({ severity, message, isOpen: true });
@@ -187,6 +199,12 @@ export const GlobalInfoProvider = ({ children }: { children: JSX.Element }) => {
setCurrentWorkflowActionsState,
shouldResetInterpretationLog,
resetInterpretationLog,
currentTextActionId,
setCurrentTextActionId,
currentListActionId,
setCurrentListActionId,
currentScreenshotActionId,
setCurrentScreenshotActionId,
}}
>
{children}