Skip to content

Commit 0646e60

Browse files
authored
Merge branch 'master' into fix/carousal_padding_fix
2 parents 4d3924b + 842f300 commit 0646e60

File tree

7 files changed

+316
-9
lines changed

7 files changed

+316
-9
lines changed

src/constants/constants.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,21 @@ export const MESHERY_CLOUD_PROD = 'https://cloud.layer5.io';
6767
export const MESHERY_CLOUD_STAGING = 'staging-cloud.layer5.io';
6868
export const MESHERY_CLOUD_WS_PROD = 'cloud-ws.layer5.io';
6969
export const MESHERY_CLOUD_WS_STAGING = 'staging-cloud-ws.layer5.io:6543';
70+
71+
export const EVENT_TYPES = {
72+
SUCCESS: {
73+
type: 'success'
74+
},
75+
DEFAULT: {
76+
type: 'default'
77+
},
78+
INFO: {
79+
type: 'info'
80+
},
81+
WARNING: {
82+
type: 'warning'
83+
},
84+
ERROR: {
85+
type: 'error'
86+
}
87+
};

src/custom/CatalogDesignTable/DesignTableColumnConfig.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { Lock, Public } from '@mui/icons-material';
2-
import RemoveCircleIcon from '@mui/icons-material/RemoveCircle';
32
import { Theme } from '@mui/material';
43
import { MUIDataTableColumn, MUIDataTableMeta } from 'mui-datatables';
54
import { Typography } from '../../base';
65
import { PLAYGROUND_MODES } from '../../constants/constants';
7-
import { ChainIcon, CopyIcon, KanvasIcon, PublishIcon } from '../../icons';
6+
import { ChainIcon, CopyIcon, KanvasIcon, MoveFileIcon, PublishIcon } from '../../icons';
87
import Download from '../../icons/Download/Download';
98
import { downloadPattern, slugify } from '../CatalogDetail/helper';
109
import { RESOURCE_TYPES } from '../CatalogDetail/types';
@@ -267,14 +266,10 @@ export const createDesignsColumnsConfig = ({
267266
},
268267

269268
{
270-
title: isFromWorkspaceTable ? 'Move Design' : 'Delete',
271-
disabled: isFromWorkspaceTable ? !isRemoveAllowed : !isDeleteAllowed,
269+
title: 'Delete',
270+
disabled: !isDeleteAllowed,
272271
onClick: () => handleDeleteModal(rowData)(),
273-
icon: isFromWorkspaceTable ? (
274-
<RemoveCircleIcon style={{ color: theme?.palette.icon.default }} />
275-
) : (
276-
<L5DeleteIcon />
277-
)
272+
icon: <L5DeleteIcon />
278273
}
279274
].filter((a) => a?.hidden != true);
280275

