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 (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
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));