Add empty states to settings tables (#10978)
## Context Fixes https://github.com/twentyhq/twenty/issues/10964 ## Test <img width="617" alt="Screenshot 2025-03-18 at 12 18 30" src="https://github.com/user-attachments/assets/dab8738d-d221-4a6b-a72e-061ab5fffb70" /> <img width="647" alt="Screenshot 2025-03-18 at 12 18 25" src="https://github.com/user-attachments/assets/45466a80-7a80-4cde-a0c5-420cd6c05cb2" /> <img width="637" alt="Screenshot 2025-03-18 at 12 18 19" src="https://github.com/user-attachments/assets/46a9f27a-bd3a-4e91-9885-668cf780d562" /> <img width="630" alt="Screenshot 2025-03-18 at 12 18 07" src="https://github.com/user-attachments/assets/e1f805a0-ed7f-4cf2-8f75-78b865bd1ca2" /> <img width="649" alt="Screenshot 2025-03-18 at 12 18 01" src="https://github.com/user-attachments/assets/e9f3086f-fe97-4f3b-99e0-25249e9dd43b" />
This commit is contained in:
@ -7,6 +7,7 @@ import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useState } from 'react';
|
||||
@ -41,19 +42,14 @@ const StyledSearchContainer = styled.div`
|
||||
padding-bottom: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledTable = styled.div<{ hasRows: boolean }>`
|
||||
border-bottom: ${({ hasRows, theme }) =>
|
||||
hasRows ? `1px solid ${theme.border.color.light}` : 'none'};
|
||||
const StyledTable = styled.div`
|
||||
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
`;
|
||||
|
||||
const StyledSearchInput = styled(TextInput)`
|
||||
input {
|
||||
background: ${({ theme }) => theme.background.transparent.lighter};
|
||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
|
||||
&:hover {
|
||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -63,6 +59,10 @@ const StyledTableRows = styled.div`
|
||||
padding-top: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledNoMembers = styled(TableCell)`
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
`;
|
||||
|
||||
type RoleAssignmentProps = {
|
||||
role: Pick<Role, 'id' | 'label' | 'canUpdateAllSettings'> & {
|
||||
workspaceMembers: Array<WorkspaceMember>;
|
||||
@ -175,21 +175,29 @@ export const RoleAssignment = ({ role }: RoleAssignmentProps) => {
|
||||
<StyledSearchInput
|
||||
value={searchFilter}
|
||||
onChange={handleSearchChange}
|
||||
placeholder={t`Search a member`}
|
||||
placeholder={t`Search an assigned team member...`}
|
||||
fullWidth
|
||||
LeftIcon={IconSearch}
|
||||
sizeVariant="lg"
|
||||
/>
|
||||
</StyledSearchContainer>
|
||||
<StyledTable hasRows={filteredWorkspaceMembers.length > 0}>
|
||||
<StyledTable>
|
||||
<RoleAssignmentTableHeader />
|
||||
<StyledTableRows>
|
||||
{filteredWorkspaceMembers.map((workspaceMember) => (
|
||||
<RoleAssignmentTableRow
|
||||
key={workspaceMember.id}
|
||||
workspaceMember={workspaceMember}
|
||||
/>
|
||||
))}
|
||||
{filteredWorkspaceMembers.length > 0 ? (
|
||||
filteredWorkspaceMembers.map((workspaceMember) => (
|
||||
<RoleAssignmentTableRow
|
||||
key={workspaceMember.id}
|
||||
workspaceMember={workspaceMember}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<StyledNoMembers>
|
||||
{!searchFilter
|
||||
? t`No members assigned`
|
||||
: t`No members match your search`}
|
||||
</StyledNoMembers>
|
||||
)}
|
||||
</StyledTableRows>
|
||||
</StyledTable>
|
||||
|
||||
|
||||
@ -1,13 +1,10 @@
|
||||
import { Table } from '@/ui/layout/table/components/Table';
|
||||
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
export const RoleAssignmentTableHeader = () => (
|
||||
<Table>
|
||||
<TableRow gridAutoColumns="2fr 4fr">
|
||||
<TableHeader>{t`Name`}</TableHeader>
|
||||
<TableHeader>{t`Email`}</TableHeader>
|
||||
</TableRow>
|
||||
</Table>
|
||||
<TableRow gridAutoColumns="2fr 4fr">
|
||||
<TableHeader>{t`Name`}</TableHeader>
|
||||
<TableHeader>{t`Email`}</TableHeader>
|
||||
</TableRow>
|
||||
);
|
||||
|
||||
@ -32,7 +32,11 @@ const StyledRolePermissionsContainer = styled.div`
|
||||
|
||||
const StyledTable = styled.div`
|
||||
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
`;
|
||||
|
||||
const StyledTableRows = styled.div`
|
||||
padding-bottom: ${({ theme }) => theme.spacing(2)};
|
||||
padding-top: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
type RolePermissionsProps = {
|
||||
@ -136,12 +140,14 @@ export const RolePermissions = ({ role }: RolePermissionsProps) => {
|
||||
/>
|
||||
<StyledTable>
|
||||
<RolePermissionsObjectsTableHeader allPermissions={true} />
|
||||
{objectPermissionsConfig.map((permission) => (
|
||||
<RolePermissionsObjectsTableRow
|
||||
key={permission.key}
|
||||
permission={permission}
|
||||
/>
|
||||
))}
|
||||
<StyledTableRows>
|
||||
{objectPermissionsConfig.map((permission) => (
|
||||
<RolePermissionsObjectsTableRow
|
||||
key={permission.key}
|
||||
permission={permission}
|
||||
/>
|
||||
))}
|
||||
</StyledTableRows>
|
||||
</StyledTable>
|
||||
</Section>
|
||||
<Section>
|
||||
@ -150,12 +156,14 @@ export const RolePermissions = ({ role }: RolePermissionsProps) => {
|
||||
<RolePermissionsSettingsTableHeader
|
||||
allPermissions={role.canUpdateAllSettings}
|
||||
/>
|
||||
{settingsPermissionsConfig.map((permission) => (
|
||||
<RolePermissionsSettingsTableRow
|
||||
key={permission.key}
|
||||
permission={permission}
|
||||
/>
|
||||
))}
|
||||
<StyledTableRows>
|
||||
{settingsPermissionsConfig.map((permission) => (
|
||||
<RolePermissionsSettingsTableRow
|
||||
key={permission.key}
|
||||
permission={permission}
|
||||
/>
|
||||
))}
|
||||
</StyledTableRows>
|
||||
</StyledTable>
|
||||
</Section>
|
||||
</StyledRolePermissionsContainer>
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { Table } from '@/ui/layout/table/components/Table';
|
||||
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
import styled from '@emotion/styled';
|
||||
@ -20,25 +19,17 @@ const StyledActionsHeader = styled(TableHeader)`
|
||||
padding-right: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledTable = styled(Table)`
|
||||
margin-bottom: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
type RolePermissionsObjectsTableHeaderProps = {
|
||||
className?: string;
|
||||
allPermissions: boolean;
|
||||
};
|
||||
|
||||
export const RolePermissionsObjectsTableHeader = ({
|
||||
className,
|
||||
allPermissions,
|
||||
}: RolePermissionsObjectsTableHeaderProps) => (
|
||||
<StyledTable className={className}>
|
||||
<StyledTableHeaderRow>
|
||||
<StyledNameHeader>{t`Name`}</StyledNameHeader>
|
||||
<StyledActionsHeader aria-label={t`Actions`}>
|
||||
<Checkbox checked={allPermissions} disabled />
|
||||
</StyledActionsHeader>
|
||||
</StyledTableHeaderRow>
|
||||
</StyledTable>
|
||||
<StyledTableHeaderRow>
|
||||
<StyledNameHeader>{t`Name`}</StyledNameHeader>
|
||||
<StyledActionsHeader aria-label={t`Actions`}>
|
||||
<Checkbox checked={allPermissions} disabled />
|
||||
</StyledActionsHeader>
|
||||
</StyledTableHeaderRow>
|
||||
);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { Table } from '@/ui/layout/table/components/Table';
|
||||
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
import styled from '@emotion/styled';
|
||||
@ -23,30 +22,22 @@ const StyledActionsHeader = styled(TableHeader)`
|
||||
padding-right: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledTable = styled(Table)`
|
||||
margin-bottom: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledTypeHeader = styled(TableHeader)`
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
type RolePermissionsSettingsTableHeaderProps = {
|
||||
className?: string;
|
||||
allPermissions: boolean;
|
||||
};
|
||||
|
||||
export const RolePermissionsSettingsTableHeader = ({
|
||||
className,
|
||||
allPermissions,
|
||||
}: RolePermissionsSettingsTableHeaderProps) => (
|
||||
<StyledTable className={className}>
|
||||
<StyledTableHeaderRow>
|
||||
<StyledNameHeader>{t`Name`}</StyledNameHeader>
|
||||
<StyledTypeHeader>{t`Type`}</StyledTypeHeader>
|
||||
<StyledActionsHeader aria-label={t`Actions`}>
|
||||
<Checkbox checked={allPermissions} disabled />
|
||||
</StyledActionsHeader>
|
||||
</StyledTableHeaderRow>
|
||||
</StyledTable>
|
||||
<StyledTableHeaderRow>
|
||||
<StyledNameHeader>{t`Name`}</StyledNameHeader>
|
||||
<StyledTypeHeader>{t`Type`}</StyledTypeHeader>
|
||||
<StyledActionsHeader aria-label={t`Actions`}>
|
||||
<Checkbox checked={allPermissions} disabled />
|
||||
</StyledActionsHeader>
|
||||
</StyledTableHeaderRow>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user