mirror of
https://github.com/twentyhq/twenty.git
synced 2024-11-23 05:53:31 +03:00
Refactor client config (#529)
* Refactor client config * Fix server tests * Fix lint
This commit is contained in:
parent
11d18cc269
commit
26b033abc9
2
front/.gitignore
vendored
2
front/.gitignore
vendored
@ -23,3 +23,5 @@ build-storybook.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
.nyc_output
|
||||
|
@ -29,6 +29,13 @@ export type Analytics = {
|
||||
success: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type AuthProviders = {
|
||||
__typename?: 'AuthProviders';
|
||||
google: Scalars['Boolean'];
|
||||
magicLink: Scalars['Boolean'];
|
||||
password: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type AuthToken = {
|
||||
__typename?: 'AuthToken';
|
||||
expiresAt: Scalars['DateTime'];
|
||||
@ -57,8 +64,10 @@ export type BoolFilter = {
|
||||
|
||||
export type ClientConfig = {
|
||||
__typename?: 'ClientConfig';
|
||||
display_google_login: Scalars['Boolean'];
|
||||
prefill_login_with_seed: Scalars['Boolean'];
|
||||
authProviders: AuthProviders;
|
||||
debugMode: Scalars['Boolean'];
|
||||
demoMode: Scalars['Boolean'];
|
||||
telemetry: Telemetry;
|
||||
};
|
||||
|
||||
export type Comment = {
|
||||
@ -756,11 +765,11 @@ export type CompanyOrderByRelationAggregateInput = {
|
||||
|
||||
export type CompanyOrderByWithRelationInput = {
|
||||
accountOwner?: InputMaybe<UserOrderByWithRelationInput>;
|
||||
accountOwnerId?: InputMaybe<SortOrderInput>;
|
||||
accountOwnerId?: InputMaybe<SortOrder>;
|
||||
address?: InputMaybe<SortOrder>;
|
||||
createdAt?: InputMaybe<SortOrder>;
|
||||
domainName?: InputMaybe<SortOrder>;
|
||||
employees?: InputMaybe<SortOrderInput>;
|
||||
employees?: InputMaybe<SortOrder>;
|
||||
id?: InputMaybe<SortOrder>;
|
||||
name?: InputMaybe<SortOrder>;
|
||||
people?: InputMaybe<PersonOrderByRelationAggregateInput>;
|
||||
@ -1247,11 +1256,6 @@ export type NullableStringFieldUpdateOperationsInput = {
|
||||
set?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export enum NullsOrder {
|
||||
First = 'first',
|
||||
Last = 'last'
|
||||
}
|
||||
|
||||
export type Person = {
|
||||
__typename?: 'Person';
|
||||
_commentCount: Scalars['Int'];
|
||||
@ -1332,7 +1336,7 @@ export type PersonOrderByRelationAggregateInput = {
|
||||
export type PersonOrderByWithRelationInput = {
|
||||
city?: InputMaybe<SortOrder>;
|
||||
company?: InputMaybe<CompanyOrderByWithRelationInput>;
|
||||
companyId?: InputMaybe<SortOrderInput>;
|
||||
companyId?: InputMaybe<SortOrder>;
|
||||
createdAt?: InputMaybe<SortOrder>;
|
||||
email?: InputMaybe<SortOrder>;
|
||||
firstName?: InputMaybe<SortOrder>;
|
||||
@ -1567,6 +1571,7 @@ export type PipelineProgressCreateInput = {
|
||||
|
||||
export type PipelineProgressCreateManyPipelineInput = {
|
||||
amount?: InputMaybe<Scalars['Int']>;
|
||||
closeDate?: InputMaybe<Scalars['DateTime']>;
|
||||
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||
id?: InputMaybe<Scalars['String']>;
|
||||
pipelineStageId: Scalars['String'];
|
||||
@ -1582,6 +1587,7 @@ export type PipelineProgressCreateManyPipelineInputEnvelope = {
|
||||
|
||||
export type PipelineProgressCreateManyPipelineStageInput = {
|
||||
amount?: InputMaybe<Scalars['Int']>;
|
||||
closeDate?: InputMaybe<Scalars['DateTime']>;
|
||||
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||
id?: InputMaybe<Scalars['String']>;
|
||||
pipelineId: Scalars['String'];
|
||||
@ -1597,6 +1603,7 @@ export type PipelineProgressCreateManyPipelineStageInputEnvelope = {
|
||||
|
||||
export type PipelineProgressCreateManyWorkspaceInput = {
|
||||
amount?: InputMaybe<Scalars['Int']>;
|
||||
closeDate?: InputMaybe<Scalars['DateTime']>;
|
||||
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||
id?: InputMaybe<Scalars['String']>;
|
||||
pipelineId: Scalars['String'];
|
||||
@ -1642,6 +1649,7 @@ export type PipelineProgressCreateOrConnectWithoutWorkspaceInput = {
|
||||
|
||||
export type PipelineProgressCreateWithoutPipelineInput = {
|
||||
amount?: InputMaybe<Scalars['Int']>;
|
||||
closeDate?: InputMaybe<Scalars['DateTime']>;
|
||||
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||
id?: InputMaybe<Scalars['String']>;
|
||||
pipelineStage: PipelineStageCreateNestedOneWithoutPipelineProgressesInput;
|
||||
@ -1652,6 +1660,7 @@ export type PipelineProgressCreateWithoutPipelineInput = {
|
||||
|
||||
export type PipelineProgressCreateWithoutPipelineStageInput = {
|
||||
amount?: InputMaybe<Scalars['Int']>;
|
||||
closeDate?: InputMaybe<Scalars['DateTime']>;
|
||||
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||
id?: InputMaybe<Scalars['String']>;
|
||||
pipeline: PipelineCreateNestedOneWithoutPipelineProgressesInput;
|
||||
@ -1662,6 +1671,7 @@ export type PipelineProgressCreateWithoutPipelineStageInput = {
|
||||
|
||||
export type PipelineProgressCreateWithoutWorkspaceInput = {
|
||||
amount?: InputMaybe<Scalars['Int']>;
|
||||
closeDate?: InputMaybe<Scalars['DateTime']>;
|
||||
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||
id?: InputMaybe<Scalars['String']>;
|
||||
pipeline: PipelineCreateNestedOneWithoutPipelineProgressesInput;
|
||||
@ -1682,8 +1692,8 @@ export type PipelineProgressOrderByRelationAggregateInput = {
|
||||
};
|
||||
|
||||
export type PipelineProgressOrderByWithRelationInput = {
|
||||
amount?: InputMaybe<SortOrderInput>;
|
||||
closeDate?: InputMaybe<SortOrderInput>;
|
||||
amount?: InputMaybe<SortOrder>;
|
||||
closeDate?: InputMaybe<SortOrder>;
|
||||
createdAt?: InputMaybe<SortOrder>;
|
||||
id?: InputMaybe<SortOrder>;
|
||||
pipeline?: InputMaybe<PipelineOrderByWithRelationInput>;
|
||||
@ -1714,6 +1724,7 @@ export type PipelineProgressScalarWhereInput = {
|
||||
NOT?: InputMaybe<Array<PipelineProgressScalarWhereInput>>;
|
||||
OR?: InputMaybe<Array<PipelineProgressScalarWhereInput>>;
|
||||
amount?: InputMaybe<IntNullableFilter>;
|
||||
closeDate?: InputMaybe<DateTimeNullableFilter>;
|
||||
createdAt?: InputMaybe<DateTimeFilter>;
|
||||
id?: InputMaybe<StringFilter>;
|
||||
pipelineId?: InputMaybe<StringFilter>;
|
||||
@ -1737,6 +1748,7 @@ export type PipelineProgressUpdateInput = {
|
||||
|
||||
export type PipelineProgressUpdateManyMutationInput = {
|
||||
amount?: InputMaybe<NullableIntFieldUpdateOperationsInput>;
|
||||
closeDate?: InputMaybe<NullableDateTimeFieldUpdateOperationsInput>;
|
||||
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||
progressableId?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||
@ -1818,6 +1830,7 @@ export type PipelineProgressUpdateWithWhereUniqueWithoutWorkspaceInput = {
|
||||
|
||||
export type PipelineProgressUpdateWithoutPipelineInput = {
|
||||
amount?: InputMaybe<NullableIntFieldUpdateOperationsInput>;
|
||||
closeDate?: InputMaybe<NullableDateTimeFieldUpdateOperationsInput>;
|
||||
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||
pipelineStage?: InputMaybe<PipelineStageUpdateOneRequiredWithoutPipelineProgressesNestedInput>;
|
||||
@ -1828,6 +1841,7 @@ export type PipelineProgressUpdateWithoutPipelineInput = {
|
||||
|
||||
export type PipelineProgressUpdateWithoutPipelineStageInput = {
|
||||
amount?: InputMaybe<NullableIntFieldUpdateOperationsInput>;
|
||||
closeDate?: InputMaybe<NullableDateTimeFieldUpdateOperationsInput>;
|
||||
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||
pipeline?: InputMaybe<PipelineUpdateOneRequiredWithoutPipelineProgressesNestedInput>;
|
||||
@ -1838,6 +1852,7 @@ export type PipelineProgressUpdateWithoutPipelineStageInput = {
|
||||
|
||||
export type PipelineProgressUpdateWithoutWorkspaceInput = {
|
||||
amount?: InputMaybe<NullableIntFieldUpdateOperationsInput>;
|
||||
closeDate?: InputMaybe<NullableDateTimeFieldUpdateOperationsInput>;
|
||||
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||
pipeline?: InputMaybe<PipelineUpdateOneRequiredWithoutPipelineProgressesNestedInput>;
|
||||
@ -2356,11 +2371,6 @@ export enum SortOrder {
|
||||
Desc = 'desc'
|
||||
}
|
||||
|
||||
export type SortOrderInput = {
|
||||
nulls?: InputMaybe<NullsOrder>;
|
||||
sort: SortOrder;
|
||||
};
|
||||
|
||||
export type StringFieldUpdateOperationsInput = {
|
||||
set?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
@ -2395,6 +2405,12 @@ export type StringNullableFilter = {
|
||||
startsWith?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Telemetry = {
|
||||
__typename?: 'Telemetry';
|
||||
anonymizationEnabled: Scalars['Boolean'];
|
||||
enabled: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type User = {
|
||||
__typename?: 'User';
|
||||
avatarUrl?: Maybe<Scalars['String']>;
|
||||
@ -2476,7 +2492,7 @@ export type UserCreateWithoutWorkspaceMemberInput = {
|
||||
};
|
||||
|
||||
export type UserOrderByWithRelationInput = {
|
||||
avatarUrl?: InputMaybe<SortOrderInput>;
|
||||
avatarUrl?: InputMaybe<SortOrder>;
|
||||
comments?: InputMaybe<CommentOrderByRelationAggregateInput>;
|
||||
companies?: InputMaybe<CompanyOrderByRelationAggregateInput>;
|
||||
createdAt?: InputMaybe<SortOrder>;
|
||||
@ -2486,10 +2502,10 @@ export type UserOrderByWithRelationInput = {
|
||||
firstName?: InputMaybe<SortOrder>;
|
||||
id?: InputMaybe<SortOrder>;
|
||||
lastName?: InputMaybe<SortOrder>;
|
||||
lastSeen?: InputMaybe<SortOrderInput>;
|
||||
lastSeen?: InputMaybe<SortOrder>;
|
||||
locale?: InputMaybe<SortOrder>;
|
||||
metadata?: InputMaybe<SortOrderInput>;
|
||||
phoneNumber?: InputMaybe<SortOrderInput>;
|
||||
metadata?: InputMaybe<SortOrder>;
|
||||
phoneNumber?: InputMaybe<SortOrder>;
|
||||
updatedAt?: InputMaybe<SortOrder>;
|
||||
};
|
||||
|
||||
@ -2766,11 +2782,6 @@ export type CreateEventMutationVariables = Exact<{
|
||||
|
||||
export type CreateEventMutation = { __typename?: 'Mutation', createEvent: { __typename?: 'Analytics', success: boolean } };
|
||||
|
||||
export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', display_google_login: boolean, prefill_login_with_seed: boolean } };
|
||||
|
||||
export type ChallengeMutationVariables = Exact<{
|
||||
email: Scalars['String'];
|
||||
password: Scalars['String'];
|
||||
@ -2793,6 +2804,11 @@ export type RenewTokenMutationVariables = Exact<{
|
||||
|
||||
export type RenewTokenMutation = { __typename?: 'Mutation', renewToken: { __typename?: 'AuthTokens', tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', expiresAt: string, token: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
||||
|
||||
export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', demoMode: boolean, debugMode: boolean, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean }, telemetry: { __typename?: 'Telemetry', enabled: boolean, anonymizationEnabled: boolean } } };
|
||||
|
||||
export type CreateCommentMutationVariables = Exact<{
|
||||
commentId: Scalars['String'];
|
||||
commentText: Scalars['String'];
|
||||
@ -2954,7 +2970,7 @@ export type UpdateOnePipelineProgressMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateOnePipelineProgressMutation = { __typename?: 'Mutation', updateOnePipelineProgress?: { __typename?: 'PipelineProgress', id: string } | null };
|
||||
export type UpdateOnePipelineProgressMutation = { __typename?: 'Mutation', updateOnePipelineProgress?: { __typename?: 'PipelineProgress', id: string, amount?: number | null, closeDate?: string | null } | null };
|
||||
|
||||
export type UpdateOnePipelineProgressStageMutationVariables = Exact<{
|
||||
id?: InputMaybe<Scalars['String']>;
|
||||
@ -3074,41 +3090,6 @@ export function useCreateEventMutation(baseOptions?: Apollo.MutationHookOptions<
|
||||
export type CreateEventMutationHookResult = ReturnType<typeof useCreateEventMutation>;
|
||||
export type CreateEventMutationResult = Apollo.MutationResult<CreateEventMutation>;
|
||||
export type CreateEventMutationOptions = Apollo.BaseMutationOptions<CreateEventMutation, CreateEventMutationVariables>;
|
||||
export const GetClientConfigDocument = gql`
|
||||
query GetClientConfig {
|
||||
clientConfig {
|
||||
display_google_login
|
||||
prefill_login_with_seed
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useGetClientConfigQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGetClientConfigQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetClientConfigQuery` 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 } = useGetClientConfigQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGetClientConfigQuery(baseOptions?: Apollo.QueryHookOptions<GetClientConfigQuery, GetClientConfigQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<GetClientConfigQuery, GetClientConfigQueryVariables>(GetClientConfigDocument, options);
|
||||
}
|
||||
export function useGetClientConfigLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetClientConfigQuery, GetClientConfigQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<GetClientConfigQuery, GetClientConfigQueryVariables>(GetClientConfigDocument, options);
|
||||
}
|
||||
export type GetClientConfigQueryHookResult = ReturnType<typeof useGetClientConfigQuery>;
|
||||
export type GetClientConfigLazyQueryHookResult = ReturnType<typeof useGetClientConfigLazyQuery>;
|
||||
export type GetClientConfigQueryResult = Apollo.QueryResult<GetClientConfigQuery, GetClientConfigQueryVariables>;
|
||||
export const ChallengeDocument = gql`
|
||||
mutation Challenge($email: String!, $password: String!) {
|
||||
challenge(email: $email, password: $password) {
|
||||
@ -3246,6 +3227,49 @@ export function useRenewTokenMutation(baseOptions?: Apollo.MutationHookOptions<R
|
||||
export type RenewTokenMutationHookResult = ReturnType<typeof useRenewTokenMutation>;
|
||||
export type RenewTokenMutationResult = Apollo.MutationResult<RenewTokenMutation>;
|
||||
export type RenewTokenMutationOptions = Apollo.BaseMutationOptions<RenewTokenMutation, RenewTokenMutationVariables>;
|
||||
export const GetClientConfigDocument = gql`
|
||||
query GetClientConfig {
|
||||
clientConfig {
|
||||
authProviders {
|
||||
google
|
||||
password
|
||||
}
|
||||
demoMode
|
||||
debugMode
|
||||
telemetry {
|
||||
enabled
|
||||
anonymizationEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useGetClientConfigQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGetClientConfigQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetClientConfigQuery` 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 } = useGetClientConfigQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGetClientConfigQuery(baseOptions?: Apollo.QueryHookOptions<GetClientConfigQuery, GetClientConfigQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<GetClientConfigQuery, GetClientConfigQueryVariables>(GetClientConfigDocument, options);
|
||||
}
|
||||
export function useGetClientConfigLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetClientConfigQuery, GetClientConfigQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<GetClientConfigQuery, GetClientConfigQueryVariables>(GetClientConfigDocument, options);
|
||||
}
|
||||
export type GetClientConfigQueryHookResult = ReturnType<typeof useGetClientConfigQuery>;
|
||||
export type GetClientConfigLazyQueryHookResult = ReturnType<typeof useGetClientConfigLazyQuery>;
|
||||
export type GetClientConfigQueryResult = Apollo.QueryResult<GetClientConfigQuery, GetClientConfigQueryVariables>;
|
||||
export const CreateCommentDocument = gql`
|
||||
mutation CreateComment($commentId: String!, $commentText: String!, $authorId: String!, $commentThreadId: String!, $createdAt: DateTime!) {
|
||||
createOneComment(
|
||||
@ -4016,6 +4040,8 @@ export const UpdateOnePipelineProgressDocument = gql`
|
||||
data: {amount: {set: $amount}, closeDate: {set: $closeDate}}
|
||||
) {
|
||||
id
|
||||
amount
|
||||
closeDate
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -8,7 +8,7 @@ import { ThemeType } from '@/ui/themes/themes';
|
||||
import '@emotion/react';
|
||||
|
||||
import { ApolloProvider } from './providers/apollo/ApolloProvider';
|
||||
import { ClientConfigProvider } from './providers/clientConfig/ClientConfigProvider';
|
||||
import { ClientConfigProvider } from './providers/client-config/ClientConfigProvider';
|
||||
import { AppThemeProvider } from './providers/theme/AppThemeProvider';
|
||||
import { UserProvider } from './providers/user/UserProvider';
|
||||
import { App } from './App';
|
||||
@ -26,11 +26,11 @@ root.render(
|
||||
<AppThemeProvider>
|
||||
<StrictMode>
|
||||
<UserProvider>
|
||||
<BrowserRouter>
|
||||
<ClientConfigProvider>
|
||||
<ClientConfigProvider>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</ClientConfigProvider>
|
||||
</BrowserRouter>
|
||||
</BrowserRouter>
|
||||
</ClientConfigProvider>
|
||||
</UserProvider>
|
||||
</StrictMode>
|
||||
</AppThemeProvider>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { telemetryState } from '@/client-config/states/telemetryState';
|
||||
import { useCreateEventMutation } from '~/generated/graphql';
|
||||
|
||||
import { useIsTelemetryEnabled } from './useIsTelemetryEnabled';
|
||||
|
||||
interface EventLocation {
|
||||
pathname: string;
|
||||
}
|
||||
@ -13,12 +13,12 @@ export interface EventData {
|
||||
}
|
||||
|
||||
export function useEventTracker() {
|
||||
const telemetryEnabled = useIsTelemetryEnabled();
|
||||
const [telemetry] = useRecoilState(telemetryState);
|
||||
const [createEventMutation] = useCreateEventMutation();
|
||||
|
||||
return useCallback(
|
||||
(eventType: string, eventData: EventData) => {
|
||||
if (telemetryEnabled) {
|
||||
if (telemetry.enabled) {
|
||||
createEventMutation({
|
||||
variables: {
|
||||
type: eventType,
|
||||
@ -27,6 +27,6 @@ export function useEventTracker() {
|
||||
});
|
||||
}
|
||||
},
|
||||
[createEventMutation, telemetryEnabled],
|
||||
[createEventMutation, telemetry],
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
export function useIsTelemetryEnabled() {
|
||||
// TODO: replace by clientConfig
|
||||
return process.env.IS_TELEMETRY_ENABLED !== 'false';
|
||||
}
|
@ -8,6 +8,7 @@ import { useRecoilState } from 'recoil';
|
||||
|
||||
import { isMockModeState } from '@/auth/states/isMockModeState';
|
||||
import { tokenPairState } from '@/auth/states/tokenPairState';
|
||||
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
|
||||
import { CommentThreadTarget } from '~/generated/graphql';
|
||||
import { mockedCompaniesData } from '~/testing/mock-data/companies';
|
||||
import { mockedUsersData } from '~/testing/mock-data/users';
|
||||
@ -16,6 +17,7 @@ import { ApolloFactory } from '../services/apollo.factory';
|
||||
|
||||
export function useApolloFactory() {
|
||||
const apolloRef = useRef<ApolloFactory<NormalizedCacheObject> | null>(null);
|
||||
const [isDebugMode] = useRecoilState(isDebugModeState);
|
||||
|
||||
const [tokenPair, setTokenPair] = useRecoilState(tokenPairState);
|
||||
const [isMockMode] = useRecoilState(isMockModeState);
|
||||
@ -64,10 +66,11 @@ export function useApolloFactory() {
|
||||
setTokenPair(null);
|
||||
},
|
||||
extraLinks: isMockMode ? [mockLink] : [],
|
||||
isDebugMode,
|
||||
});
|
||||
|
||||
return apolloRef.current.getClient();
|
||||
}, [isMockMode, setTokenPair]);
|
||||
}, [isMockMode, setTokenPair, isDebugMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (apolloRef.current) {
|
||||
|
@ -29,6 +29,7 @@ export interface Options<TCacheShape> extends ApolloClientOptions<TCacheShape> {
|
||||
onTokenPairChange?: (tokenPair: AuthTokenPair) => void;
|
||||
onUnauthenticatedError?: () => void;
|
||||
extraLinks?: ApolloLink[];
|
||||
isDebugMode?: boolean;
|
||||
}
|
||||
|
||||
export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
||||
@ -43,6 +44,7 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
||||
onTokenPairChange,
|
||||
onUnauthenticatedError,
|
||||
extraLinks,
|
||||
isDebugMode,
|
||||
...options
|
||||
} = opts;
|
||||
|
||||
@ -98,7 +100,7 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
||||
return forward(operation);
|
||||
}
|
||||
default:
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
if (isDebugMode) {
|
||||
console.warn(
|
||||
`[GraphQL error]: Message: ${
|
||||
graphQLError.message
|
||||
@ -114,7 +116,7 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
||||
}
|
||||
|
||||
if (networkError) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
if (isDebugMode) {
|
||||
console.warn(`[Network error]: ${networkError}`);
|
||||
}
|
||||
onNetworkError?.(networkError);
|
||||
@ -127,8 +129,7 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
||||
errorLink,
|
||||
authLink,
|
||||
...(extraLinks ? extraLinks : []),
|
||||
// Only show logger in dev mode
|
||||
process.env.NODE_ENV !== 'production' ? logger : null,
|
||||
isDebugMode ? logger : null,
|
||||
retryLink,
|
||||
httpLink,
|
||||
].filter(assertNotNull),
|
||||
|
@ -1,2 +1 @@
|
||||
export * from './select';
|
||||
export * from './update';
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const GET_CLIENT_CONFIG = gql`
|
||||
query GetClientConfig {
|
||||
clientConfig {
|
||||
display_google_login
|
||||
prefill_login_with_seed
|
||||
}
|
||||
}
|
||||
`;
|
@ -1,6 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const authFlowUserEmailState = atom({
|
||||
export const authFlowUserEmailState = atom<string>({
|
||||
key: 'authFlowUserEmailState',
|
||||
default: process.env.NODE_ENV === 'development' ? 'tim@apple.dev' : '',
|
||||
default: '',
|
||||
});
|
||||
|
@ -1,6 +0,0 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const displayGoogleLogin = atom<boolean>({
|
||||
key: 'displayGoogleLogin',
|
||||
default: true,
|
||||
});
|
@ -1,6 +0,0 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const prefillLoginWithSeed = atom<boolean>({
|
||||
key: 'prefillLoginWithSeed',
|
||||
default: true,
|
||||
});
|
18
front/src/modules/client-config/queries/index.tsx
Normal file
18
front/src/modules/client-config/queries/index.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const GET_CLIENT_CONFIG = gql`
|
||||
query GetClientConfig {
|
||||
clientConfig {
|
||||
authProviders {
|
||||
google
|
||||
password
|
||||
}
|
||||
demoMode
|
||||
debugMode
|
||||
telemetry {
|
||||
enabled
|
||||
anonymizationEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
@ -0,0 +1,8 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { AuthProviders } from '~/generated/graphql';
|
||||
|
||||
export const authProvidersState = atom<AuthProviders>({
|
||||
key: 'authProvidersState',
|
||||
default: { google: false, magicLink: false, password: true },
|
||||
});
|
@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const isDebugModeState = atom<boolean>({
|
||||
key: 'isDebugModeState',
|
||||
default: false,
|
||||
});
|
@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const isDemoModeState = atom<boolean>({
|
||||
key: 'isDemoModeState',
|
||||
default: false,
|
||||
});
|
8
front/src/modules/client-config/states/telemetryState.ts
Normal file
8
front/src/modules/client-config/states/telemetryState.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { Telemetry } from '~/generated/graphql';
|
||||
|
||||
export const telemetryState = atom<Telemetry>({
|
||||
key: 'telemetryState',
|
||||
default: { enabled: true, anonymizationEnabled: true },
|
||||
});
|
@ -12,6 +12,7 @@ import { Logo } from '@/auth/components/ui/Logo';
|
||||
import { Title } from '@/auth/components/ui/Title';
|
||||
import { authFlowUserEmailState } from '@/auth/states/authFlowUserEmailState';
|
||||
import { isMockModeState } from '@/auth/states/isMockModeState';
|
||||
import { authProvidersState } from '@/client-config/states/authProvidersState';
|
||||
import { captureHotkeyTypeInFocusState } from '@/hotkeys/states/captureHotkeyTypeInFocusState';
|
||||
import { MainButton } from '@/ui/components/buttons/MainButton';
|
||||
import { TextInput } from '@/ui/components/inputs/TextInput';
|
||||
@ -36,6 +37,8 @@ export function Index() {
|
||||
const navigate = useNavigate();
|
||||
const theme = useTheme();
|
||||
const [, setMockMode] = useRecoilState(isMockModeState);
|
||||
const [authProviders] = useRecoilState(authProvidersState);
|
||||
const [demoMode] = useRecoilState(authProvidersState);
|
||||
|
||||
const [authFlowUserEmail, setAuthFlowUserEmail] = useRecoilState(
|
||||
authFlowUserEmailState,
|
||||
@ -71,7 +74,14 @@ export function Index() {
|
||||
useEffect(() => {
|
||||
setMockMode(true);
|
||||
setCaptureHotkeyTypeInFocus(true);
|
||||
}, [navigate, setMockMode, setCaptureHotkeyTypeInFocus]);
|
||||
setAuthFlowUserEmail(demoMode ? 'tim@apple.dev' : '');
|
||||
}, [
|
||||
navigate,
|
||||
setMockMode,
|
||||
setCaptureHotkeyTypeInFocus,
|
||||
setAuthFlowUserEmail,
|
||||
demoMode,
|
||||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -80,12 +90,14 @@ export function Index() {
|
||||
</AnimatedEaseIn>
|
||||
<Title animate>Welcome to Twenty</Title>
|
||||
<StyledContentContainer>
|
||||
<MainButton
|
||||
icon={<IconBrandGoogle size={theme.icon.size.sm} stroke={4} />}
|
||||
title="Continue with Google"
|
||||
onClick={onGoogleLoginClick}
|
||||
fullWidth
|
||||
/>
|
||||
{authProviders.google && (
|
||||
<MainButton
|
||||
icon={<IconBrandGoogle size={theme.icon.size.sm} stroke={4} />}
|
||||
title="Continue with Google"
|
||||
onClick={onGoogleLoginClick}
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
{visible && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
|
@ -11,6 +11,7 @@ import { Title } from '@/auth/components/ui/Title';
|
||||
import { useAuth } from '@/auth/hooks/useAuth';
|
||||
import { authFlowUserEmailState } from '@/auth/states/authFlowUserEmailState';
|
||||
import { isMockModeState } from '@/auth/states/isMockModeState';
|
||||
import { isDemoModeState } from '@/client-config/states/isDemoModeState';
|
||||
import { MainButton } from '@/ui/components/buttons/MainButton';
|
||||
import { TextInput } from '@/ui/components/inputs/TextInput';
|
||||
import { SubSectionTitle } from '@/ui/components/section-titles/SubSectionTitle';
|
||||
@ -48,15 +49,15 @@ const StyledErrorContainer = styled.div`
|
||||
|
||||
export function PasswordLogin() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const prefillPassword =
|
||||
process.env.NODE_ENV === 'development' ? 'Applecar2025' : '';
|
||||
const [isDemoMode] = useRecoilState(isDemoModeState);
|
||||
|
||||
const [authFlowUserEmail, setAuthFlowUserEmail] = useRecoilState(
|
||||
authFlowUserEmailState,
|
||||
);
|
||||
const [, setMockMode] = useRecoilState(isMockModeState);
|
||||
const [internalPassword, setInternalPassword] = useState(prefillPassword);
|
||||
const [internalPassword, setInternalPassword] = useState(
|
||||
isDemoMode ? 'Applecar2025' : '',
|
||||
);
|
||||
const [formError, setFormError] = useState('');
|
||||
|
||||
const { login } = useAuth();
|
||||
|
34
front/src/providers/client-config/ClientConfigProvider.tsx
Normal file
34
front/src/providers/client-config/ClientConfigProvider.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useFetchClientConfig } from '@/auth/hooks/useFetchClientConfig';
|
||||
import { authProvidersState } from '@/client-config/states/authProvidersState';
|
||||
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
|
||||
import { isDemoModeState } from '@/client-config/states/isDemoModeState';
|
||||
import { telemetryState } from '@/client-config/states/telemetryState';
|
||||
|
||||
export const ClientConfigProvider: React.FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [, setAuthProviders] = useRecoilState(authProvidersState);
|
||||
const [, setDebugMode] = useRecoilState(isDebugModeState);
|
||||
const [, setDemoMode] = useRecoilState(isDemoModeState);
|
||||
const [, setTelemetry] = useRecoilState(telemetryState);
|
||||
|
||||
const clientConfig = useFetchClientConfig();
|
||||
|
||||
useEffect(() => {
|
||||
if (clientConfig) {
|
||||
setAuthProviders({
|
||||
google: clientConfig.authProviders.google,
|
||||
password: clientConfig.authProviders.password,
|
||||
magicLink: false,
|
||||
});
|
||||
setDebugMode(clientConfig.debugMode);
|
||||
setDemoMode(clientConfig.demoMode);
|
||||
setTelemetry(clientConfig.telemetry);
|
||||
}
|
||||
}, [clientConfig, setAuthProviders, setDebugMode, setDemoMode, setTelemetry]);
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useFetchClientConfig } from '@/auth/hooks/useFetchClientConfig';
|
||||
import { displayGoogleLogin } from '@/auth/states/displayGoogleLogin';
|
||||
import { prefillLoginWithSeed } from '@/auth/states/prefillLoginWithSeed';
|
||||
|
||||
export const ClientConfigProvider: React.FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [, setDisplayGoogleLogin] = useRecoilState(displayGoogleLogin);
|
||||
const [, setPrefillLoginWithSeed] = useRecoilState(prefillLoginWithSeed);
|
||||
const clientConfig = useFetchClientConfig();
|
||||
|
||||
useEffect(() => {
|
||||
setDisplayGoogleLogin(clientConfig?.display_google_login ?? true);
|
||||
setPrefillLoginWithSeed(clientConfig?.prefill_login_with_seed ?? true);
|
||||
}, [setDisplayGoogleLogin, setPrefillLoginWithSeed, clientConfig]);
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
@ -1,5 +1,4 @@
|
||||
DEBUG_MODE=false
|
||||
AUTH_GOOGLE_ENABLED=false
|
||||
ACCESS_TOKEN_SECRET=secret_jwt
|
||||
ACCESS_TOKEN_EXPIRES_IN=5m
|
||||
LOGIN_TOKEN_SECRET=secret_login_token
|
||||
|
@ -1,13 +1,21 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AnalyticsResolver } from './analytics.resolver';
|
||||
import { AnalyticsService } from './analytics.service';
|
||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||
|
||||
describe('AnalyticsResolver', () => {
|
||||
let resolver: AnalyticsResolver;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [AnalyticsResolver, AnalyticsService],
|
||||
providers: [
|
||||
AnalyticsResolver,
|
||||
AnalyticsService,
|
||||
{
|
||||
provide: EnvironmentService,
|
||||
useValue: {},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
resolver = module.get<AnalyticsResolver>(AnalyticsResolver);
|
||||
|
@ -1,12 +1,19 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AnalyticsService } from './analytics.service';
|
||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||
|
||||
describe('AnalyticsService', () => {
|
||||
let service: AnalyticsService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [AnalyticsService],
|
||||
providers: [
|
||||
AnalyticsService,
|
||||
{
|
||||
provide: EnvironmentService,
|
||||
useValue: {},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<AnalyticsService>(AnalyticsService);
|
||||
|
@ -3,12 +3,13 @@ import { User, Workspace } from '@prisma/client';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import { CreateAnalyticsInput } from './dto/create-analytics.input';
|
||||
import { anonymize } from 'src/utils/anonymize';
|
||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||
|
||||
@Injectable()
|
||||
export class AnalyticsService {
|
||||
private readonly httpService: AxiosInstance;
|
||||
|
||||
constructor() {
|
||||
constructor(private readonly environmentService: EnvironmentService) {
|
||||
this.httpService = axios.create({
|
||||
baseURL: 'https://t.twenty.com/api/v1/s2s',
|
||||
});
|
||||
@ -19,15 +20,26 @@ export class AnalyticsService {
|
||||
user: User | undefined,
|
||||
workspace: Workspace | undefined,
|
||||
) {
|
||||
if (process.env.IS_TELEMETRY_ENABLED === 'false') {
|
||||
return;
|
||||
if (!this.environmentService.isTelemetryEnabled()) {
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
const anonymizationEnabled =
|
||||
this.environmentService.isTelemetryAnonymizationEnabled();
|
||||
|
||||
const data = {
|
||||
type: createEventInput.type,
|
||||
data: {
|
||||
userUUID: user ? anonymize(user.id) : undefined,
|
||||
workspaceUUID: workspace ? anonymize(workspace.id) : undefined,
|
||||
userUUID: user
|
||||
? anonymizationEnabled
|
||||
? anonymize(user.id)
|
||||
: user.id
|
||||
: undefined,
|
||||
workspaceUUID: workspace
|
||||
? anonymizationEnabled
|
||||
? anonymize(workspace.id)
|
||||
: workspace.id
|
||||
: undefined,
|
||||
workspaceDomain: workspace ? workspace.domainName : undefined,
|
||||
...createEventInput.data,
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Args, Mutation, Resolver, Query } from '@nestjs/graphql';
|
||||
import { AuthTokens, ClientConfig } from './dto/token.entity';
|
||||
import { AuthTokens } from './dto/token.entity';
|
||||
import { TokenService } from './services/token.service';
|
||||
import { RefreshTokenInput } from './dto/refresh-token.input';
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
@ -61,17 +61,4 @@ export class AuthResolver {
|
||||
|
||||
return { tokens: tokens };
|
||||
}
|
||||
|
||||
@Query(() => ClientConfig)
|
||||
async clientConfig(): Promise<ClientConfig> {
|
||||
const displayGoogleLogin = process.env.AUTH_GOOGLE_CLIENT_ID !== undefined;
|
||||
const prefillLoginWithSeed = process.env.NODE_ENV === 'development';
|
||||
|
||||
const clientConfig: ClientConfig = {
|
||||
display_google_login: displayGoogleLogin,
|
||||
prefill_login_with_seed: prefillLoginWithSeed,
|
||||
};
|
||||
|
||||
return Promise.resolve(clientConfig);
|
||||
}
|
||||
}
|
||||
|
@ -23,12 +23,3 @@ export class AuthTokens {
|
||||
@Field(() => AuthTokenPair)
|
||||
tokens: AuthTokenPair;
|
||||
}
|
||||
|
||||
@ObjectType()
|
||||
export class ClientConfig {
|
||||
@Field(() => Boolean)
|
||||
display_google_login: boolean;
|
||||
|
||||
@Field(() => Boolean)
|
||||
prefill_login_with_seed: boolean;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import { GoogleStrategy } from '../strategies/google.auth.strategy';
|
||||
export class GoogleProviderEnabledGuard implements CanActivate {
|
||||
constructor(private readonly environmentService: EnvironmentService) {}
|
||||
canActivate(): boolean | Promise<boolean> | Observable<boolean> {
|
||||
if (!this.environmentService.getAuthGoogleEnabled()) {
|
||||
if (!this.environmentService.isAuthGoogleEnabled()) {
|
||||
throw new NotFoundException('Google auth is not enabled');
|
||||
}
|
||||
|
||||
|
37
server/src/core/client-config/client-config.entity.ts
Normal file
37
server/src/core/client-config/client-config.entity.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
@ObjectType()
|
||||
class AuthProviders {
|
||||
@Field(() => Boolean)
|
||||
google: boolean;
|
||||
|
||||
@Field(() => Boolean)
|
||||
magicLink: boolean;
|
||||
|
||||
@Field(() => Boolean)
|
||||
password: boolean;
|
||||
}
|
||||
|
||||
@ObjectType()
|
||||
class Telemetry {
|
||||
@Field(() => Boolean)
|
||||
enabled: boolean;
|
||||
|
||||
@Field(() => Boolean)
|
||||
anonymizationEnabled: boolean;
|
||||
}
|
||||
|
||||
@ObjectType()
|
||||
export class ClientConfig {
|
||||
@Field(() => AuthProviders, { nullable: false })
|
||||
authProviders: AuthProviders;
|
||||
|
||||
@Field(() => Telemetry, { nullable: false })
|
||||
telemetry: Telemetry;
|
||||
|
||||
@Field(() => Boolean)
|
||||
demoMode: boolean;
|
||||
|
||||
@Field(() => Boolean)
|
||||
debugMode: boolean;
|
||||
}
|
7
server/src/core/client-config/client-config.module.ts
Normal file
7
server/src/core/client-config/client-config.module.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ClientConfigResolver } from './client-config.resolver';
|
||||
|
||||
@Module({
|
||||
providers: [ClientConfigResolver],
|
||||
})
|
||||
export class ClientConfigModule {}
|
25
server/src/core/client-config/client-config.resolver.spec.ts
Normal file
25
server/src/core/client-config/client-config.resolver.spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { ClientConfigResolver } from './client-config.resolver';
|
||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||
|
||||
describe('ClientConfigResolver', () => {
|
||||
let resolver: ClientConfigResolver;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
ClientConfigResolver,
|
||||
{
|
||||
provide: EnvironmentService,
|
||||
useValue: {},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
resolver = module.get<ClientConfigResolver>(ClientConfigResolver);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(resolver).toBeDefined();
|
||||
});
|
||||
});
|
28
server/src/core/client-config/client-config.resolver.ts
Normal file
28
server/src/core/client-config/client-config.resolver.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { Resolver, Query } from '@nestjs/graphql';
|
||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||
import { ClientConfig } from './client-config.entity';
|
||||
|
||||
@Resolver()
|
||||
export class ClientConfigResolver {
|
||||
constructor(private environmentService: EnvironmentService) {}
|
||||
|
||||
@Query(() => ClientConfig)
|
||||
async clientConfig(): Promise<ClientConfig> {
|
||||
const clientConfig: ClientConfig = {
|
||||
authProviders: {
|
||||
google: this.environmentService.isAuthGoogleEnabled() ?? false,
|
||||
magicLink: false,
|
||||
password: true,
|
||||
},
|
||||
telemetry: {
|
||||
enabled: this.environmentService.isTelemetryEnabled() ?? false,
|
||||
anonymizationEnabled:
|
||||
this.environmentService.isTelemetryAnonymizationEnabled() ?? false,
|
||||
},
|
||||
demoMode: this.environmentService.isDemoMode() ?? false,
|
||||
debugMode: this.environmentService.isDebugMode() ?? false,
|
||||
};
|
||||
|
||||
return Promise.resolve(clientConfig);
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import { AuthModule } from './auth/auth.module';
|
||||
import { WorkspaceModule } from './workspace/workspace.module';
|
||||
import { AnalyticsModule } from './analytics/analytics.module';
|
||||
import { FileModule } from './file/file.module';
|
||||
import { ClientConfigModule } from './client-config/client-config.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -20,6 +21,7 @@ import { FileModule } from './file/file.module';
|
||||
WorkspaceModule,
|
||||
AnalyticsModule,
|
||||
FileModule,
|
||||
ClientConfigModule,
|
||||
],
|
||||
exports: [
|
||||
AuthModule,
|
||||
|
@ -19,7 +19,7 @@ export class PrismaService extends PrismaClient implements OnModuleInit {
|
||||
private readonly logger = new Logger(PrismaService.name);
|
||||
|
||||
constructor(private readonly environmentService: EnvironmentService) {
|
||||
const debugMode = environmentService.getDebugMode();
|
||||
const debugMode = environmentService.isDebugMode();
|
||||
super({
|
||||
errorFormat: 'minimal',
|
||||
log: debugMode
|
||||
|
@ -8,8 +8,22 @@ import { StorageType } from './interfaces/storage.interface';
|
||||
export class EnvironmentService {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
getDebugMode(): boolean | undefined {
|
||||
return this.configService.get<boolean>('DEBUG_MODE')!;
|
||||
isDebugMode(): boolean {
|
||||
return this.configService.get<boolean>('DEBUG_MODE') ?? false;
|
||||
}
|
||||
|
||||
isDemoMode(): boolean {
|
||||
return this.configService.get<boolean>('DEMO_MODE') ?? false;
|
||||
}
|
||||
|
||||
isTelemetryEnabled(): boolean {
|
||||
return this.configService.get<boolean>('TELEMETRY_ENABLED') ?? true;
|
||||
}
|
||||
|
||||
isTelemetryAnonymizationEnabled(): boolean | undefined {
|
||||
return (
|
||||
this.configService.get<boolean>('TELEMETRY_ANONYMIZATION_ENABLED') ?? true
|
||||
);
|
||||
}
|
||||
|
||||
getPGDatabaseUrl(): string {
|
||||
@ -44,7 +58,7 @@ export class EnvironmentService {
|
||||
return this.configService.get<string>('FRONT_AUTH_CALLBACK_URL')!;
|
||||
}
|
||||
|
||||
getAuthGoogleEnabled(): boolean | undefined {
|
||||
isAuthGoogleEnabled(): boolean | undefined {
|
||||
return this.configService.get<boolean>('AUTH_GOOGLE_ENABLED');
|
||||
}
|
||||
|
||||
|
@ -16,12 +16,27 @@ import { IsAWSRegion } from './decorators/is-aws-region.decorator';
|
||||
import { CastToBoolean } from './decorators/cast-to-boolean.decorator';
|
||||
|
||||
export class EnvironmentVariables {
|
||||
// Stage
|
||||
// Misc
|
||||
@CastToBoolean()
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
DEBUG_MODE?: boolean;
|
||||
|
||||
@CastToBoolean()
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
DEMO_MODE?: boolean;
|
||||
|
||||
@CastToBoolean()
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
TELEMETRY_ENABLED?: boolean;
|
||||
|
||||
@CastToBoolean()
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
TELEMETRY_ANONYMIZATION_ENABLED?: boolean;
|
||||
|
||||
// Database
|
||||
@IsUrl({ protocols: ['postgres'], require_tld: false })
|
||||
PG_DATABASE_URL: string;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
|
||||
import { EnvironmentModule } from './environment/environment.module';
|
||||
import { EnvironmentService } from './environment/environment.service';
|
||||
|
@ -1,9 +1,6 @@
|
||||
import crypto from 'crypto';
|
||||
|
||||
export function anonymize(input) {
|
||||
if (process.env.IS_TELEMETRY_ANONYMIZATION_ENABLED === 'false') {
|
||||
return input;
|
||||
}
|
||||
export function anonymize(input: string) {
|
||||
// md5 shorter than sha-256 and collisions are not a security risk in this use-case
|
||||
return crypto.createHash('md5').update(input).digest('hex');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user