Fetch roles in roles settings page (#10001)
## Context Following the addition of the new Roles page, we are now fetching roles from the DB thanks to this PR #9955 ## Test <img width="1136" alt="Screenshot 2025-02-04 at 14 46 21" src="https://github.com/user-attachments/assets/2c55c4d0-ee51-47bb-8113-efce172a9365" /> --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -1386,7 +1386,7 @@ export type Query = {
|
|||||||
getPostgresCredentials?: Maybe<PostgresCredentials>;
|
getPostgresCredentials?: Maybe<PostgresCredentials>;
|
||||||
getProductPrices: BillingProductPricesOutput;
|
getProductPrices: BillingProductPricesOutput;
|
||||||
getPublicWorkspaceDataBySubdomain: PublicWorkspaceDataOutput;
|
getPublicWorkspaceDataBySubdomain: PublicWorkspaceDataOutput;
|
||||||
getRoles: Array<RoleDto>;
|
getRoles: Array<Role>;
|
||||||
getServerlessFunctionSourceCode?: Maybe<Scalars['JSON']['output']>;
|
getServerlessFunctionSourceCode?: Maybe<Scalars['JSON']['output']>;
|
||||||
getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal;
|
getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal;
|
||||||
getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal;
|
getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal;
|
||||||
@ -1653,8 +1653,8 @@ export type ResendEmailVerificationTokenOutput = {
|
|||||||
success: Scalars['Boolean']['output'];
|
success: Scalars['Boolean']['output'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RoleDto = {
|
export type Role = {
|
||||||
__typename?: 'RoleDTO';
|
__typename?: 'Role';
|
||||||
canUpdateAllSettings: Scalars['Boolean']['output'];
|
canUpdateAllSettings: Scalars['Boolean']['output'];
|
||||||
description?: Maybe<Scalars['String']['output']>;
|
description?: Maybe<Scalars['String']['output']>;
|
||||||
id: Scalars['String']['output'];
|
id: Scalars['String']['output'];
|
||||||
|
|||||||
@ -1250,7 +1250,7 @@ export type Query = {
|
|||||||
getPostgresCredentials?: Maybe<PostgresCredentials>;
|
getPostgresCredentials?: Maybe<PostgresCredentials>;
|
||||||
getProductPrices: BillingProductPricesOutput;
|
getProductPrices: BillingProductPricesOutput;
|
||||||
getPublicWorkspaceDataBySubdomain: PublicWorkspaceDataOutput;
|
getPublicWorkspaceDataBySubdomain: PublicWorkspaceDataOutput;
|
||||||
getRoles: Array<RoleDto>;
|
getRoles: Array<Role>;
|
||||||
getServerlessFunctionSourceCode?: Maybe<Scalars['JSON']>;
|
getServerlessFunctionSourceCode?: Maybe<Scalars['JSON']>;
|
||||||
getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal;
|
getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal;
|
||||||
getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal;
|
getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal;
|
||||||
@ -1449,8 +1449,8 @@ export type ResendEmailVerificationTokenOutput = {
|
|||||||
success: Scalars['Boolean'];
|
success: Scalars['Boolean'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RoleDto = {
|
export type Role = {
|
||||||
__typename?: 'RoleDTO';
|
__typename?: 'Role';
|
||||||
canUpdateAllSettings: Scalars['Boolean'];
|
canUpdateAllSettings: Scalars['Boolean'];
|
||||||
description?: Maybe<Scalars['String']>;
|
description?: Maybe<Scalars['String']>;
|
||||||
id: Scalars['String'];
|
id: Scalars['String'];
|
||||||
@ -2242,6 +2242,11 @@ export type UpdateLabPublicFeatureFlagMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type UpdateLabPublicFeatureFlagMutation = { __typename?: 'Mutation', updateLabPublicFeatureFlag: { __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean } };
|
export type UpdateLabPublicFeatureFlagMutation = { __typename?: 'Mutation', updateLabPublicFeatureFlag: { __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean } };
|
||||||
|
|
||||||
|
export type GetRolesQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
|
export type GetRolesQuery = { __typename?: 'Query', getRoles: Array<{ __typename?: 'Role', id: string, label: string, description?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, workspaceMembers: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> }> };
|
||||||
|
|
||||||
export type CreateOidcIdentityProviderMutationVariables = Exact<{
|
export type CreateOidcIdentityProviderMutationVariables = Exact<{
|
||||||
input: SetupOidcSsoInput;
|
input: SetupOidcSsoInput;
|
||||||
}>;
|
}>;
|
||||||
@ -3936,6 +3941,47 @@ export function useUpdateLabPublicFeatureFlagMutation(baseOptions?: Apollo.Mutat
|
|||||||
export type UpdateLabPublicFeatureFlagMutationHookResult = ReturnType<typeof useUpdateLabPublicFeatureFlagMutation>;
|
export type UpdateLabPublicFeatureFlagMutationHookResult = ReturnType<typeof useUpdateLabPublicFeatureFlagMutation>;
|
||||||
export type UpdateLabPublicFeatureFlagMutationResult = Apollo.MutationResult<UpdateLabPublicFeatureFlagMutation>;
|
export type UpdateLabPublicFeatureFlagMutationResult = Apollo.MutationResult<UpdateLabPublicFeatureFlagMutation>;
|
||||||
export type UpdateLabPublicFeatureFlagMutationOptions = Apollo.BaseMutationOptions<UpdateLabPublicFeatureFlagMutation, UpdateLabPublicFeatureFlagMutationVariables>;
|
export type UpdateLabPublicFeatureFlagMutationOptions = Apollo.BaseMutationOptions<UpdateLabPublicFeatureFlagMutation, UpdateLabPublicFeatureFlagMutationVariables>;
|
||||||
|
export const GetRolesDocument = gql`
|
||||||
|
query GetRoles {
|
||||||
|
getRoles {
|
||||||
|
id
|
||||||
|
label
|
||||||
|
description
|
||||||
|
canUpdateAllSettings
|
||||||
|
isEditable
|
||||||
|
workspaceMembers {
|
||||||
|
...WorkspaceMemberQueryFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
${WorkspaceMemberQueryFragmentFragmentDoc}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useGetRolesQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useGetRolesQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useGetRolesQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = useGetRolesQuery({
|
||||||
|
* variables: {
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useGetRolesQuery(baseOptions?: Apollo.QueryHookOptions<GetRolesQuery, GetRolesQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<GetRolesQuery, GetRolesQueryVariables>(GetRolesDocument, options);
|
||||||
|
}
|
||||||
|
export function useGetRolesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetRolesQuery, GetRolesQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<GetRolesQuery, GetRolesQueryVariables>(GetRolesDocument, options);
|
||||||
|
}
|
||||||
|
export type GetRolesQueryHookResult = ReturnType<typeof useGetRolesQuery>;
|
||||||
|
export type GetRolesLazyQueryHookResult = ReturnType<typeof useGetRolesLazyQuery>;
|
||||||
|
export type GetRolesQueryResult = Apollo.QueryResult<GetRolesQuery, GetRolesQueryVariables>;
|
||||||
export const CreateOidcIdentityProviderDocument = gql`
|
export const CreateOidcIdentityProviderDocument = gql`
|
||||||
mutation CreateOIDCIdentityProvider($input: SetupOIDCSsoInput!) {
|
mutation CreateOIDCIdentityProvider($input: SetupOIDCSsoInput!) {
|
||||||
createOIDCIdentityProvider(input: $input) {
|
createOIDCIdentityProvider(input: $input) {
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { WORKSPACE_MEMBER_QUERY_FRAGMENT } from '@/workspace-member/graphql/fragments/workspaceMemberQueryFragment';
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
export const GET_ROLES = gql`
|
||||||
|
${WORKSPACE_MEMBER_QUERY_FRAGMENT}
|
||||||
|
query GetRoles {
|
||||||
|
getRoles {
|
||||||
|
id
|
||||||
|
label
|
||||||
|
description
|
||||||
|
canUpdateAllSettings
|
||||||
|
isEditable
|
||||||
|
workspaceMembers {
|
||||||
|
...WorkspaceMemberQueryFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@ -1,20 +1,86 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { Trans, useLingui } from '@lingui/react/macro';
|
import { Trans, useLingui } from '@lingui/react/macro';
|
||||||
import { Button, H2Title, IconPlus, Section } from 'twenty-ui';
|
import {
|
||||||
|
AppTooltip,
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
H2Title,
|
||||||
|
IconChevronRight,
|
||||||
|
IconLock,
|
||||||
|
IconPlus,
|
||||||
|
IconUser,
|
||||||
|
Section,
|
||||||
|
TooltipDelay,
|
||||||
|
} from 'twenty-ui';
|
||||||
|
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
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 { Table } from '@/ui/layout/table/components/Table';
|
import { Table } from '@/ui/layout/table/components/Table';
|
||||||
|
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||||
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 { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
import { useTheme } from '@emotion/react';
|
||||||
|
import { FeatureFlagKey, useGetRolesQuery } from '~/generated/graphql';
|
||||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||||
|
|
||||||
const StyledRoleTableRow = styled.div`
|
const StyledTable = styled(Table)`
|
||||||
|
margin-top: ${({ theme }) => theme.spacing(0.5)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTableRow = styled(TableRow)`
|
||||||
|
&:hover {
|
||||||
|
background: ${({ theme }) => theme.background.transparent.light};
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledNameCell = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: 1fr 1fr;
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledAssignedCell = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledAvatarGroup = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
margin-right: ${({ theme }) => theme.spacing(1)};
|
||||||
|
|
||||||
|
> * {
|
||||||
|
border: 2px solid ${({ theme }) => theme.background.primary};
|
||||||
|
margin-left: -8px;
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTableHeaderRow = styled(Table)`
|
||||||
|
margin-bottom: ${({ theme }) => theme.spacing(1.5)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledBottomSection = styled(Section)`
|
||||||
|
border-top: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
|
margin-top: ${({ theme }) => theme.spacing(2)};
|
||||||
|
padding-top: ${({ theme }) => theme.spacing(4)};
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledIconChevronRight = styled(IconChevronRight)`
|
||||||
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledAvatarContainer = styled.div`
|
||||||
|
border: 0px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const SettingsRoles = () => {
|
export const SettingsRoles = () => {
|
||||||
@ -22,22 +88,9 @@ export const SettingsRoles = () => {
|
|||||||
const isPermissionsEnabled = useIsFeatureEnabled(
|
const isPermissionsEnabled = useIsFeatureEnabled(
|
||||||
FeatureFlagKey.IsPermissionsEnabled,
|
FeatureFlagKey.IsPermissionsEnabled,
|
||||||
);
|
);
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
const GET_SETTINGS_ROLE_TABLE_METADATA = {
|
const { data: rolesData, loading: isRolesLoading } = useGetRolesQuery();
|
||||||
tableId: 'settingsRole',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
fieldName: 'name',
|
|
||||||
fieldLabel: t`Name`,
|
|
||||||
align: 'left' as const,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldName: 'assignedTo',
|
|
||||||
fieldLabel: t`Assigned to`,
|
|
||||||
align: 'left' as const,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!isPermissionsEnabled) {
|
if (!isPermissionsEnabled) {
|
||||||
return null;
|
return null;
|
||||||
@ -46,14 +99,6 @@ export const SettingsRoles = () => {
|
|||||||
return (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
title={t`Roles`}
|
title={t`Roles`}
|
||||||
actionButton={
|
|
||||||
<Button
|
|
||||||
Icon={IconPlus}
|
|
||||||
title={t`New Role`}
|
|
||||||
accent="blue"
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
links={[
|
links={[
|
||||||
{
|
{
|
||||||
children: <Trans>Workspace</Trans>,
|
children: <Trans>Workspace</Trans>,
|
||||||
@ -68,21 +113,80 @@ export const SettingsRoles = () => {
|
|||||||
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>
|
<StyledTableHeaderRow>
|
||||||
<StyledRoleTableRow>
|
<TableRow>
|
||||||
{GET_SETTINGS_ROLE_TABLE_METADATA.fields.map(
|
<TableHeader>
|
||||||
(settingsRoleTableMetadataField) => (
|
<Trans>Name</Trans>
|
||||||
<TableHeader
|
</TableHeader>
|
||||||
key={settingsRoleTableMetadataField.fieldName}
|
<TableHeader align={'right'}>
|
||||||
align={settingsRoleTableMetadataField.align}
|
<Trans>Assigned to</Trans>
|
||||||
>
|
</TableHeader>
|
||||||
{settingsRoleTableMetadataField.fieldLabel}
|
<TableHeader align={'right'}></TableHeader>
|
||||||
</TableHeader>
|
</TableRow>
|
||||||
),
|
</StyledTableHeaderRow>
|
||||||
)}
|
{!isRolesLoading &&
|
||||||
</StyledRoleTableRow>
|
rolesData?.getRoles.map((role) => (
|
||||||
</Table>
|
<StyledTableRow key={role.id}>
|
||||||
|
<TableCell>
|
||||||
|
<StyledNameCell>
|
||||||
|
<IconUser size={theme.icon.size.md} />
|
||||||
|
{role.label}
|
||||||
|
{!role.isEditable && (
|
||||||
|
<IconLock size={theme.icon.size.sm} />
|
||||||
|
)}
|
||||||
|
</StyledNameCell>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align={'right'}>
|
||||||
|
<StyledAssignedCell>
|
||||||
|
<StyledAvatarGroup>
|
||||||
|
{role.workspaceMembers
|
||||||
|
.slice(0, 5)
|
||||||
|
.map((workspaceMember) => (
|
||||||
|
<>
|
||||||
|
<StyledAvatarContainer
|
||||||
|
key={workspaceMember.id}
|
||||||
|
id={`avatar-${workspaceMember.id}`}
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
avatarUrl={workspaceMember.avatarUrl}
|
||||||
|
placeholderColorSeed={workspaceMember.id}
|
||||||
|
placeholder={
|
||||||
|
workspaceMember.name.firstName ?? ''
|
||||||
|
}
|
||||||
|
type="rounded"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</StyledAvatarContainer>
|
||||||
|
<AppTooltip
|
||||||
|
anchorSelect={`#avatar-${workspaceMember.id}`}
|
||||||
|
content={`${workspaceMember.name.firstName} ${workspaceMember.name.lastName}`}
|
||||||
|
noArrow
|
||||||
|
place="top"
|
||||||
|
positionStrategy="fixed"
|
||||||
|
delay={TooltipDelay.shortDelay}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</StyledAvatarGroup>
|
||||||
|
{role.workspaceMembers.length}
|
||||||
|
</StyledAssignedCell>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align={'right'}>
|
||||||
|
<StyledIconChevronRight size={theme.icon.size.md} />
|
||||||
|
</TableCell>
|
||||||
|
</StyledTableRow>
|
||||||
|
))}
|
||||||
|
</StyledTable>
|
||||||
|
<StyledBottomSection>
|
||||||
|
<Button
|
||||||
|
Icon={IconPlus}
|
||||||
|
title={t`Create Role`}
|
||||||
|
variant="secondary"
|
||||||
|
size="small"
|
||||||
|
soon
|
||||||
|
/>
|
||||||
|
</StyledBottomSection>
|
||||||
</Section>
|
</Section>
|
||||||
</SettingsPageContainer>
|
</SettingsPageContainer>
|
||||||
</SubMenuTopBarContainer>
|
</SubMenuTopBarContainer>
|
||||||
|
|||||||
@ -44,6 +44,7 @@ import { UserModule } from 'src/engine/core-modules/user/user.module';
|
|||||||
import { WorkflowApiModule } from 'src/engine/core-modules/workflow/workflow-api.module';
|
import { WorkflowApiModule } from 'src/engine/core-modules/workflow/workflow-api.module';
|
||||||
import { WorkspaceInvitationModule } from 'src/engine/core-modules/workspace-invitation/workspace-invitation.module';
|
import { WorkspaceInvitationModule } from 'src/engine/core-modules/workspace-invitation/workspace-invitation.module';
|
||||||
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
|
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
|
||||||
|
import { RoleModule } from 'src/engine/metadata-modules/role/role.module';
|
||||||
import { WorkspaceEventEmitterModule } from 'src/engine/workspace-event-emitter/workspace-event-emitter.module';
|
import { WorkspaceEventEmitterModule } from 'src/engine/workspace-event-emitter/workspace-event-emitter.module';
|
||||||
|
|
||||||
import { AnalyticsModule } from './analytics/analytics.module';
|
import { AnalyticsModule } from './analytics/analytics.module';
|
||||||
@ -74,6 +75,7 @@ import { FileModule } from './file/file.module';
|
|||||||
TelemetryModule,
|
TelemetryModule,
|
||||||
AdminPanelModule,
|
AdminPanelModule,
|
||||||
LabModule,
|
LabModule,
|
||||||
|
RoleModule,
|
||||||
EnvironmentModule.forRoot({}),
|
EnvironmentModule.forRoot({}),
|
||||||
RedisClientModule,
|
RedisClientModule,
|
||||||
FileStorageModule.forRootAsync({
|
FileStorageModule.forRootAsync({
|
||||||
|
|||||||
@ -54,7 +54,7 @@ export class PermissionsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw new PermissionsException(
|
throw new PermissionsException(
|
||||||
`User does not have permission to update this setting: ${setting}`,
|
`User does not have permission to access this setting: ${setting}`,
|
||||||
PermissionsExceptionCode.PERMISSION_DENIED,
|
PermissionsExceptionCode.PERMISSION_DENIED,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { Relation } from 'typeorm';
|
|||||||
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
|
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
|
||||||
import { UserWorkspaceRoleEntity } from 'src/engine/metadata-modules/role/user-workspace-role.entity';
|
import { UserWorkspaceRoleEntity } from 'src/engine/metadata-modules/role/user-workspace-role.entity';
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType('Role')
|
||||||
export class RoleDTO {
|
export class RoleDTO {
|
||||||
@Field({ nullable: false })
|
@Field({ nullable: false })
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user