diff --git a/src/components/organisms/BrowserWindow.tsx b/src/components/organisms/BrowserWindow.tsx index c205856d..880d0476 100644 --- a/src/components/organisms/BrowserWindow.tsx +++ b/src/components/organisms/BrowserWindow.tsx @@ -214,7 +214,7 @@ export const BrowserWindow = () => { const newField: TextStep = { id: Date.now(), type: 'text', - label: `Label ${Object.keys(fields).length + 1}`, + label: ``, data: data, selectorObj: { selector: highlighterData.selector, @@ -274,7 +274,7 @@ export const BrowserWindow = () => { const newField: TextStep = { id: Date.now(), type: 'text', - label: `Label ${Object.keys(fields).length + 1}`, + label: ``, data: data, selectorObj: { selector: selectedElement.selector, diff --git a/src/components/organisms/RightSidePanel.tsx b/src/components/organisms/RightSidePanel.tsx index d73d7ff2..5ba606c1 100644 --- a/src/components/organisms/RightSidePanel.tsx +++ b/src/components/organisms/RightSidePanel.tsx @@ -19,29 +19,34 @@ import Radio from '@mui/material/Radio'; import RadioGroup from '@mui/material/RadioGroup'; // TODO: -// 1. Handle field label update -// 2. Handle field deletion | confirmation -// 3. Add description for each browser step -// 4. Handle non custom action steps +// 1. Add description for each browser step +// 2. Handle non custom action steps interface RightSidePanelProps { onFinishCapture: () => void; } export const RightSidePanel: React.FC = ({ onFinishCapture }) => { - const [textLabels, setTextLabels] = useState<{ [id: number]: string }>({}); - const [errors, setErrors] = useState<{ [id: number]: string }>({}); - const [confirmedTextSteps, setConfirmedTextSteps] = useState<{ [id: number]: boolean }>({}); + const [textLabels, setTextLabels] = useState<{ [id: string]: string }>({}); + const [errors, setErrors] = useState<{ [id: string]: string }>({}); + const [confirmedTextSteps, setConfirmedTextSteps] = useState<{ [id: string]: boolean }>({}); + const [confirmedListTextFields, setConfirmedListTextFields] = useState<{ [listId: string]: { [fieldKey: string]: boolean } }>({}); const [showPaginationOptions, setShowPaginationOptions] = useState(false); const [showLimitOptions, setShowLimitOptions] = useState(false); const [captureStage, setCaptureStage] = useState<'initial' | 'pagination' | 'limit' | 'complete'>('initial'); const { lastAction, notify } = useGlobalInfoStore(); const { getText, startGetText, stopGetText, getScreenshot, startGetScreenshot, stopGetScreenshot, paginationMode, getList, startGetList, stopGetList, startPaginationMode, stopPaginationMode, paginationType, updatePaginationType, limitMode, limitType, customLimit, updateLimitType, updateCustomLimit, stopLimitMode, startLimitMode } = useActionContext(); - const { browserSteps, updateBrowserTextStepLabel, deleteBrowserStep, addScreenshotStep } = useBrowserSteps(); + const { browserSteps, updateBrowserTextStepLabel, deleteBrowserStep, addScreenshotStep, updateListTextFieldLabel, removeListTextField } = useBrowserSteps(); const { socket } = useSocketStore(); - const handleTextLabelChange = (id: number, label: string) => { - setTextLabels(prevLabels => ({ ...prevLabels, [id]: label })); + const handleTextLabelChange = (id: number, label: string, listId?: number, fieldKey?: string) => { + if (listId !== undefined && fieldKey !== undefined) { + // This is a text field within a list step + updateListTextFieldLabel(listId, fieldKey, label); + } else { + // This is a standalone text step + setTextLabels(prevLabels => ({ ...prevLabels, [id]: label })); + } if (!label.trim()) { setErrors(prevErrors => ({ ...prevErrors, [id]: 'Label cannot be empty' })); } else { @@ -71,6 +76,32 @@ export const RightSidePanel: React.FC = ({ onFinishCapture }); }; + const handleListTextFieldConfirm = (listId: number, fieldKey: string) => { + setConfirmedListTextFields(prev => ({ + ...prev, + [listId]: { + ...(prev[listId] || {}), + [fieldKey]: true + } + })); + }; + + const handleListTextFieldDiscard = (listId: number, fieldKey: string) => { + removeListTextField(listId, fieldKey); + setConfirmedListTextFields(prev => { + const updatedListFields = { ...(prev[listId] || {}) }; + delete updatedListFields[fieldKey]; + return { + ...prev, + [listId]: updatedListFields + }; + }); + setErrors(prev => { + const { [fieldKey]: _, ...rest } = prev; + return rest; + }); + }; + const getTextSettingsObject = useCallback(() => { const settings: Record = {}; browserSteps.forEach(step => { @@ -131,6 +162,7 @@ export const RightSidePanel: React.FC = ({ onFinishCapture return settings; }, [browserSteps, paginationType, limitType, customLimit]); + const resetListState = useCallback(() => { setShowPaginationOptions(false); @@ -369,7 +401,7 @@ export const RightSidePanel: React.FC = ({ onFinishCapture { }} + onChange={(e) => handleTextLabelChange(field.id, e.target.value, step.id, key)} fullWidth margin="normal" InputProps={{ @@ -394,6 +426,23 @@ export const RightSidePanel: React.FC = ({ onFinishCapture ) }} /> + {!confirmedListTextFields[step.id]?.[key] && ( + + + + + )} ))} diff --git a/src/context/browserSteps.tsx b/src/context/browserSteps.tsx index 1c9dbf34..c2cab814 100644 --- a/src/context/browserSteps.tsx +++ b/src/context/browserSteps.tsx @@ -42,12 +42,15 @@ interface BrowserStepsContextType { addScreenshotStep: (fullPage: boolean) => void; deleteBrowserStep: (id: number) => void; updateBrowserTextStepLabel: (id: number, newLabel: string) => void; + updateListTextFieldLabel: (listId: number, fieldKey: string, newLabel: string) => void; + removeListTextField: (listId: number, fieldKey: string) => void; } const BrowserStepsContext = createContext(undefined); export const BrowserStepsProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [browserSteps, setBrowserSteps] = useState([]); + const [discardedFields, setDiscardedFields] = useState>(new Set()); const addTextStep = (label: string, data: string, selectorObj: SelectorObject) => { setBrowserSteps(prevSteps => [ @@ -62,12 +65,19 @@ export const BrowserStepsProvider: React.FC<{ children: React.ReactNode }> = ({ step => step.type === 'list' && step.id === listId ); if (existingListStepIndex !== -1) { - // Update the existing ListStep with new fields + // Update the existing ListStep with new fields, excluding discarded ones const updatedSteps = [...prevSteps]; const existingListStep = updatedSteps[existingListStepIndex] as ListStep; + const filteredNewFields = Object.entries(newFields).reduce((acc, [key, value]) => { + if (!discardedFields.has(`${listId}-${key}`)) { + acc[key] = value; + } + return acc; + }, {} as { [key: string]: TextStep }); + updatedSteps[existingListStepIndex] = { ...existingListStep, - fields: { ...existingListStep.fields, ...newFields }, + fields: { ...existingListStep.fields, ...filteredNewFields }, pagination: pagination, limit: limit, }; @@ -81,7 +91,6 @@ export const BrowserStepsProvider: React.FC<{ children: React.ReactNode }> = ({ } }); }; - const addScreenshotStep = (fullPage: boolean) => { setBrowserSteps(prevSteps => [ ...prevSteps, @@ -101,6 +110,41 @@ export const BrowserStepsProvider: React.FC<{ children: React.ReactNode }> = ({ ); }; + const updateListTextFieldLabel = (listId: number, fieldKey: string, newLabel: string) => { + setBrowserSteps(prevSteps => + prevSteps.map(step => { + if (step.type === 'list' && step.id === listId) { + return { + ...step, + fields: { + ...step.fields, + [fieldKey]: { + ...step.fields[fieldKey], + label: newLabel + } + } + }; + } + return step; + }) + ); + }; + + const removeListTextField = (listId: number, fieldKey: string) => { + setBrowserSteps(prevSteps => + prevSteps.map(step => { + if (step.type === 'list' && step.id === listId) { + const { [fieldKey]: _, ...remainingFields } = step.fields; + return { + ...step, + fields: remainingFields + }; + } + return step; + }) + ); + setDiscardedFields(prevDiscarded => new Set(prevDiscarded).add(`${listId}-${fieldKey}`)); + }; return ( = ({ addScreenshotStep, deleteBrowserStep, updateBrowserTextStepLabel, + updateListTextFieldLabel, + removeListTextField, }}> {children}