Skip to content

Commit

Permalink
Merge branch 'master' into feat/panel
Browse files Browse the repository at this point in the history
amitamrutiya authored Jan 27, 2025
2 parents b13ff72 + fdb745a commit df32123
Showing 33 changed files with 692 additions and 68 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/bump-meshery-version.yml
Original file line number Diff line number Diff line change
@@ -116,7 +116,7 @@ jobs:
cache: "npm"
cache-dependency-path: '**/package-lock.json'
- name: Make changes to pull request
run: npm install @layer5/sistent@${{needs.versions-check.outputs.current}}
run: npm install @layer5/sistent@${{needs.versions-check.outputs.current}} --legacy-peer-deps
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v7
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -91,7 +91,6 @@ Find out more on the <a href="https://layer5.io/community">Layer5 community</a>.
<br /><br /><br /><br />

</p>

<div>&nbsp;</div>

<a href="https://slack.meshery.io">
7 changes: 6 additions & 1 deletion src/base/Pagination/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { Pagination as MuiPagination, PaginationProps as MuiPaginationProps } from '@mui/material';
import {
Pagination as MuiPagination,
PaginationItem as MuiPaginationItem,
PaginationProps as MuiPaginationProps
} from '@mui/material';
import React from 'react';

const Pagination = React.forwardRef<HTMLDivElement, MuiPaginationProps>((props, ref) => {
return <MuiPagination {...props} ref={ref} />;
});

export { MuiPaginationItem as PaginationItem };
export default Pagination;
4 changes: 2 additions & 2 deletions src/base/Pagination/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PaginationProps } from '@mui/material';
import Pagination from './Pagination';
import Pagination, { PaginationItem } from './Pagination';

export { Pagination };
export { Pagination, PaginationItem };
export type { PaginationProps };
39 changes: 19 additions & 20 deletions src/custom/CatalogDetail/ActionButton.tsx
Original file line number Diff line number Diff line change
@@ -76,31 +76,13 @@ const ActionButtons: React.FC<ActionButtonsProps> = ({
width: '100%'
}}
>
<ActionButton
sx={{
borderRadius: '0.2rem',
backgroundColor: 'transparent',
border: `1px solid ${theme.palette.border.normal}`,
gap: '10px',
color: theme.palette.text.default
}}
onClick={() =>
cleanedType === VIEWS
? downloadYaml(details.pattern_file, details.name)
: downloadPattern(details.id, details.name, getDownloadUrl)
}
>
<Download width={24} height={24} fill={theme.palette.icon.default} />
Download
</ActionButton>

{cleanedType !== FILTERS && (
<ActionButton
sx={{
backgroundColor: showOpenPlaygroundAction ? 'transparent' : undefined,
color: theme.palette.text.default,
borderRadius: '0.2rem',
gap: '10px',
color: theme.palette.text.default,
backgroundColor: 'transparent',
border: `1px solid ${theme.palette.border.normal}`
}}
onClick={() => handleClone(details?.name, details?.id)}
@@ -116,6 +98,23 @@ const ActionButtons: React.FC<ActionButtonsProps> = ({
)}
</ActionButton>
)}
<ActionButton
sx={{
borderRadius: '0.2rem',
backgroundColor: 'transparent',
border: `1px solid ${theme.palette.border.normal}`,
gap: '10px',
color: theme.palette.text.default
}}
onClick={() =>
cleanedType === VIEWS
? downloadYaml(details.pattern_file, details.name)
: downloadPattern(details.id, details.name, getDownloadUrl)
}
>
<Download width={24} height={24} fill={theme.palette.icon.default} />
Download
</ActionButton>
</div>
)}

