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 !== '') {
|
if (this.listSelector !== '') {
|
||||||
const childSelectors = await getChildSelectors(page, this.listSelector || '');
|
const childSelectors = await getChildSelectors(page, this.listSelector || '');
|
||||||
this.socket.emit('highlighter', { rect, selector: displaySelector, elementInfo, childSelectors })
|
this.socket.emit('highlighter', { rect, selector: displaySelector, elementInfo, childSelectors })
|
||||||
|
console.log(`Child Selectors: ${childSelectors}`)
|
||||||
|
console.log(`Parent Selector: ${this.listSelector}`)
|
||||||
} else {
|
} else {
|
||||||
this.socket.emit('highlighter', { rect, selector: displaySelector, elementInfo });
|
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[]> => {
|
export const getChildSelectors = async (page: Page, parentSelector: string): Promise<string[]> => {
|
||||||
try {
|
try {
|
||||||
const childSelectors = await page.evaluate((parentSelector: string) => {
|
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 {
|
function getNonUniqueSelector(element: HTMLElement): string {
|
||||||
let selector = element.tagName.toLowerCase();
|
let selector = element.tagName.toLowerCase();
|
||||||
|
|
||||||
@@ -811,6 +812,7 @@ export const getChildSelectors = async (page: Page, parentSelector: string): Pro
|
|||||||
return selector;
|
return selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to generate selector path from an element to its parent
|
||||||
function getSelectorPath(element: HTMLElement | null): string {
|
function getSelectorPath(element: HTMLElement | null): string {
|
||||||
if (!element || !element.parentElement) return '';
|
if (!element || !element.parentElement) return '';
|
||||||
|
|
||||||
@@ -820,22 +822,33 @@ export const getChildSelectors = async (page: Page, parentSelector: string): Pro
|
|||||||
return `${parentSelector} > ${elementSelector}`;
|
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[] = [];
|
let selectors: string[] = [];
|
||||||
const children = Array.from(element.children) as HTMLElement[];
|
const children = Array.from(element.children) as HTMLElement[];
|
||||||
|
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
selectors.push(getSelectorPath(child));
|
const childPath = getSelectorPath(child);
|
||||||
selectors = selectors.concat(getAllDescendantSelectors(child, stopAtParent));
|
if (childPath) {
|
||||||
|
selectors.push(childPath); // Add direct child path
|
||||||
|
selectors = selectors.concat(getAllDescendantSelectors(child)); // Recursively process descendants
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectors;
|
return selectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parentElement = document.querySelector(parentSelector) as HTMLElement;
|
// Find all occurrences of the parent selector in the DOM
|
||||||
if (!parentElement) return [];
|
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);
|
}, parentSelector);
|
||||||
|
|
||||||
return childSelectors || [];
|
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
|
* Returns the first pair from the given workflow that contains the given selector
|
||||||
* inside the where condition, and it is the only selector there.
|
* 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 firstKey = Object.keys(row.serializableOutput)[0];
|
||||||
const data = row.serializableOutput[firstKey];
|
const data = row.serializableOutput[firstKey];
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
setTableData(data);
|
// Filter out completely empty rows
|
||||||
if (data.length > 0) {
|
const filteredData = data.filter(row =>
|
||||||
setColumns(Object.keys(data[0]));
|
Object.values(row).some(value => value !== undefined && value !== "")
|
||||||
|
);
|
||||||
|
setTableData(filteredData);
|
||||||
|
if (filteredData.length > 0) {
|
||||||
|
setColumns(Object.keys(filteredData[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [row.serializableOutput]);
|
}, [row.serializableOutput]);
|
||||||
|
|
||||||
|
|
||||||
// Function to convert table data to CSV format
|
// Function to convert table data to CSV format
|
||||||
const convertToCSV = (data: any[], columns: string[]): string => {
|
const convertToCSV = (data: any[], columns: string[]): string => {
|
||||||
const header = columns.join(',');
|
const header = columns.join(',');
|
||||||
@@ -53,7 +58,6 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
return [header, ...rows].join('\n');
|
return [header, ...rows].join('\n');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to download CSV file when called
|
|
||||||
const downloadCSV = () => {
|
const downloadCSV = () => {
|
||||||
const csvContent = convertToCSV(tableData, columns);
|
const csvContent = convertToCSV(tableData, columns);
|
||||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
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) => (
|
{tableData.map((row, index) => (
|
||||||
<TableRow key={index}>
|
<TableRow key={index}>
|
||||||
{columns.map((column) => (
|
{columns.map((column) => (
|
||||||
<TableCell key={column}>{row[column]}</TableCell>
|
<TableCell key={column}>
|
||||||
|
{row[column] === undefined || row[column] === "" ? "-" : row[column]}
|
||||||
|
</TableCell>
|
||||||
))}
|
))}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user