feat: recorder revamp ui changes

This commit is contained in:
Rohit Rajan
2025-10-19 22:48:28 +05:30
parent af610c4284
commit 4345fc29fe
7 changed files with 2044 additions and 1072 deletions

View File

@@ -5,13 +5,14 @@ import Canvas from "../recorder/Canvas";
import { Highlighter } from "../recorder/Highlighter";
import { GenericModal } from '../ui/GenericModal';
import { useActionContext } from '../../context/browserActions';
import { useBrowserSteps, TextStep } from '../../context/browserSteps';
import { useBrowserSteps, TextStep, ListStep } from '../../context/browserSteps';
import { useGlobalInfoStore } from '../../context/globalInfo';
import { useTranslation } from 'react-i18next';
import { AuthContext } from '../../context/auth';
import { coordinateMapper } from '../../helpers/coordinateMapper';
import { useBrowserDimensionsStore } from '../../context/browserDimensions';
import { clientSelectorGenerator, ElementFingerprint } from "../../helpers/clientSelectorGenerator";
import { capturedElementHighlighter } from "../../helpers/capturedElementHighlighter";
import DatePicker from "../pickers/DatePicker";
import Dropdown from "../pickers/Dropdown";
import TimePicker from "../pickers/TimePicker";
@@ -182,10 +183,13 @@ export const BrowserWindow = () => {
count?: number;
} | null>(null);
const [initialAutoFieldIds, setInitialAutoFieldIds] = useState<Set<number>>(new Set());
const [manuallyAddedFieldIds, setManuallyAddedFieldIds] = useState<Set<number>>(new Set());
const { socket } = useSocketStore();
const { notify, currentTextActionId, currentListActionId, updateDOMMode, isDOMMode, currentSnapshot } = useGlobalInfoStore();
const { getText, getList, paginationMode, paginationType, limitMode, captureStage } = useActionContext();
const { addTextStep, addListStep } = useBrowserSteps();
const { addTextStep, addListStep, browserSteps } = useBrowserSteps();
const [currentGroupInfo, setCurrentGroupInfo] = useState<{
isGroupElement: boolean;
@@ -1159,6 +1163,7 @@ export const BrowserWindow = () => {
if (Object.keys(autoFields).length > 0) {
setFields(autoFields);
setInitialAutoFieldIds(new Set(Object.keys(autoFields).map(id => parseInt(id))));
addListStep(
listSelector,
@@ -1195,6 +1200,11 @@ export const BrowserWindow = () => {
cachedListSelector,
pendingNotification,
notify,
createFieldsFromChildSelectors,
currentListId,
currentListActionId,
paginationSelector,
addListStep
]);
useEffect(() => {
@@ -1203,6 +1213,77 @@ export const BrowserWindow = () => {
}
}, [listSelector]);
useEffect(() => {
if (!getList || !listSelector || initialAutoFieldIds.size === 0 || !currentListActionId) return;
const currentListStep = browserSteps.find(
step => step.type === 'list' && step.actionId === currentListActionId
);
if (!currentListStep || currentListStep.type !== 'list' || !currentListStep.fields) return;
const currentFieldIds = new Set(Object.keys(currentListStep.fields).map(id => parseInt(id)));
const newManualIds = new Set<number>();
currentFieldIds.forEach(fieldId => {
if (!initialAutoFieldIds.has(fieldId)) {
newManualIds.add(fieldId);
}
});
if (newManualIds.size !== manuallyAddedFieldIds.size ||
![...newManualIds].every(id => manuallyAddedFieldIds.has(id))) {
setManuallyAddedFieldIds(newManualIds);
}
}, [browserSteps, getList, listSelector, initialAutoFieldIds, currentListActionId, manuallyAddedFieldIds]);
useEffect(() => {
if (!isDOMMode) {
capturedElementHighlighter.clearHighlights();
return;
}
const capturedSelectors: Array<{ selector: string }> = [];
if (getText && currentTextActionId) {
const textSteps = browserSteps.filter(
(step): step is TextStep => step.type === 'text' && step.actionId === currentTextActionId
);
textSteps.forEach(step => {
if (step.selectorObj?.selector) {
capturedSelectors.push({
selector: step.selectorObj.selector,
});
}
});
}
if (getList && listSelector && currentListActionId && manuallyAddedFieldIds.size > 0) {
const listSteps = browserSteps.filter(
step => step.type === 'list' && step.actionId === currentListActionId
) as ListStep[];
listSteps.forEach(listStep => {
if (listStep.fields) {
Object.entries(listStep.fields).forEach(([fieldId, field]: [string, any]) => {
if (manuallyAddedFieldIds.has(parseInt(fieldId)) && field.selectorObj?.selector) {
capturedSelectors.push({
selector: field.selectorObj.selector,
});
}
});
}
});
}
if (capturedSelectors.length > 0) {
capturedElementHighlighter.applyHighlights(capturedSelectors);
} else {
capturedElementHighlighter.clearHighlights();
}
}, [browserSteps, getText, getList, listSelector, currentTextActionId, currentListActionId, isDOMMode, manuallyAddedFieldIds]);
useEffect(() => {
coordinateMapper.updateDimensions(dimensions.width, dimensions.height, viewportInfo.width, viewportInfo.height);
}, [viewportInfo, dimensions.width, dimensions.height]);
@@ -1216,7 +1297,6 @@ export const BrowserWindow = () => {
useEffect(() => {
const storedListSelector = sessionStorage.getItem('recordingListSelector');
// Only restore state if it exists in sessionStorage
if (storedListSelector && !listSelector) {
setListSelector(storedListSelector);
}
@@ -1225,7 +1305,6 @@ export const BrowserWindow = () => {
const onMouseMove = (e: MouseEvent) => {
if (canvasRef && canvasRef.current && highlighterData) {
const canvasRect = canvasRef.current.getBoundingClientRect();
// mousemove outside the browser window
if (
e.pageX < canvasRect.left
|| e.pageX > canvasRect.right
@@ -1242,6 +1321,8 @@ export const BrowserWindow = () => {
setFields({});
setCurrentListId(null);
setCachedChildSelectors([]);
setInitialAutoFieldIds(new Set());
setManuallyAddedFieldIds(new Set());
}, []);
useEffect(() => {
@@ -1262,7 +1343,7 @@ export const BrowserWindow = () => {
}
}
}
}, [screenShot, user?.id]);
}, [user?.id]);
useEffect(() => {
if (socket) {
@@ -1456,7 +1537,6 @@ export const BrowserWindow = () => {
}
highlighterUpdateRef.current = now;
// Map the incoming DOMRect from browser coordinates to canvas coordinates
const mappedRect = new DOMRect(
data.rect.x,
data.rect.y,
@@ -1477,17 +1557,14 @@ export const BrowserWindow = () => {
if (limitMode) {
setHighlighterData(null);
} else if (paginationMode) {
// Only set highlighterData if type is not empty, 'none', 'scrollDown', or 'scrollUp'
if (paginationType !== '' && !['none', 'scrollDown', 'scrollUp'].includes(paginationType)) {
setHighlighterData(mappedData);
} else {
setHighlighterData(null);
}
} else if (mappedData.childSelectors && mappedData.childSelectors.includes(mappedData.selector)) {
// Highlight only valid child elements within the listSelector
setHighlighterData(mappedData);
} else if (mappedData.elementInfo?.isIframeContent && mappedData.childSelectors) {
// Handle iframe elements
const isIframeChild = mappedData.childSelectors.some(childSelector =>
mappedData.selector.includes(':>>') &&
childSelector.split(':>>').some(part =>
@@ -1496,7 +1573,6 @@ export const BrowserWindow = () => {
);
setHighlighterData(isIframeChild ? mappedData : null);
} else if (mappedData.selector.includes(':>>') && hasValidChildSelectors) {
// Handle mixed DOM cases with iframes
const selectorParts = mappedData.selector.split(':>>').map(part => part.trim());
const isValidMixedSelector = selectorParts.some(part =>
mappedData.childSelectors!.some(childSelector =>
@@ -1505,7 +1581,6 @@ export const BrowserWindow = () => {
);
setHighlighterData(isValidMixedSelector ? mappedData : null);
} else if (mappedData.elementInfo?.isShadowRoot && mappedData.childSelectors) {
// Handle Shadow DOM elements
const isShadowChild = mappedData.childSelectors.some(childSelector =>
mappedData.selector.includes('>>') &&
childSelector.split('>>').some(part =>
@@ -1514,7 +1589,6 @@ export const BrowserWindow = () => {
);
setHighlighterData(isShadowChild ? mappedData : null);
} else if (mappedData.selector.includes('>>') && hasValidChildSelectors) {
// Handle mixed DOM cases
const selectorParts = mappedData.selector.split('>>').map(part => part.trim());
const isValidMixedSelector = selectorParts.some(part =>
mappedData.childSelectors!.some(childSelector =>
@@ -1523,15 +1597,12 @@ export const BrowserWindow = () => {
);
setHighlighterData(isValidMixedSelector ? mappedData : null);
} else {
// If not a valid child in normal mode, clear the highlighter
setHighlighterData(null);
}
} else {
// Set highlighterData for the initial listSelector selection
setHighlighterData(mappedData);
}
} else {
// For non-list steps
setHighlighterData(mappedData);
}
}, [getList, socket, listSelector, paginationMode, paginationType, limitMode]);
@@ -2114,7 +2185,7 @@ export const BrowserWindow = () => {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
`}</style>
`}</style>j
{(getText === true || getList === true) &&
!showAttributeModal &&