Skip to content

Commit e763cb6

Browse files
briantangMarkLogic Builder
authored andcommitted
DHFPROD-7601: Adjust XML view of page size for mapping UI
1 parent 8573109 commit e763cb6

File tree

4 files changed

+192
-37
lines changed

4 files changed

+192
-37
lines changed

marklogic-data-hub-central/ui/src/components/entities/mapping/mapping-step-detail/mapping-step-detail.module.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,15 @@
6969
white-space: nowrap;
7070
}
7171

72+
.tableExpandIcon {
73+
padding-right: 5px;
74+
margin-left: -15px;
75+
}
76+
77+
.filteredXMLHeader {
78+
margin-left: -2px;
79+
}
80+
7281
.sourceTitle{
7382
font-size: 16px;
7483
white-space: nowrap;

marklogic-data-hub-central/ui/src/components/entities/mapping/mapping-step-detail/mapping-step-detail.scss

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,27 @@
99
}
1010

1111
#srcContainer {
12+
#jsonTable {
13+
.ant-table-column-has-actions.ant-table-column-has-filters.ant-table-column-has-sorters.ant-table-row-cell-break-word{
14+
padding-left: 22px;
15+
}
16+
.ant-table-wrapper {
17+
margin-top: 20px;
18+
}
19+
}
20+
#lowerTableXML {
1221
.ant-table-column-has-actions.ant-table-column-has-filters.ant-table-column-has-sorters.ant-table-row-cell-break-word{
13-
padding-left: 22px;
22+
padding-left: 44px;
23+
}
1424
}
1525

16-
.ant-table-wrapper{
17-
margin-top: 20px;
26+
#upperTableXML {
27+
.ant-table-column-has-actions.ant-table-column-has-filters.ant-table-column-has-sorters.ant-table-row-cell-break-word{
28+
padding-left: 22px;
29+
}
30+
.ant-table-wrapper {
31+
margin-top: 20px;
32+
}
1833
}
1934
}
2035

marklogic-data-hub-central/ui/src/components/entities/mapping/mapping-step-detail/mapping-step-detail.test.tsx

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,14 +1461,13 @@ describe("RTL Source-to-entity map tests", () => {
14611461
let lastName = getByText("LastName");
14621462
let proteinId = getByText("proteinId");
14631463
expect(firstName).toBeInTheDocument();
1464-
expect(firstName.closest("td")?.firstElementChild).toHaveStyle("padding-left: 40px;"); // Check if the indentation is right
1465-
1464+
expect(firstName.closest("td")?.firstElementChild).toHaveStyle("padding-left: 20px;"); // Check if the indentation is right
14661465
expect(lastName).toBeInTheDocument();
1467-
expect(lastName.closest("td")?.firstElementChild).toHaveStyle("padding-left: 40px;"); // Check if the indentation is right
1466+
expect(lastName.closest("td")?.firstElementChild).toHaveStyle("padding-left: 20px;"); // Check if the indentation is right
14681467

14691468
//Collapsing back to the default view (root and 1st level)
14701469
fireEvent.click(collapseBtnSource);
1471-
expect(onClosestTableRow(proteinId)?.style.display).toBe("none");
1470+
expect(onClosestTableRow(proteinId)?.style.display).toBe("");
14721471
expect(onClosestTableRow(firstName)?.style.display).toBe("none");
14731472
expect(onClosestTableRow(lastName)?.style.display).toBe("none");
14741473
});
@@ -1879,6 +1878,59 @@ describe("RTL Source-to-entity map tests", () => {
18791878
expect(queryByTestId("Person-propId6-name")).not.toBeInTheDocument();
18801879

18811880
});
1881+
1882+
test("verify pagination and page size menu works properly in Source XML table", async () => {
1883+
mockGetMapArtifactByName.mockResolvedValue({status: 200, data: mappingStep.artifacts[4]});
1884+
mockGetUris.mockResolvedValue({status: 200, data: ["/dummy/uri/person-101.json"]});
1885+
mockGetSourceDoc.mockResolvedValue({status: 200, data: data.xmlSourceDataMultipleSiblings});
1886+
mockGetNestedEntities.mockResolvedValue({status: 200, data: personRelatedEntityDefLargePropSet});
1887+
1888+
let getByText, queryByText, getAllByTitle, getAllByText;
1889+
await act(async () => {
1890+
const renderResults = defaultRender(personMappingStepWithRelatedEntityData);
1891+
getByText = renderResults.getByText;
1892+
queryByText = renderResults.queryByText;
1893+
getAllByTitle = renderResults.getAllByTitle;
1894+
getAllByText = renderResults.getAllByText;
1895+
});
1896+
1897+
//Verify all XML source properties are displayed at first
1898+
await wait(() => expect(getByText("sampleProtein")).toBeInTheDocument());
1899+
await wait(() => expect(getByText("@proteinType")).toBeInTheDocument());
1900+
await wait(() => expect(getByText("home")).toBeInTheDocument());
1901+
await wait(() => expect(getByText("proteinId")).toBeInTheDocument());
1902+
await wait(() => expect(getByText("123EAC")).toBeInTheDocument());
1903+
await wait(() => expect(getByText("proteinCat")).toBeInTheDocument());
1904+
1905+
//Verify page size starts at 20/page by default and can be changed for source table
1906+
fireEvent.click(getAllByText("20 / page")[0]);
1907+
await wait(() => fireEvent.click(getByText("1 / page")));
1908+
1909+
//only first child property is present, in addition to top level parent
1910+
expect(getByText("sampleProtein")).toBeInTheDocument();
1911+
expect(getByText("@proteinType")).toBeInTheDocument();
1912+
1913+
//remaining children properties should no longer be present
1914+
expect(queryByText("proteinId")).not.toBeInTheDocument();
1915+
expect(queryByText("123EAC")).not.toBeInTheDocument();
1916+
expect(queryByText("proteinCat")).not.toBeInTheDocument();
1917+
1918+
//test page 4 should only have fourth property
1919+
fireEvent.click(getAllByTitle("4")[0]);
1920+
await wait(() => expect(queryByText("nutFree:")).toBeInTheDocument());
1921+
await wait(() => expect(queryByText("@proteinType")).not.toBeInTheDocument());
1922+
1923+
//reopen page size options
1924+
fireEvent.click(getAllByText("1 / page")[0]);
1925+
1926+
//test 5 per page
1927+
fireEvent.click(getByText("5 / page"));
1928+
fireEvent.click(getAllByTitle("1")[0]);
1929+
1930+
//first through fifth properties should be present
1931+
expect(queryByText("sampleProtein")).toBeInTheDocument(); //1st property
1932+
expect(queryByText("proteinCat")).toBeInTheDocument(); //5th property
1933+
});
18821934
});
18831935

