[arvados] created: 2.7.0-5794-g08fb678c7f
git repository hosting
git at public.arvados.org
Tue Jan 9 16:10:29 UTC 2024
at 08fb678c7ff12d3f420477f34610383960b65482 (commit)
commit 08fb678c7ff12d3f420477f34610383960b65482
Author: Lisa Knox <lisaknox83 at gmail.com>
Date: Tue Jan 9 11:10:05 2024 -0500
21317: initial overflow components up Arvados-DCO-1.1-Signed-off-by: Lisa Knox <lisa.knox at curii.com>
diff --git a/services/workbench2/src/components/multiselect-toolbar/MultiselectToolbar.tsx b/services/workbench2/src/components/multiselect-toolbar/MultiselectToolbar.tsx
index f92c0dcf4e..5017e99dd8 100644
--- a/services/workbench2/src/components/multiselect-toolbar/MultiselectToolbar.tsx
+++ b/services/workbench2/src/components/multiselect-toolbar/MultiselectToolbar.tsx
@@ -34,6 +34,7 @@ import { getProcess } from "store/processes/process";
import { Process } from "store/processes/process";
import { PublicFavoritesState } from "store/public-favorites/public-favorites-reducer";
import { isExactlyOneSelected } from "store/multiselect/multiselect-actions";
+import { IntersectionObserverWrapper } from "./ms-toolbar-overflow-wrapper";
const WIDTH_TRANSITION = 150
@@ -134,12 +135,14 @@ export const MultiselectToolbar = connect(
data-cy='multiselect-toolbar'
>
{actions.length ? (
- actions.map((action, i) =>{
+ <IntersectionObserverWrapper>
+ {actions.map((action, i) =>{
const { hasAlts, useAlts, name, altName, icon, altIcon } = action;
return hasAlts ? (
<Tooltip
className={classes.button}
title={currentPathIsTrash || (useAlts && useAlts(singleSelectedUuid, iconProps)) ? altName : name}
+ data-targetid={name}
key={i}
disableFocusListener
>
@@ -170,7 +173,8 @@ export const MultiselectToolbar = connect(
</span>
</Tooltip>
);
- })
+ })}
+ </IntersectionObserverWrapper>
) : (
<></>
)}
diff --git a/services/workbench2/src/components/multiselect-toolbar/ms-toolbar-overflow-menu.tsx b/services/workbench2/src/components/multiselect-toolbar/ms-toolbar-overflow-menu.tsx
new file mode 100644
index 0000000000..1f5be3b85d
--- /dev/null
+++ b/services/workbench2/src/components/multiselect-toolbar/ms-toolbar-overflow-menu.tsx
@@ -0,0 +1,72 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React, { useState, useMemo } from "react";
+import MoreVertIcon from "@material-ui/icons/MoreVert";
+import classnames from "classnames";
+import { IconButton, Menu, MenuItem, StyleRulesCallback, WithStyles, withStyles } from "@material-ui/core";
+import { ArvadosTheme } from "common/custom-theme";
+
+type CssRules = 'inOverflowMenu'
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ inOverflowMenu: {
+ "&:hover": {
+ backgroundColor: "transparent"
+ }
+ }
+});
+
+export const OverflowMenu = withStyles(styles)((props: any & WithStyles<CssRules>) => {
+ const { children, className, visibilityMap, classes } = props
+ const [anchorEl, setAnchorEl] = useState(null);
+ const open = Boolean(anchorEl);
+ const handleClick = (event) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ const shouldShowMenu = useMemo(
+ () => Object.values(visibilityMap).some((v) => v === false),
+ [visibilityMap]
+ );
+ if (!shouldShowMenu) {
+ return null;
+ }
+ return (
+ <div className={className}>
+ <IconButton
+ aria-label="more"
+ aria-controls="long-menu"
+ aria-haspopup="true"
+ onClick={handleClick}
+ >
+ <MoreVertIcon />
+ </IconButton>
+ <Menu
+ id="long-menu"
+ anchorEl={anchorEl}
+ keepMounted
+ open={open}
+ onClose={handleClose}
+ >
+ {React.Children.map(children, (child:any) => {
+ if (!visibilityMap[child.props["data-targetid"]]) {
+ return (
+ <MenuItem key={child} onClick={handleClose}>
+ {React.cloneElement(child, {
+ className: classnames(child.className, classes.inOverflowMenu)
+ })}
+ </MenuItem>
+ );
+ }
+ return null;
+ })}
+ </Menu>
+ </div>
+ );
+})
\ No newline at end of file
diff --git a/services/workbench2/src/components/multiselect-toolbar/ms-toolbar-overflow-wrapper.tsx b/services/workbench2/src/components/multiselect-toolbar/ms-toolbar-overflow-wrapper.tsx
new file mode 100644
index 0000000000..d97c2f0fc8
--- /dev/null
+++ b/services/workbench2/src/components/multiselect-toolbar/ms-toolbar-overflow-wrapper.tsx
@@ -0,0 +1,108 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React, { useState, useRef, useEffect } from 'react';
+import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
+import { ArvadosTheme } from 'common/custom-theme';
+import { OverflowMenu } from './ms-toolbar-overflow-menu';
+
+type CssRules = 'visible' | 'inVisible' | 'toolbarWrapper' | 'overflowStyle';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ visible: {
+ order: 0,
+ visibility: 'visible',
+ opacity: 1,
+ },
+ inVisible: {
+ order: 100,
+ visibility: 'hidden',
+ pointerEvents: 'none',
+ },
+ toolbarWrapper: {
+ display: 'flex',
+ overflow: 'hidden',
+ padding: '0 20px',
+ width: '75%',
+ },
+ overflowStyle: {
+ order: 99,
+ position: 'sticky',
+ right: '0',
+ backgroundColor: 'white',
+ },
+});
+
+export const IntersectionObserverWrapper = withStyles(styles)((props: any & WithStyles<CssRules>) => {
+ const { classes, children} = props
+
+ const navRef = useRef<any>(null);
+ const [visibilityMap, setVisibilityMap] = useState({});
+
+ const handleIntersection = (entries) => {
+ const updatedEntries = {};
+ entries.forEach((entry) => {
+ const targetid = entry.target.dataset.targetid;
+ console.log(entry, targetid);
+ if (entry.isIntersecting) {
+ updatedEntries[targetid] = true;
+ } else {
+ updatedEntries[targetid] = false;
+ }
+ });
+
+ setVisibilityMap((prev) => ({
+ ...prev,
+ ...updatedEntries,
+ }));
+ };
+ useEffect((): any => {
+ const observer = new IntersectionObserver(handleIntersection, {
+ root: navRef.current,
+ threshold: 1,
+ });
+ // We are addting observers to child elements of the container div
+ // with ref as navRef. Notice that we are adding observers
+ // only if we have the data attribute targetid on the child element
+ if (navRef.current)
+ Array.from(navRef.current.children).forEach((item: any) => {
+ if (item.dataset.targetid) {
+ observer.observe(item);
+ }
+ });
+ return () => {
+ observer.disconnect();
+ };
+ }, []);
+
+ return (
+ <div className={classes.toolbarWrapper} ref={navRef}>
+ {React.Children.map(children, (child) => {
+ return React.cloneElement(child, {
+ className: classnames(child.props.className, {
+ [classes.visible]: !!visibilityMap[child.props["data-targetid"]],
+ [classes.inVisible]: !visibilityMap[child.props["data-targetid"]]
+ })
+ });
+ })}
+ <OverflowMenu
+ visibilityMap={visibilityMap}
+ className={classes.overflowStyle}
+ >
+ {children}
+ </OverflowMenu>
+ </div>
+ );
+});
+
+const classnames = (...args: Array<string | Record<string, boolean>>) => {
+ return args.reduce((output: string, currentArg: any) => {
+ if (typeof currentArg === 'string') output += currentArg + ' ';
+ else
+ for (const entry in currentArg) {
+ if (currentArg[entry] === true) output += entry + ' ';
+ }
+ return output;
+ }, '');
+};
\ No newline at end of file
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list