1721/feature/drag and drop favorites (#2097)

* prisma schema updated: added index in favorite

* update abilitiy added for favorite

* update one favorite resolver added

* update on favorite mutation added

* updateFavoriteOrder added

* Draglist added in favorite

* nav item convert to div from button: because it was not working dragable with button

* changed index to position

* position added in getFavorites query

* added recoil state for favorites

* reordering updated according to new method

* Use accurate type

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Abhishek Thory
2023-10-19 16:35:23 -05:00
committed by GitHub
parent f6b5943fc6
commit 08772b4456
14 changed files with 341 additions and 42 deletions

View File

@ -395,6 +395,7 @@ export type Favorite = {
id: Scalars['ID']['output']; id: Scalars['ID']['output'];
person?: Maybe<Person>; person?: Maybe<Person>;
personId?: Maybe<Scalars['String']['output']>; personId?: Maybe<Scalars['String']['output']>;
position: Scalars['Float']['output'];
workspaceId?: Maybe<Scalars['String']['output']>; workspaceId?: Maybe<Scalars['String']['output']>;
workspaceMember?: Maybe<WorkspaceMember>; workspaceMember?: Maybe<WorkspaceMember>;
workspaceMemberId?: Maybe<Scalars['String']['output']>; workspaceMemberId?: Maybe<Scalars['String']['output']>;

View File

@ -1226,6 +1226,7 @@ export type Favorite = {
id: Scalars['ID']; id: Scalars['ID'];
person?: Maybe<Person>; person?: Maybe<Person>;
personId?: Maybe<Scalars['String']>; personId?: Maybe<Scalars['String']>;
position: Scalars['Float'];
workspaceId?: Maybe<Scalars['String']>; workspaceId?: Maybe<Scalars['String']>;
workspaceMember?: Maybe<WorkspaceMember>; workspaceMember?: Maybe<WorkspaceMember>;
workspaceMemberId?: Maybe<Scalars['String']>; workspaceMemberId?: Maybe<Scalars['String']>;
@ -1247,16 +1248,24 @@ export type FavoriteListRelationFilter = {
export type FavoriteMutationForCompanyArgs = { export type FavoriteMutationForCompanyArgs = {
companyId: Scalars['String']; companyId: Scalars['String'];
position: Scalars['Float'];
}; };
export type FavoriteMutationForPersonArgs = { export type FavoriteMutationForPersonArgs = {
personId: Scalars['String']; personId: Scalars['String'];
position: Scalars['Float'];
}; };
export type FavoriteOrderByRelationAggregateInput = { export type FavoriteOrderByRelationAggregateInput = {
_count?: InputMaybe<SortOrder>; _count?: InputMaybe<SortOrder>;
}; };
export type FavoriteUpdateInput = {
id?: InputMaybe<Scalars['String']>;
position?: InputMaybe<Scalars['Float']>;
workspaceId?: InputMaybe<Scalars['String']>;
};
export type FavoriteUpdateManyWithoutCompanyNestedInput = { export type FavoriteUpdateManyWithoutCompanyNestedInput = {
connect?: InputMaybe<Array<FavoriteWhereUniqueInput>>; connect?: InputMaybe<Array<FavoriteWhereUniqueInput>>;
disconnect?: InputMaybe<Array<FavoriteWhereUniqueInput>>; disconnect?: InputMaybe<Array<FavoriteWhereUniqueInput>>;
@ -1282,6 +1291,7 @@ export type FavoriteWhereInput = {
companyId?: InputMaybe<StringNullableFilter>; companyId?: InputMaybe<StringNullableFilter>;
id?: InputMaybe<StringFilter>; id?: InputMaybe<StringFilter>;
personId?: InputMaybe<StringNullableFilter>; personId?: InputMaybe<StringNullableFilter>;
position?: InputMaybe<FloatFilter>;
workspaceId?: InputMaybe<StringNullableFilter>; workspaceId?: InputMaybe<StringNullableFilter>;
workspaceMemberId?: InputMaybe<StringNullableFilter>; workspaceMemberId?: InputMaybe<StringNullableFilter>;
}; };
@ -1413,6 +1423,7 @@ export type Mutation = {
signUp: LoginToken; signUp: LoginToken;
updateOneActivity: Activity; updateOneActivity: Activity;
updateOneCompany?: Maybe<Company>; updateOneCompany?: Maybe<Company>;
updateOneFavorites: Favorite;
updateOneField: Field; updateOneField: Field;
updateOneObject: Object; updateOneObject: Object;
updateOnePerson?: Maybe<Person>; updateOnePerson?: Maybe<Person>;
@ -1637,6 +1648,12 @@ export type MutationUpdateOneCompanyArgs = {
}; };
export type MutationUpdateOneFavoritesArgs = {
data: FavoriteUpdateInput;
where: FavoriteWhereUniqueInput;
};
export type MutationUpdateOnePersonArgs = { export type MutationUpdateOnePersonArgs = {
data: PersonUpdateInput; data: PersonUpdateInput;
where: PersonWhereUniqueInput; where: PersonWhereUniqueInput;
@ -3854,10 +3871,18 @@ export type InsertPersonFavoriteMutationVariables = Exact<{
export type InsertPersonFavoriteMutation = { __typename?: 'Mutation', createFavoriteForPerson: { __typename?: 'Favorite', id: string, person?: { __typename?: 'Person', id: string, firstName?: string | null, lastName?: string | null, displayName: string } | null } }; export type InsertPersonFavoriteMutation = { __typename?: 'Mutation', createFavoriteForPerson: { __typename?: 'Favorite', id: string, person?: { __typename?: 'Person', id: string, firstName?: string | null, lastName?: string | null, displayName: string } | null } };
export type UpdateOneFavoriteMutationVariables = Exact<{
data: FavoriteUpdateInput;
where: FavoriteWhereUniqueInput;
}>;
export type UpdateOneFavoriteMutation = { __typename?: 'Mutation', updateOneFavorites: { __typename?: 'Favorite', id: string, person?: { __typename?: 'Person', id: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } | null, company?: { __typename?: 'Company', id: string, name: string, domainName: string, accountOwner?: { __typename?: 'User', id: string, displayName: string, avatarUrl?: string | null } | null } | null } };
export type GetFavoritesQueryVariables = Exact<{ [key: string]: never; }>; export type GetFavoritesQueryVariables = Exact<{ [key: string]: never; }>;
export type GetFavoritesQuery = { __typename?: 'Query', findFavorites: Array<{ __typename?: 'Favorite', id: string, person?: { __typename?: 'Person', id: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } | null, company?: { __typename?: 'Company', id: string, name: string, domainName: string, accountOwner?: { __typename?: 'User', id: string, displayName: string, avatarUrl?: string | null } | null } | null }> }; export type GetFavoritesQuery = { __typename?: 'Query', findFavorites: Array<{ __typename?: 'Favorite', id: string, position: number, person?: { __typename?: 'Person', id: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } | null, company?: { __typename?: 'Company', id: string, name: string, domainName: string, accountOwner?: { __typename?: 'User', id: string, displayName: string, avatarUrl?: string | null } | null } | null }> };
export type BasePersonFieldsFragmentFragment = { __typename?: 'Person', id: string, phone?: string | null, email?: string | null, city?: string | null, firstName?: string | null, lastName?: string | null, displayName: string, avatarUrl?: string | null, createdAt: string }; export type BasePersonFieldsFragmentFragment = { __typename?: 'Person', id: string, phone?: string | null, email?: string | null, city?: string | null, firstName?: string | null, lastName?: string | null, displayName: string, avatarUrl?: string | null, createdAt: string };
@ -5589,10 +5614,61 @@ export function useInsertPersonFavoriteMutation(baseOptions?: Apollo.MutationHoo
export type InsertPersonFavoriteMutationHookResult = ReturnType<typeof useInsertPersonFavoriteMutation>; export type InsertPersonFavoriteMutationHookResult = ReturnType<typeof useInsertPersonFavoriteMutation>;
export type InsertPersonFavoriteMutationResult = Apollo.MutationResult<InsertPersonFavoriteMutation>; export type InsertPersonFavoriteMutationResult = Apollo.MutationResult<InsertPersonFavoriteMutation>;
export type InsertPersonFavoriteMutationOptions = Apollo.BaseMutationOptions<InsertPersonFavoriteMutation, InsertPersonFavoriteMutationVariables>; export type InsertPersonFavoriteMutationOptions = Apollo.BaseMutationOptions<InsertPersonFavoriteMutation, InsertPersonFavoriteMutationVariables>;
export const UpdateOneFavoriteDocument = gql`
mutation UpdateOneFavorite($data: FavoriteUpdateInput!, $where: FavoriteWhereUniqueInput!) {
updateOneFavorites(data: $data, where: $where) {
id
person {
id
firstName
lastName
avatarUrl
}
company {
id
name
domainName
accountOwner {
id
displayName
avatarUrl
}
}
}
}
`;
export type UpdateOneFavoriteMutationFn = Apollo.MutationFunction<UpdateOneFavoriteMutation, UpdateOneFavoriteMutationVariables>;
/**
* __useUpdateOneFavoriteMutation__
*
* To run a mutation, you first call `useUpdateOneFavoriteMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useUpdateOneFavoriteMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [updateOneFavoriteMutation, { data, loading, error }] = useUpdateOneFavoriteMutation({
* variables: {
* data: // value for 'data'
* where: // value for 'where'
* },
* });
*/
export function useUpdateOneFavoriteMutation(baseOptions?: Apollo.MutationHookOptions<UpdateOneFavoriteMutation, UpdateOneFavoriteMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<UpdateOneFavoriteMutation, UpdateOneFavoriteMutationVariables>(UpdateOneFavoriteDocument, options);
}
export type UpdateOneFavoriteMutationHookResult = ReturnType<typeof useUpdateOneFavoriteMutation>;
export type UpdateOneFavoriteMutationResult = Apollo.MutationResult<UpdateOneFavoriteMutation>;
export type UpdateOneFavoriteMutationOptions = Apollo.BaseMutationOptions<UpdateOneFavoriteMutation, UpdateOneFavoriteMutationVariables>;
export const GetFavoritesDocument = gql` export const GetFavoritesDocument = gql`
query GetFavorites { query GetFavorites {
findFavorites { findFavorites {
id id
position
person { person {
id id
firstName firstName

View File

@ -1,11 +1,17 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList';
import NavItem from '@/ui/navigation/navbar/components/NavItem'; import NavItem from '@/ui/navigation/navbar/components/NavItem';
import NavTitle from '@/ui/navigation/navbar/components/NavTitle'; import NavTitle from '@/ui/navigation/navbar/components/NavTitle';
import { Avatar } from '@/users/components/Avatar'; import { Avatar } from '@/users/components/Avatar';
import { useGetFavoritesQuery } from '~/generated/graphql'; import { useGetFavoritesQuery } from '~/generated/graphql';
import { getLogoUrlFromDomainName } from '~/utils'; import { getLogoUrlFromDomainName } from '~/utils';
import { useFavorites } from '../hooks/useFavorites';
import { favoritesState } from '../states/favoritesState';
const StyledContainer = styled.div` const StyledContainer = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -14,46 +20,94 @@ const StyledContainer = styled.div`
`; `;
export const Favorites = () => { export const Favorites = () => {
const { data } = useGetFavoritesQuery(); const [favorites, setFavorites] = useRecoilState(favoritesState);
const favorites = data?.findFavorites; const { handleReorderFavorite } = useFavorites();
useGetFavoritesQuery({
onCompleted: (data) =>
setFavorites(
data?.findFavorites.map((favorite) => {
return {
id: favorite.id,
person: favorite.person
? {
id: favorite.person.id,
firstName: favorite.person.firstName,
lastName: favorite.person.lastName,
avatarUrl: favorite.person.avatarUrl,
}
: undefined,
company: favorite.company
? {
id: favorite.company.id,
name: favorite.company.name,
domainName: favorite.company.domainName,
}
: undefined,
position: favorite.position,
};
}) ?? [],
),
});
if (!favorites || favorites.length === 0) return <></>; if (!favorites || favorites.length === 0) return <></>;
return ( return (
<StyledContainer> <StyledContainer>
<NavTitle label="Favorites" /> <NavTitle label="Favorites" />
{favorites.map( <DraggableList
({ id, person, company }) => onDragEnd={handleReorderFavorite}
(person && ( draggableItems={
<NavItem <>
key={id} {favorites.map((favorite, index) => {
label={`${person.firstName} ${person.lastName}`} const { id, person, company } = favorite;
Icon={() => ( return (
<Avatar <DraggableItem
colorId={person.id} key={id}
avatarUrl={person.avatarUrl ?? ''} draggableId={id}
type="rounded" index={index}
placeholder={`${person.firstName} ${person.lastName}`} itemComponent={
<>
{person && (
<NavItem
key={id}
label={`${person.firstName} ${person.lastName}`}
Icon={() => (
<Avatar
colorId={person.id}
avatarUrl={person.avatarUrl ?? ''}
type="rounded"
placeholder={`${person.firstName} ${person.lastName}`}
/>
)}
to={`/person/${person.id}`}
/>
)}
{company && (
<NavItem
key={id}
label={company.name}
Icon={() => (
<Avatar
avatarUrl={
getLogoUrlFromDomainName(company.domainName) ??
''
}
type="squared"
placeholder={company.name}
/>
)}
to={`/companies/${company.id}`}
/>
)}
</>
}
/> />
)} );
to={`/person/${person.id}`} })}
/> </>
)) ?? }
(company && ( />
<NavItem
key={id}
label={company.name}
Icon={() => (
<Avatar
avatarUrl={getLogoUrlFromDomainName(company.domainName) ?? ''}
type="squared"
placeholder={company.name}
/>
)}
to={`/companies/${company.id}`}
/>
)),
)}
</StyledContainer> </StyledContainer>
); );
}; };

View File

@ -0,0 +1,28 @@
import { gql } from '@apollo/client';
export const UPDATE_FAVORITE = gql`
mutation UpdateOneFavorite(
$data: FavoriteUpdateInput!
$where: FavoriteWhereUniqueInput!
) {
updateOneFavorites(data: $data, where: $where) {
id
person {
id
firstName
lastName
avatarUrl
}
company {
id
name
domainName
accountOwner {
id
displayName
avatarUrl
}
}
}
}
`;

View File

@ -4,6 +4,7 @@ export const GET_FAVORITES = gql`
query GetFavorites { query GetFavorites {
findFavorites { findFavorites {
id id
position
person { person {
id id
firstName firstName

View File

@ -1,25 +1,34 @@
import { getOperationName } from '@apollo/client/utilities'; import { getOperationName } from '@apollo/client/utilities';
import { OnDragEndResponder } from '@hello-pangea/dnd';
import { useRecoilState } from 'recoil';
import { GET_COMPANY } from '@/companies/graphql/queries/getCompany'; import { GET_COMPANY } from '@/companies/graphql/queries/getCompany';
import { GET_PERSON } from '@/people/graphql/queries/getPerson'; import { GET_PERSON } from '@/people/graphql/queries/getPerson';
import { import {
Favorite,
useDeleteFavoriteMutation, useDeleteFavoriteMutation,
useInsertCompanyFavoriteMutation, useInsertCompanyFavoriteMutation,
useInsertPersonFavoriteMutation, useInsertPersonFavoriteMutation,
useUpdateOneFavoriteMutation,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { GET_FAVORITES } from '../graphql/queries/getFavorites'; import { GET_FAVORITES } from '../graphql/queries/getFavorites';
import { favoritesState } from '../states/favoritesState';
export const useFavorites = () => { export const useFavorites = () => {
const [favorites, setFavorites] = useRecoilState(favoritesState);
const [insertCompanyFavoriteMutation] = useInsertCompanyFavoriteMutation(); const [insertCompanyFavoriteMutation] = useInsertCompanyFavoriteMutation();
const [insertPersonFavoriteMutation] = useInsertPersonFavoriteMutation(); const [insertPersonFavoriteMutation] = useInsertPersonFavoriteMutation();
const [deleteFavoriteMutation] = useDeleteFavoriteMutation(); const [deleteFavoriteMutation] = useDeleteFavoriteMutation();
const [updateOneFavoritesMutation] = useUpdateOneFavoriteMutation();
const insertCompanyFavorite = (companyId: string) => { const insertCompanyFavorite = (companyId: string) => {
insertCompanyFavoriteMutation({ insertCompanyFavoriteMutation({
variables: { variables: {
data: { data: {
companyId, companyId,
position: favorites.length + 1,
}, },
}, },
refetchQueries: [ refetchQueries: [
@ -34,6 +43,7 @@ export const useFavorites = () => {
variables: { variables: {
data: { data: {
personId, personId,
position: favorites.length + 1,
}, },
}, },
refetchQueries: [ refetchQueries: [
@ -43,6 +53,25 @@ export const useFavorites = () => {
}); });
}; };
const updateFavoritePosition = async (
favorites: Pick<Favorite, 'id' | 'position'>,
) => {
await updateOneFavoritesMutation({
variables: {
data: {
position: favorites?.position,
},
where: {
id: favorites.id,
},
},
refetchQueries: [
getOperationName(GET_FAVORITES) ?? '',
getOperationName(GET_PERSON) ?? '',
getOperationName(GET_COMPANY) ?? '',
],
});
};
const deleteCompanyFavorite = (companyId: string) => { const deleteCompanyFavorite = (companyId: string) => {
deleteFavoriteMutation({ deleteFavoriteMutation({
variables: { variables: {
@ -75,10 +104,37 @@ export const useFavorites = () => {
}); });
}; };
const computeNewPosition = (destIndex: number) => {
if (destIndex === 0) {
return favorites[destIndex].position / 2;
}
if (destIndex === favorites.length - 1) {
return favorites[destIndex].position + 1;
}
return (
(favorites[destIndex - 1].position + favorites[destIndex].position) / 2
);
};
const handleReorderFavorite: OnDragEndResponder = (result) => {
if (!result.destination || !favorites) {
return;
}
const newPosition = computeNewPosition(result.destination.index);
const reorderFavorites = Array.from(favorites);
const [removed] = reorderFavorites.splice(result.source.index, 1);
const removedFav = { ...removed, position: newPosition };
reorderFavorites.splice(result.destination.index, 0, removedFav);
setFavorites(reorderFavorites);
updateFavoritePosition(removedFav);
};
return { return {
insertCompanyFavorite, insertCompanyFavorite,
insertPersonFavorite, insertPersonFavorite,
deleteCompanyFavorite, deleteCompanyFavorite,
deletePersonFavorite, deletePersonFavorite,
handleReorderFavorite,
}; };
}; };

View File

@ -0,0 +1,16 @@
import { atom } from 'recoil';
import { Company, Favorite, Person } from '~/generated/graphql';
export const favoritesState = atom<
Array<
Pick<Favorite, 'id' | 'position'> & {
company?: Pick<Company, 'id' | 'name' | 'domainName'>;
} & {
person?: Pick<Person, 'id' | 'firstName' | 'lastName' | 'avatarUrl'>;
}
>
>({
key: 'favoritesState',
default: [],
});

View File

@ -27,7 +27,7 @@ type StyledItemProps = {
soon?: boolean; soon?: boolean;
}; };
const StyledItem = styled.button<StyledItemProps>` const StyledItem = styled.div<StyledItemProps>`
align-items: center; align-items: center;
background: ${(props) => background: ${(props) =>
props.active ? props.theme.background.transparent.light : 'inherit'}; props.active ? props.theme.background.transparent.light : 'inherit'};

View File

@ -201,6 +201,7 @@ export class AbilityFactory {
// Favorite // Favorite
can(AbilityAction.Read, 'Favorite', { workspaceId: workspace.id }); can(AbilityAction.Read, 'Favorite', { workspaceId: workspace.id });
can(AbilityAction.Create, 'Favorite'); can(AbilityAction.Create, 'Favorite');
can(AbilityAction.Update, 'Favorite', { workspaceId: workspace.id });
can(AbilityAction.Delete, 'Favorite', { workspaceId: workspace.id }); can(AbilityAction.Delete, 'Favorite', { workspaceId: workspace.id });
return build(); return build();

View File

@ -103,6 +103,7 @@ import {
CreateFavoriteAbilityHandler, CreateFavoriteAbilityHandler,
ReadFavoriteAbilityHandler, ReadFavoriteAbilityHandler,
DeleteFavoriteAbilityHandler, DeleteFavoriteAbilityHandler,
UpdateFavoriteAbilityHandler,
} from './handlers/favorite.ability-handler'; } from './handlers/favorite.ability-handler';
import { import {
CreateViewSortAbilityHandler, CreateViewSortAbilityHandler,
@ -219,6 +220,7 @@ import {
//Favorite //Favorite
ReadFavoriteAbilityHandler, ReadFavoriteAbilityHandler,
CreateFavoriteAbilityHandler, CreateFavoriteAbilityHandler,
UpdateFavoriteAbilityHandler,
DeleteFavoriteAbilityHandler, DeleteFavoriteAbilityHandler,
// View // View
ReadViewAbilityHandler, ReadViewAbilityHandler,

View File

@ -57,6 +57,34 @@ export class CreateFavoriteAbilityHandler implements IAbilityHandler {
} }
} }
@Injectable()
export class UpdateFavoriteAbilityHandler implements IAbilityHandler {
constructor(private readonly prismaService: PrismaService) {}
async handle(ability: AppAbility, context: ExecutionContext) {
const gqlContext = GqlExecutionContext.create(context);
const args = gqlContext.getArgs<FavoriteArgs>();
const favorite = await this.prismaService.client.favorite.findFirst({
where: args.where,
});
assert(favorite, '', NotFoundException);
const allowed = await relationAbilityChecker(
'Favorite',
ability,
this.prismaService.client,
args,
);
if (!allowed) {
return false;
}
return ability.can(AbilityAction.Update, 'Favorite');
}
}
@Injectable() @Injectable()
export class DeleteFavoriteAbilityHandler implements IAbilityHandler { export class DeleteFavoriteAbilityHandler implements IAbilityHandler {
constructor(private readonly prismaService: PrismaService) {} constructor(private readonly prismaService: PrismaService) {}

View File

@ -17,21 +17,28 @@ import {
CreateFavoriteAbilityHandler, CreateFavoriteAbilityHandler,
DeleteFavoriteAbilityHandler, DeleteFavoriteAbilityHandler,
ReadFavoriteAbilityHandler, ReadFavoriteAbilityHandler,
UpdateFavoriteAbilityHandler,
} from 'src/ability/handlers/favorite.ability-handler'; } from 'src/ability/handlers/favorite.ability-handler';
import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator'; import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator';
import { FavoriteService } from 'src/core/favorite/services/favorite.service'; import { FavoriteService } from 'src/core/favorite/services/favorite.service';
import { FavoriteWhereInput } from 'src/core/@generated/favorite/favorite-where.input'; import { FavoriteWhereInput } from 'src/core/@generated/favorite/favorite-where.input';
import { SortOrder } from 'src/core/@generated/prisma/sort-order.enum';
import { UpdateOneFavoriteArgs } from 'src/core/@generated/favorite/update-one-favorite.args';
@InputType() @InputType()
class FavoriteMutationForPersonArgs { class FavoriteMutationForPersonArgs {
@Field(() => String) @Field(() => String)
personId: string; personId: string;
@Field(() => Number)
position: number;
} }
@InputType() @InputType()
class FavoriteMutationForCompanyArgs { class FavoriteMutationForCompanyArgs {
@Field(() => String) @Field(() => String)
companyId: string; companyId: string;
@Field(() => Number)
position: number;
} }
@UseGuards(JwtAuthGuard) @UseGuards(JwtAuthGuard)
@ -49,6 +56,7 @@ export class FavoriteResolver {
where: { where: {
workspaceId: workspace.id, workspaceId: workspace.id,
}, },
orderBy: [{ position: SortOrder.asc }],
include: { include: {
person: true, person: true,
company: { company: {
@ -86,6 +94,7 @@ export class FavoriteResolver {
connect: { id: args.personId }, connect: { id: args.personId },
}, },
workspaceId: workspace.id, workspaceId: workspace.id,
position: args.position,
}, },
select: prismaSelect.value, select: prismaSelect.value,
}); });
@ -115,11 +124,29 @@ export class FavoriteResolver {
connect: { id: args.companyId }, connect: { id: args.companyId },
}, },
workspaceId: workspace.id, workspaceId: workspace.id,
position: args.position,
}, },
select: prismaSelect.value, select: prismaSelect.value,
}); });
} }
@Mutation(() => Favorite, {
nullable: false,
})
@UseGuards(AbilityGuard)
@CheckAbilities(UpdateFavoriteAbilityHandler)
async updateOneFavorites(
@Args() args: UpdateOneFavoriteArgs,
@PrismaSelector({ modelName: 'Favorite' })
prismaSelect: PrismaSelect<'Favorite'>,
): Promise<Partial<Favorite>> {
return this.favoriteService.update({
data: args.data,
where: args.where,
select: prismaSelect.value,
});
}
@Mutation(() => Favorite, { @Mutation(() => Favorite, {
nullable: false, nullable: false,
}) })

View File

@ -0,0 +1,8 @@
/*
Warnings:
- Added the required column `position` to the `favorites` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "favorites" ADD COLUMN "position" DOUBLE PRECISION NOT NULL;

View File

@ -789,6 +789,7 @@ model Favorite {
/// @TypeGraphQL.omit(input: true, output: false) /// @TypeGraphQL.omit(input: true, output: false)
workspaceMember WorkspaceMember? @relation(fields: [workspaceMemberId], references: [id]) workspaceMember WorkspaceMember? @relation(fields: [workspaceMemberId], references: [id])
workspaceMemberId String? workspaceMemberId String?
position Float
@@map("favorites") @@map("favorites")
} }
@ -892,19 +893,19 @@ model ViewField {
model ApiKey { model ApiKey {
/// @Validator.IsString() /// @Validator.IsString()
/// @Validator.IsOptional() /// @Validator.IsOptional()
id String @id @default(uuid()) id String @id @default(uuid())
name String name String
/// @TypeGraphQL.omit(input: true, output: true) /// @TypeGraphQL.omit(input: true, output: true)
workspace Workspace @relation(fields: [workspaceId], references: [id]) workspace Workspace @relation(fields: [workspaceId], references: [id])
/// @TypeGraphQL.omit(input: true, output: true) /// @TypeGraphQL.omit(input: true, output: true)
workspaceId String workspaceId String
expiresAt DateTime? expiresAt DateTime?
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
/// @TypeGraphQL.omit(input: true, output: true) /// @TypeGraphQL.omit(input: true, output: true)
deletedAt DateTime? deletedAt DateTime?
/// @TypeGraphQL.omit(input: true, output: true) /// @TypeGraphQL.omit(input: true, output: true)
revokedAt DateTime? revokedAt DateTime?
@@map("api_keys") @@map("api_keys")
} }