diff --git a/front/src/components/editable-cell/EditableChip.tsx b/front/src/components/editable-cell/EditableChip.tsx index 8e5cb2627..81516008c 100644 --- a/front/src/components/editable-cell/EditableChip.tsx +++ b/front/src/components/editable-cell/EditableChip.tsx @@ -25,7 +25,7 @@ const StyledInplaceInput = styled.input` } `; -const StyledInplaceShow = styled.input` +const StyledInplaceShow = styled.div` width: 100%; border: none; outline: none; diff --git a/front/src/components/form/Checkbox.tsx b/front/src/components/form/Checkbox.tsx index 10ca8a473..05781e0e7 100644 --- a/front/src/components/form/Checkbox.tsx +++ b/front/src/components/form/Checkbox.tsx @@ -56,7 +56,7 @@ function Checkbox({ name, id, checked, onChange, indeterminate }: OwnProps) { name={name} checked={checked} onChange={onChange} - > + /> ); } diff --git a/front/src/components/table/table-header/__stories__/SortDropdownButton.stories.tsx b/front/src/components/table/table-header/__stories__/SortDropdownButton.stories.tsx index 17427a835..ebc02ccb8 100644 --- a/front/src/components/table/table-header/__stories__/SortDropdownButton.stories.tsx +++ b/front/src/components/table/table-header/__stories__/SortDropdownButton.stories.tsx @@ -33,14 +33,14 @@ const availableSorts = [ label: 'People', icon: , _type: 'custom_sort', - orderByTemplate: () => ({ email: Order_By.Asc }), + orderByTemplates: [() => ({ email: Order_By.Asc })], }, { key: 'company_name', label: 'Company', icon: , _type: 'custom_sort', - orderByTemplate: () => ({ email: Order_By.Asc }), + orderByTemplates: [() => ({ email: Order_By.Asc })], }, { key: 'email', diff --git a/front/src/components/table/table-header/helpers.ts b/front/src/components/table/table-header/helpers.ts index b80eedb16..1304ca642 100644 --- a/front/src/components/table/table-header/helpers.ts +++ b/front/src/components/table/table-header/helpers.ts @@ -33,9 +33,13 @@ export const reduceSortsToOrderBy = ( sorts: Array>, ): OrderByTemplate[] => { const mappedSorts = sorts.map((sort) => { - if (sort._type === 'custom_sort') - return sort.orderByTemplate(mapOrderToOrder_By(sort.order)); + if (sort._type === 'custom_sort') { + return sort.orderByTemplates.map((orderByTemplate) => + orderByTemplate(mapOrderToOrder_By(sort.order)), + ); + } + return defaultOrderByTemplateFactory(sort.key as string)(sort.order); }); - return mappedSorts as OrderByTemplate[]; + return mappedSorts.flat() as OrderByTemplate[]; }; diff --git a/front/src/interfaces/sorts/interface.ts b/front/src/interfaces/sorts/interface.ts index 8e6c949de..b5d64afb7 100644 --- a/front/src/interfaces/sorts/interface.ts +++ b/front/src/interfaces/sorts/interface.ts @@ -13,7 +13,7 @@ export type SortType = label: string; key: string; icon?: ReactNode; - orderByTemplate: (order: Order_By) => OrderByTemplate; + orderByTemplates: Array<(order: Order_By) => OrderByTemplate>; }; export type SelectedSortType = SortType & { diff --git a/front/src/pages/people/people-sorts.tsx b/front/src/pages/people/people-sorts.tsx index 62faa7fb9..e1a2de4d9 100644 --- a/front/src/pages/people/people-sorts.tsx +++ b/front/src/pages/people/people-sorts.tsx @@ -18,17 +18,21 @@ export const availableSorts = [ label: 'People', icon: , _type: 'custom_sort', - orderByTemplate: (order: Order_By) => ({ - firstname: order, - lastname: order, - }), + orderByTemplates: [ + (order: Order_By) => ({ + firstname: order, + }), + (order: Order_By) => ({ + lastname: order, + }), + ], }, { key: 'company_name', label: 'Company', icon: , _type: 'custom_sort', - orderByTemplate: (order: Order_By) => ({ company: { name: order } }), + orderByTemplates: [(order: Order_By) => ({ company: { name: order } })], }, { key: 'email', diff --git a/front/src/services/api/users/index.tsx b/front/src/services/api/users/index.tsx index 77d71b281..84f30b30f 100644 --- a/front/src/services/api/users/index.tsx +++ b/front/src/services/api/users/index.tsx @@ -2,7 +2,7 @@ import { QueryResult, gql, useQuery } from '@apollo/client'; import { GraphqlQueryUser } from '../../../interfaces/entities/user.interface'; export const GET_CURRENT_USER = gql` - query getUser($uuid: String) { + query getCurrentUser($uuid: String) { users(where: { id: { equals: $uuid } }) { id email diff --git a/front/src/services/auth/AuthService.ts b/front/src/services/auth/AuthService.ts index 0f53d4d06..f612d90d6 100644 --- a/front/src/services/auth/AuthService.ts +++ b/front/src/services/auth/AuthService.ts @@ -13,7 +13,7 @@ export const getUserIdFromToken: () => string | null = () => { } try { - return jwt<{ sub: string }>(accessToken).sub; + return jwt<{ userId: string }>(accessToken).userId; } catch (error) { return null; } diff --git a/server/src/api/api.module.ts b/server/src/api/api.module.ts index 8ce428f5c..5c298aa8a 100644 --- a/server/src/api/api.module.ts +++ b/server/src/api/api.module.ts @@ -10,6 +10,7 @@ import { PeopleResolver } from './resolvers/people.resolver'; import { PersonRelationsResolver } from './resolvers/relations/people-relations.resolver'; import { UserRelationsResolver } from './resolvers/relations/user-relations.resolver'; import { WorkspaceMemberRelationsResolver } from './resolvers/relations/workspace-member-relations.resolver'; +import { PrismaModule } from 'src/database/prisma.module'; @Module({ imports: [ @@ -17,6 +18,7 @@ import { WorkspaceMemberRelationsResolver } from './resolvers/relations/workspac driver: ApolloDriver, autoSchemaFile: true, }), + PrismaModule, ], providers: [ PrismaClient, diff --git a/server/src/api/resolvers/relation-resolver/workspace-member-relations.resolver.ts b/server/src/api/resolvers/relation-resolver/workspace-member-relations.resolver.ts deleted file mode 100644 index c23a4446d..000000000 --- a/server/src/api/resolvers/relation-resolver/workspace-member-relations.resolver.ts +++ /dev/null @@ -1,43 +0,0 @@ -import * as TypeGraphQL from '@nestjs/graphql'; -import type { GraphQLResolveInfo } from 'graphql'; -import { User } from '../../generated-graphql/models/User'; -import { Workspace } from '../../generated-graphql/models/Workspace'; -import { WorkspaceMember } from '../../generated-graphql/models/WorkspaceMember'; -import { PrismaClient } from '@prisma/client'; - -@TypeGraphQL.Resolver(() => WorkspaceMember) -export class WorkspaceMemberRelationsResolver { - constructor(private readonly prismaClient: PrismaClient) {} - - @TypeGraphQL.ResolveField(() => User, { - nullable: false, - }) - async user( - @TypeGraphQL.Parent() workspaceMember: WorkspaceMember, - @TypeGraphQL.Info() info: GraphQLResolveInfo, - ): Promise { - return this.prismaClient.workspaceMember - .findUniqueOrThrow({ - where: { - id: workspaceMember.id, - }, - }) - .user({}); - } - - @TypeGraphQL.ResolveField((_type) => Workspace, { - nullable: false, - }) - async workspace( - @TypeGraphQL.Parent() workspaceMember: WorkspaceMember, - @TypeGraphQL.Info() info: GraphQLResolveInfo, - ): Promise { - return this.prismaClient.workspaceMember - .findUniqueOrThrow({ - where: { - id: workspaceMember.id, - }, - }) - .workspace({}); - } -} diff --git a/server/src/api/resolvers/relations/user-relations.resolver.ts b/server/src/api/resolvers/relations/user-relations.resolver.ts index a76101e78..ae9d7a510 100644 --- a/server/src/api/resolvers/relations/user-relations.resolver.ts +++ b/server/src/api/resolvers/relations/user-relations.resolver.ts @@ -7,10 +7,11 @@ import { WorkspaceMember } from '../../generated-graphql/models/WorkspaceMember' import { PrismaClient } from '@prisma/client'; import { UserCompaniesArgs } from '../../generated-graphql/resolvers/relations/User/args/UserCompaniesArgs'; import { UserRefreshTokensArgs } from '../../generated-graphql/resolvers/relations/User/args/UserRefreshTokensArgs'; +import { PrismaService } from 'src/database/prisma.service'; @TypeGraphQL.Resolver(() => User) export class UserRelationsResolver { - constructor(private readonly prismaClient: PrismaClient) {} + constructor(private readonly prismaService: PrismaService) {} @TypeGraphQL.ResolveField(() => WorkspaceMember, { nullable: true, @@ -18,8 +19,8 @@ export class UserRelationsResolver { async WorkspaceMember( @TypeGraphQL.Parent() user: User, ): Promise { - return this.prismaClient.user - .findUniqueOrThrow({ + return await this.prismaService.user + .findFirst({ where: { id: user.id, }, @@ -35,7 +36,7 @@ export class UserRelationsResolver { @TypeGraphQL.Info() info: GraphQLResolveInfo, @TypeGraphQL.Args() args: UserCompaniesArgs, ): Promise { - return this.prismaClient.user + return this.prismaService.user .findUniqueOrThrow({ where: { id: user.id, @@ -54,7 +55,7 @@ export class UserRelationsResolver { @TypeGraphQL.Info() info: GraphQLResolveInfo, @TypeGraphQL.Args() args: UserRefreshTokensArgs, ): Promise { - return this.prismaClient.user + return this.prismaService.user .findUniqueOrThrow({ where: { id: user.id, diff --git a/server/src/api/resolvers/relations/workspace-member-relations.resolver.ts b/server/src/api/resolvers/relations/workspace-member-relations.resolver.ts index c23a4446d..4b3a952dd 100644 --- a/server/src/api/resolvers/relations/workspace-member-relations.resolver.ts +++ b/server/src/api/resolvers/relations/workspace-member-relations.resolver.ts @@ -4,10 +4,11 @@ import { User } from '../../generated-graphql/models/User'; import { Workspace } from '../../generated-graphql/models/Workspace'; import { WorkspaceMember } from '../../generated-graphql/models/WorkspaceMember'; import { PrismaClient } from '@prisma/client'; +import { PrismaService } from 'src/database/prisma.service'; @TypeGraphQL.Resolver(() => WorkspaceMember) export class WorkspaceMemberRelationsResolver { - constructor(private readonly prismaClient: PrismaClient) {} + constructor(private readonly prismaService: PrismaService) {} @TypeGraphQL.ResolveField(() => User, { nullable: false, @@ -16,7 +17,7 @@ export class WorkspaceMemberRelationsResolver { @TypeGraphQL.Parent() workspaceMember: WorkspaceMember, @TypeGraphQL.Info() info: GraphQLResolveInfo, ): Promise { - return this.prismaClient.workspaceMember + return await this.prismaService.workspaceMember .findUniqueOrThrow({ where: { id: workspaceMember.id, @@ -32,7 +33,7 @@ export class WorkspaceMemberRelationsResolver { @TypeGraphQL.Parent() workspaceMember: WorkspaceMember, @TypeGraphQL.Info() info: GraphQLResolveInfo, ): Promise { - return this.prismaClient.workspaceMember + return this.prismaService.workspaceMember .findUniqueOrThrow({ where: { id: workspaceMember.id, diff --git a/server/src/api/resolvers/user.resolver.ts b/server/src/api/resolvers/user.resolver.ts index 9c54595b9..d57f68db7 100644 --- a/server/src/api/resolvers/user.resolver.ts +++ b/server/src/api/resolvers/user.resolver.ts @@ -1,27 +1,27 @@ -import { PrismaClient } from '@prisma/client'; import { Person, User } from '../generated-graphql/models'; import { Resolver, Query, Args, Mutation } from '@nestjs/graphql'; import { FindManyUserArgs } from '../generated-graphql/resolvers/crud/User/args/FindManyUserArgs'; import { FindUniqueUserOrThrowArgs } from '../generated-graphql'; +import { PrismaService } from 'src/database/prisma.service'; @Resolver(() => User) export class UserResolver { - constructor(private readonly prismaClient: PrismaClient) {} + constructor(private readonly prismaService: PrismaService) {} @Query(() => [User], { nullable: false, }) async users(@Args() args: FindManyUserArgs): Promise { - return this.prismaClient.user.findMany({ + return await this.prismaService.user.findMany({ ...args, }); } @Query(() => User, { - nullable: true, + nullable: false, }) - async getUser(@Args() args: FindUniqueUserOrThrowArgs): Promise { - return this.prismaClient.user.findUniqueOrThrow({ + async user(@Args() args: FindUniqueUserOrThrowArgs): Promise { + return await this.prismaService.user.findUnique({ ...args, }); } diff --git a/server/src/app.module.ts b/server/src/app.module.ts index b8440ec61..f9b091f4d 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -8,12 +8,7 @@ import { AuthModule } from './auth/auth.module'; import { ConfigModule } from '@nestjs/config'; import { ApiModule } from './api/api.module'; @Module({ - imports: [ - ConfigModule.forRoot({}), - TerminusModule, - AuthModule, - ApiModule, - ], + imports: [ConfigModule.forRoot({}), TerminusModule, AuthModule, ApiModule], controllers: [AppController, HealthController], providers: [AppService], }) diff --git a/server/src/auth/auth.module.ts b/server/src/auth/auth.module.ts index 09639bc5f..d49f7ae84 100644 --- a/server/src/auth/auth.module.ts +++ b/server/src/auth/auth.module.ts @@ -12,18 +12,21 @@ import { RefreshTokenRepository } from 'src/entities/refresh-token/refresh-token import { PrismaService } from 'src/database/prisma.service'; @Module({ - imports: [JwtModule.registerAsync({ - useFactory: async (configService: ConfigService) => { - return { - secret: configService.get('JWT_SECRET'), - signOptions: { - expiresIn: configService.get('JWT_EXPIRES_IN'), - }, - }; - }, - imports: [ConfigModule.forRoot({})], - inject: [ConfigService], - }), ConfigModule.forRoot({})], + imports: [ + JwtModule.registerAsync({ + useFactory: async (configService: ConfigService) => { + return { + secret: configService.get('JWT_SECRET'), + signOptions: { + expiresIn: configService.get('JWT_EXPIRES_IN'), + }, + }; + }, + imports: [ConfigModule.forRoot({})], + inject: [ConfigService], + }), + ConfigModule.forRoot({}), + ], controllers: [GoogleAuthController, AuthController], providers: [ AuthService, @@ -35,4 +38,4 @@ import { PrismaService } from 'src/database/prisma.service'; PrismaService, ], }) -export class AuthModule {} \ No newline at end of file +export class AuthModule {} diff --git a/server/src/database/schema.prisma b/server/src/database/schema.prisma index afab93007..2f2ef6d1c 100644 --- a/server/src/database/schema.prisma +++ b/server/src/database/schema.prisma @@ -1,5 +1,6 @@ generator client { provider = "prisma-client-js" + engineType = "binary" } datasource db { diff --git a/server/src/entities/person/person.repository.ts b/server/src/entities/person/person.repository.ts index f18523c33..8e0beed50 100644 --- a/server/src/entities/person/person.repository.ts +++ b/server/src/entities/person/person.repository.ts @@ -4,16 +4,16 @@ import { PrismaService } from 'src/database/prisma.service'; @Injectable() export class PersonRepository { - constructor(private prisma: PrismaService) {} + constructor(private prisma: PrismaService) {} - async findMany(params: { - skip?: number; - take?: number; - cursor?: Prisma.PersonWhereUniqueInput; - where?: Prisma.PersonWhereInput; - orderBy?: Prisma.PersonOrderByWithRelationInput; - }): Promise { - const { skip, take, cursor, where, orderBy } = params; - return this.prisma.person.findMany({ skip, take, cursor, where, orderBy }); - } + async findMany(params: { + skip?: number; + take?: number; + cursor?: Prisma.PersonWhereUniqueInput; + where?: Prisma.PersonWhereInput; + orderBy?: Prisma.PersonOrderByWithRelationInput; + }): Promise { + const { skip, take, cursor, where, orderBy } = params; + return this.prisma.person.findMany({ skip, take, cursor, where, orderBy }); + } } diff --git a/server/src/prisma/prisma.module.ts b/server/src/prisma/prisma.module.ts new file mode 100644 index 000000000..ec0ce3291 --- /dev/null +++ b/server/src/prisma/prisma.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { PrismaService } from './prisma.service'; + +@Module({ + providers: [PrismaService], + exports: [PrismaService], +}) +export class PrismaModule {} diff --git a/server/src/prisma/prisma.service.ts b/server/src/prisma/prisma.service.ts new file mode 100644 index 000000000..edf653202 --- /dev/null +++ b/server/src/prisma/prisma.service.ts @@ -0,0 +1,15 @@ +import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common'; +import { PrismaClient } from '@prisma/client'; + +@Injectable() +export class PrismaService extends PrismaClient implements OnModuleInit { + async onModuleInit() { + await this.$connect(); + } + + async enableShutdownHooks(app: INestApplication) { + this.$on('beforeExit', async () => { + await app.close(); + }); + } +}