Simplify code/extract some logic in Items.tsx
Signed-off-by: hiba-aldalaty <hibaaldalaty@gmail.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { IconComponent } from '@backstage/core-plugin-api';
|
||||
import { IconComponent, useElementFilter } from '@backstage/core-plugin-api';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { makeStyles, styled, Theme } from '@material-ui/core/styles';
|
||||
import Badge from '@material-ui/core/Badge';
|
||||
@@ -173,25 +173,16 @@ type ItemWithSubmenuProps = {
|
||||
icon: IconComponent;
|
||||
submenu: ReactNode;
|
||||
};
|
||||
const ItemWithSubmenu = ({
|
||||
label,
|
||||
hasNotifications = false,
|
||||
icon: Icon,
|
||||
submenu,
|
||||
}: ItemWithSubmenuProps) => {
|
||||
const classes = useStyles();
|
||||
const [isHoveredOn, setIsHoveredOn] = useState(false);
|
||||
|
||||
function isItemWithSubmenuActive(submenu: ReactNode, locationPathname: string) {
|
||||
// Item is active if any of submenu items have active paths
|
||||
const toPathnames: string[] = [];
|
||||
let isActive = false;
|
||||
let submenuItems: ReactNode;
|
||||
Children.forEach(submenu, element => {
|
||||
if (!React.isValidElement(element)) return;
|
||||
submenuItems = element.props.children;
|
||||
});
|
||||
|
||||
const toPathnames: string[] = [];
|
||||
let isActive;
|
||||
const { pathname: locationPathname } = useLocation();
|
||||
|
||||
// SidebarItem is active if any of submenu items have active paths
|
||||
Children.forEach(submenuItems, element => {
|
||||
if (!React.isValidElement(element)) return;
|
||||
if (element.props.dropdownItems) {
|
||||
@@ -202,11 +193,23 @@ const ItemWithSubmenu = ({
|
||||
toPathnames.push(element.props.to);
|
||||
}
|
||||
});
|
||||
toPathnames.some(to => {
|
||||
isActive = toPathnames.some(to => {
|
||||
const toPathname = resolvePath(to);
|
||||
isActive = locationPathname === toPathname.pathname;
|
||||
return isActive;
|
||||
return locationPathname === toPathname.pathname;
|
||||
});
|
||||
return isActive;
|
||||
}
|
||||
|
||||
const ItemWithSubmenu = ({
|
||||
label,
|
||||
hasNotifications = false,
|
||||
icon: Icon,
|
||||
submenu,
|
||||
}: ItemWithSubmenuProps) => {
|
||||
const classes = useStyles();
|
||||
const [isHoveredOn, setIsHoveredOn] = useState(false);
|
||||
const { pathname: locationPathname } = useLocation();
|
||||
const isActive = isItemWithSubmenuActive(submenu, locationPathname);
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
setIsHoveredOn(true);
|
||||
@@ -408,19 +411,30 @@ export const SidebarItem = forwardRef<any, SidebarItemProps>((props, ref) => {
|
||||
};
|
||||
|
||||
let hasSubmenu = false;
|
||||
let submenu: any;
|
||||
let submenu: ReactNode;
|
||||
const componentType = (
|
||||
<SidebarSubmenu>
|
||||
<></>
|
||||
</SidebarSubmenu>
|
||||
).type;
|
||||
Children.forEach(children, element => {
|
||||
if (!React.isValidElement(element)) return;
|
||||
if (element.type === componentType) {
|
||||
submenu = element;
|
||||
hasSubmenu = true;
|
||||
}
|
||||
});
|
||||
// Filter children for SidebarSubmenu components
|
||||
const submenus = useElementFilter(children, elements =>
|
||||
elements
|
||||
.getElements()
|
||||
.filter(
|
||||
child => React.isValidElement(child) && child.type === componentType,
|
||||
),
|
||||
);
|
||||
// Error thrown if more than one SidebarSubmenu in a SidebarItem
|
||||
if (submenus.length > 1) {
|
||||
throw new Error(
|
||||
'Cannot render more than one SidebarSubmenu inside a SidebarItem',
|
||||
);
|
||||
} else if (submenus.length === 1) {
|
||||
hasSubmenu = true;
|
||||
submenu = submenus[0];
|
||||
}
|
||||
|
||||
if (hasSubmenu) {
|
||||
return (
|
||||
<ItemWithSubmenu
|
||||
|
||||
@@ -133,7 +133,6 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => {
|
||||
dropdownItems.some(item => {
|
||||
const resolvedPath = resolvePath(item.to);
|
||||
isActive = locationPathname === resolvedPath.pathname;
|
||||
return isActive;
|
||||
});
|
||||
return (
|
||||
<div className={classes.itemContainer}>
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
OktaAuth,
|
||||
Auth0Auth,
|
||||
ConfigReader,
|
||||
LocalStorageFeatureFlags,
|
||||
} from '@backstage/core-app-api';
|
||||
|
||||
import {
|
||||
@@ -25,10 +26,13 @@ import {
|
||||
oktaAuthApiRef,
|
||||
auth0AuthApiRef,
|
||||
configApiRef,
|
||||
featureFlagsApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
const builder = ApiRegistry.builder();
|
||||
|
||||
builder.add(featureFlagsApiRef, new LocalStorageFeatureFlags());
|
||||
|
||||
builder.add(configApiRef, new ConfigReader({}));
|
||||
|
||||
const alertApi = builder.add(alertApiRef, new AlertApiForwarder());
|
||||
|
||||
Reference in New Issue
Block a user