Merge pull request #187 from getmaxun/list-nest
feat: better nested elements capture in capture list
This commit is contained in:
@@ -559,6 +559,8 @@ export class WorkflowGenerator {
|
||||
if (this.listSelector !== '') {
|
||||
const childSelectors = await getChildSelectors(page, this.listSelector || '');
|
||||
this.socket.emit('highlighter', { rect, selector: displaySelector, elementInfo, childSelectors })
|
||||
console.log(`Child Selectors: ${childSelectors}`)
|
||||
console.log(`Parent Selector: ${this.listSelector}`)
|
||||
} else {
|
||||
this.socket.emit('highlighter', { rect, selector: displaySelector, elementInfo });
|
||||
}
|
||||
|
||||
@@ -794,6 +794,7 @@ export const getNonUniqueSelectors = async (page: Page, coordinates: Coordinates
|
||||
export const getChildSelectors = async (page: Page, parentSelector: string): Promise<string[]> => {
|
||||
try {
|
||||
const childSelectors = await page.evaluate((parentSelector: string) => {
|
||||
// Function to get a non-unique selector based on tag and class (if present)
|
||||
function getNonUniqueSelector(element: HTMLElement): string {
|
||||
let selector = element.tagName.toLowerCase();
|
||||
|
||||
@@ -811,6 +812,7 @@ export const getChildSelectors = async (page: Page, parentSelector: string): Pro
|
||||
return selector;
|
||||
}
|
||||
|
||||
// Function to generate selector path from an element to its parent
|
||||
function getSelectorPath(element: HTMLElement | null): string {
|
||||
if (!element || !element.parentElement) return '';
|
||||
|
||||
@@ -820,22 +822,33 @@ export const getChildSelectors = async (page: Page, parentSelector: string): Pro
|
||||
return `${parentSelector} > ${elementSelector}`;
|
||||
}
|
||||
|
||||
function getAllDescendantSelectors(element: HTMLElement, stopAtParent: HTMLElement | null): string[] {
|
||||
// Function to recursively get all descendant selectors
|
||||
function getAllDescendantSelectors(element: HTMLElement): string[] {
|
||||
let selectors: string[] = [];
|
||||
const children = Array.from(element.children) as HTMLElement[];
|
||||
|
||||
for (const child of children) {
|
||||
selectors.push(getSelectorPath(child));
|
||||
selectors = selectors.concat(getAllDescendantSelectors(child, stopAtParent));
|
||||
const childPath = getSelectorPath(child);
|
||||
if (childPath) {
|
||||
selectors.push(childPath); // Add direct child path
|
||||
selectors = selectors.concat(getAllDescendantSelectors(child)); // Recursively process descendants
|
||||
}
|
||||
}
|
||||
|
||||
return selectors;
|
||||
}
|
||||
|
||||
const parentElement = document.querySelector(parentSelector) as HTMLElement;
|
||||
if (!parentElement) return [];
|
||||
// Find all occurrences of the parent selector in the DOM
|
||||
const parentElements = Array.from(document.querySelectorAll(parentSelector)) as HTMLElement[];
|
||||
const allChildSelectors = new Set<string>(); // Use a set to ensure uniqueness
|
||||
|
||||
return getAllDescendantSelectors(parentElement, parentElement);
|
||||
// Process each parent element and its descendants
|
||||
parentElements.forEach((parentElement) => {
|
||||
const descendantSelectors = getAllDescendantSelectors(parentElement);
|
||||
descendantSelectors.forEach((selector) => allChildSelectors.add(selector)); // Add selectors to the set
|
||||
});
|
||||
|
||||
return Array.from(allChildSelectors); // Convert the set back to an array
|
||||
}, parentSelector);
|
||||
|
||||
return childSelectors || [];
|
||||
@@ -845,6 +858,7 @@ export const getChildSelectors = async (page: Page, parentSelector: string): Pro
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the first pair from the given workflow that contains the given selector
|
||||
* inside the where condition, and it is the only selector there.
|
||||
|
||||
@@ -36,14 +36,19 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
||||
const firstKey = Object.keys(row.serializableOutput)[0];
|
||||
const data = row.serializableOutput[firstKey];
|
||||
if (Array.isArray(data)) {
|
||||
setTableData(data);
|
||||
if (data.length > 0) {
|
||||
setColumns(Object.keys(data[0]));
|
||||
// Filter out completely empty rows
|
||||
const filteredData = data.filter(row =>
|
||||
Object.values(row).some(value => value !== undefined && value !== "")
|
||||
);
|
||||
setTableData(filteredData);
|
||||
if (filteredData.length > 0) {
|
||||
setColumns(Object.keys(filteredData[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [row.serializableOutput]);
|
||||
|
||||
|
||||
// Function to convert table data to CSV format
|
||||
const convertToCSV = (data: any[], columns: string[]): string => {
|
||||
const header = columns.join(',');
|
||||
@@ -53,7 +58,6 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
||||
return [header, ...rows].join('\n');
|
||||
};
|
||||
|
||||
// Function to download CSV file when called
|
||||
const downloadCSV = () => {
|
||||
const csvContent = convertToCSV(tableData, columns);
|
||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
@@ -140,7 +144,9 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
||||
{tableData.map((row, index) => (
|
||||
<TableRow key={index}>
|
||||
{columns.map((column) => (
|
||||
<TableCell key={column}>{row[column]}</TableCell>
|
||||
<TableCell key={column}>
|
||||
{row[column] === undefined || row[column] === "" ? "-" : row[column]}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user