New view picker (#4610)
* Implement new view picker * Complete feature * Fixes according to review
This commit is contained in:
@ -0,0 +1,81 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
import { useViewPickerPersistView } from '@/views/view-picker/hooks/useViewPickerPersistView';
|
||||
import { useViewPickerStates } from '@/views/view-picker/hooks/useViewPickerStates';
|
||||
|
||||
export const ViewPickerCreateOrEditButton = () => {
|
||||
const { availableFieldsForKanban, navigateToSelectSettings } =
|
||||
useGetAvailableFieldsForKanban();
|
||||
|
||||
const {
|
||||
viewPickerIsPersistingState,
|
||||
viewPickerKanbanFieldMetadataIdState,
|
||||
viewPickerTypeState,
|
||||
} = useViewPickerStates();
|
||||
|
||||
const { viewPickerMode } = useViewPickerMode();
|
||||
const viewPickerType = useRecoilValue(viewPickerTypeState);
|
||||
const viewPickerIsPersisting = useRecoilValue(viewPickerIsPersistingState);
|
||||
const viewPickerKanbanFieldMetadataId = useRecoilValue(
|
||||
viewPickerKanbanFieldMetadataIdState,
|
||||
);
|
||||
|
||||
const { handleCreate, handleDelete } = useViewPickerPersistView();
|
||||
|
||||
if (viewPickerMode === 'edit') {
|
||||
return (
|
||||
<Button
|
||||
title="Delete"
|
||||
onClick={handleDelete}
|
||||
accent="danger"
|
||||
fullWidth
|
||||
size="small"
|
||||
justify="center"
|
||||
focus={false}
|
||||
variant="secondary"
|
||||
disabled={viewPickerIsPersisting}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
viewPickerType === ViewType.Kanban &&
|
||||
availableFieldsForKanban.length === 0
|
||||
) {
|
||||
return (
|
||||
<Button
|
||||
title="Go to Settings"
|
||||
onClick={navigateToSelectSettings}
|
||||
size="small"
|
||||
accent="blue"
|
||||
fullWidth
|
||||
justify="center"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
viewPickerType === ViewType.Table ||
|
||||
viewPickerKanbanFieldMetadataId !== ''
|
||||
) {
|
||||
return (
|
||||
<Button
|
||||
title="Create"
|
||||
onClick={handleCreate}
|
||||
accent="blue"
|
||||
fullWidth
|
||||
size="small"
|
||||
justify="center"
|
||||
disabled={
|
||||
viewPickerIsPersisting ||
|
||||
(viewPickerType === ViewType.Kanban &&
|
||||
viewPickerKanbanFieldMetadataId === '')
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,180 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { IconChevronLeft, IconX } from '@/ui/display/icon';
|
||||
import { IconPicker } from '@/ui/input/components/IconPicker';
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
||||
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
import { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { ViewPickerCreateOrEditButton } from '@/views/view-picker/components/ViewPickerCreateOrEditButton';
|
||||
import { VIEW_PICKER_KANBAN_FIELD_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerKanbanFieldDropdownId';
|
||||
import { VIEW_PICKER_VIEW_TYPE_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerViewTypeDropdownId';
|
||||
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
import { useViewPickerPersistView } from '@/views/view-picker/hooks/useViewPickerPersistView';
|
||||
import { useViewPickerStates } from '@/views/view-picker/hooks/useViewPickerStates';
|
||||
|
||||
const StyledIconAndNameContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
margin-left: ${({ theme }) => theme.spacing(1)};
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledSelectContainer = styled.div`
|
||||
display: flex;
|
||||
width: calc(100% - ${({ theme }) => theme.spacing(2)});
|
||||
margin: ${({ theme }) => theme.spacing(1)};
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
user-select: none;
|
||||
`;
|
||||
|
||||
const StyledNoKanbanFieldAvailableContainer = styled.div`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
display: flex;
|
||||
margin: ${({ theme }) => theme.spacing(1, 2)};
|
||||
user-select: none;
|
||||
width: calc(100% - ${({ theme }) => theme.spacing(4)});
|
||||
`;
|
||||
|
||||
const StyledSaveButtonContainer = styled.div`
|
||||
display: flex;
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
width: calc(100% - ${({ theme }) => theme.spacing(2)});
|
||||
`;
|
||||
export const ViewPickerCreateOrEditContent = () => {
|
||||
const { viewPickerMode, setViewPickerMode } = useViewPickerMode();
|
||||
const {
|
||||
viewPickerInputNameState,
|
||||
viewPickerSelectedIconState,
|
||||
viewPickerIsPersistingState,
|
||||
viewPickerKanbanFieldMetadataIdState,
|
||||
viewPickerTypeState,
|
||||
} = useViewPickerStates();
|
||||
|
||||
const [viewPickerInputName, setViewPickerInputName] = useRecoilState(
|
||||
viewPickerInputNameState,
|
||||
);
|
||||
const [viewPickerSelectedIcon, setViewPickerSelectedIcon] = useRecoilState(
|
||||
viewPickerSelectedIconState,
|
||||
);
|
||||
const viewPickerIsPersisting = useRecoilValue(viewPickerIsPersistingState);
|
||||
|
||||
const [viewPickerKanbanFieldMetadataId, setViewPickerKanbanFieldMetadataId] =
|
||||
useRecoilState(viewPickerKanbanFieldMetadataIdState);
|
||||
|
||||
const [viewPickerType, setViewPickerType] =
|
||||
useRecoilState(viewPickerTypeState);
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
const { handleCreate, handleUpdate } = useViewPickerPersistView();
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Enter,
|
||||
async () => {
|
||||
if (viewPickerMode === 'create') {
|
||||
if (viewPickerIsPersisting) {
|
||||
return;
|
||||
}
|
||||
await handleCreate();
|
||||
}
|
||||
if (viewPickerMode === 'edit') {
|
||||
if (viewPickerIsPersisting) {
|
||||
return;
|
||||
}
|
||||
await handleUpdate();
|
||||
}
|
||||
},
|
||||
ViewsHotkeyScope.ListDropdown,
|
||||
);
|
||||
|
||||
const onIconChange = ({ iconKey }: { iconKey: string }) => {
|
||||
setViewPickerSelectedIcon(iconKey);
|
||||
};
|
||||
|
||||
const { availableFieldsForKanban } = useGetAvailableFieldsForKanban();
|
||||
|
||||
return (
|
||||
<>
|
||||
<DropdownMenuHeader
|
||||
StartIcon={viewPickerMode === 'create' ? IconX : IconChevronLeft}
|
||||
onClick={() => setViewPickerMode('list')}
|
||||
>
|
||||
{viewPickerMode === 'create' ? 'Create view' : 'Edit view'}
|
||||
</DropdownMenuHeader>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer>
|
||||
<StyledIconAndNameContainer>
|
||||
<IconPicker
|
||||
onChange={onIconChange}
|
||||
selectedIconKey={viewPickerSelectedIcon}
|
||||
disableBlur
|
||||
onClose={() => setHotkeyScope(ViewsHotkeyScope.ListDropdown)}
|
||||
/>
|
||||
<DropdownMenuInput
|
||||
value={viewPickerInputName}
|
||||
onChange={(event) => setViewPickerInputName(event.target.value)}
|
||||
autoFocus
|
||||
/>
|
||||
</StyledIconAndNameContainer>
|
||||
{viewPickerMode === 'create' && (
|
||||
<StyledSelectContainer>
|
||||
<Select
|
||||
disableBlur
|
||||
label="View type"
|
||||
fullWidth
|
||||
value={viewPickerType}
|
||||
onChange={(value) => setViewPickerType(value)}
|
||||
options={[
|
||||
{ value: ViewType.Table, label: 'Table' },
|
||||
{ value: ViewType.Kanban, label: 'Kanban' },
|
||||
]}
|
||||
dropdownId={VIEW_PICKER_VIEW_TYPE_DROPDOWN_ID}
|
||||
/>
|
||||
</StyledSelectContainer>
|
||||
)}
|
||||
{viewPickerType === ViewType.Kanban && viewPickerMode === 'create' && (
|
||||
<>
|
||||
<StyledSelectContainer>
|
||||
<Select
|
||||
disableBlur
|
||||
label="Stages"
|
||||
fullWidth
|
||||
value={viewPickerKanbanFieldMetadataId}
|
||||
onChange={(value) => setViewPickerKanbanFieldMetadataId(value)}
|
||||
options={
|
||||
availableFieldsForKanban.length > 0
|
||||
? availableFieldsForKanban.map((field) => ({
|
||||
value: field.id,
|
||||
label: field.label,
|
||||
}))
|
||||
: [{ value: '', label: 'No Select field' }]
|
||||
}
|
||||
dropdownId={VIEW_PICKER_KANBAN_FIELD_DROPDOWN_ID}
|
||||
/>
|
||||
</StyledSelectContainer>
|
||||
{availableFieldsForKanban.length === 0 && (
|
||||
<StyledNoKanbanFieldAvailableContainer>
|
||||
Set up a Select field on Companies to create a Kanban
|
||||
</StyledNoKanbanFieldAvailableContainer>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuItemsContainer>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer>
|
||||
<StyledSaveButtonContainer>
|
||||
<ViewPickerCreateOrEditButton />
|
||||
</StyledSaveButtonContainer>
|
||||
</DropdownMenuItemsContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,65 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
||||
import { useViewPickerStates } from '@/views/view-picker/hooks/useViewPickerStates';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const ViewPickerCreateOrEditContentEffect = () => {
|
||||
const {
|
||||
viewPickerSelectedIconState,
|
||||
viewPickerInputNameState,
|
||||
viewPickerReferenceViewIdState,
|
||||
viewPickerIsPersistingState,
|
||||
viewPickerKanbanFieldMetadataIdState,
|
||||
viewPickerTypeState,
|
||||
} = useViewPickerStates();
|
||||
|
||||
const setViewPickerSelectedIcon = useSetRecoilState(
|
||||
viewPickerSelectedIconState,
|
||||
);
|
||||
const setViewPickerInputName = useSetRecoilState(viewPickerInputNameState);
|
||||
|
||||
const setViewPickerKanbanFieldMetadataId = useSetRecoilState(
|
||||
viewPickerKanbanFieldMetadataIdState,
|
||||
);
|
||||
const setViewPickerType = useSetRecoilState(viewPickerTypeState);
|
||||
|
||||
const viewPickerReferenceViewId = useRecoilValue(
|
||||
viewPickerReferenceViewIdState,
|
||||
);
|
||||
|
||||
const viewPickerIsPersisting = useRecoilValue(viewPickerIsPersistingState);
|
||||
|
||||
const { viewsOnCurrentObject } = useGetCurrentView();
|
||||
const referenceView = viewsOnCurrentObject.find(
|
||||
(view) => view.id === viewPickerReferenceViewId,
|
||||
);
|
||||
|
||||
const { availableFieldsForKanban } = useGetAvailableFieldsForKanban();
|
||||
|
||||
useEffect(() => {
|
||||
if (isDefined(referenceView) && !viewPickerIsPersisting) {
|
||||
setViewPickerSelectedIcon(referenceView.icon);
|
||||
setViewPickerInputName(referenceView.name);
|
||||
setViewPickerKanbanFieldMetadataId(referenceView.kanbanFieldMetadataId);
|
||||
setViewPickerType(referenceView.type);
|
||||
}
|
||||
}, [
|
||||
referenceView,
|
||||
setViewPickerInputName,
|
||||
setViewPickerKanbanFieldMetadataId,
|
||||
setViewPickerSelectedIcon,
|
||||
setViewPickerType,
|
||||
viewPickerIsPersisting,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (availableFieldsForKanban.length > 0) {
|
||||
setViewPickerKanbanFieldMetadataId(availableFieldsForKanban[0].id);
|
||||
}
|
||||
}, [availableFieldsForKanban, setViewPickerKanbanFieldMetadataId]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
@ -0,0 +1,100 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { IconChevronDown, IconList } from '@/ui/display/icon';
|
||||
import { useIcons } from '@/ui/display/icon/hooks/useIcons';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { MOBILE_VIEWPORT } from '@/ui/theme/constants/MobileViewport';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
||||
import { ViewPickerCreateOrEditContent } from '@/views/view-picker/components/ViewPickerCreateOrEditContent';
|
||||
import { ViewPickerCreateOrEditContentEffect } from '@/views/view-picker/components/ViewPickerCreateOrEditContentEffect';
|
||||
import { ViewPickerListContent } from '@/views/view-picker/components/ViewPickerListContent';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
|
||||
import { useViewStates } from '../../hooks/internal/useViewStates';
|
||||
|
||||
const StyledDropdownLabelAdornments = styled.span`
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.grayScale.gray35};
|
||||
display: inline-flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
margin-left: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledViewName = styled.span`
|
||||
margin-left: ${({ theme }) => theme.spacing(1)};
|
||||
display: inline-block;
|
||||
max-width: 130px;
|
||||
@media (max-width: 375px) {
|
||||
max-width: 90px;
|
||||
}
|
||||
@media (min-width: 376px) and (max-width: ${MOBILE_VIEWPORT}px) {
|
||||
max-width: 110px;
|
||||
}
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
export const ViewPickerDropdown = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
const { entityCountInCurrentViewState } = useViewStates();
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||
|
||||
const entityCountInCurrentView = useRecoilValue(
|
||||
entityCountInCurrentViewState,
|
||||
);
|
||||
|
||||
const { isDropdownOpen: isViewsListDropdownOpen } = useDropdown(
|
||||
VIEW_PICKER_DROPDOWN_ID,
|
||||
);
|
||||
|
||||
const { viewPickerMode, setViewPickerMode } = useViewPickerMode();
|
||||
|
||||
const { getIcon } = useIcons();
|
||||
const CurrentViewIcon = getIcon(currentViewWithCombinedFiltersAndSorts?.icon);
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={VIEW_PICKER_DROPDOWN_ID}
|
||||
dropdownHotkeyScope={{ scope: ViewsHotkeyScope.ListDropdown }}
|
||||
dropdownOffset={{ x: 0, y: 8 }}
|
||||
dropdownMenuWidth={200}
|
||||
onClickOutside={() => setViewPickerMode('list')}
|
||||
clickableComponent={
|
||||
<StyledDropdownButtonContainer isUnfolded={isViewsListDropdownOpen}>
|
||||
{currentViewWithCombinedFiltersAndSorts && CurrentViewIcon ? (
|
||||
<CurrentViewIcon size={theme.icon.size.md} />
|
||||
) : (
|
||||
<IconList size={theme.icon.size.md} />
|
||||
)}
|
||||
<StyledViewName>
|
||||
{currentViewWithCombinedFiltersAndSorts?.name ?? 'All'}
|
||||
</StyledViewName>
|
||||
<StyledDropdownLabelAdornments>
|
||||
· {entityCountInCurrentView}{' '}
|
||||
<IconChevronDown size={theme.icon.size.sm} />
|
||||
</StyledDropdownLabelAdornments>
|
||||
</StyledDropdownButtonContainer>
|
||||
}
|
||||
dropdownComponents={
|
||||
viewPickerMode === 'list' ? (
|
||||
<ViewPickerListContent />
|
||||
) : (
|
||||
<>
|
||||
<ViewPickerCreateOrEditContent />
|
||||
<ViewPickerCreateOrEditContentEffect />
|
||||
</>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,93 @@
|
||||
import { MouseEvent } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { IconLock, IconPencil, IconPlus } from '@/ui/display/icon';
|
||||
import { useIcons } from '@/ui/display/icon/hooks/useIcons';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useHandleViews } from '@/views/hooks/useHandleViews';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
import { useViewPickerStates } from '@/views/view-picker/hooks/useViewPickerStates';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
|
||||
font-weight: ${({ theme }) => theme.font.weight.regular};
|
||||
`;
|
||||
|
||||
export const ViewPickerListContent = () => {
|
||||
const { selectView } = useHandleViews();
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts, viewsOnCurrentObject } =
|
||||
useGetCurrentView();
|
||||
|
||||
const { viewPickerReferenceViewIdState } = useViewPickerStates();
|
||||
const setViewPickerReferenceViewId = useSetRecoilState(
|
||||
viewPickerReferenceViewIdState,
|
||||
);
|
||||
|
||||
const { setViewPickerMode } = useViewPickerMode();
|
||||
|
||||
const { closeDropdown } = useDropdown(VIEW_PICKER_DROPDOWN_ID);
|
||||
|
||||
const handleViewSelect = (viewId: string) => {
|
||||
selectView(viewId);
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
const handleAddViewButtonClick = () => {
|
||||
if (isDefined(currentViewWithCombinedFiltersAndSorts?.id)) {
|
||||
setViewPickerReferenceViewId(currentViewWithCombinedFiltersAndSorts.id);
|
||||
setViewPickerMode('create');
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditViewButtonClick = (
|
||||
event: MouseEvent<HTMLButtonElement>,
|
||||
viewId: string,
|
||||
) => {
|
||||
event.stopPropagation();
|
||||
setViewPickerReferenceViewId(viewId);
|
||||
setViewPickerMode('edit');
|
||||
};
|
||||
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
return (
|
||||
<>
|
||||
<DropdownMenuItemsContainer>
|
||||
{viewsOnCurrentObject.map((view) => (
|
||||
<MenuItem
|
||||
key={view.id}
|
||||
iconButtons={[
|
||||
view.key !== 'INDEX'
|
||||
? {
|
||||
Icon: IconPencil,
|
||||
onClick: (event: MouseEvent<HTMLButtonElement>) =>
|
||||
handleEditViewButtonClick(event, view.id),
|
||||
}
|
||||
: {
|
||||
Icon: IconLock,
|
||||
},
|
||||
].filter(isDefined)}
|
||||
onClick={() => handleViewSelect(view.id)}
|
||||
LeftIcon={getIcon(view.icon)}
|
||||
text={view.name}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
<DropdownMenuSeparator />
|
||||
<StyledBoldDropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
onClick={handleAddViewButtonClick}
|
||||
LeftIcon={IconPlus}
|
||||
text="Add view"
|
||||
/>
|
||||
</StyledBoldDropdownMenuItemsContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user