You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by pp...@apache.org on 2025/09/25 07:09:04 UTC
(atlas) 01/01: ATLAS-5132: [REACT UI] Unique Advanced/Search queries do not work as expected
This is an automated email from the ASF dual-hosted git repository.
ppawar pushed a commit to branch ATLAS-5132
in repository https://gitbox.apache.org/repos/asf/atlas.git
commit b36d705866e68b733c05795d6e2e0702dbeca0ec
Author: Prasad Pawar <pr...@freestoneinfotech.com>
AuthorDate: Thu Sep 25 12:36:02 2025 +0530
ATLAS-5132: [REACT UI] Unique Advanced/Search queries do not work as expected
---
dashboard/src/components/Table/TableLayout.tsx | 50 +++++++-
dashboard/src/components/muiComponents.tsx | 26 ++--
dashboard/src/views/SearchResult/SearchResult.tsx | 134 +++++++++++++++++----
.../public/js/views/graph/LineageLayoutView.js | 4 +-
.../public/js/views/graph/TypeSystemTreeView.js | 7 +-
.../public/js/views/graph/LineageLayoutView.js | 4 +-
.../public/js/views/graph/TypeSystemTreeView.js | 7 +-
7 files changed, 186 insertions(+), 46 deletions(-)
diff --git a/dashboard/src/components/Table/TableLayout.tsx b/dashboard/src/components/Table/TableLayout.tsx
index f58d150b0..931bda7ac 100644
--- a/dashboard/src/components/Table/TableLayout.tsx
+++ b/dashboard/src/components/Table/TableLayout.tsx
@@ -374,14 +374,40 @@ const TableLayout: FC<TableProps> = ({
const [goToPageVal, setGoToPageVal] = useState<any>("");
const [rowSelection, setRowSelection] = useState({});
- const [sorting, setSorting] = useState<SortingState>(
- !isEmpty(defaultSortCol) ? defaultSortCol : []
+ const existingColumnIds = useMemo(
+ () =>
+ (!isEmpty(memoizedColumns)
+ ? memoizedColumns.map((c: any) => c.id || c.accessorKey)
+ : []) as string[],
+ [memoizedColumns]
);
+
+ const sanitizeSorting = (sortingState: SortingState) => {
+ if (isEmpty(sortingState)) return [] as SortingState;
+ return sortingState.filter(
+ (s: any) => s && existingColumnIds.includes(s.id)
+ );
+ };
+
+ const [sorting, setSorting] = useState<SortingState>(() => []);
+
const [columnOrder, setColumnOrder] = useState<any>(() =>
!isEmpty(memoizedColumns)
- ? memoizedColumns.map((c: any) => c.accessorKey)
+ ? memoizedColumns
+ .map((c: any) => c.id || c.accessorKey)
+ .filter(Boolean)
: []
);
+
+ useEffect(() => {
+ setColumnOrder(
+ !isEmpty(memoizedColumns)
+ ? memoizedColumns
+ .map((c: any) => c.id || c.accessorKey)
+ .filter(Boolean)
+ : []
+ )
+ }, [memoizedColumns])
const [columnVisibility, setColumnVisibility] = useState(defaultHideColumns);
const [tagModal, setTagModal] = useState<boolean>(false);
let currentParams = searchParams;
@@ -426,7 +452,7 @@ const TableLayout: FC<TableProps> = ({
columnVisibility: columnVisibilityParams
? defaultHideColumns
: columnVisibility,
- sorting,
+ sorting: sanitizeSorting(sorting),
pagination,
rowSelection,
columnOrder
@@ -437,6 +463,17 @@ const TableLayout: FC<TableProps> = ({
autoResetPageIndex: false
});
+ useEffect(() => {
+ setSorting((prev) => sanitizeSorting(prev));
+ setColumnOrder(
+ !isEmpty(memoizedColumns)
+ ? memoizedColumns
+ .map((c: any) => c.id || c.accessorKey)
+ .filter(Boolean)
+ : []
+ );
+ }, [existingColumnIds]);
+
useEffect(() => {
if (typeof fetchData === "function") {
fetchData({
@@ -474,7 +511,8 @@ const TableLayout: FC<TableProps> = ({
resetSorting(true);
resetRowSelection(true);
setRowSelection({});
- setSorting(!isEmpty(defaultSortCol) ? defaultSortCol : []);
+ const candidate = !isEmpty(defaultSortCol) ? defaultSortCol : []
+ setSorting(sanitizeSorting(candidate));
}, [typeParam, defaultSortCol, setSearchParams]);
const handleCloseTagModal = () => {
@@ -619,7 +657,7 @@ const TableLayout: FC<TableProps> = ({
items={columnOrder}
strategy={horizontalListSortingStrategy}
>
- {" "}
+
{headerGroup.headers.map((header) =>
header.isPlaceholder ? null : (
<DraggableTableHeader
diff --git a/dashboard/src/components/muiComponents.tsx b/dashboard/src/components/muiComponents.tsx
index fc4492ef1..cf96d2c6d 100644
--- a/dashboard/src/components/muiComponents.tsx
+++ b/dashboard/src/components/muiComponents.tsx
@@ -104,18 +104,20 @@ const CustomButton = ({
let mergedStyle = { ...defaultStyles, ...customStyles };
return (
- <Button
- variant={variant}
- color={color}
- sx={mergedStyle}
- onClick={onClick}
- size={size}
- endIcon={endIcon}
- startIcon={startIcon}
- disabled={disabled}
- >
- {children}
- </Button>
+ <Box component="span" sx={{ display: 'inline-flex' }}>
+ <Button
+ variant={variant}
+ color={color}
+ sx={mergedStyle}
+ onClick={onClick}
+ size={size}
+ endIcon={endIcon}
+ startIcon={startIcon}
+ disabled={disabled}
+ >
+ {children}
+ </Button>
+ </Box>
);
};
diff --git a/dashboard/src/views/SearchResult/SearchResult.tsx b/dashboard/src/views/SearchResult/SearchResult.tsx
index aa1cd0921..c181aa877 100644
--- a/dashboard/src/views/SearchResult/SearchResult.tsx
+++ b/dashboard/src/views/SearchResult/SearchResult.tsx
@@ -207,8 +207,17 @@ const SearchResult = ({ classificationParams, glossaryTypeParams }: any) => {
globalSearchParams.basicParams = params;
globalSearchParams.dslParams = dslParams;
- let searchTypeParams =
- searchParams.get("searchType") == "dsl" ? dslParams : params;
+
+ const qParam = searchParams.get("query");
+ if (qParam) {
+ try {
+ (globalSearchParams as any).basicParams.query = qParam;
+ (globalSearchParams as any).dslParams.query = qParam;
+ } catch (_e) {}
+ }
+
+ const isDslSearch = searchParams.get("searchType") == "dsl";
+ let searchTypeParams = isDslSearch ? dslParams : params;
try {
const searchResp = await getBasicSearchResult(
{
@@ -221,21 +230,43 @@ const SearchResult = ({ classificationParams, glossaryTypeParams }: any) => {
searchParams.get("searchType") || "basic"
);
const { data = {} } = searchResp || {};
- const { approximateCount, entities } = data || {};
- let totalCount = approximateCount;
- let dataLength;
- if (entities) {
- dataLength = entities?.length;
+
+ const hasEntities = Array.isArray((data as any)?.entities);
+ const hasDslAttributes =
+ Array.isArray((data as any)?.attributes) ||
+ Array.isArray((data as any)?.attributes?.name);
+ const hasDslValues =
+ Array.isArray((data as any)?.attributes?.values) ||
+ Array.isArray((data as any)?.values);
+
+ if (isDslSearch && !hasEntities && !hasDslAttributes) {
+ setSearchData({ entities: [] });
+ setIsEmptyData(true);
+ setLoader(false);
+ return;
+ }
+
+ let dataLength = 0;
+ let totalCountLocal = 0;
+ if (isDslSearch && !hasEntities && hasDslAttributes && hasDslValues) {
+ const vals = (data as any).attributes?.values || (data as any).values;
+ dataLength = (vals as any[])?.length || 0;
+ totalCountLocal = dataLength;
} else {
- dataLength = searchResp?.data?.length;
+ const { approximateCount, entities } = data as any;
+ dataLength = Array.isArray(entities) ? entities.length : 0;
+ totalCountLocal = approximateCount ?? dataLength;
}
+
if (!dataLength) {
setIsEmptyData(true);
setLoader(false);
} else {
setSearchData(searchResp.data);
- setTotalCount(totalCount || 0);
- setPageCount(Math.ceil(totalCount / pagination.pageSize));
+ setTotalCount(totalCountLocal || 0);
+ setPageCount(
+ Math.ceil((totalCountLocal || dataLength) / (pagination.pageSize || pageSize))
+ );
setLoader(false);
}
} catch (error: any) {
@@ -745,10 +776,40 @@ const SearchResult = ({ classificationParams, glossaryTypeParams }: any) => {
}
);
+ const isDslSearchMode = searchParams.get("searchType") === "dsl";
+ const getDslAttributeNames = () => {
+ const src: any = Array.isArray(searchData) ? searchData[0] : searchData;
+ if (!src) return [] as string[];
+ if (Array.isArray(src?.attributes)) {
+ return src.attributes
+ .map((a: any) => (typeof a === 'string' ? a : a?.name))
+ .filter(Boolean);
+ }
+ if (src?.attributes && Array.isArray(src?.attributes?.name)) {
+ return src.attributes.name as string[];
+ }
+ return [] as string[];
+ };
+ const sanitize = (name: string) =>
+ String(name).replace(/[^A-Za-z0-9_]/g, "_").replace(/_{2,}/g, "_");
+ const dslAttrNames = isDslSearchMode ? getDslAttributeNames() : [];
+ const dslColumns = dslAttrNames.map((label: string, idx: number) => {
+ const key = `dsl_${sanitize(label)}` || `dsl_${idx}`
+ return {
+ id: key,
+ accessorKey: key,
+ header: label,
+ cell: (info: any) => <span>{info.getValue()}</span>,
+ show: true
+ }
+ });
+
let allColumns =
- isEmpty(searchParams.get("type")) &&
- isEmpty(searchParams.get("tag")) &&
- !isEmpty(searchParams.get("term"))
+ isDslSearchMode && dslColumns.length > 0
+ ? dslColumns
+ : isEmpty(searchParams.get("type")) &&
+ isEmpty(searchParams.get("tag")) &&
+ !isEmpty(searchParams.get("term"))
? removeDuplicateObjects([...defaultColumns])
: removeDuplicateObjects([
...defaultColumns,
@@ -756,6 +817,8 @@ const SearchResult = ({ classificationParams, glossaryTypeParams }: any) => {
...defaultHideColumns
]);
+ const isDslAggregate = isDslSearchMode && dslColumns.length > 0;
+
const defaultColumnVisibility: any = (columns: any) => {
let columnsParams: any = searchParams.get("attributes");
let hideColumns: any = {};
@@ -778,7 +841,12 @@ const SearchResult = ({ classificationParams, glossaryTypeParams }: any) => {
return hideColumns;
};
- const getDefaultSort = useMemo(() => [{ id: "name", asc: true }], []);
+ const getDefaultSort = useMemo(() => {
+ if (isDslAggregate) {
+ return [] as any[]; // no default sorting for DSL aggregates
+ }
+ return [{ id: "name", asc: true }];
+ }, [isDslAggregate]);
return (
<Stack position="relative" gap={"1rem"}>
@@ -833,27 +901,49 @@ const SearchResult = ({ classificationParams, glossaryTypeParams }: any) => {
<TableLayout
fetchData={fetchSearchResult}
- data={searchData.entities || []}
+ data={
+ isDslSearchMode && dslColumns.length > 0
+ ? (() => {
+ const src: any = Array.isArray(searchData)
+ ? searchData[0]
+ : searchData;
+ const values: any[] = Array.isArray(src?.values)
+ ? src.values
+ : Array.isArray(src?.attributes?.values)
+ ? src.attributes.values
+ : [];
+ return values.map((row: any[], idx: number) => {
+ const obj: any = { id: `dsl-row-${idx}` };
+ dslAttrNames.forEach((n: string, i: number) => {
+ const colKey = `dsl_${sanitize(n)}`
+ obj[colKey] = Array.isArray(row) ? row[i] : row
+ });
+ return obj;
+ });
+ })()
+ : searchData.entities || []
+ }
columns={allColumns.filter(
(value: {}) => Object.keys(value).length !== 0
)}
emptyText="No Records found!"
isFetching={loader}
pageCount={pageCount}
- columnVisibilityParams={true}
- defaultColumnVisibility={defaultColumnVisibility(allColumns)}
+ // columnVisibilityParams={true}
+ columnVisibilityParams={!isDslAggregate}
+ defaultColumnVisibility={isDslAggregate ? {} : defaultColumnVisibility(allColumns)}
defaultColumnParams={defaultColumnsName.join(",")}
- columnVisibility={true}
+ columnVisibility={!isDslAggregate}
+ // columnVisibility={true}
refreshTable={refreshTable}
defaultSortCol={getDefaultSort}
clientSideSorting={true}
isClientSidePagination={false}
columnSort={true}
showPagination={true}
- showRowSelection={true}
- tableFilters={
- isEmpty(classificationParams || glossaryTypeParams) ? true : false
- }
+ showRowSelection={!isDslAggregate}
+ // showRowSelection={true}
+ tableFilters={true}
assignFilters={
!isEmpty(classificationParams || glossaryTypeParams)
? {
diff --git a/dashboardv2/public/js/views/graph/LineageLayoutView.js b/dashboardv2/public/js/views/graph/LineageLayoutView.js
index ce7692535..15f7d775f 100644
--- a/dashboardv2/public/js/views/graph/LineageLayoutView.js
+++ b/dashboardv2/public/js/views/graph/LineageLayoutView.js
@@ -576,7 +576,9 @@ define(['require',
if ((that.filterObj.isProcessHideCheck && obj && obj.isProcess) || (that.filterObj.isDeletedEntityHideCheck && obj && obj.isDeleted) || (Globals.isLineageOnDemandEnabled && obj && _.contains(["Input", "Output"], obj.btnType))) {
return;
}
- typeStr += '<option value="' + obj.guid + '">' + obj.displayText + '</option>';
+ var label = _.escape(obj.displayText);
+ var value = _.escape(obj.guid);
+ typeStr += '<option value="' + value + '">' + label + '</option>';
});
}
that.ui.lineageTypeSearch.html(typeStr);
diff --git a/dashboardv2/public/js/views/graph/TypeSystemTreeView.js b/dashboardv2/public/js/views/graph/TypeSystemTreeView.js
index 935cae001..a75139443 100644
--- a/dashboardv2/public/js/views/graph/TypeSystemTreeView.js
+++ b/dashboardv2/public/js/views/graph/TypeSystemTreeView.js
@@ -460,10 +460,13 @@ define([
var nodes = that.LineageHelperRef.getNodes();
if (!_.isEmpty(nodes)) {
_.each(nodes, function(obj) {
- searchStr += '<option value="' + obj.guid + '">' + obj.name + "</option>";
+ var label = _.escape(obj.name)
+ var value = _.escape(obj.guid)
+ searchStr += '<option value="' + value + '">' + label + "</option>";
if (obj.serviceType && !tempFilteMap[obj.serviceType]) {
tempFilteMap[obj.serviceType] = obj.serviceType;
- filterStr += '<option value="' + obj.serviceType + '">' + obj.serviceType + "</option>";
+ var svc = _.escape(obj.serviceType)
+ filterStr += '<option value="' + svc + '">' + svc + "</option>";
}
});
}
diff --git a/dashboardv3/public/js/views/graph/LineageLayoutView.js b/dashboardv3/public/js/views/graph/LineageLayoutView.js
index ce7692535..15f7d775f 100644
--- a/dashboardv3/public/js/views/graph/LineageLayoutView.js
+++ b/dashboardv3/public/js/views/graph/LineageLayoutView.js
@@ -576,7 +576,9 @@ define(['require',
if ((that.filterObj.isProcessHideCheck && obj && obj.isProcess) || (that.filterObj.isDeletedEntityHideCheck && obj && obj.isDeleted) || (Globals.isLineageOnDemandEnabled && obj && _.contains(["Input", "Output"], obj.btnType))) {
return;
}
- typeStr += '<option value="' + obj.guid + '">' + obj.displayText + '</option>';
+ var label = _.escape(obj.displayText);
+ var value = _.escape(obj.guid);
+ typeStr += '<option value="' + value + '">' + label + '</option>';
});
}
that.ui.lineageTypeSearch.html(typeStr);
diff --git a/dashboardv3/public/js/views/graph/TypeSystemTreeView.js b/dashboardv3/public/js/views/graph/TypeSystemTreeView.js
index 935cae001..a75139443 100644
--- a/dashboardv3/public/js/views/graph/TypeSystemTreeView.js
+++ b/dashboardv3/public/js/views/graph/TypeSystemTreeView.js
@@ -460,10 +460,13 @@ define([
var nodes = that.LineageHelperRef.getNodes();
if (!_.isEmpty(nodes)) {
_.each(nodes, function(obj) {
- searchStr += '<option value="' + obj.guid + '">' + obj.name + "</option>";
+ var label = _.escape(obj.name)
+ var value = _.escape(obj.guid)
+ searchStr += '<option value="' + value + '">' + label + "</option>";
if (obj.serviceType && !tempFilteMap[obj.serviceType]) {
tempFilteMap[obj.serviceType] = obj.serviceType;
- filterStr += '<option value="' + obj.serviceType + '">' + obj.serviceType + "</option>";
+ var svc = _.escape(obj.serviceType)
+ filterStr += '<option value="' + svc + '">' + svc + "</option>";
}
});
}