Enforce front project structure through ESLINT (#7863)

Fixes: https://github.com/twentyhq/twenty/issues/7329
This commit is contained in:
Charles Bochet
2024-10-20 20:20:19 +02:00
committed by GitHub
parent f801f3aa9f
commit eccf0bf8ba
260 changed files with 500 additions and 290 deletions
@@ -0,0 +1,51 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { OverflowingTextWithTooltip, useIcons } from 'twenty-ui';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/components/SettingsDataModelObjectTypeTag';
import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel';
export type SettingsDataModelObjectSummaryProps = {
className?: string;
objectMetadataItem: ObjectMetadataItem;
};
const StyledObjectSummary = styled.div`
align-items: center;
display: flex;
justify-content: space-between;
`;
const StyledObjectName = styled.div`
display: flex;
gap: ${({ theme }) => theme.spacing(2)};
max-width: 60%;
`;
const StyledIconContainer = styled.div`
flex-shrink: 0;
`;
export const SettingsDataModelObjectSummary = ({
className,
objectMetadataItem,
}: SettingsDataModelObjectSummaryProps) => {
const theme = useTheme();
const { getIcon } = useIcons();
const ObjectIcon = getIcon(objectMetadataItem.icon);
const objectTypeLabel = getObjectTypeLabel(objectMetadataItem);
return (
<StyledObjectSummary className={className}>
<StyledObjectName>
<StyledIconContainer>
<ObjectIcon size={theme.icon.size.sm} stroke={theme.icon.stroke.md} />
</StyledIconContainer>
<OverflowingTextWithTooltip text={objectMetadataItem.labelPlural} />
</StyledObjectName>
<SettingsDataModelObjectTypeTag objectTypeLabel={objectTypeLabel} />
</StyledObjectSummary>
);
};
@@ -0,0 +1,22 @@
import { Tag } from 'twenty-ui';
import { ObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel';
type SettingsDataModelObjectTypeTagProps = {
objectTypeLabel: ObjectTypeLabel;
className?: string;
};
export const SettingsDataModelObjectTypeTag = ({
className,
objectTypeLabel,
}: SettingsDataModelObjectTypeTagProps) => {
return (
<Tag
className={className}
color={objectTypeLabel.labelColor}
text={objectTypeLabel.labelText}
weight="medium"
/>
);
};
@@ -0,0 +1,43 @@
import styled from '@emotion/styled';
import { IconEye } from 'twenty-ui';
import { FloatingButton } from '@/ui/input/button/components/FloatingButton';
import { Card } from '@/ui/layout/card/components/Card';
import { SettingsPath } from '@/types/SettingsPath';
import DarkCoverImage from '../../assets/cover-dark.png';
import LightCoverImage from '../../assets/cover-light.png';
const StyledCoverImageContainer = styled(Card)`
align-items: center;
background-image: ${({ theme }) =>
theme.name === 'light'
? `url('${LightCoverImage.toString()}')`
: `url('${DarkCoverImage.toString()}')`};
background-size: cover;
border-radius: ${({ theme }) => theme.border.radius.md};
box-sizing: border-box;
display: flex;
height: 153px;
justify-content: center;
position: relative;
margin-bottom: ${({ theme }) => theme.spacing(8)};
`;
const StyledButtonContainer = styled.div`
padding-top: ${({ theme }) => theme.spacing(5)};
`;
export const SettingsObjectCoverImage = () => {
return (
<StyledCoverImageContainer>
<StyledButtonContainer>
<FloatingButton
Icon={IconEye}
title="Visualize"
size="small"
to={'/settings/' + SettingsPath.ObjectOverview}
/>
</StyledButtonContainer>
</StyledCoverImageContainer>
);
};
@@ -0,0 +1,67 @@
import { IconArchiveOff, IconDotsVertical, IconTrash } from 'twenty-ui';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
type SettingsObjectInactiveMenuDropDownProps = {
isCustomObject: boolean;
onActivate: () => void;
onDelete: () => void;
scopeKey: string;
};
export const SettingsObjectInactiveMenuDropDown = ({
onActivate,
scopeKey,
onDelete,
isCustomObject,
}: SettingsObjectInactiveMenuDropDownProps) => {
const dropdownId = `${scopeKey}-settings-object-inactive-menu-dropdown`;
const { closeDropdown } = useDropdown(dropdownId);
const handleActivate = () => {
onActivate();
closeDropdown();
};
const handleDelete = () => {
onDelete();
closeDropdown();
};
return (
<Dropdown
dropdownId={dropdownId}
clickableComponent={
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
}
dropdownComponents={
<DropdownMenu width="160px">
<DropdownMenuItemsContainer>
<MenuItem
text="Activate"
LeftIcon={IconArchiveOff}
onClick={handleActivate}
/>
{isCustomObject && (
<MenuItem
text="Delete"
LeftIcon={IconTrash}
accent="danger"
onClick={handleDelete}
/>
)}
</DropdownMenuItemsContainer>
</DropdownMenu>
}
dropdownHotkeyScope={{
scope: dropdownId,
}}
/>
);
};
@@ -0,0 +1,86 @@
import { Decorator, Meta, StoryObj } from '@storybook/react';
import { expect, fn, userEvent, within } from '@storybook/test';
import { ComponentDecorator } from 'twenty-ui';
import { SettingsObjectInactiveMenuDropDown } from '../SettingsObjectInactiveMenuDropDown';
const handleActivateMockFunction = fn();
const handleDeleteMockFunction = fn();
const ClearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks === true) {
handleActivateMockFunction.mockClear();
handleDeleteMockFunction.mockClear();
}
return <Story />;
};
const meta: Meta<typeof SettingsObjectInactiveMenuDropDown> = {
title: 'Modules/Settings/DataModel/SettingsObjectInactiveMenuDropDown',
component: SettingsObjectInactiveMenuDropDown,
args: {
scopeKey: 'settings-object-inactive-menu-dropdown',
onActivate: handleActivateMockFunction,
onDelete: handleDeleteMockFunction,
},
decorators: [ComponentDecorator, ClearMocksDecorator],
parameters: {
clearMocks: true,
},
};
export default meta;
type Story = StoryObj<typeof SettingsObjectInactiveMenuDropDown>;
export const Default: Story = {};
export const Open: Story = {
play: async () => {
const canvas = within(document.body);
const dropdownButton = await canvas.getByRole('button');
await userEvent.click(dropdownButton);
},
};
export const WithActivate: Story = {
play: async () => {
const canvas = within(document.body);
const dropdownButton = await canvas.getByRole('button');
await userEvent.click(dropdownButton);
await expect(handleActivateMockFunction).toHaveBeenCalledTimes(0);
const activateMenuItem = await canvas.getByText('Activate');
await userEvent.click(activateMenuItem);
await expect(handleActivateMockFunction).toHaveBeenCalledTimes(1);
await userEvent.click(dropdownButton);
},
};
export const WithDelete: Story = {
args: { isCustomObject: true },
play: async () => {
const canvas = within(document.body);
const dropdownButton = await canvas.getByRole('button');
await userEvent.click(dropdownButton);
await expect(handleDeleteMockFunction).toHaveBeenCalledTimes(0);
const deleteMenuItem = await canvas.getByText('Delete');
await userEvent.click(deleteMenuItem);
await expect(handleDeleteMockFunction).toHaveBeenCalledTimes(1);
await userEvent.click(dropdownButton);
},
};