5899 display a banner to alert users which need to reconnect their account (#6301)

Closes #5899

<img width="1280" alt="Index - banner"
src="https://github.com/twentyhq/twenty/assets/71827178/313cf20d-eb34-496a-8c7c-7589fbd55954">

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
bosiraphael
2024-07-27 18:34:52 +02:00
committed by GitHub
parent d0db3b765f
commit 6728e40256
48 changed files with 910 additions and 147 deletions

View File

@ -1,5 +1,6 @@
import { Field, ObjectType } from '@nestjs/graphql';
import { IDField } from '@ptc-org/nestjs-query-graphql';
import {
Column,
CreateDateColumn,
@ -12,12 +13,17 @@ import {
Unique,
UpdateDateColumn,
} from 'typeorm';
import { IDField } from '@ptc-org/nestjs-query-graphql';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { User } from 'src/engine/core-modules/user/user.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
export enum KeyValuePairType {
USER_VAR = 'USER_VAR',
FEATURE_FLAG = 'FEATURE_FLAG',
SYSTEM_VAR = 'SYSTEM_VAR',
}
@Entity({ name: 'keyValuePair', schema: 'core' })
@ObjectType('KeyValuePair')
@Unique('IndexOnKeyUserIdWorkspaceIdUnique', ['key', 'userId', 'workspaceId'])
@ -41,7 +47,7 @@ export class KeyValuePair {
user: Relation<User>;
@Column({ nullable: true })
userId: string;
userId: string | null;
@ManyToOne(() => Workspace, (workspace) => workspace.keyValuePairs, {
onDelete: 'CASCADE',
@ -50,15 +56,28 @@ export class KeyValuePair {
workspace: Relation<Workspace>;
@Column({ nullable: true })
workspaceId: string;
workspaceId: string | null;
@Field(() => String)
@Column({ nullable: false, type: 'text' })
key: string;
@Field(() => String, { nullable: true })
@Column({ nullable: true, type: 'text' })
value: string;
@Field(() => JSON, { nullable: true })
@Column('jsonb', { nullable: true })
value: JSON;
@Field(() => String)
@Column({ nullable: false, type: 'text' })
textValueDeprecated: string;
@Field(() => KeyValuePairType)
@Column({
type: 'enum',
enum: Object.values(KeyValuePairType),
nullable: false,
default: KeyValuePairType.USER_VAR,
})
type: KeyValuePairType;
@CreateDateColumn({ type: 'timestamptz' })
createdAt: Date;

View File

@ -1,59 +1,79 @@
import { InjectRepository } from '@nestjs/typeorm';
import { BadRequestException } from '@nestjs/common';
import { Repository } from 'typeorm';
import { IsNull, Repository } from 'typeorm';
import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
import {
KeyValuePair,
KeyValuePairType,
} from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
export class KeyValuePairService<TYPE> {
export class KeyValuePairService<
KeyValueTypesMap extends Record<string, any> = Record<string, any>,
> {
constructor(
@InjectRepository(KeyValuePair, 'core')
private readonly keyValuePairRepository: Repository<KeyValuePair>,
) {}
async get<K extends keyof TYPE>({
async get<K extends keyof KeyValueTypesMap>({
userId,
workspaceId,
type,
key,
}: {
userId?: string;
workspaceId?: string;
key: K;
}): Promise<TYPE[K] | undefined> {
return (
await this.keyValuePairRepository.findOne({
where: {
userId,
workspaceId,
key: key as string,
},
})
)?.value as TYPE[K] | undefined;
userId?: string | null;
workspaceId?: string | null;
type: KeyValuePairType;
key?: Extract<K, string>;
}): Promise<Array<KeyValueTypesMap[K]>> {
const keyValuePairs = (await this.keyValuePairRepository.find({
where: {
...(userId === undefined
? {}
: userId === null
? { userId: IsNull() }
: { userId }),
...(workspaceId === undefined
? {}
: workspaceId === null
? { workspaceId: IsNull() }
: { workspaceId }),
...(key === undefined ? {} : { key }),
type,
},
})) as Array<KeyValueTypesMap[K]>;
return keyValuePairs.map((keyValuePair) => ({
...keyValuePair,
value: keyValuePair.value ?? keyValuePair.textValueDeprecated,
}));
}
async set<K extends keyof TYPE>({
async set<K extends keyof KeyValueTypesMap>({
userId,
workspaceId,
key,
value,
type,
}: {
userId?: string;
workspaceId?: string;
key: K;
value: TYPE[K];
userId?: string | null;
workspaceId?: string | null;
key: Extract<K, string>;
value: KeyValueTypesMap[K];
type: KeyValuePairType;
}) {
if (!userId && !workspaceId) {
throw new BadRequestException('userId and workspaceId are undefined');
}
const upsertData = {
userId,
workspaceId,
key: key as string,
value: value as string,
key,
value,
type,
};
const conflictPaths = Object.keys(upsertData).filter(
(key) => key !== 'value' && upsertData[key] !== undefined,
(key) =>
['userId', 'workspaceId', 'key'].includes(key) &&
upsertData[key] !== undefined,
);
const indexPredicate = !userId
@ -67,4 +87,31 @@ export class KeyValuePairService<TYPE> {
indexPredicate,
});
}
async delete({
userId,
workspaceId,
type,
key,
}: {
userId?: string | null;
workspaceId?: string | null;
type: KeyValuePairType;
key: Extract<keyof KeyValueTypesMap, string>;
}) {
await this.keyValuePairRepository.delete({
...(userId === undefined
? {}
: userId === null
? { userId: IsNull() }
: { userId }),
...(workspaceId === undefined
? {}
: workspaceId === null
? { workspaceId: IsNull() }
: { workspaceId }),
type,
key,
});
}
}