3628 timebox separate user creation from workspace creation (#3737)
* Remove workspace schema creation from signUp * Set user workspaceMember nullable * Remove workspace creation * Handle null workspace in tokens * Update onboarding status * Generate types * Move createWorkspace to workspace resolver * Create workspace after signup * Update createWorkspace return type * Update createWorkspace return type * Create core.workspace at signup * WIP * Fix create workspace * Fix create workspace * Clean code * Remove useless recoil set * Simplify create workspace request * Set currentWorkspace at login * Fix tests * Create a recoil value for is workspaceSchema created * Rename createWorkspace to createWorkspaceSchema * Code review returns * Use AppPath when possible * Try without state * Fix * Fixes * Rename createWorkspaceSchema to activateWorkspace * Remove defaultAvatarUrl from user * Add defaultAvatarUrl to core user This reverts commit 1701c30eb18804558293cc42043aedf96ea888df. * Add defaultAvatarUrl to core user This reverts commit 1701c30eb18804558293cc42043aedf96ea888df. * Fix ci * Fix tests * Fix storybook * Fix test * Remove useless query * Fix test * Fix test * Fix mock data * Fix test * Clean Mock Requests * Fix tentative * Revert "Clean Mock Requests" This reverts commit 8aa20a34363ffddfdee24f18fc80b27ea0ad5e1d. * Fix * Revert "Fix" This reverts commit 2df7e9b6569b8bfb53f6a45391db725e28d16a18. * Revert "Revert "Clean Mock Requests"" This reverts commit 3aefef8e9600d161434a047e845563d1b8e0692e. * Revert "Fix tentative" This reverts commit 13e7748d6f3b3858d30fb08adbc8ad347c5556ee. * Update filename --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -88,7 +88,7 @@ export const PageChangeEffect = () => {
|
|||||||
) {
|
) {
|
||||||
navigate(AppPath.PlanRequired);
|
navigate(AppPath.PlanRequired);
|
||||||
} else if (
|
} else if (
|
||||||
onboardingStatus === OnboardingStatus.OngoingWorkspaceCreation &&
|
onboardingStatus === OnboardingStatus.OngoingWorkspaceActivation &&
|
||||||
!isMatchingLocation(AppPath.CreateWorkspace)
|
!isMatchingLocation(AppPath.CreateWorkspace)
|
||||||
) {
|
) {
|
||||||
navigate(AppPath.CreateWorkspace);
|
navigate(AppPath.CreateWorkspace);
|
||||||
@ -101,7 +101,7 @@ export const PageChangeEffect = () => {
|
|||||||
onboardingStatus === OnboardingStatus.Completed &&
|
onboardingStatus === OnboardingStatus.Completed &&
|
||||||
isMatchingOnboardingRoute
|
isMatchingOnboardingRoute
|
||||||
) {
|
) {
|
||||||
navigate('/');
|
navigate(AppPath.Index);
|
||||||
} else if (isMatchingLocation(AppPath.Invite)) {
|
} else if (isMatchingLocation(AppPath.Invite)) {
|
||||||
const inviteHash =
|
const inviteHash =
|
||||||
matchPath({ path: '/invite/:workspaceInviteHash' }, location.pathname)
|
matchPath({ path: '/invite/:workspaceInviteHash' }, location.pathname)
|
||||||
|
|||||||
@ -19,6 +19,10 @@ export type Scalars = {
|
|||||||
Upload: any;
|
Upload: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ActivateWorkspaceInput = {
|
||||||
|
displayName?: InputMaybe<Scalars['String']>;
|
||||||
|
};
|
||||||
|
|
||||||
export type Analytics = {
|
export type Analytics = {
|
||||||
__typename?: 'Analytics';
|
__typename?: 'Analytics';
|
||||||
/** Boolean that confirms query was dispatched */
|
/** Boolean that confirms query was dispatched */
|
||||||
@ -77,15 +81,6 @@ export type ClientConfig = {
|
|||||||
telemetry: Telemetry;
|
telemetry: Telemetry;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CreateOneRefreshTokenInput = {
|
|
||||||
/** The record to create */
|
|
||||||
refreshToken: CreateRefreshTokenInput;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CreateRefreshTokenInput = {
|
|
||||||
expiresAt: Scalars['DateTime'];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CursorPaging = {
|
export type CursorPaging = {
|
||||||
/** Paginate after opaque cursor */
|
/** Paginate after opaque cursor */
|
||||||
after?: InputMaybe<Scalars['ConnectionCursor']>;
|
after?: InputMaybe<Scalars['ConnectionCursor']>;
|
||||||
@ -223,6 +218,7 @@ export type LoginToken = {
|
|||||||
|
|
||||||
export type Mutation = {
|
export type Mutation = {
|
||||||
__typename?: 'Mutation';
|
__typename?: 'Mutation';
|
||||||
|
activateWorkspace: Workspace;
|
||||||
challenge: LoginToken;
|
challenge: LoginToken;
|
||||||
createEvent: Analytics;
|
createEvent: Analytics;
|
||||||
createOneObject: Object;
|
createOneObject: Object;
|
||||||
@ -247,6 +243,11 @@ export type Mutation = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationActivateWorkspaceArgs = {
|
||||||
|
data: ActivateWorkspaceInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationChallengeArgs = {
|
export type MutationChallengeArgs = {
|
||||||
email: Scalars['String'];
|
email: Scalars['String'];
|
||||||
password: Scalars['String'];
|
password: Scalars['String'];
|
||||||
@ -259,11 +260,6 @@ export type MutationCreateEventArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationCreateOneRefreshTokenArgs = {
|
|
||||||
input: CreateOneRefreshTokenInput;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export type MutationDeleteOneObjectArgs = {
|
export type MutationDeleteOneObjectArgs = {
|
||||||
input: DeleteOneObjectInput;
|
input: DeleteOneObjectInput;
|
||||||
};
|
};
|
||||||
@ -532,6 +528,7 @@ export type User = {
|
|||||||
__typename?: 'User';
|
__typename?: 'User';
|
||||||
canImpersonate: Scalars['Boolean'];
|
canImpersonate: Scalars['Boolean'];
|
||||||
createdAt: Scalars['DateTime'];
|
createdAt: Scalars['DateTime'];
|
||||||
|
defaultAvatarUrl?: Maybe<Scalars['String']>;
|
||||||
defaultWorkspace: Workspace;
|
defaultWorkspace: Workspace;
|
||||||
deletedAt?: Maybe<Scalars['DateTime']>;
|
deletedAt?: Maybe<Scalars['DateTime']>;
|
||||||
disabled?: Maybe<Scalars['Boolean']>;
|
disabled?: Maybe<Scalars['Boolean']>;
|
||||||
@ -545,7 +542,7 @@ export type User = {
|
|||||||
passwordResetTokenExpiresAt?: Maybe<Scalars['DateTime']>;
|
passwordResetTokenExpiresAt?: Maybe<Scalars['DateTime']>;
|
||||||
supportUserHash?: Maybe<Scalars['String']>;
|
supportUserHash?: Maybe<Scalars['String']>;
|
||||||
updatedAt: Scalars['DateTime'];
|
updatedAt: Scalars['DateTime'];
|
||||||
workspaceMember: WorkspaceMember;
|
workspaceMember?: Maybe<WorkspaceMember>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserEdge = {
|
export type UserEdge = {
|
||||||
@ -778,7 +775,7 @@ export type ImpersonateMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
||||||
|
|
||||||
export type RenewTokenMutationVariables = Exact<{
|
export type RenewTokenMutationVariables = Exact<{
|
||||||
refreshToken: Scalars['String'];
|
refreshToken: Scalars['String'];
|
||||||
@ -809,7 +806,7 @@ export type VerifyMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
||||||
|
|
||||||
export type CheckUserExistsQueryVariables = Exact<{
|
export type CheckUserExistsQueryVariables = Exact<{
|
||||||
email: Scalars['String'];
|
email: Scalars['String'];
|
||||||
@ -846,7 +843,7 @@ export type UploadImageMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type UploadImageMutation = { __typename?: 'Mutation', uploadImage: string };
|
export type UploadImageMutation = { __typename?: 'Mutation', uploadImage: string };
|
||||||
|
|
||||||
export type UserQueryFragmentFragment = { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } };
|
export type UserQueryFragmentFragment = { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } };
|
||||||
|
|
||||||
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
|
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
@ -860,6 +857,18 @@ export type UploadProfilePictureMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProfilePicture: string };
|
export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProfilePicture: string };
|
||||||
|
|
||||||
|
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
|
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: string, key: string, value: boolean, workspaceId: string }> | null } } };
|
||||||
|
|
||||||
|
export type ActivateWorkspaceMutationVariables = Exact<{
|
||||||
|
input: ActivateWorkspaceInput;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ActivateWorkspaceMutation = { __typename?: 'Mutation', activateWorkspace: { __typename?: 'Workspace', id: string } };
|
||||||
|
|
||||||
export type DeleteCurrentWorkspaceMutationVariables = Exact<{ [key: string]: never; }>;
|
export type DeleteCurrentWorkspaceMutationVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
@ -1677,6 +1686,103 @@ export function useUploadProfilePictureMutation(baseOptions?: Apollo.MutationHoo
|
|||||||
export type UploadProfilePictureMutationHookResult = ReturnType<typeof useUploadProfilePictureMutation>;
|
export type UploadProfilePictureMutationHookResult = ReturnType<typeof useUploadProfilePictureMutation>;
|
||||||
export type UploadProfilePictureMutationResult = Apollo.MutationResult<UploadProfilePictureMutation>;
|
export type UploadProfilePictureMutationResult = Apollo.MutationResult<UploadProfilePictureMutation>;
|
||||||
export type UploadProfilePictureMutationOptions = Apollo.BaseMutationOptions<UploadProfilePictureMutation, UploadProfilePictureMutationVariables>;
|
export type UploadProfilePictureMutationOptions = Apollo.BaseMutationOptions<UploadProfilePictureMutation, UploadProfilePictureMutationVariables>;
|
||||||
|
export const GetCurrentUserDocument = gql`
|
||||||
|
query GetCurrentUser {
|
||||||
|
currentUser {
|
||||||
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
email
|
||||||
|
canImpersonate
|
||||||
|
supportUserHash
|
||||||
|
workspaceMember {
|
||||||
|
id
|
||||||
|
name {
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
}
|
||||||
|
colorScheme
|
||||||
|
avatarUrl
|
||||||
|
locale
|
||||||
|
}
|
||||||
|
defaultWorkspace {
|
||||||
|
id
|
||||||
|
displayName
|
||||||
|
logo
|
||||||
|
domainName
|
||||||
|
inviteHash
|
||||||
|
allowImpersonation
|
||||||
|
subscriptionStatus
|
||||||
|
featureFlags {
|
||||||
|
id
|
||||||
|
key
|
||||||
|
value
|
||||||
|
workspaceId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useGetCurrentUserQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useGetCurrentUserQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useGetCurrentUserQuery` 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 } = useGetCurrentUserQuery({
|
||||||
|
* variables: {
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useGetCurrentUserQuery(baseOptions?: Apollo.QueryHookOptions<GetCurrentUserQuery, GetCurrentUserQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<GetCurrentUserQuery, GetCurrentUserQueryVariables>(GetCurrentUserDocument, options);
|
||||||
|
}
|
||||||
|
export function useGetCurrentUserLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetCurrentUserQuery, GetCurrentUserQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<GetCurrentUserQuery, GetCurrentUserQueryVariables>(GetCurrentUserDocument, options);
|
||||||
|
}
|
||||||
|
export type GetCurrentUserQueryHookResult = ReturnType<typeof useGetCurrentUserQuery>;
|
||||||
|
export type GetCurrentUserLazyQueryHookResult = ReturnType<typeof useGetCurrentUserLazyQuery>;
|
||||||
|
export type GetCurrentUserQueryResult = Apollo.QueryResult<GetCurrentUserQuery, GetCurrentUserQueryVariables>;
|
||||||
|
export const ActivateWorkspaceDocument = gql`
|
||||||
|
mutation ActivateWorkspace($input: ActivateWorkspaceInput!) {
|
||||||
|
activateWorkspace(data: $input) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type ActivateWorkspaceMutationFn = Apollo.MutationFunction<ActivateWorkspaceMutation, ActivateWorkspaceMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useActivateWorkspaceMutation__
|
||||||
|
*
|
||||||
|
* To run a mutation, you first call `useActivateWorkspaceMutation` within a React component and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useActivateWorkspaceMutation` 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 [activateWorkspaceMutation, { data, loading, error }] = useActivateWorkspaceMutation({
|
||||||
|
* variables: {
|
||||||
|
* input: // value for 'input'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useActivateWorkspaceMutation(baseOptions?: Apollo.MutationHookOptions<ActivateWorkspaceMutation, ActivateWorkspaceMutationVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useMutation<ActivateWorkspaceMutation, ActivateWorkspaceMutationVariables>(ActivateWorkspaceDocument, options);
|
||||||
|
}
|
||||||
|
export type ActivateWorkspaceMutationHookResult = ReturnType<typeof useActivateWorkspaceMutation>;
|
||||||
|
export type ActivateWorkspaceMutationResult = Apollo.MutationResult<ActivateWorkspaceMutation>;
|
||||||
|
export type ActivateWorkspaceMutationOptions = Apollo.BaseMutationOptions<ActivateWorkspaceMutation, ActivateWorkspaceMutationVariables>;
|
||||||
export const DeleteCurrentWorkspaceDocument = gql`
|
export const DeleteCurrentWorkspaceDocument = gql`
|
||||||
mutation DeleteCurrentWorkspace {
|
mutation DeleteCurrentWorkspace {
|
||||||
deleteCurrentWorkspace {
|
deleteCurrentWorkspace {
|
||||||
|
|||||||
@ -66,16 +66,6 @@ describe('useOnboardingStatus', () => {
|
|||||||
expect(result.current.onboardingStatus).toBe('ongoing_user_creation');
|
expect(result.current.onboardingStatus).toBe('ongoing_user_creation');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return undefined when currentWorkspaceMember in undefined', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
result.current.setTokenPair(tokenPair);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "incomplete"', async () => {
|
it('should return "incomplete"', async () => {
|
||||||
const { result } = renderHooks();
|
const { result } = renderHooks();
|
||||||
const {
|
const {
|
||||||
@ -120,14 +110,9 @@ describe('useOnboardingStatus', () => {
|
|||||||
expect(result.current.onboardingStatus).toBe('canceled');
|
expect(result.current.onboardingStatus).toBe('canceled');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return "ongoing_workspace_creation"', async () => {
|
it('should return "ongoing_workspace_activation"', async () => {
|
||||||
const { result } = renderHooks();
|
const { result } = renderHooks();
|
||||||
const {
|
const { setTokenPair, setBilling, setCurrentWorkspace } = result.current;
|
||||||
setTokenPair,
|
|
||||||
setBilling,
|
|
||||||
setCurrentWorkspace,
|
|
||||||
setCurrentWorkspaceMember,
|
|
||||||
} = result.current;
|
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
setTokenPair(tokenPair);
|
setTokenPair(tokenPair);
|
||||||
@ -135,12 +120,31 @@ describe('useOnboardingStatus', () => {
|
|||||||
setCurrentWorkspace({
|
setCurrentWorkspace({
|
||||||
...currentWorkspace,
|
...currentWorkspace,
|
||||||
displayName: '',
|
displayName: '',
|
||||||
subscriptionStatus: 'completed',
|
subscriptionStatus: 'active',
|
||||||
});
|
});
|
||||||
setCurrentWorkspaceMember(currentWorkspaceMember);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe('ongoing_workspace_creation');
|
expect(result.current.onboardingStatus).toBe(
|
||||||
|
'ongoing_workspace_activation',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return "ongoing_workspace_activation"', async () => {
|
||||||
|
const { result } = renderHooks();
|
||||||
|
const { setTokenPair, setBilling, setCurrentWorkspace } = result.current;
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
setTokenPair(tokenPair);
|
||||||
|
setBilling(billing);
|
||||||
|
setCurrentWorkspace({
|
||||||
|
...currentWorkspace,
|
||||||
|
subscriptionStatus: 'active',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.current.onboardingStatus).toBe(
|
||||||
|
'ongoing_workspace_activation',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return "ongoing_profile_creation"', async () => {
|
it('should return "ongoing_profile_creation"', async () => {
|
||||||
@ -157,7 +161,7 @@ describe('useOnboardingStatus', () => {
|
|||||||
setBilling(billing);
|
setBilling(billing);
|
||||||
setCurrentWorkspace({
|
setCurrentWorkspace({
|
||||||
...currentWorkspace,
|
...currentWorkspace,
|
||||||
subscriptionStatus: 'completed',
|
subscriptionStatus: 'active',
|
||||||
});
|
});
|
||||||
setCurrentWorkspaceMember(currentWorkspaceMember);
|
setCurrentWorkspaceMember(currentWorkspaceMember);
|
||||||
});
|
});
|
||||||
@ -179,7 +183,7 @@ describe('useOnboardingStatus', () => {
|
|||||||
setBilling(billing);
|
setBilling(billing);
|
||||||
setCurrentWorkspace({
|
setCurrentWorkspace({
|
||||||
...currentWorkspace,
|
...currentWorkspace,
|
||||||
subscriptionStatus: 'completed',
|
subscriptionStatus: 'active',
|
||||||
});
|
});
|
||||||
setCurrentWorkspaceMember({
|
setCurrentWorkspaceMember({
|
||||||
...currentWorkspaceMember,
|
...currentWorkspaceMember,
|
||||||
|
|||||||
@ -89,13 +89,16 @@ export const useAuth = () => {
|
|||||||
setTokenPair(verifyResult.data?.verify.tokens);
|
setTokenPair(verifyResult.data?.verify.tokens);
|
||||||
|
|
||||||
const user = verifyResult.data?.verify.user;
|
const user = verifyResult.data?.verify.user;
|
||||||
const workspaceMember = {
|
let workspaceMember = null;
|
||||||
...user.workspaceMember,
|
|
||||||
colorScheme: user.workspaceMember?.colorScheme as ColorScheme,
|
|
||||||
};
|
|
||||||
const workspace = user.defaultWorkspace ?? null;
|
|
||||||
setCurrentUser(user);
|
setCurrentUser(user);
|
||||||
setCurrentWorkspaceMember(workspaceMember);
|
if (user.workspaceMember) {
|
||||||
|
workspaceMember = {
|
||||||
|
...user.workspaceMember,
|
||||||
|
colorScheme: user.workspaceMember?.colorScheme as ColorScheme,
|
||||||
|
};
|
||||||
|
setCurrentWorkspaceMember(workspaceMember);
|
||||||
|
}
|
||||||
|
const workspace = user.defaultWorkspace ?? null;
|
||||||
setCurrentWorkspace(workspace);
|
setCurrentWorkspace(workspace);
|
||||||
return {
|
return {
|
||||||
user,
|
user,
|
||||||
|
|||||||
@ -143,16 +143,15 @@ export const useSignInUp = () => {
|
|||||||
billing?.isBillingEnabled &&
|
billing?.isBillingEnabled &&
|
||||||
currentWorkspace.subscriptionStatus !== 'active'
|
currentWorkspace.subscriptionStatus !== 'active'
|
||||||
) {
|
) {
|
||||||
navigate('/plan-required');
|
navigate(AppPath.PlanRequired);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentWorkspace.displayName) {
|
if (currentWorkspace.displayName) {
|
||||||
navigate('/');
|
navigate(AppPath.Index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate('/create/workspace');
|
navigate(AppPath.CreateWorkspace);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
enqueueSnackBar(err?.message, {
|
enqueueSnackBar(err?.message, {
|
||||||
variant: 'error',
|
variant: 'error',
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { selector } from 'recoil';
|
||||||
|
|
||||||
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
|
|
||||||
|
export const isCurrentWorkspaceActiveSelector = selector({
|
||||||
|
key: 'isCurrentWorkspaceActiveSelector',
|
||||||
|
get: ({ get }) => {
|
||||||
|
const currentWorkspaceMember = get(currentWorkspaceMemberState);
|
||||||
|
return !!currentWorkspaceMember;
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -11,27 +11,24 @@ describe('getOnboardingStatus', () => {
|
|||||||
currentWorkspace: null,
|
currentWorkspace: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const unknownStatus = getOnboardingStatus({
|
const ongoingWorkspaceActivation = getOnboardingStatus({
|
||||||
isLoggedIn: true,
|
isLoggedIn: true,
|
||||||
currentWorkspaceMember: null,
|
currentWorkspaceMember: null,
|
||||||
currentWorkspace: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
const ongoingWorkspaceCreation = getOnboardingStatus({
|
|
||||||
isLoggedIn: true,
|
|
||||||
currentWorkspaceMember: {
|
|
||||||
id: '1',
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
} as WorkspaceMember,
|
|
||||||
currentWorkspace: {
|
currentWorkspace: {
|
||||||
id: '1',
|
id: '1',
|
||||||
displayName: null,
|
displayName: null,
|
||||||
} as CurrentWorkspace,
|
} as CurrentWorkspace,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ongoingWorkspaceActivationPreviouslyActive = getOnboardingStatus({
|
||||||
|
isLoggedIn: true,
|
||||||
|
currentWorkspaceMember: null,
|
||||||
|
currentWorkspace: {
|
||||||
|
id: '1',
|
||||||
|
displayName: 'My Workspace',
|
||||||
|
} as CurrentWorkspace,
|
||||||
|
});
|
||||||
|
|
||||||
const ongoingProfileCreation = getOnboardingStatus({
|
const ongoingProfileCreation = getOnboardingStatus({
|
||||||
isLoggedIn: true,
|
isLoggedIn: true,
|
||||||
currentWorkspaceMember: {
|
currentWorkspaceMember: {
|
||||||
@ -110,8 +107,10 @@ describe('getOnboardingStatus', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(ongoingUserCreation).toBe('ongoing_user_creation');
|
expect(ongoingUserCreation).toBe('ongoing_user_creation');
|
||||||
expect(unknownStatus).toBe(undefined);
|
expect(ongoingWorkspaceActivation).toBe('ongoing_workspace_activation');
|
||||||
expect(ongoingWorkspaceCreation).toBe('ongoing_workspace_creation');
|
expect(ongoingWorkspaceActivationPreviouslyActive).toBe(
|
||||||
|
'ongoing_workspace_activation',
|
||||||
|
);
|
||||||
expect(ongoingProfileCreation).toBe('ongoing_profile_creation');
|
expect(ongoingProfileCreation).toBe('ongoing_profile_creation');
|
||||||
expect(completed).toBe('completed');
|
expect(completed).toBe('completed');
|
||||||
expect(incomplete).toBe('incomplete');
|
expect(incomplete).toBe('incomplete');
|
||||||
|
|||||||
@ -5,7 +5,7 @@ export enum OnboardingStatus {
|
|||||||
Incomplete = 'incomplete',
|
Incomplete = 'incomplete',
|
||||||
Canceled = 'canceled',
|
Canceled = 'canceled',
|
||||||
OngoingUserCreation = 'ongoing_user_creation',
|
OngoingUserCreation = 'ongoing_user_creation',
|
||||||
OngoingWorkspaceCreation = 'ongoing_workspace_creation',
|
OngoingWorkspaceActivation = 'ongoing_workspace_activation',
|
||||||
OngoingProfileCreation = 'ongoing_profile_creation',
|
OngoingProfileCreation = 'ongoing_profile_creation',
|
||||||
Completed = 'completed',
|
Completed = 'completed',
|
||||||
}
|
}
|
||||||
@ -28,11 +28,6 @@ export const getOnboardingStatus = ({
|
|||||||
return OnboardingStatus.OngoingUserCreation;
|
return OnboardingStatus.OngoingUserCreation;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the user has not been fetched yet, we can't know the onboarding status
|
|
||||||
if (!currentWorkspaceMember) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isBillingEnabled &&
|
isBillingEnabled &&
|
||||||
currentWorkspace?.subscriptionStatus === 'incomplete'
|
currentWorkspace?.subscriptionStatus === 'incomplete'
|
||||||
@ -44,9 +39,10 @@ export const getOnboardingStatus = ({
|
|||||||
return OnboardingStatus.Canceled;
|
return OnboardingStatus.Canceled;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currentWorkspace?.displayName) {
|
if (!currentWorkspaceMember) {
|
||||||
return OnboardingStatus.OngoingWorkspaceCreation;
|
return OnboardingStatus.OngoingWorkspaceActivation;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!currentWorkspaceMember.name.firstName ||
|
!currentWorkspaceMember.name.firstName ||
|
||||||
!currentWorkspaceMember.name.lastName
|
!currentWorkspaceMember.name.lastName
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
import { expect, userEvent, within } from '@storybook/test';
|
import { expect, userEvent, within } from '@storybook/test';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||||
import { CommandType } from '@/command-menu/types/Command';
|
import { CommandType } from '@/command-menu/types/Command';
|
||||||
@ -11,7 +12,10 @@ import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWith
|
|||||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { mockDefaultWorkspace } from '~/testing/mock-data/users';
|
import {
|
||||||
|
mockDefaultWorkspace,
|
||||||
|
mockedWorkspaceMemberData,
|
||||||
|
} from '~/testing/mock-data/users';
|
||||||
import { sleep } from '~/testing/sleep';
|
import { sleep } from '~/testing/sleep';
|
||||||
|
|
||||||
import { CommandMenu } from '../CommandMenu';
|
import { CommandMenu } from '../CommandMenu';
|
||||||
@ -24,10 +28,14 @@ const meta: Meta<typeof CommandMenu> = {
|
|||||||
decorators: [
|
decorators: [
|
||||||
(Story) => {
|
(Story) => {
|
||||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
||||||
|
const setCurrentWorkspaceMember = useSetRecoilState(
|
||||||
|
currentWorkspaceMemberState,
|
||||||
|
);
|
||||||
const { addToCommandMenu, setToIntitialCommandMenu, openCommandMenu } =
|
const { addToCommandMenu, setToIntitialCommandMenu, openCommandMenu } =
|
||||||
useCommandMenu();
|
useCommandMenu();
|
||||||
|
|
||||||
setCurrentWorkspace(mockDefaultWorkspace);
|
setCurrentWorkspace(mockDefaultWorkspace);
|
||||||
|
setCurrentWorkspaceMember(mockedWorkspaceMemberData);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setToIntitialCommandMenu();
|
setToIntitialCommandMenu();
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { useRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||||
|
import { AppPath } from '@/types/AppPath';
|
||||||
import {
|
import {
|
||||||
IconCheckbox,
|
IconCheckbox,
|
||||||
IconList,
|
IconList,
|
||||||
@ -71,7 +72,7 @@ export const MobileNavigationBar = () => {
|
|||||||
onClick: () => {
|
onClick: () => {
|
||||||
closeCommandMenu();
|
closeCommandMenu();
|
||||||
setIsNavigationDrawerOpen(false);
|
setIsNavigationDrawerOpen(false);
|
||||||
navigate('/tasks');
|
navigate(AppPath.TasksPage);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
|
||||||
import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/ObjectMetadataItemsLoadEffect';
|
import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/ObjectMetadataItemsLoadEffect';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope';
|
import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope';
|
||||||
@ -9,12 +9,14 @@ export const ObjectMetadataItemsProvider = ({
|
|||||||
children,
|
children,
|
||||||
}: React.PropsWithChildren) => {
|
}: React.PropsWithChildren) => {
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const isCurrentWorkspaceActive = useRecoilValue(
|
||||||
|
isCurrentWorkspaceActiveSelector,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ObjectMetadataItemsLoadEffect />
|
<ObjectMetadataItemsLoadEffect />
|
||||||
{(!currentWorkspace || !!objectMetadataItems.length) && (
|
{(!isCurrentWorkspaceActive || !!objectMetadataItems.length) && (
|
||||||
<RelationPickerScope relationPickerScopeId="relation-picker">
|
<RelationPickerScope relationPickerScopeId="relation-picker">
|
||||||
{children}
|
{children}
|
||||||
</RelationPickerScope>
|
</RelationPickerScope>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
|
||||||
import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError';
|
import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError';
|
||||||
import { useGetObjectOrderByField } from '@/object-metadata/hooks/useGetObjectOrderByField';
|
import { useGetObjectOrderByField } from '@/object-metadata/hooks/useGetObjectOrderByField';
|
||||||
import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier';
|
import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier';
|
||||||
@ -40,7 +40,9 @@ export const useObjectMetadataItem = (
|
|||||||
{ objectNameSingular }: ObjectMetadataItemIdentifier,
|
{ objectNameSingular }: ObjectMetadataItemIdentifier,
|
||||||
depth?: number,
|
depth?: number,
|
||||||
) => {
|
) => {
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const isCurrentWorkspaceActive = useRecoilValue(
|
||||||
|
isCurrentWorkspaceActiveSelector,
|
||||||
|
);
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||||
|
|
||||||
let objectMetadataItem = useRecoilValue(
|
let objectMetadataItem = useRecoilValue(
|
||||||
@ -52,7 +54,7 @@ export const useObjectMetadataItem = (
|
|||||||
|
|
||||||
let objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
let objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
|
|
||||||
if (!currentWorkspace) {
|
if (!isCurrentWorkspaceActive) {
|
||||||
objectMetadataItem =
|
objectMetadataItem =
|
||||||
mockObjectMetadataItems.find(
|
mockObjectMetadataItems.find(
|
||||||
(objectMetadataItem) =>
|
(objectMetadataItem) =>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
|
||||||
import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError';
|
import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError';
|
||||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
@ -12,7 +12,9 @@ import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentif
|
|||||||
export const useObjectMetadataItemOnly = ({
|
export const useObjectMetadataItemOnly = ({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
}: ObjectMetadataItemIdentifier) => {
|
}: ObjectMetadataItemIdentifier) => {
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const isCurrentWorkspaceActive = useRecoilValue(
|
||||||
|
isCurrentWorkspaceActiveSelector,
|
||||||
|
);
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||||
|
|
||||||
let objectMetadataItem = useRecoilValue(
|
let objectMetadataItem = useRecoilValue(
|
||||||
@ -24,7 +26,7 @@ export const useObjectMetadataItemOnly = ({
|
|||||||
|
|
||||||
let objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
let objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
|
|
||||||
if (!currentWorkspace) {
|
if (!isCurrentWorkspaceActive) {
|
||||||
objectMetadataItem =
|
objectMetadataItem =
|
||||||
mockObjectMetadataItems.find(
|
mockObjectMetadataItems.find(
|
||||||
(objectMetadataItem) =>
|
(objectMetadataItem) =>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
|
||||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
@ -10,7 +10,9 @@ export const useObjectNamePluralFromSingular = ({
|
|||||||
}: {
|
}: {
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
}) => {
|
}) => {
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const isCurrentWorkspaceActive = useRecoilValue(
|
||||||
|
isCurrentWorkspaceActiveSelector,
|
||||||
|
);
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||||
|
|
||||||
let objectMetadataItem = useRecoilValue(
|
let objectMetadataItem = useRecoilValue(
|
||||||
@ -20,7 +22,7 @@ export const useObjectNamePluralFromSingular = ({
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!currentWorkspace) {
|
if (!isCurrentWorkspaceActive) {
|
||||||
objectMetadataItem =
|
objectMetadataItem =
|
||||||
mockObjectMetadataItems.find(
|
mockObjectMetadataItems.find(
|
||||||
(objectMetadataItem) =>
|
(objectMetadataItem) =>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
|
||||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
@ -10,7 +10,9 @@ export const useObjectNameSingularFromPlural = ({
|
|||||||
}: {
|
}: {
|
||||||
objectNamePlural: string;
|
objectNamePlural: string;
|
||||||
}) => {
|
}) => {
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const isCurrentWorkspaceActive = useRecoilValue(
|
||||||
|
isCurrentWorkspaceActiveSelector,
|
||||||
|
);
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||||
|
|
||||||
let objectMetadataItem = useRecoilValue(
|
let objectMetadataItem = useRecoilValue(
|
||||||
@ -20,7 +22,7 @@ export const useObjectNameSingularFromPlural = ({
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!currentWorkspace) {
|
if (!isCurrentWorkspaceActive) {
|
||||||
objectMetadataItem =
|
objectMetadataItem =
|
||||||
mockObjectMetadataItems.find(
|
mockObjectMetadataItems.find(
|
||||||
(objectMetadataItem) =>
|
(objectMetadataItem) =>
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { MockedProvider } from '@apollo/client/testing';
|
|||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||||
import {
|
import {
|
||||||
@ -39,7 +39,7 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
describe('useFindManyRecords', () => {
|
describe('useFindManyRecords', () => {
|
||||||
it('should skip fetch if currentWorkspace is undefined', async () => {
|
it('should skip fetch if currentWorkspaceMember is undefined', async () => {
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => useFindManyRecords({ objectNameSingular: 'person' }),
|
() => useFindManyRecords({ objectNameSingular: 'person' }),
|
||||||
{
|
{
|
||||||
@ -56,12 +56,12 @@ describe('useFindManyRecords', () => {
|
|||||||
|
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
const setCurrentWorkspaceMember = useSetRecoilState(
|
||||||
setCurrentWorkspace({
|
currentWorkspaceMemberState,
|
||||||
|
);
|
||||||
|
setCurrentWorkspaceMember({
|
||||||
id: '32219445-f587-4c40-b2b1-6d3205ed96da',
|
id: '32219445-f587-4c40-b2b1-6d3205ed96da',
|
||||||
displayName: 'cool-workspace',
|
name: { firstName: 'John', lastName: 'Connor' },
|
||||||
allowImpersonation: false,
|
|
||||||
subscriptionStatus: 'incomplete',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { isNonEmptyArray } from '@apollo/client/utilities';
|
|||||||
import { isNonEmptyString } from '@sniptt/guards';
|
import { isNonEmptyString } from '@sniptt/guards';
|
||||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
|
import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
|
||||||
import { useMapConnectionToRecords } from '@/object-record/hooks/useMapConnectionToRecords';
|
import { useMapConnectionToRecords } from '@/object-record/hooks/useMapConnectionToRecords';
|
||||||
@ -65,12 +65,12 @@ export const useFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
|
|
||||||
const { data, loading, error, fetchMore } = useQuery<
|
const { data, loading, error, fetchMore } = useQuery<
|
||||||
ObjectRecordQueryResult<T>
|
ObjectRecordQueryResult<T>
|
||||||
>(findManyRecordsQuery, {
|
>(findManyRecordsQuery, {
|
||||||
skip: skip || !objectMetadataItem || !currentWorkspace,
|
skip: skip || !objectMetadataItem || !currentWorkspaceMember,
|
||||||
variables: {
|
variables: {
|
||||||
filter,
|
filter,
|
||||||
limit,
|
limit,
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {
|
|||||||
} from '@storybook/test';
|
} from '@storybook/test';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
@ -17,7 +18,10 @@ import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/Componen
|
|||||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { mockDefaultWorkspace } from '~/testing/mock-data/users';
|
import {
|
||||||
|
mockDefaultWorkspace,
|
||||||
|
mockedWorkspaceMemberData,
|
||||||
|
} from '~/testing/mock-data/users';
|
||||||
|
|
||||||
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||||
import {
|
import {
|
||||||
@ -27,10 +31,14 @@ import {
|
|||||||
|
|
||||||
const RelationWorkspaceSetterEffect = () => {
|
const RelationWorkspaceSetterEffect = () => {
|
||||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
||||||
|
const setCurrentWorkspaceMember = useSetRecoilState(
|
||||||
|
currentWorkspaceMemberState,
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCurrentWorkspace(mockDefaultWorkspace);
|
setCurrentWorkspace(mockDefaultWorkspace);
|
||||||
}, [setCurrentWorkspace]);
|
setCurrentWorkspaceMember(mockedWorkspaceMemberData);
|
||||||
|
}, [setCurrentWorkspace, setCurrentWorkspaceMember]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { isCurrentWorkspaceActiveSelector } from '@/auth/states/selectors/isCurrentWorkspaceActiveSelector';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||||
import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter';
|
import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter';
|
||||||
@ -13,8 +13,10 @@ import { useFindManyRecords } from '../../hooks/useFindManyRecords';
|
|||||||
export const useLoadRecordIndexTable = (objectNameSingular: string) => {
|
export const useLoadRecordIndexTable = (objectNameSingular: string) => {
|
||||||
const { setRecordTableData, setIsRecordTableInitialLoading } =
|
const { setRecordTableData, setIsRecordTableInitialLoading } =
|
||||||
useRecordTable();
|
useRecordTable();
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
|
||||||
|
|
||||||
|
const isCurrentWorkspaceActive = useRecoilValue(
|
||||||
|
isCurrentWorkspaceActiveSelector,
|
||||||
|
);
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
const { objectMetadataItem } = useObjectMetadataItem({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
@ -51,7 +53,7 @@ export const useLoadRecordIndexTable = (objectNameSingular: string) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
records: currentWorkspace ? records : signInBackgroundMockCompanies,
|
records: isCurrentWorkspaceActive ? records : signInBackgroundMockCompanies,
|
||||||
loading,
|
loading,
|
||||||
fetchMoreRecords,
|
fetchMoreRecords,
|
||||||
queryStateIdentifier,
|
queryStateIdentifier,
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
import { atomFamily } from 'recoil';
|
|
||||||
|
|
||||||
export const isCreateModeScopedState = atomFamily<boolean, string>({
|
|
||||||
key: 'isCreateModeScopedState',
|
|
||||||
default: false,
|
|
||||||
});
|
|
||||||
@ -3,7 +3,7 @@ import { MockedProvider } from '@apollo/client/testing';
|
|||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||||
import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/types/EntitiesForMultipleEntitySelect';
|
import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/types/EntitiesForMultipleEntitySelect';
|
||||||
@ -66,12 +66,12 @@ describe('useFilteredSearchEntityQuery', () => {
|
|||||||
it('returns the correct result when everything is provided', async () => {
|
it('returns the correct result when everything is provided', async () => {
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
const setCurrentWorkspaceMember = useSetRecoilState(
|
||||||
setCurrentWorkspace({
|
currentWorkspaceMemberState,
|
||||||
|
);
|
||||||
|
setCurrentWorkspaceMember({
|
||||||
id: '32219445-f587-4c40-b2b1-6d3205ed96da',
|
id: '32219445-f587-4c40-b2b1-6d3205ed96da',
|
||||||
displayName: 'cool-workspace',
|
name: { firstName: 'John', lastName: 'Connor' },
|
||||||
allowImpersonation: false,
|
|
||||||
subscriptionStatus: 'incomplete',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||||
|
|||||||
@ -28,7 +28,6 @@ export const SignInBackgroundMockContainerEffect = ({
|
|||||||
const {
|
const {
|
||||||
setAvailableTableColumns,
|
setAvailableTableColumns,
|
||||||
setOnEntityCountChange,
|
setOnEntityCountChange,
|
||||||
setRecordTableData,
|
|
||||||
setTableColumns,
|
setTableColumns,
|
||||||
resetTableRowSelection,
|
resetTableRowSelection,
|
||||||
} = useRecordTable({
|
} = useRecordTable({
|
||||||
@ -77,7 +76,6 @@ export const SignInBackgroundMockContainerEffect = ({
|
|||||||
setAvailableFieldDefinitions,
|
setAvailableFieldDefinitions,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
setAvailableTableColumns,
|
setAvailableTableColumns,
|
||||||
setRecordTableData,
|
|
||||||
setTableColumns,
|
setTableColumns,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { useSetRecoilState } from 'recoil';
|
|||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { GET_CURRENT_USER_AND_VIEWS } from '@/users/graphql/queries/getCurrentUserAndViews';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
||||||
|
|
||||||
export const UserProvider = ({ children }: React.PropsWithChildren) => {
|
export const UserProvider = ({ children }: React.PropsWithChildren) => {
|
||||||
@ -13,21 +13,22 @@ export const UserProvider = ({ children }: React.PropsWithChildren) => {
|
|||||||
|
|
||||||
const setCurrentUser = useSetRecoilState(currentUserState);
|
const setCurrentUser = useSetRecoilState(currentUserState);
|
||||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
||||||
|
|
||||||
const setCurrentWorkspaceMember = useSetRecoilState(
|
const setCurrentWorkspaceMember = useSetRecoilState(
|
||||||
currentWorkspaceMemberState,
|
currentWorkspaceMemberState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { loading: queryLoading, data: queryData } = useQuery(
|
const { loading: queryLoading, data: queryData } = useQuery(GET_CURRENT_USER);
|
||||||
GET_CURRENT_USER_AND_VIEWS,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!queryLoading) {
|
if (!queryLoading) {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
if (queryData?.currentUser?.workspaceMember) {
|
if (queryData?.currentUser) {
|
||||||
setCurrentUser(queryData.currentUser);
|
setCurrentUser(queryData.currentUser);
|
||||||
setCurrentWorkspace(queryData.currentUser.defaultWorkspace);
|
setCurrentWorkspace(queryData.currentUser.defaultWorkspace);
|
||||||
|
}
|
||||||
|
if (queryData?.currentUser?.workspaceMember) {
|
||||||
const workspaceMember = queryData.currentUser.workspaceMember;
|
const workspaceMember = queryData.currentUser.workspaceMember;
|
||||||
setCurrentWorkspaceMember({
|
setCurrentWorkspaceMember({
|
||||||
...workspaceMember,
|
...workspaceMember,
|
||||||
|
|||||||
@ -0,0 +1,40 @@
|
|||||||
|
// This query cannot be put in the graphQL folder because it cannot be generated by the graphQL codegen.
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
export const GET_CURRENT_USER = gql`
|
||||||
|
query GetCurrentUser {
|
||||||
|
currentUser {
|
||||||
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
email
|
||||||
|
canImpersonate
|
||||||
|
supportUserHash
|
||||||
|
workspaceMember {
|
||||||
|
id
|
||||||
|
name {
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
}
|
||||||
|
colorScheme
|
||||||
|
avatarUrl
|
||||||
|
locale
|
||||||
|
}
|
||||||
|
defaultWorkspace {
|
||||||
|
id
|
||||||
|
displayName
|
||||||
|
logo
|
||||||
|
domainName
|
||||||
|
inviteHash
|
||||||
|
allowImpersonation
|
||||||
|
subscriptionStatus
|
||||||
|
featureFlags {
|
||||||
|
id
|
||||||
|
key
|
||||||
|
value
|
||||||
|
workspaceId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@ -1,103 +0,0 @@
|
|||||||
// This query cannot be put in the graphQL folder because it cannot be generated by the graphQL codegen.
|
|
||||||
import { gql } from '@apollo/client';
|
|
||||||
|
|
||||||
export const GET_CURRENT_USER_AND_VIEWS = gql`
|
|
||||||
query GetCurrentUserAndViews {
|
|
||||||
currentUser {
|
|
||||||
id
|
|
||||||
firstName
|
|
||||||
lastName
|
|
||||||
email
|
|
||||||
canImpersonate
|
|
||||||
supportUserHash
|
|
||||||
workspaceMember {
|
|
||||||
id
|
|
||||||
name {
|
|
||||||
firstName
|
|
||||||
lastName
|
|
||||||
}
|
|
||||||
colorScheme
|
|
||||||
avatarUrl
|
|
||||||
locale
|
|
||||||
}
|
|
||||||
defaultWorkspace {
|
|
||||||
id
|
|
||||||
displayName
|
|
||||||
logo
|
|
||||||
domainName
|
|
||||||
inviteHash
|
|
||||||
allowImpersonation
|
|
||||||
subscriptionStatus
|
|
||||||
featureFlags {
|
|
||||||
id
|
|
||||||
key
|
|
||||||
value
|
|
||||||
workspaceId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
views {
|
|
||||||
pageInfo {
|
|
||||||
hasNextPage
|
|
||||||
hasPreviousPage
|
|
||||||
startCursor
|
|
||||||
endCursor
|
|
||||||
}
|
|
||||||
edges {
|
|
||||||
cursor
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
name
|
|
||||||
objectMetadataId
|
|
||||||
type
|
|
||||||
deletedAt
|
|
||||||
viewFilters {
|
|
||||||
edges {
|
|
||||||
cursor
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
fieldMetadataId
|
|
||||||
operand
|
|
||||||
value
|
|
||||||
displayValue
|
|
||||||
deletedAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewSorts {
|
|
||||||
edges {
|
|
||||||
cursor
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
fieldMetadataId
|
|
||||||
direction
|
|
||||||
deletedAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewFields {
|
|
||||||
edges {
|
|
||||||
cursor
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
fieldMetadataId
|
|
||||||
isVisible
|
|
||||||
size
|
|
||||||
position
|
|
||||||
deletedAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
export const ACTIVATE_WORKSPACE = gql`
|
||||||
|
mutation ActivateWorkspace($input: ActivateWorkspaceInput!) {
|
||||||
|
activateWorkspace(data: $input) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@ -1,6 +1,5 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
|
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
@ -54,7 +53,6 @@ const validationSchema = z
|
|||||||
type Form = z.infer<typeof validationSchema>;
|
type Form = z.infer<typeof validationSchema>;
|
||||||
|
|
||||||
export const CreateProfile = () => {
|
export const CreateProfile = () => {
|
||||||
const navigate = useNavigate();
|
|
||||||
const onboardingStatus = useOnboardingStatus();
|
const onboardingStatus = useOnboardingStatus();
|
||||||
|
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
@ -114,8 +112,6 @@ export const CreateProfile = () => {
|
|||||||
colorScheme: 'System',
|
colorScheme: 'System',
|
||||||
}) as any,
|
}) as any,
|
||||||
);
|
);
|
||||||
|
|
||||||
navigate('/');
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
enqueueSnackBar(error?.message, {
|
enqueueSnackBar(error?.message, {
|
||||||
variant: 'error',
|
variant: 'error',
|
||||||
@ -125,7 +121,6 @@ export const CreateProfile = () => {
|
|||||||
[
|
[
|
||||||
currentWorkspaceMember?.id,
|
currentWorkspaceMember?.id,
|
||||||
enqueueSnackBar,
|
enqueueSnackBar,
|
||||||
navigate,
|
|
||||||
setCurrentWorkspaceMember,
|
setCurrentWorkspaceMember,
|
||||||
updateOneRecord,
|
updateOneRecord,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -3,22 +3,24 @@ import { Controller, SubmitHandler, useForm } from 'react-hook-form';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useSetRecoilState } from 'recoil';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { SubTitle } from '@/auth/components/SubTitle';
|
import { SubTitle } from '@/auth/components/SubTitle';
|
||||||
import { Title } from '@/auth/components/Title';
|
import { Title } from '@/auth/components/Title';
|
||||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
|
||||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
||||||
|
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries';
|
||||||
|
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
|
||||||
import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader';
|
import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader';
|
||||||
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||||
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { MainButton } from '@/ui/input/button/components/MainButton';
|
import { MainButton } from '@/ui/input/button/components/MainButton';
|
||||||
import { TextInput } from '@/ui/input/components/TextInput';
|
import { TextInput } from '@/ui/input/components/TextInput';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { useUpdateWorkspaceMutation } from '~/generated/graphql';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
|
import { useActivateWorkspaceMutation } from '~/generated/graphql';
|
||||||
|
|
||||||
const StyledContentContainer = styled.div`
|
const StyledContentContainer = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -46,9 +48,9 @@ export const CreateWorkspace = () => {
|
|||||||
|
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
const onboardingStatus = useOnboardingStatus();
|
const onboardingStatus = useOnboardingStatus();
|
||||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
|
||||||
|
|
||||||
const [updateWorkspace] = useUpdateWorkspaceMutation();
|
const [activateWorkspace] = useActivateWorkspaceMutation();
|
||||||
|
const apolloMetadataClient = useApolloMetadataClient();
|
||||||
|
|
||||||
// Form
|
// Form
|
||||||
const {
|
const {
|
||||||
@ -67,28 +69,25 @@ export const CreateWorkspace = () => {
|
|||||||
const onSubmit: SubmitHandler<Form> = useCallback(
|
const onSubmit: SubmitHandler<Form> = useCallback(
|
||||||
async (data) => {
|
async (data) => {
|
||||||
try {
|
try {
|
||||||
const result = await updateWorkspace({
|
const result = await activateWorkspace({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
displayName: data.name,
|
displayName: data.name,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
refetchQueries: [GET_CURRENT_USER],
|
||||||
setCurrentWorkspace({
|
|
||||||
id: result.data?.updateWorkspace?.id ?? '',
|
|
||||||
displayName: data.name,
|
|
||||||
subscriptionStatus:
|
|
||||||
result.data?.updateWorkspace?.subscriptionStatus ?? 'incomplete',
|
|
||||||
allowImpersonation:
|
|
||||||
result.data?.updateWorkspace?.allowImpersonation ?? false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.errors || !result.data?.updateWorkspace) {
|
await apolloMetadataClient?.refetchQueries({
|
||||||
|
include: [FIND_MANY_OBJECT_METADATA_ITEMS],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.errors) {
|
||||||
throw result.errors ?? new Error('Unknown error');
|
throw result.errors ?? new Error('Unknown error');
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigate('/create/profile');
|
navigate(AppPath.CreateProfile);
|
||||||
}, 20);
|
}, 20);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
enqueueSnackBar(error?.message, {
|
enqueueSnackBar(error?.message, {
|
||||||
@ -96,7 +95,7 @@ export const CreateWorkspace = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[enqueueSnackBar, navigate, setCurrentWorkspace, updateWorkspace],
|
[enqueueSnackBar, navigate, apolloMetadataClient, activateWorkspace],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
@ -115,7 +114,7 @@ export const CreateWorkspace = () => {
|
|||||||
[onSubmit],
|
[onSubmit],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (onboardingStatus !== OnboardingStatus.OngoingWorkspaceCreation) {
|
if (onboardingStatus !== OnboardingStatus.OngoingWorkspaceActivation) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,7 @@ import { useRecoilValue } from 'recoil';
|
|||||||
import { useAuth } from '@/auth/hooks/useAuth';
|
import { useAuth } from '@/auth/hooks/useAuth';
|
||||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { AppPath } from '../../modules/types/AppPath';
|
|
||||||
|
|
||||||
export const VerifyEffect = () => {
|
export const VerifyEffect = () => {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { within } from '@storybook/test';
|
|||||||
import { graphql, HttpResponse } from 'msw';
|
import { graphql, HttpResponse } from 'msw';
|
||||||
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { GET_CURRENT_USER_AND_VIEWS } from '@/users/graphql/queries/getCurrentUserAndViews';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
import {
|
import {
|
||||||
PageDecorator,
|
PageDecorator,
|
||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
@ -22,16 +22,13 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
parameters: {
|
parameters: {
|
||||||
msw: {
|
msw: {
|
||||||
handlers: [
|
handlers: [
|
||||||
graphql.query(
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
getOperationName(GET_CURRENT_USER_AND_VIEWS) ?? '',
|
return HttpResponse.json({
|
||||||
() => {
|
data: {
|
||||||
return HttpResponse.json({
|
currentUser: mockedOnboardingUsersData[0],
|
||||||
data: {
|
},
|
||||||
currentUser: mockedOnboardingUsersData[0],
|
});
|
||||||
},
|
}),
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
graphqlMocks.handlers,
|
graphqlMocks.handlers,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
import { within } from '@storybook/test';
|
import { within } from '@storybook/test';
|
||||||
|
import { graphql, HttpResponse } from 'msw';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
import {
|
import {
|
||||||
PageDecorator,
|
PageDecorator,
|
||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
} from '~/testing/decorators/PageDecorator';
|
} from '~/testing/decorators/PageDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
|
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
import { CreateWorkspace } from '../CreateWorkspace';
|
import { CreateWorkspace } from '../CreateWorkspace';
|
||||||
|
|
||||||
@ -25,7 +29,18 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
],
|
],
|
||||||
args: { routePath: AppPath.CreateWorkspace },
|
args: { routePath: AppPath.CreateWorkspace },
|
||||||
parameters: {
|
parameters: {
|
||||||
msw: graphqlMocks,
|
msw: {
|
||||||
|
handlers: [
|
||||||
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
currentUser: mockedOnboardingUsersData[1],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
graphqlMocks.handlers,
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { within } from '@storybook/test';
|
|||||||
import { graphql, HttpResponse } from 'msw';
|
import { graphql, HttpResponse } from 'msw';
|
||||||
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { GET_CURRENT_USER_AND_VIEWS } from '@/users/graphql/queries/getCurrentUserAndViews';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
import {
|
import {
|
||||||
PageDecorator,
|
PageDecorator,
|
||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
@ -22,22 +22,19 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
parameters: {
|
parameters: {
|
||||||
msw: {
|
msw: {
|
||||||
handlers: [
|
handlers: [
|
||||||
graphql.query(
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
getOperationName(GET_CURRENT_USER_AND_VIEWS) ?? '',
|
return HttpResponse.json({
|
||||||
() => {
|
data: {
|
||||||
return HttpResponse.json({
|
currentUser: {
|
||||||
data: {
|
...mockedOnboardingUsersData[0],
|
||||||
currentUser: {
|
defaultWorkspace: {
|
||||||
...mockedOnboardingUsersData[0],
|
...mockedOnboardingUsersData[0].defaultWorkspace,
|
||||||
defaultWorkspace: {
|
subscriptionStatus: 'incomplete',
|
||||||
...mockedOnboardingUsersData[0].defaultWorkspace,
|
|
||||||
subscriptionStatus: 'incomplete',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
},
|
});
|
||||||
),
|
}),
|
||||||
graphqlMocks.handlers,
|
graphqlMocks.handlers,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { fireEvent, within } from '@storybook/test';
|
|||||||
import { graphql, HttpResponse } from 'msw';
|
import { graphql, HttpResponse } from 'msw';
|
||||||
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { GET_CURRENT_USER_AND_VIEWS } from '@/users/graphql/queries/getCurrentUserAndViews';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
import {
|
import {
|
||||||
PageDecorator,
|
PageDecorator,
|
||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
@ -22,16 +22,13 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
parameters: {
|
parameters: {
|
||||||
msw: {
|
msw: {
|
||||||
handlers: [
|
handlers: [
|
||||||
graphql.query(
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
getOperationName(GET_CURRENT_USER_AND_VIEWS) ?? '',
|
return HttpResponse.json({
|
||||||
() => {
|
data: {
|
||||||
return HttpResponse.json({
|
currentUser: mockedOnboardingUsersData[0],
|
||||||
data: {
|
},
|
||||||
currentUser: mockedOnboardingUsersData[0],
|
});
|
||||||
},
|
}),
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
graphqlMocks.handlers,
|
graphqlMocks.handlers,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -6,10 +6,9 @@ import { useRecoilState, useSetRecoilState } from 'recoil';
|
|||||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { tokenPairState } from '@/auth/states/tokenPairState';
|
import { tokenPairState } from '@/auth/states/tokenPairState';
|
||||||
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { useImpersonateMutation } from '~/generated/graphql';
|
import { useImpersonateMutation } from '~/generated/graphql';
|
||||||
|
|
||||||
import { AppPath } from '../../modules/types/AppPath';
|
|
||||||
|
|
||||||
export const ImpersonateEffect = () => {
|
export const ImpersonateEffect = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { userId } = useParams();
|
const { userId } = useParams();
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { SignInBackgroundMockPage } from '@/sign-in-background-mock/components/SignInBackgroundMockPage';
|
import { SignInBackgroundMockPage } from '@/sign-in-background-mock/components/SignInBackgroundMockPage';
|
||||||
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { MainButton } from '@/ui/input/button/components/MainButton';
|
import { MainButton } from '@/ui/input/button/components/MainButton';
|
||||||
import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder';
|
import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder';
|
||||||
import { StyledEmptyTextContainer } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
|
import { StyledEmptyTextContainer } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
|
||||||
@ -49,7 +50,7 @@ export const NotFound = () => {
|
|||||||
<MainButton
|
<MainButton
|
||||||
title="Back to content"
|
title="Back to content"
|
||||||
fullWidth
|
fullWidth
|
||||||
onClick={() => navigate('/')}
|
onClick={() => navigate(AppPath.Index)}
|
||||||
/>
|
/>
|
||||||
</StyledButtonContainer>
|
</StyledButtonContainer>
|
||||||
</StyledErrorContainer>
|
</StyledErrorContainer>
|
||||||
|
|||||||
@ -1,10 +1,6 @@
|
|||||||
import { useEffect } from 'react';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
|
||||||
|
|
||||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
|
||||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
|
||||||
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
|
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
|
||||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
@ -32,10 +28,6 @@ export const RecordIndexPage = () => {
|
|||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
});
|
});
|
||||||
|
|
||||||
const onboardingStatus = useOnboardingStatus();
|
|
||||||
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const { findObjectMetadataItemByNamePlural } =
|
const { findObjectMetadataItemByNamePlural } =
|
||||||
useObjectMetadataItemForSettings();
|
useObjectMetadataItemForSettings();
|
||||||
|
|
||||||
@ -44,15 +36,6 @@ export const RecordIndexPage = () => {
|
|||||||
findObjectMetadataItemByNamePlural(objectNamePlural)?.icon,
|
findObjectMetadataItemByNamePlural(objectNamePlural)?.icon,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
!isNonEmptyString(objectNamePlural) &&
|
|
||||||
onboardingStatus === OnboardingStatus.Completed
|
|
||||||
) {
|
|
||||||
navigate('/');
|
|
||||||
}
|
|
||||||
}, [objectNamePlural, navigate, onboardingStatus]);
|
|
||||||
|
|
||||||
const { createOneRecord: createOneObject } = useCreateOneRecord({
|
const { createOneRecord: createOneObject } = useCreateOneRecord({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { graphql, HttpResponse } from 'msw';
|
|||||||
import { CREATE_EVENT } from '@/analytics/graphql/queries/createEvent';
|
import { CREATE_EVENT } from '@/analytics/graphql/queries/createEvent';
|
||||||
import { GET_CLIENT_CONFIG } from '@/client-config/graphql/queries/getClientConfig';
|
import { GET_CLIENT_CONFIG } from '@/client-config/graphql/queries/getClientConfig';
|
||||||
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries';
|
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries';
|
||||||
import { GET_CURRENT_USER_AND_VIEWS } from '@/users/graphql/queries/getCurrentUserAndViews';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
||||||
import { mockedActivities } from '~/testing/mock-data/activities';
|
import { mockedActivities } from '~/testing/mock-data/activities';
|
||||||
import { mockedCompaniesData } from '~/testing/mock-data/companies';
|
import { mockedCompaniesData } from '~/testing/mock-data/companies';
|
||||||
@ -22,22 +22,10 @@ const metadataGraphql = graphql.link(`${REACT_APP_SERVER_BASE_URL}/metadata`);
|
|||||||
|
|
||||||
export const graphqlMocks = {
|
export const graphqlMocks = {
|
||||||
handlers: [
|
handlers: [
|
||||||
graphql.query(getOperationName(GET_CURRENT_USER_AND_VIEWS) ?? '', () => {
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: mockedUsersData[0],
|
currentUser: mockedUsersData[0],
|
||||||
views: {
|
|
||||||
edges: mockedViewsData.map((view) => ({
|
|
||||||
node: view,
|
|
||||||
cursor: null,
|
|
||||||
})),
|
|
||||||
pageInfo: {
|
|
||||||
hasNextPage: false,
|
|
||||||
hasPreviousPage: false,
|
|
||||||
startCursor: null,
|
|
||||||
endCursor: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@ type MockedUser = Pick<
|
|||||||
| '__typename'
|
| '__typename'
|
||||||
| 'supportUserHash'
|
| 'supportUserHash'
|
||||||
> & {
|
> & {
|
||||||
workspaceMember: WorkspaceMember;
|
workspaceMember: WorkspaceMember | null;
|
||||||
locale: string;
|
locale: string;
|
||||||
defaultWorkspace: Workspace;
|
defaultWorkspace: Workspace;
|
||||||
};
|
};
|
||||||
@ -34,7 +34,7 @@ export const mockDefaultWorkspace: Workspace = {
|
|||||||
updatedAt: '2023-04-26T10:23:42.33625+00:00',
|
updatedAt: '2023-04-26T10:23:42.33625+00:00',
|
||||||
};
|
};
|
||||||
|
|
||||||
const workspaceMember: WorkspaceMember = {
|
export const mockedWorkspaceMemberData: WorkspaceMember = {
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
||||||
colorScheme: 'Light',
|
colorScheme: 'Light',
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
@ -59,7 +59,7 @@ export const mockedUsersData: Array<MockedUser> = [
|
|||||||
canImpersonate: false,
|
canImpersonate: false,
|
||||||
supportUserHash:
|
supportUserHash:
|
||||||
'a95afad9ff6f0b364e2a3fd3e246a1a852c22b6e55a3ca33745a86c201f9c10d',
|
'a95afad9ff6f0b364e2a3fd3e246a1a852c22b6e55a3ca33745a86c201f9c10d',
|
||||||
workspaceMember,
|
workspaceMember: mockedWorkspaceMemberData,
|
||||||
defaultWorkspace: mockDefaultWorkspace,
|
defaultWorkspace: mockDefaultWorkspace,
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
},
|
},
|
||||||
@ -73,7 +73,7 @@ export const mockedUsersData: Array<MockedUser> = [
|
|||||||
supportUserHash:
|
supportUserHash:
|
||||||
'54ac3986035961724cdb9a7a30c70e6463a4b68f0ecd2014c727171a82144b74',
|
'54ac3986035961724cdb9a7a30c70e6463a4b68f0ecd2014c727171a82144b74',
|
||||||
workspaceMember: {
|
workspaceMember: {
|
||||||
...workspaceMember,
|
...mockedWorkspaceMemberData,
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6c',
|
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6c',
|
||||||
name: {
|
name: {
|
||||||
firstName: 'Felix',
|
firstName: 'Felix',
|
||||||
@ -97,7 +97,7 @@ export const mockedOnboardingUsersData: Array<MockedUser> = [
|
|||||||
supportUserHash:
|
supportUserHash:
|
||||||
'4fb61d34ed3a4aeda2476d4b308b5162db9e1809b2b8277e6fdc6efc4a609254',
|
'4fb61d34ed3a4aeda2476d4b308b5162db9e1809b2b8277e6fdc6efc4a609254',
|
||||||
workspaceMember: {
|
workspaceMember: {
|
||||||
...workspaceMember,
|
...mockedWorkspaceMemberData,
|
||||||
id: 'd454f075-c72f-4ebe-bac7-d28e75e74a23',
|
id: 'd454f075-c72f-4ebe-bac7-d28e75e74a23',
|
||||||
name: {
|
name: {
|
||||||
firstName: '',
|
firstName: '',
|
||||||
@ -116,7 +116,7 @@ export const mockedOnboardingUsersData: Array<MockedUser> = [
|
|||||||
firstName: '',
|
firstName: '',
|
||||||
lastName: '',
|
lastName: '',
|
||||||
canImpersonate: false,
|
canImpersonate: false,
|
||||||
workspaceMember,
|
workspaceMember: null,
|
||||||
defaultWorkspace: {
|
defaultWorkspace: {
|
||||||
...mockDefaultWorkspace,
|
...mockDefaultWorkspace,
|
||||||
displayName: '',
|
displayName: '',
|
||||||
|
|||||||
@ -101,6 +101,10 @@ export class AuthResolver {
|
|||||||
@AuthUser() user: User,
|
@AuthUser() user: User,
|
||||||
): Promise<TransientToken | void> {
|
): Promise<TransientToken | void> {
|
||||||
const workspaceMember = await this.userService.loadWorkspaceMember(user);
|
const workspaceMember = await this.userService.loadWorkspaceMember(user);
|
||||||
|
|
||||||
|
if (!workspaceMember) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const transientToken = await this.tokenService.generateTransientToken(
|
const transientToken = await this.tokenService.generateTransientToken(
|
||||||
workspaceMember.id,
|
workspaceMember.id,
|
||||||
user.defaultWorkspace.id,
|
user.defaultWorkspace.id,
|
||||||
|
|||||||
@ -7,11 +7,11 @@ import {
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { HttpService } from '@nestjs/axios';
|
import { HttpService } from '@nestjs/axios';
|
||||||
|
|
||||||
import FileType from 'file-type';
|
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
import { render } from '@react-email/components';
|
import { render } from '@react-email/components';
|
||||||
import { PasswordUpdateNotifyEmail } from 'twenty-emails';
|
import { PasswordUpdateNotifyEmail } from 'twenty-emails';
|
||||||
|
import FileType from 'file-type';
|
||||||
|
|
||||||
import { FileFolder } from 'src/core/file/interfaces/file-folder.interface';
|
import { FileFolder } from 'src/core/file/interfaces/file-folder.interface';
|
||||||
|
|
||||||
@ -29,11 +29,11 @@ import { User } from 'src/core/user/user.entity';
|
|||||||
import { Workspace } from 'src/core/workspace/workspace.entity';
|
import { Workspace } from 'src/core/workspace/workspace.entity';
|
||||||
import { UserService } from 'src/core/user/services/user.service';
|
import { UserService } from 'src/core/user/services/user.service';
|
||||||
import { WorkspaceManagerService } from 'src/workspace/workspace-manager/workspace-manager.service';
|
import { WorkspaceManagerService } from 'src/workspace/workspace-manager/workspace-manager.service';
|
||||||
import { getImageBufferFromUrl } from 'src/utils/image';
|
|
||||||
import { FileUploadService } from 'src/core/file/services/file-upload.service';
|
import { FileUploadService } from 'src/core/file/services/file-upload.service';
|
||||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||||
import { EmailService } from 'src/integrations/email/email.service';
|
import { EmailService } from 'src/integrations/email/email.service';
|
||||||
import { UpdatePassword } from 'src/core/auth/dto/update-password.entity';
|
import { UpdatePassword } from 'src/core/auth/dto/update-password.entity';
|
||||||
|
import { getImageBufferFromUrl } from 'src/utils/image';
|
||||||
|
|
||||||
import { TokenService } from './token.service';
|
import { TokenService } from './token.service';
|
||||||
|
|
||||||
@ -135,18 +135,8 @@ export class AuthService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
workspace = await this.workspaceRepository.save(workspaceToCreate);
|
workspace = await this.workspaceRepository.save(workspaceToCreate);
|
||||||
await this.workspaceManagerService.init(workspace.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const userToCreate = this.userRepository.create({
|
|
||||||
email: email,
|
|
||||||
firstName: firstName,
|
|
||||||
lastName: lastName,
|
|
||||||
canImpersonate: false,
|
|
||||||
passwordHash,
|
|
||||||
defaultWorkspace: workspace,
|
|
||||||
});
|
|
||||||
const user = await this.userRepository.save(userToCreate);
|
|
||||||
let imagePath: string | undefined = undefined;
|
let imagePath: string | undefined = undefined;
|
||||||
|
|
||||||
if (picture) {
|
if (picture) {
|
||||||
@ -166,9 +156,18 @@ export class AuthService {
|
|||||||
|
|
||||||
imagePath = paths[0];
|
imagePath = paths[0];
|
||||||
}
|
}
|
||||||
await this.userService.createWorkspaceMember(user, imagePath);
|
|
||||||
|
|
||||||
return user;
|
const userToCreate = this.userRepository.create({
|
||||||
|
email: email,
|
||||||
|
firstName: firstName,
|
||||||
|
lastName: lastName,
|
||||||
|
defaultAvatarUrl: imagePath,
|
||||||
|
canImpersonate: false,
|
||||||
|
passwordHash,
|
||||||
|
defaultWorkspace: workspace,
|
||||||
|
});
|
||||||
|
|
||||||
|
return await this.userRepository.save(userToCreate);
|
||||||
}
|
}
|
||||||
|
|
||||||
async verify(email: string): Promise<Verify> {
|
async verify(email: string): Promise<Verify> {
|
||||||
@ -189,7 +188,11 @@ export class AuthService {
|
|||||||
|
|
||||||
// passwordHash is hidden for security reasons
|
// passwordHash is hidden for security reasons
|
||||||
user.passwordHash = '';
|
user.passwordHash = '';
|
||||||
user.workspaceMember = await this.userService.loadWorkspaceMember(user);
|
const workspaceMember = await this.userService.loadWorkspaceMember(user);
|
||||||
|
|
||||||
|
if (workspaceMember) {
|
||||||
|
user.workspaceMember = workspaceMember;
|
||||||
|
}
|
||||||
|
|
||||||
const accessToken = await this.tokenService.generateAccessToken(user.id);
|
const accessToken = await this.tokenService.generateAccessToken(user.id);
|
||||||
const refreshToken = await this.tokenService.generateRefreshToken(user.id);
|
const refreshToken = await this.tokenService.generateRefreshToken(user.id);
|
||||||
|
|||||||
@ -21,11 +21,23 @@ export class UserService extends TypeOrmQueryService<User> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async loadWorkspaceMember(user: User) {
|
async loadWorkspaceMember(user: User) {
|
||||||
const dataSourceMetadata =
|
const dataSourcesMetadata =
|
||||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
await this.dataSourceService.getDataSourcesMetadataFromWorkspaceId(
|
||||||
user.defaultWorkspace.id,
|
user.defaultWorkspace.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!dataSourcesMetadata.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataSourcesMetadata.length > 1) {
|
||||||
|
throw new Error(
|
||||||
|
`user '${user.id}' default workspace '${user.defaultWorkspace.id}' has multiple data source metadata`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataSourceMetadata = dataSourcesMetadata[0];
|
||||||
|
|
||||||
const workspaceDataSource =
|
const workspaceDataSource =
|
||||||
await this.typeORMService.connectToDataSource(dataSourceMetadata);
|
await this.typeORMService.connectToDataSource(dataSourceMetadata);
|
||||||
|
|
||||||
@ -33,6 +45,10 @@ export class UserService extends TypeOrmQueryService<User> {
|
|||||||
`SELECT * FROM ${dataSourceMetadata.schema}."workspaceMember" WHERE "userId" = '${user.id}'`,
|
`SELECT * FROM ${dataSourceMetadata.schema}."workspaceMember" WHERE "userId" = '${user.id}'`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!workspaceMembers.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
assert(workspaceMembers.length === 1, 'WorkspaceMember not found');
|
assert(workspaceMembers.length === 1, 'WorkspaceMember not found');
|
||||||
|
|
||||||
const userWorkspaceMember = new WorkspaceMember();
|
const userWorkspaceMember = new WorkspaceMember();
|
||||||
@ -63,7 +79,7 @@ export class UserService extends TypeOrmQueryService<User> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createWorkspaceMember(user: User, avatarUrl?: string) {
|
async createWorkspaceMember(user: User) {
|
||||||
const dataSourceMetadata =
|
const dataSourceMetadata =
|
||||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
||||||
user.defaultWorkspace.id,
|
user.defaultWorkspace.id,
|
||||||
@ -77,7 +93,7 @@ export class UserService extends TypeOrmQueryService<User> {
|
|||||||
("nameFirstName", "nameLastName", "colorScheme", "userId", "userEmail", "avatarUrl")
|
("nameFirstName", "nameLastName", "colorScheme", "userId", "userEmail", "avatarUrl")
|
||||||
VALUES ('${user.firstName}', '${user.lastName}', 'Light', '${
|
VALUES ('${user.firstName}', '${user.lastName}', 'Light', '${
|
||||||
user.id
|
user.id
|
||||||
}', '${user.email}', '${avatarUrl ?? ''}')`,
|
}', '${user.email}', '${user.defaultAvatarUrl ?? ''}')`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,10 @@ export class User {
|
|||||||
@Column()
|
@Column()
|
||||||
email: string;
|
email: string;
|
||||||
|
|
||||||
|
@Field({ nullable: true })
|
||||||
|
@Column({ nullable: true })
|
||||||
|
defaultAvatarUrl: string;
|
||||||
|
|
||||||
@Field()
|
@Field()
|
||||||
@Column({ default: false })
|
@Column({ default: false })
|
||||||
emailVerified: boolean;
|
emailVerified: boolean;
|
||||||
@ -81,6 +85,6 @@ export class User {
|
|||||||
})
|
})
|
||||||
refreshTokens: RefreshToken[];
|
refreshTokens: RefreshToken[];
|
||||||
|
|
||||||
@Field(() => WorkspaceMember, { nullable: false })
|
@Field(() => WorkspaceMember, { nullable: true })
|
||||||
workspaceMember: WorkspaceMember;
|
workspaceMember: WorkspaceMember;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,9 +55,11 @@ export class UserResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ResolveField(() => WorkspaceMember, {
|
@ResolveField(() => WorkspaceMember, {
|
||||||
nullable: false,
|
nullable: true,
|
||||||
})
|
})
|
||||||
async workspaceMember(@Parent() user: User): Promise<WorkspaceMember> {
|
async workspaceMember(
|
||||||
|
@Parent() user: User,
|
||||||
|
): Promise<WorkspaceMember | undefined> {
|
||||||
return this.userService.loadWorkspaceMember(user);
|
return this.userService.loadWorkspaceMember(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { Field, InputType } from '@nestjs/graphql';
|
||||||
|
|
||||||
|
import { IsOptional, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
@InputType()
|
||||||
|
export class ActivateWorkspaceInput {
|
||||||
|
@Field({ nullable: true })
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
displayName?: string;
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
|
|||||||
|
|
||||||
import { Workspace } from 'src/core/workspace/workspace.entity';
|
import { Workspace } from 'src/core/workspace/workspace.entity';
|
||||||
import { WorkspaceManagerService } from 'src/workspace/workspace-manager/workspace-manager.service';
|
import { WorkspaceManagerService } from 'src/workspace/workspace-manager/workspace-manager.service';
|
||||||
|
import { UserService } from 'src/core/user/services/user.service';
|
||||||
|
|
||||||
import { WorkspaceService } from './workspace.service';
|
import { WorkspaceService } from './workspace.service';
|
||||||
|
|
||||||
@ -21,6 +22,10 @@ describe('WorkspaceService', () => {
|
|||||||
provide: WorkspaceManagerService,
|
provide: WorkspaceManagerService,
|
||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: UserService,
|
||||||
|
useValue: {},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { BadRequestException } from '@nestjs/common';
|
||||||
|
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
|
||||||
@ -7,16 +8,33 @@ import { Repository } from 'typeorm';
|
|||||||
|
|
||||||
import { WorkspaceManagerService } from 'src/workspace/workspace-manager/workspace-manager.service';
|
import { WorkspaceManagerService } from 'src/workspace/workspace-manager/workspace-manager.service';
|
||||||
import { Workspace } from 'src/core/workspace/workspace.entity';
|
import { Workspace } from 'src/core/workspace/workspace.entity';
|
||||||
|
import { User } from 'src/core/user/user.entity';
|
||||||
|
import { UserService } from 'src/core/user/services/user.service';
|
||||||
|
import { ActivateWorkspaceInput } from 'src/core/workspace/dtos/activate-workspace-input';
|
||||||
|
|
||||||
export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Workspace, 'core')
|
@InjectRepository(Workspace, 'core')
|
||||||
private readonly workspaceRepository: Repository<Workspace>,
|
private readonly workspaceRepository: Repository<Workspace>,
|
||||||
private readonly workspaceManagerService: WorkspaceManagerService,
|
private readonly workspaceManagerService: WorkspaceManagerService,
|
||||||
|
private readonly userService: UserService,
|
||||||
) {
|
) {
|
||||||
super(workspaceRepository);
|
super(workspaceRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async activateWorkspace(user: User, data: ActivateWorkspaceInput) {
|
||||||
|
if (!data.displayName || !data.displayName.length) {
|
||||||
|
throw new BadRequestException("'displayName' not provided");
|
||||||
|
}
|
||||||
|
await this.workspaceRepository.update(user.defaultWorkspace.id, {
|
||||||
|
displayName: data.displayName,
|
||||||
|
});
|
||||||
|
await this.workspaceManagerService.init(user.defaultWorkspace.id);
|
||||||
|
await this.userService.createWorkspaceMember(user);
|
||||||
|
|
||||||
|
return user.defaultWorkspace;
|
||||||
|
}
|
||||||
|
|
||||||
async deleteWorkspace(id: string, shouldDeleteCoreWorkspace = true) {
|
async deleteWorkspace(id: string, shouldDeleteCoreWorkspace = true) {
|
||||||
const workspace = await this.workspaceRepository.findOneBy({ id });
|
const workspace = await this.workspaceRepository.findOneBy({ id });
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { WorkspaceManagerModule } from 'src/workspace/workspace-manager/workspac
|
|||||||
import { WorkspaceResolver } from 'src/core/workspace/workspace.resolver';
|
import { WorkspaceResolver } from 'src/core/workspace/workspace.resolver';
|
||||||
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
||||||
import { FeatureFlagEntity } from 'src/core/feature-flag/feature-flag.entity';
|
import { FeatureFlagEntity } from 'src/core/feature-flag/feature-flag.entity';
|
||||||
|
import { UserModule } from 'src/core/user/user.module';
|
||||||
|
|
||||||
import { Workspace } from './workspace.entity';
|
import { Workspace } from './workspace.entity';
|
||||||
import { workspaceAutoResolverOpts } from './workspace.auto-resolver-opts';
|
import { workspaceAutoResolverOpts } from './workspace.auto-resolver-opts';
|
||||||
@ -24,6 +25,7 @@ import { WorkspaceService } from './services/workspace.service';
|
|||||||
'core',
|
'core',
|
||||||
),
|
),
|
||||||
WorkspaceManagerModule,
|
WorkspaceManagerModule,
|
||||||
|
UserModule,
|
||||||
FileModule,
|
FileModule,
|
||||||
],
|
],
|
||||||
services: [WorkspaceService],
|
services: [WorkspaceService],
|
||||||
|
|||||||
@ -12,6 +12,9 @@ import { assert } from 'src/utils/assert';
|
|||||||
import { JwtAuthGuard } from 'src/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from 'src/guards/jwt.auth.guard';
|
||||||
import { UpdateWorkspaceInput } from 'src/core/workspace/dtos/update-workspace-input';
|
import { UpdateWorkspaceInput } from 'src/core/workspace/dtos/update-workspace-input';
|
||||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||||
|
import { User } from 'src/core/user/user.entity';
|
||||||
|
import { AuthUser } from 'src/decorators/auth/auth-user.decorator';
|
||||||
|
import { ActivateWorkspaceInput } from 'src/core/workspace/dtos/activate-workspace-input';
|
||||||
|
|
||||||
import { Workspace } from './workspace.entity';
|
import { Workspace } from './workspace.entity';
|
||||||
|
|
||||||
@ -35,6 +38,15 @@ export class WorkspaceResolver {
|
|||||||
return workspace;
|
return workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Mutation(() => Workspace)
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
async activateWorkspace(
|
||||||
|
@Args('data') data: ActivateWorkspaceInput,
|
||||||
|
@AuthUser() user: User,
|
||||||
|
) {
|
||||||
|
return await this.workspaceService.activateWorkspace(user, data);
|
||||||
|
}
|
||||||
|
|
||||||
@Mutation(() => Workspace)
|
@Mutation(() => Workspace)
|
||||||
async updateWorkspace(
|
async updateWorkspace(
|
||||||
@Args('data') data: UpdateWorkspaceInput,
|
@Args('data') data: UpdateWorkspaceInput,
|
||||||
|
|||||||
Reference in New Issue
Block a user