3 changes: 1 addition & 2 deletions src/custom/CatalogDetail/style.tsx
Original file line number Diff line number Diff line change
@@ -264,8 +264,7 @@ export const RedirectLink = styled(Link)(({ theme }) => ({
export const ShareButtonGroup = styled(ButtonGroup)({
boxShadow: 'none',
border: 'none',
outline: 'none',
height: '76%'
outline: 'none'
});

export const ShareButton = styled(Button)(({ theme }) => ({
4 changes: 3 additions & 1 deletion src/custom/Markdown/index.tsx
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import {
BasicAnchorMarkdown,
StyledMarkdown,
StyledMarkdownBlockquote,
StyledMarkdownCode,
StyledMarkdownH1,
StyledMarkdownH2,
StyledMarkdownH3,
@@ -54,7 +55,8 @@ export const RenderMarkdown: React.FC<RenderMarkdownProps> = ({ content }) => {
li: ({ ...props }) => <StyledMarkdownLi>{props.children}</StyledMarkdownLi>,
th: ({ ...props }) => <StyledMarkdownTh>{props.children}</StyledMarkdownTh>,
td: ({ ...props }) => <StyledMarkdownTd>{props.children}</StyledMarkdownTd>,
pre: ({ ...props }) => <StyledMarkdownPre>{props.children}</StyledMarkdownPre>
pre: ({ ...props }) => <StyledMarkdownPre>{props.children}</StyledMarkdownPre>,
code: ({ ...props }) => <StyledMarkdownCode>{props.children}</StyledMarkdownCode>
}}
>
{content}
9 changes: 9 additions & 0 deletions src/custom/Markdown/style.tsx
Original file line number Diff line number Diff line change
@@ -98,3 +98,12 @@ export const StyledMarkdownPre = styled('pre')(({ theme }) => ({
whiteSpace: 'pre-line',
fontFamily: 'inherit'
}));

export const StyledMarkdownCode = styled('code')(({ theme }) => ({
background: theme.palette.background.code,
whiteSpace: 'pre-line',
padding: '1.5px',
paddingInline: '5px',
fontFamily: 'inherit',
borderRadius: 3
}));
4 changes: 2 additions & 2 deletions src/custom/Prompt/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import PromptComponent from './promt-component';

import PromptComponent, { PROMPT_VARIANTS } from './promt-component';
export { PROMPT_VARIANTS, PromptComponent };
export default PromptComponent;
46 changes: 40 additions & 6 deletions src/custom/Prompt/promt-component.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { forwardRef, useImperativeHandle, useRef, useState } from 'react';
import { Typography } from '../../base';
import { Checkbox, FormControlLabel, Typography } from '../../base';
import { useTheme } from '../../theme';
import { Modal, ModalBody, ModalButtonPrimary, ModalButtonSecondary, ModalFooter } from '../Modal';
import { ActionComponent, Subtitle } from './style';
@@ -26,6 +26,8 @@ interface State {
showInfoIcon?: string;
variant?: PromptVariant;
headerIcon?: React.ReactNode;
showCheckbox?: boolean;
isChecked?: boolean;
}

interface ShowParams {
@@ -34,11 +36,13 @@ interface ShowParams {
primaryOption: string;
variant: PromptVariant;
showInfoIcon?: string;
showCheckbox?: boolean;
headerIcon?: React.ReactNode;
}

export interface PromptRef {
show: (params: ShowParams) => Promise<string>;
getCheckboxState: () => boolean;
}

const PromptComponent = forwardRef<PromptRef, PromptProps>(({ variant }, ref) => {
@@ -49,7 +53,9 @@ const PromptComponent = forwardRef<PromptRef, PromptProps>(({ variant }, ref) =>
primaryOption: '',
showInfoIcon: '',
variant,
headerIcon: undefined
headerIcon: undefined,
isChecked: false,
showCheckbox: false
});

/* This ref is used to store the resolve and reject functions of the promise returned by the show method */
@@ -67,7 +73,8 @@ const PromptComponent = forwardRef<PromptRef, PromptProps>(({ variant }, ref) =>
setState({
...params,
isOpen: true,
showInfoIcon: params.showInfoIcon || ''
showInfoIcon: params.showInfoIcon || '',
showCheckbox: !!params.showCheckbox
});
});
};
@@ -77,11 +84,20 @@ const PromptComponent = forwardRef<PromptRef, PromptProps>(({ variant }, ref) =>
setState((prevState) => ({ ...prevState, isOpen: false }));
};

const handleCheckboxChange = () => {
setState((prevState) => ({ ...prevState, isChecked: !prevState.isChecked }));
};

const getCheckboxState = () => {
return !!state.isChecked;
};

useImperativeHandle(ref, () => ({
show
show,
getCheckboxState
}));

const { isOpen, primaryOption, title, subtitle, showInfoIcon, headerIcon } = state;
const { isOpen, primaryOption, title, subtitle, showInfoIcon, headerIcon, showCheckbox } = state;
const { resolve } = promiseInfoRef.current;

return (
@@ -96,10 +112,28 @@ const PromptComponent = forwardRef<PromptRef, PromptProps>(({ variant }, ref) =>
{subtitle && (
<ModalBody>
<Subtitle id="alert-dialog-description" variant="body1" component="div">
<Typography variant="body1" component="div">
<Typography
variant="body1"
component="div"
style={{
color: theme.palette.text.primary
}}
>
{subtitle}
</Typography>
</Subtitle>
{showCheckbox && (
<FormControlLabel
control={
<Checkbox
checked={getCheckboxState()}
onChange={handleCheckboxChange}
color="primary"
/>
}
label={<span style={{ fontSize: '1rem' }}>Do not show again</span>}
/>
)}
</ModalBody>
)}
<ModalFooter variant="filled" helpText={showInfoIcon}>
3 changes: 2 additions & 1 deletion src/custom/ResourceDetailFormatters/Formatter.tsx
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@ import {
StyledEnvironmentVariablesCode,
StyledEnvironmentVariablesPre,
StyledTitle,
TextValue,
Wrap
} from './styles';
import {
@@ -201,7 +202,7 @@ export const OperatorDynamicFormatter: React.FC<OperatorDynamicFormatterProps> =
return (
<>
<ElementData>
{data}
<TextValue>{data}</TextValue>
{regex.test(data) && <CopyToClipboard data={data} />}
</ElementData>
</>
13 changes: 10 additions & 3 deletions src/custom/ResourceDetailFormatters/styles.ts
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@ export const Title = styled('span')({
fontFamily: 'Qanelas Soft, sans-serif'
});

export const ElementData = styled('span')({
export const ElementData = styled('div')({
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
@@ -184,14 +184,21 @@ export const EnvironmentVariableValue = styled('span')({
export const CodeFormatterPre = styled('pre')(({ theme }) => ({
backgroundColor: theme.palette.mode === 'light' ? '#e9eff1' : '#212121',
color: theme.palette.text.primary,
width: '100%',
wordWrap: 'break-word',
overflowWrap: 'break-word',
wordBreak: 'break-all',
margin: 0,
padding: '0.5rem'
padding: '0.5rem',
maxWidth: '-moz-available'
}));

export const TextValue = styled(Box)({
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
width: 'inherit',
overflow: 'hidden'
});

export const CodeFormatterCode = styled('code')(({ theme }) => ({
backgroundColor: theme.palette.mode === 'light' ? '#e9eff1' : '#212121',
color: theme.palette.text.primary,
1 change: 1 addition & 0 deletions src/custom/ResourceDetailFormatters/types.ts
Original file line number Diff line number Diff line change
@@ -264,4 +264,5 @@ export interface GetResourceCleanDataProps {
dispatchMsgToEditor?: (msg: any) => void;
activeLabels?: string[];
showStatus?: boolean;
container?: any;
}
4 changes: 3 additions & 1 deletion src/custom/ResourceDetailFormatters/useResourceCleanData.ts
Original file line number Diff line number Diff line change
@@ -67,13 +67,15 @@ export const useResourceCleanData = () => {
resource,
activeLabels,
dispatchMsgToEditor,
showStatus = true
showStatus = true,
container
}: GetResourceCleanDataProps) => {
const parsedStatus = resource?.status?.attribute && JSON.parse(resource?.status?.attribute);
const parsedSpec = resource?.spec?.attribute && JSON.parse(resource?.spec.attribute);
const numberStates = structureNumberStates(parsedStatus, parsedSpec);
const kind = resource?.kind ?? resource?.component?.kind;
const cleanData = {
container: container,
age: getAge(resource?.metadata?.creationTimestamp),
kind: kind,
status: showStatus && getStatus(parsedStatus),
2 changes: 1 addition & 1 deletion src/custom/TransferModal/TransferList/TransferList.tsx
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ export function getFallbackImageBasedOnKind(kind: string | undefined): JSX.Eleme
}

export interface TransferListProps {
name: string;
name?: string;
assignableData: ListItemType[];
assignedData: (data: ListItemType[]) => void;
originalAssignedData: ListItemType[];
30 changes: 16 additions & 14 deletions src/custom/UserSearchField/UserSearchField.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Autocomplete from '@mui/material/Autocomplete';
import CircularProgress from '@mui/material/CircularProgress';
import { debounce } from 'lodash';
import React, { useState } from 'react';
import { Avatar, Box, Chip, Grid, TextField, Tooltip, Typography } from '../../base';
import { iconSmall } from '../../constants/iconsSizes';
@@ -88,21 +89,22 @@ const UserShareSearch: React.FC<UserSearchFieldProps> = ({
}
};

const handleInputChange = (_event: React.SyntheticEvent<Element, Event>, value: string) => {
if (value === '') {
setOptions([]);
setOpen(false);
} else {
setSearchUserLoading(true);
fetchSuggestions(value).then((filteredData) => {
setOptions(filteredData);
const handleInputChange = debounce(
async (_event: React.SyntheticEvent<Element, Event>, value: string) => {
if (value === '') {
setOptions([]);
setOpen(false);
} else {
setSearchUserLoading(true);
const suggestions = await fetchSuggestions(value);
setOptions(suggestions);
setSearchUserLoading(false);
});
setError(false);
setOpen(true);
}
};

setError(false);
setOpen(true);
}
},
300
);
/**
* Clone customUsersList component to pass necessary props
*/
57 changes: 56 additions & 1 deletion src/custom/Workspaces/AssignmentModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Divider } from '../../base';
import { Modal, ModalBody, ModalButtonPrimary, ModalButtonSecondary, ModalFooter } from '../Modal';
import { TransferList } from '../TransferModal/TransferList';
import { ModalActionDiv } from './styles';
@@ -22,6 +23,21 @@ interface AssignmentModalProps {
isAssignAllowed: boolean;
isRemoveAllowed: boolean;
helpText: string;
showViews?: boolean;
nameViews?: string;
assignableViewsData?: any[];
handleAssignedViewsData?: (data: any) => void;
originalAssignedViewsData?: any[];

emptyStateViewsIcon?: JSX.Element;
handleAssignableViewsPage?: () => void;
handleAssignedViewsPage?: () => void;
originalLeftViewsCount?: number;
originalRightViewsCount?: number;
onAssignViews?: () => void;
disableTransferViews?: boolean;
isAssignAllowedViews?: boolean;
isRemoveAllowedViews?: boolean;
}

const AssignmentModal: React.FC<AssignmentModalProps> = ({
@@ -42,7 +58,19 @@ const AssignmentModal: React.FC<AssignmentModalProps> = ({
disableTransfer,
isAssignAllowed,
isRemoveAllowed,
helpText
helpText,
showViews,
nameViews,
assignableViewsData,
handleAssignedViewsData,
originalAssignedViewsData,
emptyStateViewsIcon,
handleAssignableViewsPage,
handleAssignedViewsPage,
originalLeftViewsCount,
originalRightViewsCount,
isAssignAllowedViews = false,
isRemoveAllowedViews = false
}) => {
return (
<Modal
@@ -71,6 +99,33 @@ const AssignmentModal: React.FC<AssignmentModalProps> = ({
rightPermission={isRemoveAllowed}
transferComponentType={''}
/>
<Divider
style={{
margin: 'auto',
width: '80%',
marginTop: '22px',
marginBottom: '22px'
}}
/>
{showViews && (
<TransferList
name={nameViews}
assignableData={assignableViewsData || []}
assignedData={handleAssignedViewsData || (() => {})}
originalAssignedData={originalAssignedViewsData || []}
emptyStateIconLeft={emptyStateViewsIcon || <></>}
emtyStateMessageLeft={`No views available`}
emptyStateIconRight={emptyStateViewsIcon || <></>}
emtyStateMessageRight={`No views assigned`}
assignablePage={handleAssignableViewsPage || (() => {})}
assignedPage={handleAssignedViewsPage || (() => {})}
originalLeftCount={originalLeftViewsCount ?? 0}
originalRightCount={originalRightViewsCount ?? 0}
leftPermission={isAssignAllowedViews}
rightPermission={isRemoveAllowedViews}
transferComponentType={''}
/>
)}
</ModalBody>
<ModalFooter variant="filled" helpText={helpText}>
<ModalActionDiv>
1 change: 1 addition & 0 deletions src/custom/Workspaces/DesignTable.tsx
Original file line number Diff line number Diff line change
@@ -264,6 +264,7 @@ const DesignTable: React.FC<DesignTableProps> = ({
helpText={`Assign Designs to ${workspaceName}`}
isAssignAllowed={isAssignAllowed}
isRemoveAllowed={isRemoveAllowed}
showViews={false}
/>
<GenericRJSFModal
open={publishModal.open}
312 changes: 312 additions & 0 deletions src/custom/Workspaces/WorkspaceViewsTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { MUIDataTableColumn, MUIDataTableMeta } from 'mui-datatables';
import React, { useState } from 'react';
import { Accordion, AccordionDetails, AccordionSummary, Typography } from '../../base';
import { DeleteIcon, EnvironmentIcon } from '../../icons';
import { CHARCOAL, SistentThemeProvider } from '../../theme';
import { NameDiv } from '../CatalogDesignTable/style';
import { RESOURCE_TYPES } from '../CatalogDetail/types';
import { CustomColumnVisibilityControl } from '../CustomColumnVisibilityControl';
import { CustomTooltip } from '../CustomTooltip';
import { ConditionalTooltip } from '../Helpers/CondtionalTooltip';
import { useWindowDimensions } from '../Helpers/Dimension';
import {
ColView,
updateVisibleColumns
} from '../Helpers/ResponsiveColumns/responsive-coulmns.tsx/responsive-column';
import ResponsiveDataTable, { IconWrapper } from '../ResponsiveDataTable';
import SearchBar from '../SearchBar';
import { TooltipIcon } from '../TooltipIconButton';
import AssignmentModal from './AssignmentModal';
import EditButton from './EditButton';
import useViewAssignment from './hooks/useViewsAssignment';
import { CellStyle, CustomBodyRenderStyle, TableHeader, TableRightActionHeader } from './styles';

interface ViewsTableProps {
workspaceId: string;
workspaceName: string;
useGetViewsOfWorkspaceQuery: any;
useUnassignViewFromWorkspaceMutation: any;
useAssignViewToWorkspaceMutation: any;
isRemoveAllowed: boolean;
isAssignAllowed: boolean;
handleShowDetails: (viewId: string, viewName: string, filterType: string) => void;
}

const colViews: ColView[] = [
['id', 'na'],
['name', 'xs'],
['description', 'm'],
['organization_id', 'l'],
['created_at', 'xl'],
['updated_at', 'xl'],
['visibility', 'l'],
['actions', 'xs']
];

export const ResizableDescriptionCell = ({ value }: { value: string }) => (
<div style={{ position: 'relative', height: '20px' }}>
<CustomBodyRenderStyle>
<CellStyle>
<CustomTooltip title={value} placement="top-start">
<span style={{ cursor: 'pointer' }}>{value}</span>
</CustomTooltip>
</CellStyle>
</CustomBodyRenderStyle>
</div>
);

const WorkspaceViewsTable: React.FC<ViewsTableProps> = ({
workspaceId,
workspaceName,
isRemoveAllowed,
useGetViewsOfWorkspaceQuery,
useUnassignViewFromWorkspaceMutation,
useAssignViewToWorkspaceMutation,
isAssignAllowed,
handleShowDetails
}) => {
const [expanded, setExpanded] = useState<boolean>(true);
const handleAccordionChange = () => {
setExpanded(!expanded);
};
const [search, setSearch] = useState('');
const [isSearchExpanded, setIsSearchExpanded] = useState(false);
const [page, setPage] = useState<number>(0);
const [pageSize, setPageSize] = useState<number>(10);
const [sortOrder, setSortOrder] = useState<string>('updated_at desc');
const { data: viewsOfWorkspace } = useGetViewsOfWorkspaceQuery({
workspaceId,
page: page,
pageSize: pageSize,
search: search,
order: sortOrder
});
const { width } = useWindowDimensions();
const [unassignviewFromWorkspace] = useUnassignViewFromWorkspaceMutation();
const columns: MUIDataTableColumn[] = [
{
name: 'id',
label: 'ID',
options: {
filter: false,
customBodyRender: (value) => <ConditionalTooltip value={value} maxLength={10} />
}
},
{
name: 'name',
label: 'Name',
options: {
filter: false,
sort: true,
searchable: true,
customBodyRender: (value, tableMeta) => {
const viewId = tableMeta.tableData[tableMeta.rowIndex]?.id ?? '';
const viewName = tableMeta.tableData[tableMeta.rowIndex]?.name ?? '';
return (
<NameDiv onClick={() => handleShowDetails(viewId, viewName, RESOURCE_TYPES.VIEW)}>
{value}
</NameDiv>
);
}
}
},
{
name: 'created_at',
label: 'Created At',
options: {
filter: false,
sort: true,
searchable: true,
setCellHeaderProps: () => {
return { align: 'center' };
}
}
},
{
name: 'updated_at',
label: 'Updated At',
options: {
filter: false,
sort: true,
searchable: true,
setCellHeaderProps: () => {
return { align: 'center' };
}
}
},
{
name: 'visibility',
label: 'Visibility',
options: {
filter: false,
sort: false,
searchable: true,
setCellHeaderProps: () => {
return { align: 'center' };
}
}
},
{
name: 'actions',
label: 'Actions',
options: {
filter: false,
sort: false,
searchable: false,
customBodyRender: (_: string, tableMeta: MUIDataTableMeta) => (
<IconWrapper disabled={!isRemoveAllowed}>
<TooltipIcon
id={`delete_team-${tableMeta.rowIndex}`}
title="Remove View"
onClick={() => {
isRemoveAllowed &&
unassignviewFromWorkspace({
workspaceId,
viewId: tableMeta.rowData[0]
});
}}
iconType="delete"
>
<DeleteIcon height={28} width={28} fill={CHARCOAL} />
</TooltipIcon>
</IconWrapper>
)
}
}
];

const viewAssignment = useViewAssignment({
workspaceId,
useGetViewsOfWorkspaceQuery,
useUnassignViewFromWorkspaceMutation,
useAssignViewToWorkspaceMutation
});

const [columnVisibility, setColumnVisibility] = useState<Record<string, boolean>>(() => {
const showCols = updateVisibleColumns(colViews, width);
const initialVisibility: Record<string, boolean> = {};
columns.forEach((col) => {
initialVisibility[col.name] = showCols[col.name];
});
return initialVisibility;
});

const options = {
filter: false,
responsive: 'standard',
selectableRows: 'none',
count: viewsOfWorkspace?.total_count,
rowsPerPage: pageSize,
page,
elevation: 0,
sortOrder: {
name: sortOrder.split(' ')[0],
direction: sortOrder.split(' ')[1]
},
onTableChange: (action: string, tableState: any) => {
const sortInfo = tableState.announceText ? tableState.announceText.split(' : ') : [];
let order = '';
if (tableState.activeColumn) {
order = `${columns[tableState.activeColumn].name} desc`;
}
switch (action) {
case 'changePage':
setPage(tableState.page);
break;
case 'changeRowsPerPage':
setPageSize(tableState.rowsPerPage);
break;
case 'sort':
if (sortInfo.length == 2) {
if (sortInfo[1] === 'ascending') {
order = `${columns[tableState.activeColumn].name} asc`;
} else {
order = `${columns[tableState.activeColumn].name} desc`;
}
}
if (order !== sortOrder) {
setSortOrder(order);
}
break;
}
}
};
const [tableCols, updateCols] = useState(columns);

return (
<SistentThemeProvider>
<Accordion expanded={expanded} onChange={handleAccordionChange} style={{ margin: 0 }}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
sx={{
backgroundColor: 'background.paper'
}}
>
<TableHeader>
<Typography variant="h6" fontWeight={'bold'}>
Assigned Views
</Typography>
<TableRightActionHeader>
<SearchBar
onSearch={(value) => {
setSearch(value);
}}
onClear={() => {
setSearch('');
}}
expanded={isSearchExpanded}
setExpanded={setIsSearchExpanded}
placeholder="Search workspaces..."
/>
<CustomColumnVisibilityControl
columns={columns}
customToolsProps={{
columnVisibility,
setColumnVisibility
}}
id={'views-table'}
/>
<EditButton onClick={viewAssignment.handleAssignModal} disabled={!isAssignAllowed} />
</TableRightActionHeader>
</TableHeader>
</AccordionSummary>
<AccordionDetails style={{ padding: 0 }}>
<ResponsiveDataTable
columns={columns}
data={viewsOfWorkspace?.views}
options={options}
colViews={colViews}
tableCols={tableCols}
updateCols={updateCols}
columnVisibility={columnVisibility}
/>
</AccordionDetails>
</Accordion>

<AssignmentModal
open={viewAssignment.assignModal}
onClose={viewAssignment.handleAssignModalClose}
title={`Assign Views to ${workspaceName}`}
headerIcon={<EnvironmentIcon height="40" width="40" fill={'white'} />}
name="Views"
assignableData={viewAssignment.data}
handleAssignedData={viewAssignment.handleAssignData}
originalAssignedData={viewAssignment.workspaceData}
emptyStateIcon={<EnvironmentIcon height="5rem" width="5rem" fill={'#808080'} />}
handleAssignablePage={viewAssignment.handleAssignablePage}
handleAssignedPage={viewAssignment.handleAssignedPage}
originalLeftCount={viewAssignment.data?.length || 0}
originalRightCount={viewsOfWorkspace?.total_count || 0}
onAssign={viewAssignment.handleAssign}
disableTransfer={viewAssignment.disableTransferButton}
helpText={`Assign Views to ${workspaceName}`}
isAssignAllowed={isAssignAllowed}
isRemoveAllowed={isRemoveAllowed}
/>
</SistentThemeProvider>
);
};

export default WorkspaceViewsTable;
6 changes: 6 additions & 0 deletions src/custom/Workspaces/hooks/useDesignAssignment.tsx
Original file line number Diff line number Diff line change
@@ -104,6 +104,11 @@ const useDesignAssignment = ({
return { addedDesignsIds, removedDesignsIds };
};

const isDesignsActivityOccurred = (allAssignedDesigns: Pattern[]): boolean => {
const { addedDesignsIds, removedDesignsIds } = getAddedAndRemovedDesigns(allAssignedDesigns);
return addedDesignsIds.length > 0 || removedDesignsIds.length > 0;
};

const handleAssignDesigns = async (): Promise<void> => {
const { addedDesignsIds, removedDesignsIds } = getAddedAndRemovedDesigns(assignedDesigns);

@@ -144,6 +149,7 @@ const useDesignAssignment = ({
handleAssignedPage: handleAssignedPageDesign,
handleAssign: handleAssignDesigns,
handleAssignData: handleAssignDesignsData,
isActivityOccurred: isDesignsActivityOccurred,
disableTransferButton,
assignedItems: assignedDesigns
};
158 changes: 158 additions & 0 deletions src/custom/Workspaces/hooks/useViewsAssignment.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useEffect, useState } from 'react';
import { Pattern } from '../../CustomCatalog/CustomCard';
import { withDefaultPageArgs } from '../../PerformersSection/PerformersSection';
import { AssignmentHookResult } from '../types';

interface AddedAndRemovedViews {
addedviewsIds: string[];
removedviewsIds: string[];
}

interface useViewAssignmentProps {
workspaceId: string;
useGetViewsOfWorkspaceQuery: any;
useAssignViewToWorkspaceMutation: any;
useUnassignViewFromWorkspaceMutation: any;
}

const useViewAssignment = ({
workspaceId,
useGetViewsOfWorkspaceQuery,
useAssignViewToWorkspaceMutation,
useUnassignViewFromWorkspaceMutation
}: useViewAssignmentProps): AssignmentHookResult<Pattern> => {
const [viewsPage, setviewsPage] = useState<number>(0);
const [viewsData, setviewsData] = useState<Pattern[]>([]);
const viewsPageSize = 25;
const [viewsOfWorkspacePage, setviewsOfWorkspacePage] = useState<number>(0);
const [workspaceviewsData, setWorkspaceviewsData] = useState<Pattern[]>([]);
const [assignviewModal, setAssignviewModal] = useState<boolean>(false);
const [skipviews, setSkipviews] = useState<boolean>(true);
const [disableTransferButton, setDisableTransferButton] = useState<boolean>(true);
const [assignedviews, setAssignedviews] = useState<Pattern[]>([]);

const { data: views } = useGetViewsOfWorkspaceQuery(
withDefaultPageArgs({
workspaceId,
page: viewsPage,
pagesize: viewsPageSize,
filter: '{"assigned":false}'
}),
{
skip: skipviews
}
);

const { data: viewsOfWorkspace } = useGetViewsOfWorkspaceQuery(
withDefaultPageArgs({
workspaceId,
page: viewsOfWorkspacePage,
pagesize: viewsPageSize
}),
{
skip: skipviews
}
);

const [assignviewToWorkspace] = useAssignViewToWorkspaceMutation();
const [unassignviewFromWorkspace] = useUnassignViewFromWorkspaceMutation();

useEffect(() => {
const viewsDataRtk = views?.views ? views.views : [];
setviewsData((prevData) => [...prevData, ...viewsDataRtk]);
}, [views]);

useEffect(() => {
const viewsOfWorkspaceDataRtk = viewsOfWorkspace?.views ? viewsOfWorkspace.views : [];
setWorkspaceviewsData((prevData) => [...prevData, ...viewsOfWorkspaceDataRtk]);
}, [viewsOfWorkspace]);

const handleAssignviewModal = (e?: React.MouseEvent): void => {
e?.stopPropagation();
setAssignviewModal(true);
setSkipviews(false);
};

const handleAssignviewModalClose = (e?: React.MouseEvent): void => {
e?.stopPropagation();
setAssignviewModal(false);
setSkipviews(true);
};

const handleAssignablePageview = (): void => {
const pagesCount = Math.ceil(Number(views?.total_count) / viewsPageSize);
if (viewsPage < pagesCount - 1) {
setviewsPage((prevviewsPage) => prevviewsPage + 1);
}
};

const handleAssignedPageview = (): void => {
const pagesCount = Math.ceil(Number(viewsOfWorkspace?.total_count) / viewsPageSize);
if (viewsOfWorkspacePage < pagesCount - 1) {
setviewsOfWorkspacePage((prevPage) => prevPage + 1);
}
};

const getAddedAndRemovedviews = (allAssignedviews: Pattern[]): AddedAndRemovedViews => {
const originalviewsIds = workspaceviewsData.map((view) => view.id);
const updatedviewsIds = allAssignedviews.map((view) => view.id);

const addedviewsIds = updatedviewsIds.filter((id) => !originalviewsIds.includes(id));
const removedviewsIds = originalviewsIds.filter((id) => !updatedviewsIds.includes(id));

return { addedviewsIds, removedviewsIds };
};

const isViewsActivityOccurred = (allViews: Pattern[]): boolean => {
const { addedviewsIds, removedviewsIds } = getAddedAndRemovedviews(allViews);
return addedviewsIds.length > 0 || removedviewsIds.length > 0;
};

const handleAssignviews = async (): Promise<void> => {
const { addedviewsIds, removedviewsIds } = getAddedAndRemovedviews(assignedviews);

addedviewsIds.map((id) =>
assignviewToWorkspace({
workspaceId,
viewId: id
}).unwrap()
);

removedviewsIds.map((id) =>
unassignviewFromWorkspace({
workspaceId,
viewId: id
}).unwrap()
);

setviewsData([]);
setWorkspaceviewsData([]);
setviewsPage(0);
setviewsOfWorkspacePage(0);
handleAssignviewModalClose();
};

const handleAssignviewsData = (updatedAssignedData: Pattern[]): void => {
const { addedviewsIds, removedviewsIds } = getAddedAndRemovedviews(updatedAssignedData);
setDisableTransferButton(!(addedviewsIds.length > 0 || removedviewsIds.length > 0));
setAssignedviews(updatedAssignedData);
};

return {
data: viewsData,
workspaceData: workspaceviewsData,
assignModal: assignviewModal,
handleAssignModal: handleAssignviewModal,
handleAssignModalClose: handleAssignviewModalClose,
handleAssignablePage: handleAssignablePageview,
handleAssignedPage: handleAssignedPageview,
handleAssign: handleAssignviews,
isActivityOccurred: isViewsActivityOccurred,
handleAssignData: handleAssignviewsData,
disableTransferButton,
assignedItems: assignedviews
};
};

export default useViewAssignment;
6 changes: 5 additions & 1 deletion src/custom/Workspaces/index.ts
Original file line number Diff line number Diff line change
@@ -2,16 +2,20 @@ import AssignmentModal from './AssignmentModal';
import DesignTable from './DesignTable';
import EnvironmentTable from './EnvironmentTable';
import WorkspaceTeamsTable from './WorkspaceTeamsTable';
import WorkspaceViewsTable from './WorkspaceViewsTable';
import useDesignAssignment from './hooks/useDesignAssignment';
import useEnvironmentAssignment from './hooks/useEnvironmentAssignment';
import useTeamAssignment from './hooks/useTeamAssignment';
import useViewAssignment from './hooks/useViewsAssignment';

export {
AssignmentModal,
DesignTable,
EnvironmentTable,
WorkspaceTeamsTable,
WorkspaceViewsTable,
useDesignAssignment,
useEnvironmentAssignment,
useTeamAssignment
useTeamAssignment,
useViewAssignment
};
1 change: 1 addition & 0 deletions src/custom/Workspaces/types.ts
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ export interface AssignmentHookResult<T> {
handleAssignedPage: () => void;
handleAssign: () => void;
handleAssignData: (data: T[]) => void;
isActivityOccurred?: (allItems: T[]) => boolean;
disableTransferButton: boolean;
assignedItems: T[];
}
3 changes: 2 additions & 1 deletion src/custom/index.tsx
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ import { LearningCard } from './LearningCard';
import { BasicMarkdown, RenderMarkdown } from './Markdown';
import { ModalCard } from './ModalCard';
import PopperListener, { IPopperListener } from './PopperListener';
import PromptComponent from './Prompt';
import { PROMPT_VARIANTS, PromptComponent } from './Prompt';
import ResponsiveDataTable, {
DataTableEllipsisMenu,
ResponsiveDataTableProps
@@ -91,6 +91,7 @@ export {
InfoTooltip,
LearningCard,
ModalCard,
PROMPT_VARIANTS,
PopperListener,
PromptComponent,
ResponsiveDataTable,
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -6,3 +6,4 @@ export * from './icons';
export * from './redux-persist';
export * from './schemas';
export * from './theme';
export * from './utils';
5 changes: 5 additions & 0 deletions src/theme/colors/colors.ts
Original file line number Diff line number Diff line change
@@ -102,6 +102,11 @@ export const charcoal = {
10: '#000D12'
};

export const gray = {
10: '#1A1A1A',
20: '#212121'
};

export const accentGrey = {
100: '#F6F8F8',
90: '#E8EFF3',
1 change: 1 addition & 0 deletions src/theme/colors/index.ts
Original file line number Diff line number Diff line change
@@ -57,6 +57,7 @@ export {
darkSlateGray,
darkTeal,
eerieBlack,
gray,
green,
jungleGreen,
keppel,
4 changes: 2 additions & 2 deletions src/theme/components/button.modifier.ts
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ export const MuiButton: Components<Theme>['MuiButton'] = {
root: ({ theme }) => {
const {
palette: {
background: { brand, neutral: BgNeutral },
background: { brand, hover },
text: { disabled, constant, neutral: TextNeutral },
border: { neutral }
},
@@ -24,7 +24,7 @@ export const MuiButton: Components<Theme>['MuiButton'] = {
'&.MuiButton-outlined': {
border: `1px solid ${neutral?.default}`,
'&:hover': {
backgroundColor: BgNeutral?.pressed,
backgroundColor: hover,
color: TextNeutral?.default
}
},
2 changes: 1 addition & 1 deletion src/theme/components/tab.modifier.ts
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ export const MuiTab: Components<Theme>['MuiTab'] = {
const {
palette: {
text: { default: defaultText },
background: { default: defaultBackground }
background: { tabs: defaultBackground }
}
} = theme;
return {
2 changes: 1 addition & 1 deletion src/theme/components/tabs.modifier.ts
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import { Components, Theme } from '@mui/material';
export const MuiTabs: Components<Theme>['MuiTabs'] = {
styleOverrides: {
root: ({ theme }) => ({
backgroundColor: theme.palette.background.default
backgroundColor: theme.palette.background.tabs
}),
indicator: ({ theme }) => ({
backgroundColor: theme.palette.background.brand?.default
14 changes: 9 additions & 5 deletions src/theme/palette.ts
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ declare module '@mui/material/styles' {
default: string;
};
tabs?: string;
card?: string;
tertiary?: string;
hover?: string;
blur?: {
@@ -195,7 +196,8 @@ export const lightModePalette: PaletteOptions = {
default: Colors.charcoal[100],
secondary: Colors.accentGrey[90],
tertiary: Colors.accentGrey[80],
tabs: Colors.charcoal[70],
tabs: Colors.accentGrey[100], // TODO: Make this name or token to more genric
card: Colors.charcoal[100],
hover: Colors.charcoal[90],
supplementary: Colors.accentGrey[40],
blur: {
@@ -255,6 +257,7 @@ export const lightModePalette: PaletteOptions = {
tertiary: Colors.red[70]
},
code: Colors.charcoal[90],

constant: {
white: Colors.accentGrey[100],
disabled: Colors.charcoal[70],
@@ -311,7 +314,8 @@ export const darkModePalette: PaletteOptions = {
default: Colors.charcoal[10],
secondary: Colors.accentGrey[20],
tertiary: Colors.accentGrey[30],
tabs: Colors.charcoal[110],
tabs: Colors.gray[10], // TODO: Make this name or token to more genric
card: Colors.gray[20],
hover: Colors.charcoal[20],
supplementary: Colors.accentGrey[40],
blur: {
@@ -326,7 +330,7 @@ export const darkModePalette: PaletteOptions = {
brand: {
default: Colors.keppel[40],
hover: Colors.keppel[50],
disabled: Colors.charcoal[20],
disabled: Colors.charcoal[30],
pressed: Colors.keppel[60],
secondary: Colors.keppel[20],
tertiary: Colors.keppel[10]
@@ -349,7 +353,7 @@ export const darkModePalette: PaletteOptions = {
tertiary: Colors.blue[10]
},
success: {
default: Colors.green[40],
default: Colors.KEPPEL,
hover: Colors.green[50],
pressed: Colors.green[60],
secondary: Colors.green[20],
@@ -369,7 +373,7 @@ export const darkModePalette: PaletteOptions = {
secondary: Colors.red[20],
tertiary: Colors.red[10]
},
code: Colors.accentGrey[90],
code: Colors.charcoal[10],
constant: {
white: Colors.accentGrey[100],
disabled: Colors.charcoal[70],
14 changes: 14 additions & 0 deletions src/utils/components.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const componentIcon = ({
kind,
model,
color
}: {
kind: string;
model: string;
color: 'white' | 'color' | 'complete';
}) => {
if (!kind || !model || !color) {
return null;
}
return `/ui/public/static/img/meshmodels/${model}/${color}/${kind.toLowerCase()}-${color}.svg`;
};
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components';

0 comments on commit df32123

Please sign in to comment.