Fix permissions front followup (#10758)

This commit is contained in:
Weiko
2025-03-10 18:56:23 +01:00
committed by GitHub
parent c8b44aa242
commit 5fb613a8f7
9 changed files with 109 additions and 106 deletions

View File

@ -7,16 +7,17 @@ import { RolesTableRow } from '@/settings/roles/components/RolesTableRow';
import { Button, H2Title, IconPlus, Section } from 'twenty-ui'; import { Button, H2Title, IconPlus, Section } from 'twenty-ui';
import { Role } from '~/generated-metadata/graphql'; import { Role } from '~/generated-metadata/graphql';
const StyledTable = styled(Table)` const StyledCreateRoleSection = styled(Section)`
margin-top: ${({ theme }) => theme.spacing(0.5)};
`;
const StyledBottomSection = styled(Section)`
border-top: 1px solid ${({ theme }) => theme.border.color.light}; border-top: 1px solid ${({ theme }) => theme.border.color.light};
margin-top: ${({ theme }) => theme.spacing(2)};
padding-top: ${({ theme }) => theme.spacing(4)};
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
padding-top: ${({ theme }) => theme.spacing(2)};
padding-bottom: ${({ theme }) => theme.spacing(2)};
`;
const StyledTableRows = styled.div`
padding-bottom: ${({ theme }) => theme.spacing(2)};
padding-top: ${({ theme }) => theme.spacing(2)};
`; `;
export const Roles = ({ roles }: { roles: Role[] }) => { export const Roles = ({ roles }: { roles: Role[] }) => {
@ -26,13 +27,15 @@ export const Roles = ({ roles }: { roles: Role[] }) => {
title={t`All roles`} title={t`All roles`}
description={t`Assign roles to specify each member's access permissions`} description={t`Assign roles to specify each member's access permissions`}
/> />
<StyledTable> <Table>
<RolesTableHeader /> <RolesTableHeader />
{roles.map((role) => ( <StyledTableRows>
<RolesTableRow key={role.id} role={role} /> {roles.map((role) => (
))} <RolesTableRow key={role.id} role={role} />
</StyledTable> ))}
<StyledBottomSection> </StyledTableRows>
</Table>
<StyledCreateRoleSection>
<Button <Button
Icon={IconPlus} Icon={IconPlus}
title={t`Create Role`} title={t`Create Role`}
@ -40,7 +43,7 @@ export const Roles = ({ roles }: { roles: Role[] }) => {
size="small" size="small"
soon soon
/> />
</StyledBottomSection> </StyledCreateRoleSection>
</Section> </Section>
); );
}; };

View File

@ -1,25 +1,20 @@
import { Table } from '@/ui/layout/table/components/Table'; import { Table } from '@/ui/layout/table/components/Table';
import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { TableRow } from '@/ui/layout/table/components/TableRow'; import { TableRow } from '@/ui/layout/table/components/TableRow';
import styled from '@emotion/styled';
import { Trans } from '@lingui/react/macro'; import { Trans } from '@lingui/react/macro';
const StyledTableHeaderRow = styled(Table)`
margin-bottom: ${({ theme }) => theme.spacing(2)};
`;
export const RolesTableHeader = () => { export const RolesTableHeader = () => {
return ( return (
<StyledTableHeaderRow> <Table>
<TableRow gridAutoColumns="3fr 2fr 1fr"> <TableRow gridAutoColumns="332px 3fr 2fr 1fr">
<TableHeader> <TableHeader>
<Trans>Name</Trans> <Trans>Name</Trans>
</TableHeader> </TableHeader>
<TableHeader align={'right'}> <TableHeader align={'right'}>
<Trans>Assigned to</Trans> <Trans>Assigned to</Trans>
</TableHeader> </TableHeader>
<TableHeader align={'right'}></TableHeader> <TableHeader></TableHeader>
</TableRow> </TableRow>
</StyledTableHeaderRow> </Table>
); );
}; };

View File

@ -15,36 +15,20 @@ import {
import { Role } from '~/generated-metadata/graphql'; import { Role } from '~/generated-metadata/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings'; import { useNavigateSettings } from '~/hooks/useNavigateSettings';
const StyledIconChevronRight = styled(IconChevronRight)`
color: ${({ theme }) => theme.font.color.tertiary};
`;
const StyledAvatarContainer = styled.div`
border: 0px;
`;
const StyledAssignedText = styled.div` const StyledAssignedText = styled.div`
color: ${({ theme }) => theme.font.color.secondary}; color: ${({ theme }) => theme.font.color.secondary};
font-size: ${({ theme }) => theme.font.size.sm}; font-size: ${({ theme }) => theme.font.size.sm};
`; `;
const StyledNameCell = styled.div` const StyledNameCell = styled.div`
align-items: center; color: ${({ theme }) => theme.font.color.primary};
display: flex; display: flex;
gap: ${({ theme }) => theme.spacing(1)}; gap: ${({ theme }) => theme.spacing(1)};
color: ${({ theme }) => theme.font.color.primary};
`;
const StyledAssignedCell = styled.div`
align-items: center;
display: flex;
gap: ${({ theme }) => theme.spacing(4)};
`; `;
const StyledAvatarGroup = styled.div` const StyledAvatarGroup = styled.div`
align-items: center;
display: flex; display: flex;
margin-right: ${({ theme }) => theme.spacing(1)}; justify-content: flex-end;
> * { > * {
margin-left: -5px; margin-left: -5px;
@ -55,6 +39,12 @@ const StyledAvatarGroup = styled.div`
} }
`; `;
const StyledIconLockContainer = styled.div`
align-items: center;
display: flex;
justify-content: flex-end;
`;
const StyledTableRow = styled(TableRow)` const StyledTableRow = styled(TableRow)`
&:hover { &:hover {
background: ${({ theme }) => theme.background.transparent.light}; background: ${({ theme }) => theme.background.transparent.light};
@ -74,48 +64,57 @@ export const RolesTableRow = ({ role }: { role: Role }) => {
return ( return (
<StyledTableRow <StyledTableRow
key={role.id} key={role.id}
gridAutoColumns="3fr 2fr 1fr" gridAutoColumns="332px 3fr 2fr 1fr"
onClick={() => handleRoleClick(role.id)} onClick={() => handleRoleClick(role.id)}
> >
<TableCell> <TableCell>
<StyledNameCell> <StyledNameCell>
<IconUser size={theme.icon.size.md} /> <IconUser size={theme.icon.size.md} stroke={theme.icon.stroke.sm} />
{role.label} {role.label}
{!role.isEditable && <IconLock size={theme.icon.size.sm} />} {!role.isEditable && (
<StyledIconLockContainer>
<IconLock
color={theme.font.color.light}
stroke={theme.icon.stroke.sm}
size={theme.icon.size.sm}
/>
</StyledIconLockContainer>
)}
</StyledNameCell> </StyledNameCell>
</TableCell> </TableCell>
<TableCell align={'right'}> <TableCell align={'right'}>
<StyledAssignedCell> <StyledAvatarGroup>
<StyledAvatarGroup> {role.workspaceMembers.slice(0, 5).map((workspaceMember) => (
{role.workspaceMembers.slice(0, 5).map((workspaceMember) => ( <React.Fragment key={workspaceMember.id}>
<React.Fragment key={workspaceMember.id}> <div id={`avatar-${workspaceMember.id}`}>
<StyledAvatarContainer id={`avatar-${workspaceMember.id}`}> <Avatar
<Avatar avatarUrl={workspaceMember.avatarUrl}
avatarUrl={workspaceMember.avatarUrl} placeholderColorSeed={workspaceMember.id}
placeholderColorSeed={workspaceMember.id} placeholder={workspaceMember.name.firstName ?? ''}
placeholder={workspaceMember.name.firstName ?? ''} type="rounded"
type="rounded" size="md"
size="md"
/>
</StyledAvatarContainer>
<AppTooltip
anchorSelect={`#avatar-${workspaceMember.id}`}
content={`${workspaceMember.name.firstName} ${workspaceMember.name.lastName}`}
noArrow
place="top"
positionStrategy="fixed"
delay={TooltipDelay.shortDelay}
/> />
</React.Fragment> </div>
))} <AppTooltip
</StyledAvatarGroup> anchorSelect={`#avatar-${workspaceMember.id}`}
<StyledAssignedText> content={`${workspaceMember.name.firstName} ${workspaceMember.name.lastName}`}
{role.workspaceMembers.length} noArrow
</StyledAssignedText> place="top"
</StyledAssignedCell> positionStrategy="fixed"
delay={TooltipDelay.shortDelay}
/>
</React.Fragment>
))}
</StyledAvatarGroup>
</TableCell>
<TableCell align={'left'}>
<StyledAssignedText>{role.workspaceMembers.length}</StyledAssignedText>
</TableCell> </TableCell>
<TableCell align={'right'}> <TableCell align={'right'}>
<StyledIconChevronRight size={theme.icon.size.md} /> <IconChevronRight
size={theme.icon.size.md}
color={theme.font.color.tertiary}
/>
</TableCell> </TableCell>
</StyledTableRow> </StyledTableRow>
); );

