diff --git a/ui/components/MesheryPatterns/ActionButton.js b/ui/components/MesheryPatterns/ActionButton.js new file mode 100644 index 00000000000..62047b397e5 --- /dev/null +++ b/ui/components/MesheryPatterns/ActionButton.js @@ -0,0 +1,86 @@ +import * as React from 'react'; +import { + Button, + ButtonGroup, + Paper, + Popper, + MenuItem, + MenuList, + ClickAwayListener, +} from '@material-ui/core'; +import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; + +export default function ActionButton({ defaultActionClick, options }) { + const [open, setOpen] = React.useState(false); + const anchorRef = React.useRef(null); + + const handleMenuItemClick = () => { + setOpen(false); + }; + + const handleToggle = (event) => { + event.stopPropagation(); + setOpen((prevOpen) => !prevOpen); + }; + + const handleClose = (event) => { + if (anchorRef.current && anchorRef.current.contains(event.target)) { + return; + } + + setOpen(false); + }; + + return ( + + + + + + + + + + {options.map((option, index) => ( + { + handleMenuItemClick(event); + option.onClick(event, index); + }} + > +
{option.icon}
+ {option.label} +
+ ))} +
+
+
+
+
+ ); +} diff --git a/ui/components/MesheryPatterns/MesheryPatternCard.js b/ui/components/MesheryPatterns/MesheryPatternCard.js index 572708acc73..da9e6504525 100644 --- a/ui/components/MesheryPatterns/MesheryPatternCard.js +++ b/ui/components/MesheryPatterns/MesheryPatternCard.js @@ -4,6 +4,7 @@ import DeleteIcon from '@material-ui/icons/Delete'; import Save from '@material-ui/icons/Save'; import Fullscreen from '@material-ui/icons/Fullscreen'; import Moment from 'react-moment'; +import GetAppIcon from '@material-ui/icons/GetApp'; import FlipCard from '../FlipCard'; import { UnControlled as CodeMirror } from 'react-codemirror2'; import FullscreenExit from '@material-ui/icons/FullscreenExit'; @@ -26,6 +27,7 @@ import { Provider } from 'react-redux'; import { store } from '../../store'; import CAN from '@/utils/can'; import { keys } from '@/utils/permission_constants'; +import ActionButton from './ActionButton'; const INITIAL_GRID_SIZE = { xl: 4, md: 6, xs: 12 }; @@ -40,6 +42,7 @@ function MesheryPatternCard_({ handleUnpublishModal, handleDeploy, handleUnDeploy, + handleDownload, updateHandler, deleteHandler, handleClone, @@ -164,39 +167,39 @@ function MesheryPatternCard_({ Unpublish )} - - genericClickHandler(e, handleVerify)} - disabled={!CAN(keys.VALIDATE_DESIGN.action, keys.VALIDATE_DESIGN.subject)} - > - - Validate - - + genericClickHandler(e, handleVerify)} + options={[ + { + label: 'Validate', + icon: , + onClick: (e) => genericClickHandler(e, handleVerify), + disabled: !CAN(keys.VALIDATE_DESIGN.action, keys.VALIDATE_DESIGN.subject), + }, + { + label: 'Deploy', + icon: , + onClick: (e) => genericClickHandler(e, handleDeploy), + disabled: !CAN(keys.DEPLOY_DESIGN.action, keys.DEPLOY_DESIGN.subject), + }, + { + label: 'Undeploy', + icon: , + onClick: (e) => genericClickHandler(e, handleUnDeploy), + disabled: !CAN(keys.DEPLOY_DESIGN.action, keys.DEPLOY_DESIGN.subject), + }, + ]} + /> genericClickHandler(ev, handleDeploy)} + color="primary" + onClick={handleDownload} className={classes.testsButton} - disabled={!CAN(keys.DEPLOY_DESIGN.action, keys.DEPLOY_DESIGN.subject)} - > - - Deploy - - genericClickHandler(ev, handleUnDeploy)} - disabled={!CAN(keys.DEPLOY_DESIGN.action, keys.DEPLOY_DESIGN.subject)} // use undeploy keys after it get seeded > - - Undeploy + + Download - {visibility === VISIBILITY.PRIVATE ? ( handleSubmit({ data: yaml, @@ -130,9 +140,11 @@ function MesheryPatternGrid({ selectedK8sContexts, publishSchema, user, + updateProgress, handleInfoModal, }) { const classes = useStyles(); + const { notify } = useNotification(); const handlePublishModal = (pattern) => { if (canPublishPattern) { setPublishModal({ @@ -160,6 +172,40 @@ function MesheryPatternGrid({ dryRunComponent: null, }); + const [downloadModal, setDownloadModal] = useState({ + open: false, + content: null, + }); + const handleDownload = (e, design, source_type, params) => { + e.stopPropagation(); + updateProgress({ showProgress: true }); + try { + let id = design.id; + let name = design.name; + downloadContent({ id, name, type: 'pattern', source_type, params }); + updateProgress({ showProgress: false }); + notify({ message: `"${name}" design downloaded`, event_type: EVENT_TYPES.INFO }); + } catch (e) { + console.error(e); + } + }; + const handleDownloadDialogClose = () => { + setDownloadModal((prevState) => ({ + ...prevState, + open: false, + content: null, + })); + }; + + const handleDesignDownloadModal = (e, pattern) => { + e.stopPropagation(); + setDownloadModal((prevState) => ({ + ...prevState, + open: true, + content: pattern, + })); + }; + const handleModalClose = () => { setModalOpen({ open: false, @@ -227,6 +273,7 @@ function MesheryPatternGrid({ handleUnpublishModal={(e) => handleUnpublishModal(e, pattern)()} handleInfoModal={() => handleInfoModal(pattern)} handleSubmit={handleSubmit} + handleDownload={(e) => handleDesignDownloadModal(e, pattern)} setSelectedPatterns={setSelectedPattern} /> ))} @@ -296,8 +343,18 @@ function MesheryPatternGrid({ submitBtnIcon={} /> )} + ); } -export default MesheryPatternGrid; +const mapDispatchToProps = (dispatch) => ({ + updateProgress: bindActionCreators(updateProgress, dispatch), +}); + +// @ts-ignore +export default connect(mapDispatchToProps)(withSnackbar(MesheryPatternGrid));