18841936
describe("Enzyme Source-to-entity map tests", () => {

marklogic-data-hub-central/ui/src/components/entities/mapping/mapping-step-detail/mapping-step-detail.tsx

Lines changed: 109 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ const MappingStepDetail: React.FC = () => {
8181
/*-------------------*/
8282

8383
const [entityTypeProperties, setEntityTypeProperties] = useState<any[]>([]);
84-
84+
const [srcPropertiesXML, setSrcPropertiesXML] = useState<any[]>([]);
8585
const [mapExpTouched, setMapExpTouched] = useState(false);
8686
const [editingURI, setEditingUri] = useState(false);
8787
const [showEditURIOption, setShowEditURIOption] = useState(false);
@@ -115,6 +115,7 @@ const MappingStepDetail: React.FC = () => {
115115
const [allSourceKeys, setAllSourceKeys] = useState<any[]>([]);
116116
const [allEntityKeys, setAllEntityKeys] = useState<any[]>([]);
117117
const [allRelatedEntitiesKeys, setAllRelatedEntitiesKeys] = useState<any[]>([]);
118+
const [tableCollapsed, setTableCollapsed] = useState(false);
118119

119120
// For Entity table
120121
const [tgtEntityReferences, setTgtEntityReferences] = useState({});
@@ -256,7 +257,8 @@ const MappingStepDetail: React.FC = () => {
256257
let sDta = generateNestedDataSource(docRoot, nestedDoc);
257258
setSourceData([]);
258259
setSourceData([...sDta]);
259-
if (typeof (srcDocResp.data) === "string") {
260+
setSrcPropertiesXML(sDta[0].children);
261+
if (typeof(srcDocResp.data) === "string") {
260262
let mData = await getMappingArtifactByMapName(curationOptions.activeStep.stepArtifact.targetEntityType, stepName);
261263
updateMappingWithNamespaces(mData);
262264
}
@@ -651,6 +653,16 @@ const MappingStepDetail: React.FC = () => {
651653
setEditingUri(false);
652654
};
653655

656+
const toggleSourceTable = () => {
657+
if (tableCollapsed) {
658+
setSrcPropertiesXML(sourceData[0].children);
659+
setTableCollapsed(false);
660+
} else {
661+
setSrcPropertiesXML([]);
662+
setTableCollapsed(true);
663+
}
664+
};
665+
654666
const srcDetails = mapData && mapData["sourceQuery"] && mapData["selectedSource"] ? <div className={styles.xpathDoc}>
655667
{mapData["selectedSource"] === "collection" ? <div className={styles.sourceQuery}>Collection: {extractCollectionFromSrcQuery(mapData["sourceQuery"])}</div> : <div className={styles.sourceQuery}>Source Query: {getInitialChars(mapData["sourceQuery"], 32, "...")}</div>}
656668
{!editingURI ? <div onMouseOver={(e) => handleMouseOver(e)} onMouseLeave={(e) => setShowEditURIOption(false)}
@@ -660,6 +672,10 @@ const MappingStepDetail: React.FC = () => {
660672
<Icon type="close" className={styles.closeIcon} onClick={() => handleCloseEditOption()} />&nbsp;<Icon type="check" className={styles.checkIcon} onClick={() => handleSubmitUri(sourceURI)} /></span></div>}
661673
</div> : "";
662674

675+
const expandTableIcon = (
676+
<a onClick={() => toggleSourceTable()}><Icon type={tableCollapsed && srcPropertiesXML.length < 1 ? "right" : "down"}/></a>
677+
);
678+
663679
// Run when mapping details is opened or returned to
664680
useEffect(() => {
665681
if (Object.keys(curationOptions.activeStep.stepArtifact).length !== 0) {
@@ -856,7 +872,7 @@ const MappingStepDetail: React.FC = () => {
856872
filterIcon: filtered => <i><FontAwesomeIcon data-testid={`filterIcon-${dataIndex}`} icon={faSearch} size="lg" className={filtered ? "active" : "inactive"} /></i>,
857873
onFilter: (value, record) => {
858874
let recordString = getPropValueFromDataIndex(record, dataIndex);
859-
return recordString.toString().toLowerCase().includes(value.toLowerCase());
875+
return sourceFormat === "xml" ? true : recordString.toString().toLowerCase().includes(value.toLowerCase());
860876
},
861877
onFilterDropdownVisibleChange: visible => {
862878
if (visible) {
@@ -880,12 +896,24 @@ const MappingStepDetail: React.FC = () => {
880896

881897
const getRenderOutput = (textToSearchInto, valueToDisplay, columnName, searchedCol, searchTxt, rowNum) => {
882898
if (searchedCol === columnName && rowNum !== 0) {
883-
return <Highlighter
884-
highlightClassName={styles.highlightStyle}
885-
searchWords={[searchTxt]}
886-
autoEscape
887-
textToHighlight={textToSearchInto}
888-
/>;
899+
if (sourceFormat === "xml" && rowNum === 1) {
900+
return <div className={styles.filteredXMLHeader}>
901+
<span className={styles.tableExpandIcon}>{expandTableIcon}</span>
902+
<Highlighter
903+
highlightClassName={styles.highlightStyle}
904+
searchWords={[searchTxt]}
905+
autoEscape
906+
textToHighlight={textToSearchInto}
907+
/>
908+
</div>;
909+
} else {
910+
return <Highlighter
911+
highlightClassName={styles.highlightStyle}
912+
searchWords={[searchTxt]}
913+
autoEscape
914+
textToHighlight={textToSearchInto}
915+
/>;
916+
}
889917
} else {
890918
return valueToDisplay;
891919
}
@@ -924,9 +952,9 @@ const MappingStepDetail: React.FC = () => {
924952
width: "60%",
925953
defaultFilteredValue: searchSourceText ? [searchSourceText] : [],
926954
render: (text, row) => {
927-
let textToSearchInto = text?.split(":").length > 1 ? text?.split(":")[0] + ": " + text?.split(":")[1] : text;
928-
let valueToDisplay = <span className={styles.sourceName}>{text?.split(":").length > 1 ? <span><MLTooltip title={text?.split(":")[0] + " = \"" + namespaces[text?.split(":")[0]] + "\""}><span className={styles.namespace}>{text?.split(":")[0] + ": "}</span></MLTooltip><span>{text?.split(":")[1]}</span></span> : text}</span>;
929-
return getRenderOutput(textToSearchInto, valueToDisplay, "key", searchedSourceColumn, searchSourceText, row.key);
955+
let textToSearchInto = text?.split(":").length > 1 ? text?.split(":")[0]+": "+text?.split(":")[1] : text;
956+
let valueToDisplay = sourceFormat === "xml" && row.rowKey === 1 ? <div><span className={styles.tableExpandIcon}>{expandTableIcon}</span><span className={styles.sourceName}>{text?.split(":").length > 1 ? <span><MLTooltip title={text?.split(":")[0]+" = \""+namespaces[text?.split(":")[0]]+"\""}><span className={styles.namespace}>{text?.split(":")[0]+": "}</span></MLTooltip><span>{text?.split(":")[1]}</span></span> : text}</span></div>: <span className={styles.sourceName}>{text?.split(":").length > 1 ? <span><MLTooltip title={text?.split(":")[0]+" = \""+namespaces[text?.split(":")[0]]+"\""}><span className={styles.namespace}>{text?.split(":")[0]+": "}</span></MLTooltip><span>{text?.split(":")[1]}</span></span> : text}</span>;
957+
return getRenderOutput(textToSearchInto, valueToDisplay, "key", searchedSourceColumn, searchSourceText, row.rowKey);
930958
}
931959
},
932960
{
@@ -1415,24 +1443,75 @@ const MappingStepDetail: React.FC = () => {
14151443
<span className={styles.navigationButtons}>{navigationButtons}</span>
14161444
<span className={styles.sourceCollapseButtons}><ExpandCollapse handleSelection={(id) => handleSourceExpandCollapse(id)} currentSelection={""} /></span>
14171445
</div>
1418-
<Table
1419-
pagination={paginationMapping}
1420-
expandIcon={(props) => customExpandIcon(props)}
1421-
onExpand={(expanded, record) => toggleSourceRowExpanded(expanded, record, "rowKey")}
1422-
expandedRowKeys={sourceExpandedKeys}
1423-
className={styles.sourceTable}
1424-
rowClassName={() => styles.sourceTableRows}
1425-
scroll={{x: 300}}
1426-
indentSize={20}
1427-
//defaultExpandAllRows={true}
1428-
//size="small"
1429-
columns={columns}
1430-
dataSource={sourceData}
1431-
tableLayout="unset"
1432-
rowKey={(record) => record.rowKey}
1433-
getPopupContainer={() => document.getElementById("srcContainer") || document.body}
1434-
/>
1435-
</div>}
1446+
{
1447+
sourceFormat === "xml" ?
1448+
<div>
1449+
<div id="upperTableXML">
1450+
<Table
1451+
pagination={false}
1452+
expandIcon={(props) => customExpandIcon(props)}
1453+
onExpand={(expanded, record) => toggleSourceRowExpanded(expanded, record, "rowKey")}
1454+
expandedRowKeys={sourceExpandedKeys}
1455+
className={styles.sourceTable}
1456+
rowClassName={() => styles.sourceTableRows}
1457+
scroll={{x: 300}}
1458+
indentSize={20}
1459+
//defaultExpandAllRows={true}
1460+
//size="small"
1461+
columns={columns}
1462+
dataSource={[{rowKey: 1, key: sourceData[0]?.key}]}
1463+
tableLayout="unset"
1464+
rowKey={(record:any) => record.rowKey}
1465+
getPopupContainer={() => document.getElementById("srcContainer") || document.body}
1466+
/>
1467+
</div>
1468+
<div id="lowerTableXML">
1469+
{srcPropertiesXML.length > 0 ?
1470+
<Table
1471+
pagination={paginationMapping}
1472+
expandIcon={(props) => customExpandIcon(props)}
1473+
onExpand={(expanded, record) => toggleSourceRowExpanded(expanded, record, "rowKey")}
1474+
expandedRowKeys={sourceExpandedKeys}
1475+
className={styles.sourceTable}
1476+
rowClassName={() => styles.sourceTableRows}
1477+
scroll={{x: 300}}
1478+
indentSize={20}
1479+
showHeader={false}
1480+
//defaultExpandAllRows={true}
1481+
//size="small"
1482+
columns={columns}
1483+
dataSource={srcPropertiesXML}
1484+
tableLayout="unset"
1485+
rowKey={(record:any) => record.rowKey}
1486+
getPopupContainer={() => document.getElementById("srcContainer") || document.body}
1487+
/>
1488+
: null
1489+
}
1490+
</div>
1491+
</div>
1492+
:
1493+
<div id="jsonTable">
1494+
<Table
1495+
pagination={paginationMapping}
1496+
expandIcon={(props) => customExpandIcon(props)}
1497+
onExpand={(expanded, record) => toggleSourceRowExpanded(expanded, record, "rowKey")}
1498+
expandedRowKeys={sourceExpandedKeys}
1499+
className={styles.sourceTable}
1500+
rowClassName={() => styles.sourceTableRows}
1501+
scroll={{x: 300}}
1502+
indentSize={20}
1503+
//defaultExpandAllRows={true}
1504+
//size="small"
1505+
columns={columns}
1506+
dataSource={sourceData}
1507+
tableLayout="unset"
1508+
rowKey={(record) => record.rowKey}
1509+
getPopupContainer={() => document.getElementById("srcContainer") || document.body}
1510+
/>
1511+
</div>
1512+
}
1513+
1514+
</div> }
14361515
</div>
14371516
<div
14381517
id="entityContainer"

0 commit comments

Comments
 (0)