Brijesh619 commented on code in PR #688:
URL: https://github.com/apache/atlas/pull/688#discussion_r3978777072
##########
dashboard/src/redux/slice/__tests__/sessionSlice.test.ts:
##########
Review Comment:
Added the `fetchSessionData.rejected` test to ensure it retains previous
stale data, mirroring the behavior of the version test. Thanks for catching
that!
##########
dashboard/src/views/DetailPage/EntityDetailPage.tsx:
##########
@@ -350,7 +353,7 @@ const EntityDetailPage: React.FC = () => {
<Stack spacing={2} direction="row" alignItems="center">
{!isEmpty(entity) && (
<DisplayImage
- entity={entity}
+ entity={{ ...entity, serviceType: entityObj?.serviceType }}
Review Comment:
Thanks for the suggestion! I've added a unit test in
`EntityDetailPage.test.tsx` to explicitly verify that the `serviceType` from
`entityObj` is successfully merged into the `entity` object passed to
`DisplayImage` when the detail API omits it.
##########
dashboard/src/views/SideBar/SideBarBody.tsx:
##########
@@ -101,61 +93,122 @@ const DrawerHeader = styled("div")(({ theme }) => ({
marginBottom: "1rem",
}));
+
const SideBarBody = (props: {
- loading: boolean;
- handleOpenModal: any;
- handleOpenAboutModal: any;
+ handleOpenModal: () => void;
+ handleOpenAboutModal: () => void;
}) => {
const location = useLocation();
const routes = useRoutes(AppRoutes as RouteObject[]);
const history = useHistory();
const dispatch = useAppDispatch();
- const { loading: loader, handleOpenModal, handleOpenAboutModal } = props;
+ const { handleOpenModal, handleOpenAboutModal } = props;
const navigate = useNavigate();
- const { loading } = useSelector((state: TypeHeaderState) =>
state.typeHeader);
- const { relationshipSearch = {} } = globalSessionData || {};
+ const relationshipSearch = Boolean(globalSessionData?.relationshipSearch);
const [open, setOpen] = useState(true);
const [searchTerm, setSearchTerm] = useState<string>("");
+ const { data: versionData, loading: isVersionLoading, error: versionError }
= useAppSelector((state) => state.session?.versionData || {});
+ const activeModule = useMemo(() => {
+ const searchParams = new URLSearchParams(location.search);
+ if (searchParams.get("isCF") === "true") return "customFilters";
+ if (location.pathname.includes("/glossary") || !!searchParams.get("gtype")
|| !!searchParams.get("term") || !!searchParams.get("category")) return
"glossary";
+ if (location.pathname.includes("/administrator/businessMetadata")) return
"businessMetadata";
+ if (!!searchParams.get("tag") ||
location.pathname.includes("/tag/tagAttribute")) return "classification";
+ if (!!searchParams.get("relationshipName") ||
location.pathname.includes("/relationshipDetailPage")) return "relationships";
+ if (!!searchParams.get("type") ||
location.pathname.includes("/detailPage")) return "entities";
+ return null;
+ }, [location.pathname, location.search]);
+
+ const isCustomFilterActive = activeModule === "customFilters";
+ const isGlossaryActive = activeModule === "glossary";
+ const isBusinessMetadataActive = activeModule === "businessMetadata";
+ const isClassificationActive = activeModule === "classification";
+ const isRelationshipActive = activeModule === "relationships";
+ const isEntitiesActive = activeModule === "entities";
+
+ const modules = useMemo(() => [
+ { id: "entities", title: "Entities", isActive: isEntitiesActive, iconUrl:
"/img/sidebar-icons/icon-entities.svg", Component: EntitiesTree, isVisible:
true },
+ { id: "classification", title: "Classifications", isActive:
isClassificationActive, iconUrl: "/img/sidebar-icons/icon-classifications.svg",
Component: ClassificationTree, isVisible: true },
+ { id: "glossary", title: "Glossary", isActive: isGlossaryActive, iconUrl:
"/img/sidebar-icons/icon-glossary.svg", Component: GlossaryTree, isVisible:
true },
+ { id: "businessMetadata", title: "Business Metadata", isActive:
isBusinessMetadataActive, iconUrl:
"/img/sidebar-icons/icon-business-metadata.svg", Component:
BusinessMetadataTree, isVisible: true },
+ { id: "relationships", title: "Relationships", isActive:
isRelationshipActive, iconUrl: "/img/sidebar-icons/icon-relationships.svg",
Component: RelationshipsTree, isVisible: !!relationshipSearch },
+ { id: "customFilters", title: "Custom Filters", isActive:
isCustomFilterActive, iconUrl: "/img/sidebar-icons/icon-custom-filters.svg",
Component: CustomFiltersTree, isVisible: true }
+ ], [
+ isEntitiesActive,
+ isClassificationActive,
+ isGlossaryActive,
+ isBusinessMetadataActive,
+ isRelationshipActive,
+ isCustomFilterActive,
+ relationshipSearch
+ ]);
+
+ const [popoverAnchor, setPopoverAnchor] = useState<HTMLButtonElement |
null>(null);
+ const [activePopover, setActivePopover] = useState<string | null>(null);
+ const [popoverMaxHeight, setPopoverMaxHeight] = useState<string>("calc(100vh
- 100px)");
+ const [isBottomHalf, setIsBottomHalf] = useState<boolean>(false);
+ const [popoverContainer, setPopoverContainer] = useState<HTMLDivElement |
null>(null);
+ const [sidebarRefs, setSidebarRefs] = useState<Record<string, HTMLDivElement
| null>>({});
+ const refCallbacks = useRef<Record<string, (el: HTMLDivElement | null) =>
void>>({});
+ const setSidebarRef = useCallback((id: string) => {
+ if (!refCallbacks.current[id]) {
+ refCallbacks.current[id] = (el: HTMLDivElement | null) => {
+ setSidebarRefs(prev => prev[id] === el ? prev : { ...prev, [id]: el });
+ };
+ }
+ return refCallbacks.current[id];
+ }, []);
- const handleDrawerOpen = () => {
- setOpen(!open);
- };
- const [position, setPosition] = useState<string |
number>(defaultDrawerWidth);
- const draggerRef = useRef<HTMLDivElement>(null);
- const headerRef = useRef<HTMLDivElement>(null);
- const windowWidth = window.innerWidth;
- const minPosition = 300;
- const maxPosition = windowWidth * 0.6;
+ const handlePopoverOpen = (event: React.MouseEvent<HTMLButtonElement>, id:
string) => {
+ const target = event.currentTarget;
- const handleMouseMove = (e: MouseEvent) => {
- let newPosition = e.clientX;
+ setPopoverAnchor(target);
+ setActivePopover(id);
- if (newPosition < minPosition) {
- newPosition = minPosition;
- } else if (newPosition > maxPosition) {
- newPosition = maxPosition;
- }
+ // Calculate remaining screen height from the anchor to the bottom
+ const rect = target.getBoundingClientRect();
+ const spaceBelow = window.innerHeight - rect.top - 24;
+ const isBottom = spaceBelow < 350;
+ setIsBottomHalf(isBottom);
- setPosition(newPosition);
+ if (isBottom) {
+ const spaceAbove = rect.bottom - 24;
+ setPopoverMaxHeight(`${Math.max(250, spaceAbove)}px`);
+ } else {
+ setPopoverMaxHeight(`${Math.max(250, spaceBelow)}px`);
+ }
};
- const handleMouseUp = () => {
- window.removeEventListener("mousemove", handleMouseMove);
- window.removeEventListener("mouseup", handleMouseUp);
+ const handlePopoverClose = () => {
+ setPopoverAnchor(null);
+ setActivePopover(null);
};
- const handleMouseDown = () => {
- window.addEventListener("mousemove", handleMouseMove);
- window.addEventListener("mouseup", handleMouseUp);
+ const handleDrawerOpen = () => {
+ setOpen(!open);
+ if (!open) {
+ handlePopoverClose();
+ }
};
+
+
+ const renderPopoverSearch = () => (
+ <div className="sidebar-popover-search">
+ <SidebarSearchInput searchTerm={searchTerm} onChange={setSearchTerm} />
+ </div>
+ );
+
+ const headerRef = useRef<HTMLDivElement>(null);
+
useEffect(() => {
Review Comment:
Thanks for the suggestion! I've added cache guards using `isEmpty` checks
for `fetchTypeHeaderData`, `fetchRootEntity`, `fetchRootClassification`,
`fetchEnumData`, `fetchMetricEntity`, and `fetchVersionData` in
`SideBarBody.tsx` to prevent redundant API calls on layout remount, aligning it
with the behavior in the tree components.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]