Skip to content

Commit c0287c1

Browse files
committed
ATLAS-5324: Enhance Collapsed Sidebar with Module Icons, Interactive Tree Tooltips, and Active State Markers
1 parent 99fc73c commit c0287c1

26 files changed

Lines changed: 1782 additions & 1592 deletions
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

dashboard/src/components/EntityDisplayImage.tsx

Lines changed: 19 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { useEffect, useState } from "react";
19-
import { Avatar, Skeleton } from "@mui/material";
18+
import { Avatar } from "@mui/material";
2019
import { getEntityIconPath } from "../utils/Utils";
2120

2221
const DisplayImage = ({
@@ -26,75 +25,40 @@ const DisplayImage = ({
2625
avatarDisplay,
2726
isProcess
2827
}: any) => {
29-
const [imageUrl, setImageUrl] = useState<any>(null);
30-
const [checkEntityImage, setCheckEntityImage] = useState<any>({
31-
[entity.guid]: false
32-
});
28+
const entityData = { ...entity, isProcess: isProcess };
29+
30+
const primaryUrl = getEntityIconPath({ entityData }) || "";
31+
const fallbackUrl = getEntityIconPath({ entityData, errorUrl: primaryUrl }) || "";
3332

34-
useEffect(() => {
35-
const fetchImagePath = async () => {
36-
let entityData = { ...entity, ...{ isProcess: isProcess } };
37-
let imagePath: any = getEntityIconPath({ entityData: entityData });
38-
try {
39-
const response = await fetch(imagePath);
40-
const contentType: any = response.headers.get("Content-Type");
33+
const handleError = (e: React.SyntheticEvent<HTMLImageElement, Event>) => {
34+
const target = e.currentTarget;
35+
if (target.src !== fallbackUrl) {
36+
target.onerror = null;
37+
target.src = fallbackUrl;
38+
}
39+
};
4140

42-
if (contentType.startsWith("image/")) {
43-
let cache = { [entityData.guid]: imagePath };
44-
setCheckEntityImage(cache);
45-
setImageUrl(getEntityIconPath({ entityData: entityData }));
46-
} else {
47-
setImageUrl(
48-
getEntityIconPath({ entityData: entityData, errorUrl: imagePath })
49-
);
50-
}
51-
} catch (error) {
52-
setImageUrl(
53-
getEntityIconPath({ entityData: entityData, errorUrl: imagePath })
54-
);
55-
}
56-
};
57-
58-
fetchImagePath();
59-
}, []);
60-
61-
return imageUrl != undefined ? (
41+
return (
6242
<div className="search-result-table-name-col" data-cy="entityIcon">
63-
{checkEntityImage[entity.guid] !== false ? (
64-
avatarDisplay == undefined ? (
65-
<img
66-
className="search-result-table-img"
67-
id={entity.guid}
68-
data-cy={entity.guid}
69-
src={checkEntityImage[entity.guid]}
70-
alt="Entity Icon"
71-
/>
72-
) : (
73-
<Avatar
74-
alt="entityImg"
75-
src={checkEntityImage[entity.guid]}
76-
sx={{ width: width, height: height }}
77-
variant="square"
78-
></Avatar>
79-
)
80-
) : avatarDisplay == undefined ? (
43+
{avatarDisplay == undefined ? (
8144
<img
8245
className="search-result-table-img"
8346
id={entity.guid}
8447
data-cy={entity.guid}
85-
src={imageUrl}
48+
src={primaryUrl}
8649
alt="Entity Icon"
50+
onError={handleError}
8751
/>
8852
) : (
8953
<Avatar
9054
alt="entityImg"
91-
src={imageUrl}
55+
src={primaryUrl}
9256
sx={{ width: width, height: height }}
57+
variant="square"
58+
imgProps={{ onError: handleError }}
9359
></Avatar>
9460
)}
9561
</div>
96-
) : (
97-
<div>{<Skeleton variant="circular" width={22} height={20} />}</div>
9862
);
9963
};
10064

dashboard/src/components/GlobalSearch/QuickSearch.tsx

Lines changed: 77 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -198,24 +198,24 @@ const QuickSearch = () => {
198198

199199
entities = !isEmpty(searchResults?.entities)
200200
? searchResults?.entities?.map((entityDef: any) => {
201-
const { name }: { name: string; found: boolean; key: any } =
202-
extractKeyValueFromEntity(entityDef);
203-
return {
204-
title: `${name}`,
205-
parent: entityDef.typeName,
206-
types: "Entities",
207-
entityObj: entityDef
208-
};
209-
})
201+
const { name }: { name: string; found: boolean; key: any } =
202+
extractKeyValueFromEntity(entityDef);
203+
return {
204+
title: `${name}`,
205+
parent: entityDef.typeName,
206+
types: "Entities",
207+
entityObj: entityDef
208+
};
209+
})
210210
: [{ title: "No Entities Found", types: "Entities" }];
211211

212212
suggestionNames = !isEmpty(suggestions)
213213
? suggestions.map((suggestion: any) => {
214-
return {
215-
title: `${suggestion}`,
216-
types: "Suggestions"
217-
};
218-
})
214+
return {
215+
title: `${suggestion}`,
216+
types: "Suggestions"
217+
};
218+
})
219219
: [{ title: "No Suggestions Found", types: "Suggestions" }];
220220

221221
setOptions([...entities, ...suggestionNames] as GlobalOptionRow[]);
@@ -400,6 +400,7 @@ const QuickSearch = () => {
400400
onChange={handleScopeChange}
401401
aria-label="Search scope"
402402
displayEmpty
403+
sx={{ height: "32px", boxSizing: "border-box" }}
403404
renderValue={(v) => SCOPE_LABELS[v as QuickSearchScope]}
404405
>
405406
<MenuItem value="default">Select All</MenuItem>
@@ -494,14 +495,14 @@ const QuickSearch = () => {
494495

495496
const { entityObj, types, parent } =
496497
typeof option !== "string" &&
497-
"entityObj" in option &&
498-
"types" in option &&
499-
"parent" in option
498+
"entityObj" in option &&
499+
"types" in option &&
500+
"parent" in option
500501
? (option as {
501-
entityObj: { status?: string; guid?: string };
502-
types: string;
503-
parent: string;
504-
})
502+
entityObj: { status?: string; guid?: string };
503+
types: string;
504+
parent: string;
505+
})
505506
: { entityObj: null, types: "", parent: "" };
506507
const title =
507508
typeof option !== "string" && "title" in option
@@ -557,7 +558,7 @@ const QuickSearch = () => {
557558
to={{ pathname: href }}
558559
color={
559560
entityObj?.status &&
560-
entityStateReadOnly[entityObj.status]
561+
entityStateReadOnly[entityObj.status]
561562
? "error"
562563
: "primary"
563564
}
@@ -567,48 +568,48 @@ const QuickSearch = () => {
567568
)}
568569
{types === "Entities" && !isEmpty(entityObj)
569570
? parts.map((part, index) => (
570-
<Stack
571-
flexDirection="row"
572-
key={index}
573-
style={{
574-
fontWeight: part.highlight ? "bold" : "regular"
575-
}}
576-
>
577-
{entityObj?.guid !== "-1" && !part.highlight ? (
578-
<Link
579-
className="entity-name text-blue text-decoration-none"
580-
style={{
581-
color: "black",
582-
textDecoration: "none",
583-
maxWidth: "100%",
584-
width: "100%"
585-
}}
586-
to={{ pathname: href }}
587-
color={
588-
entityObj?.status &&
571+
<Stack
572+
flexDirection="row"
573+
key={index}
574+
style={{
575+
fontWeight: part.highlight ? "bold" : "regular"
576+
}}
577+
>
578+
{entityObj?.guid !== "-1" && !part.highlight ? (
579+
<Link
580+
className="entity-name text-blue text-decoration-none"
581+
style={{
582+
color: "black",
583+
textDecoration: "none",
584+
maxWidth: "100%",
585+
width: "100%"
586+
}}
587+
to={{ pathname: href }}
588+
color={
589+
entityObj?.status &&
589590
entityStateReadOnly[entityObj.status]
590-
? "error"
591-
: "primary"
592-
}
593-
>
594-
{part.text}
595-
</Link>
596-
) : (
597-
part.text
598-
)}
599-
</Stack>
600-
))
591+
? "error"
592+
: "primary"
593+
}
594+
>
595+
{part.text}
596+
</Link>
597+
) : (
598+
part.text
599+
)}
600+
</Stack>
601+
))
601602
: parts.map((part, index) => (
602-
<Stack
603-
flexDirection="row"
604-
key={index}
605-
style={{
606-
fontWeight: part.highlight ? "bold" : "regular"
607-
}}
608-
>
609-
{part.text}
610-
</Stack>
611-
))}
603+
<Stack
604+
flexDirection="row"
605+
key={index}
606+
style={{
607+
fontWeight: part.highlight ? "bold" : "regular"
608+
}}
609+
>
610+
{part.text}
611+
</Stack>
612+
))}
612613
{types === "Entities" &&
613614
!isEmpty(entityObj) &&
614615
` (${parent})`}
@@ -640,11 +641,13 @@ const QuickSearch = () => {
640641
}}
641642
className="text-black-default"
642643
InputProps={{
643-
style: {
644-
padding: "1px 10px",
644+
sx: {
645+
height: "32px",
646+
padding: "0 10px !important",
645647
borderRadius: "4px",
646648
color: "#1a1a1a",
647-
backgroundColor: "white"
649+
backgroundColor: "white",
650+
boxSizing: "border-box"
648651
},
649652
...params.InputProps,
650653
type: "search",
@@ -681,7 +684,11 @@ const QuickSearch = () => {
681684
backgroundColor: "#4a90e2 !important",
682685
color: "#fff !important",
683686
textTransform: "none",
684-
fontWeight: 600
687+
fontWeight: 600,
688+
height: "32px !important",
689+
minHeight: "32px !important",
690+
maxHeight: "32px !important",
691+
boxSizing: "border-box"
685692
}}
686693
onClick={handleSubmitSearch}
687694
aria-label="Run search"
@@ -696,6 +703,10 @@ const QuickSearch = () => {
696703
backgroundColor: "white !important",
697704
color: "#4a90e2 !important",
698705
borderColor: "#dddddd !important",
706+
height: "32px !important",
707+
minHeight: "32px !important",
708+
maxHeight: "32px !important",
709+
boxSizing: "border-box",
699710
"&:hover": {
700711
backgroundColor: "rgba(74, 144, 226, 0.08) !important",
701712
color: "#4a90e2 !important"

dashboard/src/components/TreeNodeIcons.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ const TreeNodeIcons = (props: {
5555
treeName: string;
5656
updatedData: any;
5757
isEmptyServicetype: boolean | undefined;
58+
isHovered?: boolean;
5859
}) => {
59-
const { node, treeName, updatedData, isEmptyServicetype } = props;
60+
const { node, treeName, updatedData, isEmptyServicetype, isHovered } = props;
6061
const navigate = useNavigate();
6162
const toastId: any = useRef(null);
6263
const [expandNode, setExpandNode] = useState<null | HTMLElement>(null);
@@ -189,6 +190,7 @@ const TreeNodeIcons = (props: {
189190
size="small"
190191
className="tree-item-more-label"
191192
data-cy="dropdownMenuButton"
193+
style={{ visibility: isHovered || openNode ? "visible" : "hidden" }}
192194
>
193195
<MoreHorizOutlinedIcon />
194196
</IconButton>
@@ -209,6 +211,7 @@ const TreeNodeIcons = (props: {
209211
className="tree-item-more-label"
210212
size="small"
211213
data-cy="dropdownMenuButton"
214+
style={{ visibility: isHovered || openNode ? "visible" : "hidden" }}
212215
>
213216
<MoreHorizOutlinedIcon className="treeitem-dropdown-toggle" />
214217
</IconButton>

0 commit comments

Comments
 (0)