Skip to content

Commit e797e5e

Browse files
committed
feat: introduce EnvironmentTable component and enhance design table functionality
Signed-off-by: Amit Amrutiya <amitamrutiya2210@gmail.com>
1 parent 3e5764e commit e797e5e

7 files changed

Lines changed: 539 additions & 9 deletions

File tree

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import AssignmentModal from './AssignmentModal';
2020
import EditButton from './EditButton';
2121
import useDesignAssignment from './hooks/useDesignAssignment';
2222
import { TableHeader, TableRightActionHeader } from './styles';
23+
import { ColumnVisibility } from './types';
2324

2425
export interface DesignTableProps {
2526
workspaceId: string;
@@ -62,9 +63,6 @@ export interface PublishModalState {
6263
pattern: Partial<Pattern>;
6364
}
6465

65-
export interface ColumnVisibility {
66-
[key: string]: boolean;
67-
}
6866
export interface TableColumn {
6967
name: string;
7068
label: string;
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
3+
import { MUIDataTableMeta } from 'mui-datatables';
4+
import React, { useState } from 'react';
5+
import { Accordion, AccordionDetails, AccordionSummary, Typography } from '../../base';
6+
import { DeleteIcon, EnvironmentIcon } from '../../icons';
7+
import { CHARCOAL, SistentThemeProvider } from '../../theme';
8+
import { CustomColumnVisibilityControl } from '../CustomColumnVisibilityControl';
9+
import { CustomTooltip } from '../CustomTooltip';
10+
import { ConditionalTooltip } from '../Helpers/CondtionalTooltip';
11+
import { useWindowDimensions } from '../Helpers/Dimension';
12+
import {
13+
ColView,
14+
updateVisibleColumns
15+
} from '../Helpers/ResponsiveColumns/responsive-coulmns.tsx/responsive-column';
16+
import ResponsiveDataTable, { IconWrapper } from '../ResponsiveDataTable';
17+
import AssignmentModal from './AssignmentModal';
18+
import EditButton from './EditButton';
19+
import TooltipIcon from './TooltipIcon';
20+
import useEnvironmentAssignment from './hooks/useEnvironmentAssignment';
21+
import { CellStyle, CustomBodyRenderStyle, TableHeader, TableRightActionHeader } from './styles';
22+
import { ColumnVisibility } from './types';
23+
24+
interface EnvironmentTableProps {
25+
workspaceId: string;
26+
workspaceName: string;
27+
useGetEnvironmentsOfWorkspaceQuery: any;
28+
useUnassignEnvironmentFromWorkspaceMutation: any;
29+
useAssignEnvironmentToWorkspaceMutation: any;
30+
isRemoveDisabled: boolean;
31+
isAssignDisabled: boolean;
32+
}
33+
34+
const colViews: ColView[] = [
35+
['id', 'na'],
36+
['name', 'xs'],
37+
['description', 'm'],
38+
['organization_id', 'l'],
39+
['created_at', 'na'],
40+
['updated_at', 'xl'],
41+
['actions', 'xs']
42+
];
43+
44+
export const ResizableDescriptionCell = ({ value }: { value: string }) => (
45+
<div style={{ position: 'relative', height: '20px' }}>
46+
<CustomBodyRenderStyle>
47+
<CellStyle>
48+
<CustomTooltip title={value} placement="top-start">
49+
<span style={{ cursor: 'pointer' }}>{value}</span>
50+
</CustomTooltip>
51+
</CellStyle>
52+
</CustomBodyRenderStyle>
53+
</div>
54+
);
55+
56+
const EnvironmentTable: React.FC<EnvironmentTableProps> = ({
57+
workspaceId,
58+
workspaceName,
59+
isRemoveDisabled,
60+
useGetEnvironmentsOfWorkspaceQuery,
61+
useUnassignEnvironmentFromWorkspaceMutation,
62+
useAssignEnvironmentToWorkspaceMutation,
63+
isAssignDisabled
64+
}) => {
65+
const [expanded, setExpanded] = useState<boolean>(true);
66+
const handleAccordionChange = () => {
67+
setExpanded(!expanded);
68+
};
69+
const [page, setPage] = useState<number>(0);
70+
const [pageSize, setPageSize] = useState<number>(10);
71+
const [sortOrder, setSortOrder] = useState<string>('');
72+
const { data: environmentsOfWorkspace } = useGetEnvironmentsOfWorkspaceQuery({
73+
workspaceId,
74+
page: page,
75+
pageSize: pageSize,
76+
order: sortOrder
77+
});
78+
const { width } = useWindowDimensions();
79+
const [unassignEnvironmentFromWorkspace] = useUnassignEnvironmentFromWorkspaceMutation();
80+
const columns: any[] = [
81+
{
82+
name: 'id',
83+
label: 'ID',
84+
options: {
85+
filter: false,
86+
customBodyRender: (value: string) => <ConditionalTooltip value={value} maxLength={10} />
87+
}
88+
},
89+
{
90+
name: 'name',
91+
label: 'Name',
92+
options: {
93+
filter: false,
94+
sort: true,
95+
searchable: true,
96+
customBodyRender: (value: string) => <ConditionalTooltip value={value} maxLength={10} />
97+
}
98+
},
99+
{
100+
name: 'organization_id',
101+
label: 'Organization ID',
102+
options: {
103+
filter: false,
104+
sort: false,
105+
searchable: false
106+
}
107+
},
108+
109+
{
110+
name: 'description',
111+
label: 'Description',
112+
options: {
113+
filter: false,
114+
sort: true,
115+
searchable: true,
116+
customBodyRender: (value: string) => <ResizableDescriptionCell value={value} />
117+
}
118+
},
119+
{
120+
name: 'created_at',
121+
label: 'Created At',
122+
options: {
123+
filter: false,
124+
sort: true,
125+
searchable: true,
126+
setCellHeaderProps: () => {
127+
return { align: 'center' };
128+
}
129+
}
130+
},
131+
{
132+
name: 'updated_at',
133+
label: 'Updated At',
134+
options: {
135+
filter: false,
136+
sort: true,
137+
searchable: true,
138+
setCellHeaderProps: () => {
139+
return { align: 'center' };
140+
}
141+
}
142+
},
143+
{
144+
name: 'actions',
145+
label: 'Actions',
146+
options: {
147+
filter: false,
148+
sort: false,
149+
searchable: false,
150+
customBodyRender: (_: any, tableMeta: MUIDataTableMeta) => (
151+
<IconWrapper disabled={isRemoveDisabled}>
152+
<TooltipIcon
153+
id={`delete_team-${tableMeta.rowIndex}`}
154+
title="Remove Environment"
155+
onClick={() => {
156+
!isRemoveDisabled &&
157+
unassignEnvironmentFromWorkspace({
158+
workspaceId,
159+
environmentId: tableMeta.rowData[0]
160+
});
161+
}}
162+
iconType="delete"
163+
>
164+
<DeleteIcon
165+
height={28}
166+
width={28}
167+
style={{
168+
color: CHARCOAL
169+
}}
170+
/>
171+
</TooltipIcon>
172+
</IconWrapper>
173+
)
174+
}
175+
}
176+
];
177+
178+
const environmentAssignment = useEnvironmentAssignment({
179+
workspaceId,
180+
useGetEnvironmentsOfWorkspaceQuery,
181+
useUnassignEnvironmentFromWorkspaceMutation,
182+
useAssignEnvironmentToWorkspaceMutation
183+
});
184+
185+
const [columnVisibility, setColumnVisibility] = useState<ColumnVisibility>(() => {
186+
const showCols = updateVisibleColumns(colViews, width);
187+
const initialVisibility: ColumnVisibility = {};
188+
columns.forEach((col) => {
189+
initialVisibility[col.name] = showCols[col.name];
190+
});
191+
return initialVisibility;
192+
});
193+
194+
const options = {
195+
filter: false,
196+
responsive: 'standard',
197+
selectableRows: 'none',
198+
count: environmentsOfWorkspace?.total_count,
199+
rowsPerPage: pageSize,
200+
page,
201+
elevation: 0,
202+
serverSide: true,
203+
onTableChange: (action: string, tableState: any) => {
204+
const sortInfo = tableState.announceText ? tableState.announceText.split(' : ') : [];
205+
let order = '';
206+
if (tableState.activeColumn) {
207+
order = `${columns[tableState.activeColumn].name} desc`;
208+
}
209+
210+
switch (action) {
211+
case 'changePage':
212+
setPage(tableState.page);
213+
break;
214+
case 'changeRowsPerPage':
215+
setPageSize(tableState.rowsPerPage);
216+
break;
217+
case 'sort':
218+
if (sortInfo.length == 2) {
219+
if (sortInfo[1] === 'ascending') {
220+
order = `${columns[tableState.activeColumn].name} asc`;
221+
} else {
222+
order = `${columns[tableState.activeColumn].name} desc`;
223+
}
224+
}
225+
if (order !== sortOrder) {
226+
setSortOrder(order);
227+
}
228+
break;
229+
}
230+
}
231+
};
232+
const [tableCols, updateCols] = useState(columns);
233+
234+
return (
235+
<SistentThemeProvider>
236+
<Accordion expanded={expanded} onChange={handleAccordionChange} style={{ margin: 0 }}>
237+
<AccordionSummary
238+
expandIcon={<ExpandMoreIcon />}
239+
sx={{
240+
backgroundColor: 'background.paper'
241+
}}
242+
>
243+
<TableHeader>
244+
<Typography variant="h6" fontWeight={'bold'}>
245+
Assigned Environments
246+
</Typography>
247+
<TableRightActionHeader>
248+
<CustomColumnVisibilityControl
249+
columns={columns}
250+
customToolsProps={{
251+
columnVisibility,
252+
setColumnVisibility
253+
}}
254+
id={'environments-table'}
255+
/>
256+
<EditButton
257+
onClick={environmentAssignment.handleAssignModal}
258+
disabled={isAssignDisabled}
259+
/>
260+
</TableRightActionHeader>
261+
</TableHeader>
262+
</AccordionSummary>
263+
<AccordionDetails style={{ padding: 0 }}>
264+
<ResponsiveDataTable
265+
columns={columns}
266+
data={environmentsOfWorkspace?.environments}
267+
options={options}
268+
colViews={colViews}
269+
tableCols={tableCols}
270+
updateCols={updateCols}
271+
columnVisibility={columnVisibility}
272+
/>
273+
</AccordionDetails>
274+
</Accordion>
275+
276+
<AssignmentModal
277+
open={environmentAssignment.assignModal}
278+
onClose={environmentAssignment.handleAssignModalClose}
279+
title={`Assign Environments to ${workspaceName}`}
280+
headerIcon={<EnvironmentIcon height="40" width="40" fill={'white'} />}
281+
name="Environments"
282+
assignableData={environmentAssignment.data}
283+
handleAssignedData={environmentAssignment.handleAssignData}
284+
originalAssignedData={environmentAssignment.workspaceData}
285+
emptyStateIcon={<EnvironmentIcon height="5rem" width="5rem" fill={'#808080'} />}
286+
handleAssignablePage={environmentAssignment.handleAssignablePage}
287+
handleAssignedPage={environmentAssignment.handleAssignedPage}
288+
originalLeftCount={environmentAssignment.data?.length || 0}
289+
originalRightCount={environmentsOfWorkspace?.total_count || 0}
290+
onAssign={environmentAssignment.handleAssign}
291+
disableTransfer={environmentAssignment.disableTransferButton}
292+
helpText={`Assign Environments to ${workspaceName}`}
293+
isAssignDisabled={!isAssignDisabled}
294+
isRemoveDisabled={!isRemoveDisabled}
295+
/>
296+
</SistentThemeProvider>
297+
);
298+
};
299+
300+
export default EnvironmentTable;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { IconButton } from '@mui/material';
2+
import { useTheme } from '../../theme';
3+
import { CustomTooltip } from '../CustomTooltip';
4+
import { IconWrapper } from '../ResponsiveDataTable';
5+
6+
interface TooltipIconProps {
7+
children: React.ReactNode;
8+
onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
9+
title: string;
10+
iconType: string;
11+
id: string;
12+
style?: React.CSSProperties;
13+
placement?: 'bottom' | 'top' | 'left' | 'right';
14+
disabled?: boolean;
15+
}
16+
17+
const TooltipIcon: React.FC<TooltipIconProps> = ({
18+
children,
19+
onClick,
20+
title,
21+
iconType,
22+
id,
23+
style,
24+
placement,
25+
disabled = false
26+
}) => {
27+
const theme = useTheme();
28+
return (
29+
<CustomTooltip key={id} title={title} placement={placement}>
30+
<IconWrapper disabled={disabled}>
31+
<IconButton
32+
disabled={disabled}
33+
onClick={onClick}
34+
sx={{
35+
'&:hover': {
36+
'& svg': {
37+
fill:
38+
iconType === 'delete'
39+
? theme.palette.error.main
40+
: theme.palette.primary.brand?.default
41+
}
42+
},
43+
...style
44+
}}
45+
disableRipple
46+
>
47+
{children}
48+
</IconButton>
49+
</IconWrapper>
50+
</CustomTooltip>
51+
);
52+
};
53+
54+
export default TooltipIcon;

0 commit comments

Comments
 (0)