View File

@ -38,7 +38,7 @@ const StyledAssignToMemberContainer = styled.div`
`; `;
const StyledSearchContainer = styled.div` const StyledSearchContainer = styled.div`
margin: ${({ theme }) => theme.spacing(2)} 0; padding-bottom: ${({ theme }) => theme.spacing(2)};
`; `;
const StyledTable = styled.div<{ hasRows: boolean }>` const StyledTable = styled.div<{ hasRows: boolean }>`
@ -57,6 +57,12 @@ const StyledSearchInput = styled(TextInput)`
} }
`; `;
const StyledTableRows = styled.div`
gap: ${({ theme }) => theme.spacing(0.5)};
padding-bottom: ${({ theme }) => theme.spacing(2)};
padding-top: ${({ theme }) => theme.spacing(2)};
`;
type RoleAssignmentProps = { type RoleAssignmentProps = {
role: Pick<Role, 'id' | 'label' | 'canUpdateAllSettings'> & { role: Pick<Role, 'id' | 'label' | 'canUpdateAllSettings'> & {
workspaceMembers: Array<WorkspaceMember>; workspaceMembers: Array<WorkspaceMember>;
@ -177,12 +183,14 @@ export const RoleAssignment = ({ role }: RoleAssignmentProps) => {
</StyledSearchContainer> </StyledSearchContainer>
<StyledTable hasRows={filteredWorkspaceMembers.length > 0}> <StyledTable hasRows={filteredWorkspaceMembers.length > 0}>
<RoleAssignmentTableHeader /> <RoleAssignmentTableHeader />
{filteredWorkspaceMembers.map((workspaceMember) => ( <StyledTableRows>
<RoleAssignmentTableRow {filteredWorkspaceMembers.map((workspaceMember) => (
key={workspaceMember.id} <RoleAssignmentTableRow
workspaceMember={workspaceMember} key={workspaceMember.id}
/> workspaceMember={workspaceMember}
))} />
))}
</StyledTableRows>
</StyledTable> </StyledTable>
<StyledAssignToMemberContainer> <StyledAssignToMemberContainer>

View File

@ -1,18 +1,13 @@
import { Table } from '@/ui/layout/table/components/Table'; import { Table } from '@/ui/layout/table/components/Table';
import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { TableRow } from '@/ui/layout/table/components/TableRow'; import { TableRow } from '@/ui/layout/table/components/TableRow';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
const StyledTableHeaderRow = styled(Table)`
margin-bottom: ${({ theme }) => theme.spacing(2)};
`;
export const RoleAssignmentTableHeader = () => ( export const RoleAssignmentTableHeader = () => (
<StyledTableHeaderRow> <Table>
<TableRow gridAutoColumns="2fr 4fr"> <TableRow gridAutoColumns="2fr 4fr">
<TableHeader>{t`Name`}</TableHeader> <TableHeader>{t`Name`}</TableHeader>
<TableHeader>{t`Email`}</TableHeader> <TableHeader>{t`Email`}</TableHeader>
</TableRow> </TableRow>
</StyledTableHeaderRow> </Table>
); );

View File

@ -18,8 +18,6 @@ const StyledPermissionCell = styled(TableCell)`
flex: 1; flex: 1;
gap: ${({ theme }) => theme.spacing(2)}; gap: ${({ theme }) => theme.spacing(2)};
padding-left: ${({ theme }) => theme.spacing(2)}; padding-left: ${({ theme }) => theme.spacing(2)};
color: ${({ theme }) => theme.font.color.secondary};
font-size: ${({ theme }) => theme.font.size.sm};
`; `;
const StyledCheckboxCell = styled(TableCell)` const StyledCheckboxCell = styled(TableCell)`

View File

@ -43,8 +43,6 @@ export const SettingsRoleEdit = () => {
} }
}, [role, navigateSettings, rolesLoading]); }, [role, navigateSettings, rolesLoading]);
if (!role) return null;
const tabs = [ const tabs = [
{ {
id: SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.ASSIGNMENT, id: SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.ASSIGNMENT,
@ -67,6 +65,10 @@ export const SettingsRoleEdit = () => {
]; ];
const renderActiveTabContent = () => { const renderActiveTabContent = () => {
if (!role) {
return null;
}
switch (activeTabId) { switch (activeTabId) {
case SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.ASSIGNMENT: case SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.ASSIGNMENT:
return <RoleAssignment role={role} />; return <RoleAssignment role={role} />;
@ -81,7 +83,7 @@ export const SettingsRoleEdit = () => {
return ( return (
<SubMenuTopBarContainer <SubMenuTopBarContainer
title={<H3Title title={role.label} />} title={role && <H3Title title={role.label} />}
links={[ links={[
{ {
children: 'Workspace', children: 'Workspace',
@ -92,18 +94,22 @@ export const SettingsRoleEdit = () => {
href: getSettingsPath(SettingsPath.Roles), href: getSettingsPath(SettingsPath.Roles),
}, },
{ {
children: role.label, children: role?.label,
}, },
]} ]}
> >
<SettingsPageContainer> {!rolesLoading && role ? (
<TabList <SettingsPageContainer>
tabListInstanceId={SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID} <TabList
tabs={tabs} tabListInstanceId={SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID}
className="tab-list" tabs={tabs}
/> className="tab-list"
{renderActiveTabContent()} />
</SettingsPageContainer> {renderActiveTabContent()}
</SettingsPageContainer>
) : (
<></>
)}
</SubMenuTopBarContainer> </SubMenuTopBarContainer>
); );
}; };

View File

@ -5,6 +5,7 @@ import { Roles } from '@/settings/roles/components/Roles';
import { RolesDefaultRole } from '@/settings/roles/components/RolesDefaultRole'; import { RolesDefaultRole } from '@/settings/roles/components/RolesDefaultRole';
import { SettingsPath } from '@/types/SettingsPath'; import { SettingsPath } from '@/types/SettingsPath';
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
import { H3Title } from 'twenty-ui';
import { useGetRolesQuery } from '~/generated/graphql'; import { useGetRolesQuery } from '~/generated/graphql';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath'; import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
@ -16,7 +17,7 @@ export const SettingsRoles = () => {
return ( return (
<SubMenuTopBarContainer <SubMenuTopBarContainer
title={t`Roles`} title={rolesData && <H3Title title={t`Roles`} />}
links={[ links={[
{ {
children: <Trans>Workspace</Trans>, children: <Trans>Workspace</Trans>,
@ -26,10 +27,10 @@ export const SettingsRoles = () => {
]} ]}
> >
<SettingsPageContainer> <SettingsPageContainer>
{!rolesLoading && ( {!rolesLoading && rolesData && (
<> <>
<Roles roles={rolesData?.getRoles ?? []} /> <Roles roles={rolesData.getRoles ?? []} />
<RolesDefaultRole roles={rolesData?.getRoles ?? []} /> <RolesDefaultRole roles={rolesData.getRoles ?? []} />
</> </>
)} )}
</SettingsPageContainer> </SettingsPageContainer>

View File

@ -15,8 +15,6 @@ type Checkers = Parameters<typeof checker>[0];
export default defineConfig(({ command, mode }) => { export default defineConfig(({ command, mode }) => {
const env = loadEnv(mode, __dirname, ''); const env = loadEnv(mode, __dirname, '');
console.log(__dirname);
const { const {
REACT_APP_SERVER_BASE_URL, REACT_APP_SERVER_BASE_URL,
VITE_BUILD_SOURCEMAP, VITE_BUILD_SOURCEMAP,