@@ -299,6 +294,17 @@ export const createDesignsColumnsConfig = ({
299294
icon: <CopyIcon width={24} height={24} fill={theme?.palette.icon.secondary} />
300295
};
301296

297+
const moveAction = {
298+
title: 'Move Design',
299+
disabled: !isRemoveAllowed,
300+
onClick: () => handleDeleteModal(rowData)(),
301+
icon: <MoveFileIcon />
302+
};
303+
304+
if (isFromWorkspaceTable) {
305+
actionsList.splice(0, 0, moveAction);
306+
}
307+
302308
if (rowData.visibility === 'published') {
303309
actionsList.splice(0, 0, cloneAction);
304310
actionsList.splice(2, 0, unpublishAction);
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
3+
import React, { useContext, useState } from 'react';
4+
import {
5+
Box,
6+
Button,
7+
CircularProgress,
8+
Divider,
9+
List,
10+
ListItem,
11+
ListItemText,
12+
Typography
13+
} from '../../base';
14+
import { EVENT_TYPES, RESOURCE_TYPE } from '../../constants/constants';
15+
import { OpenFileIcon } from '../../icons';
16+
import { styled } from '../../theme';
17+
import { Pattern } from '../CustomCatalog/CustomCard';
18+
import { Modal, ModalBody, ModalFooter, PrimaryActionButtons } from '../Modal';
19+
20+
interface WorkspaceContentMoveModalProps {
21+
workspaceContentMoveModal: boolean;
22+
setWorkspaceContentMoveModal: (open: boolean) => void;
23+
currentWorkspace: any;
24+
type: string;
25+
selectedContent: any;
26+
refetch?: () => void;
27+
useGetWorkspacesQuery: any;
28+
isCreateWorkspaceAllowed: boolean;
29+
isMoveDesignAllowed: boolean;
30+
isMoveViewAllowed: boolean;
31+
assignDesignToWorkspace: (params: { workspaceId: string; designId: string }) => Promise<any>;
32+
assignViewToWorkspace: (params: { workspaceId: string; viewId: string }) => Promise<any>;
33+
WorkspaceModalContext: React.Context<any>;
34+
notify: any;
35+
router: any;
36+
currentOrgId: string;
37+
}
38+
39+
interface Workspace {
40+
id: string;
41+
name: string;
42+
}
43+
44+
const WorkspaceItem = styled(ListItem)({
45+
borderRadius: '8px'
46+
});
47+
48+
const CurrentWorkspaceSection = styled(Typography)(({ theme }) => ({
49+
marginBottom: '1rem',
50+
color: theme.palette.text.secondary
51+
}));
52+
53+
const NoWorkspacesContainer = styled('div')(({ theme }) => ({
54+
padding: '1rem',
55+
textAlign: 'center',
56+
color: theme.palette.text.secondary,
57+
border: `1px dashed ${theme.palette.border.strong}`,
58+
borderRadius: '8px',
59+
margin: '1rem 0',
60+
display: 'flex',
61+
flexDirection: 'column',
62+
alignItems: 'center',
63+
gap: '1rem'
64+
}));
65+
66+
const getModalTitle = (type: string, selectedContent: any, multiSelectedContent: any[]): string => {
67+
const itemCount = multiSelectedContent?.length || 1;
68+
const resourceName = selectedContent?.name || itemCount;
69+
const resourceType = type === RESOURCE_TYPE.DESIGN ? 'Design' : 'View';
70+
71+
return `Move ${resourceName} ${resourceType}${itemCount > 1 ? 's' : ''}`;
72+
};
73+
74+
const WorkspaceContentMoveModal: React.FC<WorkspaceContentMoveModalProps> = ({
75+
workspaceContentMoveModal,
76+
setWorkspaceContentMoveModal,
77+
currentWorkspace,
78+
type,
79+
selectedContent,
80+
refetch,
81+
useGetWorkspacesQuery,
82+
isCreateWorkspaceAllowed,
83+
isMoveDesignAllowed,
84+
isMoveViewAllowed,
85+
assignDesignToWorkspace,
86+
assignViewToWorkspace,
87+
WorkspaceModalContext,
88+
notify,
89+
router,
90+
currentOrgId
91+
}) => {
92+
const { setMultiSelectedContent, multiSelectedContent, closeModal } =
93+
useContext(WorkspaceModalContext);
94+
const { data: workspaceData, isLoading } = useGetWorkspacesQuery(
95+
{
96+
page: 0,
97+
pagesize: 'all',
98+
order: 'updated_at desc',
99+
orgID: currentOrgId
100+
},
101+
{
102+
skip: !currentOrgId
103+
}
104+
);
105+
106+
const filteredWorkspaces = workspaceData?.workspaces?.filter(
107+
(workspace: Workspace) => workspace.id !== currentWorkspace.id
108+
);
109+
const [selectedWorkspaceForMove, setSelectedWorkspaceForMove] = useState<Workspace | null>(null);
110+
111+
const handleMove = async (): Promise<void> => {
112+
setWorkspaceContentMoveModal(false);
113+
114+
try {
115+
const moveDesign = async (designId: string): Promise<void> => {
116+
await assignDesignToWorkspace({
117+
workspaceId: selectedWorkspaceForMove!.id,
118+
designId
119+
});
120+
};
121+
122+
const moveView = async (viewId: string): Promise<void> => {
123+
await assignViewToWorkspace({
124+
workspaceId: selectedWorkspaceForMove!.id,
125+
viewId
126+
});
127+
};
128+
129+
if (RESOURCE_TYPE.DESIGN === type) {
130+
if (multiSelectedContent.length > 0) {
131+
await Promise.all(multiSelectedContent.map((design: Pattern) => moveDesign(design.id)));
132+
setMultiSelectedContent([]);
133+
}
134+
if (selectedContent) {
135+
await moveDesign(selectedContent.id);
136+
}
137+
} else {
138+
if (multiSelectedContent.length > 0) {
139+
await Promise.all(multiSelectedContent.map((view: { id: string }) => moveView(view.id)));
140+
setMultiSelectedContent([]);
141+
}
142+
if (selectedContent) {
143+
await moveView(selectedContent.id);
144+
}
145+
}
146+
if (refetch) {
147+
refetch();
148+
}
149+
notify({
150+
message: `Successfully moved ${type === RESOURCE_TYPE.DESIGN ? 'design' : 'view'}${multiSelectedContent.length > 1 ? 's' : ''} to ${selectedWorkspaceForMove!.name}`,
151+
event_type: EVENT_TYPES.SUCCESS
152+
});
153+
} catch (error) {
154+
notify({
155+
message: `Failed to move ${type === RESOURCE_TYPE.DESIGN ? 'design' : 'view'}. Please try again.`,
156+
event_type: EVENT_TYPES.ERROR
157+
});
158+
}
159+
};
160+
161+
const handleCreateWorkspace = (): void => {
162+
closeModal();
163+
setWorkspaceContentMoveModal(false);
164+
router.push('/management/workspaces');
165+
};
166+
167+
const isMoveAllowed = type === RESOURCE_TYPE.DESIGN ? isMoveDesignAllowed : isMoveViewAllowed;
168+
169+
return (
170+
<Modal
171+
open={workspaceContentMoveModal}
172+
headerIcon={<OpenFileIcon />}
173+
closeModal={() => setWorkspaceContentMoveModal(false)}
174+
title={getModalTitle(type, selectedContent, multiSelectedContent)}
175+
>
176+
<ModalBody>
177+
<CurrentWorkspaceSection>
178+
Current Workspace: <strong>{currentWorkspace.name}</strong>
179+
</CurrentWorkspaceSection>
180+
<Divider />
181+
<Box display="flex" flexDirection="column" marginTop={'1rem'}>
182+
{isLoading ? (
183+
<CircularProgress size={24} />
184+
) : !filteredWorkspaces?.length ? (
185+
<NoWorkspacesContainer>
186+
<Typography>No other workspaces available to move content to.</Typography>
187+
<Button
188+
variant="contained"
189+
color="primary"
190+
onClick={handleCreateWorkspace}
191+
disabled={!isCreateWorkspaceAllowed}
192+
>
193+
Create Workspace
194+
</Button>
195+
</NoWorkspacesContainer>
196+
) : (
197+
<>
198+
<Typography style={{ marginBottom: '0.5rem' }}>
199+
Select destination workspace
200+
</Typography>
201+
202+
<List>
203+
{filteredWorkspaces.map((workspace: Workspace) => (
204+
<WorkspaceItem
205+
key={workspace.id}
206+
selected={selectedWorkspaceForMove?.id === workspace.id}
207+
onClick={() => isMoveAllowed && setSelectedWorkspaceForMove(workspace)}
208+
disabled={!isMoveAllowed}
209+
>
210+
<ListItemText primary={workspace.name} />
211+
</WorkspaceItem>
212+
))}
213+
</List>
214+
</>
215+
)}
216+
</Box>
217+
</ModalBody>
218+
<ModalFooter variant="filled">
219+
<PrimaryActionButtons
220+
primaryText={'Move'}
221+
secondaryText="Cancel"
222+
primaryButtonProps={{
223+
onClick: handleMove,
224+
disabled:
225+
isLoading ||
226+
!selectedWorkspaceForMove ||
227+
!filteredWorkspaces?.length ||
228+
!isMoveAllowed
229+
}}
230+
secondaryButtonProps={{
231+
onClick: () => setWorkspaceContentMoveModal(false)
232+
}}
233+
/>
234+
</ModalFooter>
235+
</Modal>
236+
);
237+
};
238+
239+
export default WorkspaceContentMoveModal;

src/custom/Workspaces/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import AssignmentModal from './AssignmentModal';
22
import DesignTable from './DesignTable';
33
import EnvironmentTable from './EnvironmentTable';
44
import WorkspaceCard from './WorkspaceCard';
5+
import WorkspaceContentMoveModal from './WorkspaceContentMoveModal';
56
import WorkspaceEnvironmentSelection from './WorkspaceEnvironmentSelection';
67
import WorkspaceRecentActivityModal from './WorkspaceRecentActivityModal';
78
import WorkspaceTeamsTable from './WorkspaceTeamsTable';
@@ -23,6 +24,7 @@ export {
2324
useTeamAssignment,
2425
useViewAssignment,
2526
WorkspaceCard,
27+
WorkspaceContentMoveModal,
2628
WorkspaceEnvironmentSelection,
2729
WorkspaceRecentActivityModal,
2830
WorkspaceTeamsTable,

src/icons/MoveFile/MoveFileIcon.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { FC } from 'react';
2+
import { DEFAULT_HEIGHT, DEFAULT_WIDTH } from '../../constants/constants';
3+
import { useTheme } from '../../theme';
4+
import { IconProps } from '../types';
5+
6+
export const MoveFileIcon: FC<IconProps> = ({
7+
width = DEFAULT_WIDTH,
8+
height = DEFAULT_HEIGHT,
9+
fill,
10+
style = {}
11+
}) => {
12+
const theme = useTheme();
13+
14+
return (
15+
<>
16+
<svg
17+
xmlns="http://www.w3.org/2000/svg"
18+
width={width || '24'}
19+
height={height || '24'}
20+
viewBox="0 0 24 24"
21+
>
22+
<g>
23+
<path
24+
fill={fill || theme.palette.icon.default}
25+
fill-rule="evenodd"
26+
d="M2 6a3 3 0 0 1 3-3h4.172a3 3 0 0 1 2.12.879L12.415 5H19a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3zm11.08 10.664 2.667-3a1 1 0 0 0 0-1.328l-2.666-3a1 1 0 1 0-1.495 1.328L12.773 12H9a1 1 0 1 0 0 2h3.773l-1.187 1.336a1 1 0 0 0 1.495 1.328z"
27+
clip-rule="evenodd"
28+
opacity="1"
29+
data-original="#000000"
30+
style={style}
31+
></path>
32+
</g>
33+
</svg>
34+
</>
35+
);
36+
};
37+
38+
export default MoveFileIcon;

src/icons/MoveFile/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import MoveFileIcon from './MoveFileIcon';
2+
3+
export { MoveFileIcon };

src/icons/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export * from './Mendeley';
8282
export * from './Menu';
8383
export * from './MesheryFilter';
8484
export * from './MesheryOperator';
85+
export * from './MoveFile';
8586
export * from './Open';
8687
export * from './OpenInNew';
8788
export * from './Organization';

0 commit comments

Comments
 (0)