Skip to content

Commit f460a8c

Browse files
authored
Front End: Resolve hydration error found in Conversation Header (#932)
* fix(assistants_web): resolve hydration error found in Conversation Header * fix(assistants_web): separated Connection Component into it's own file and resolve hydration error
1 parent 83cd749 commit f460a8c

File tree

3 files changed

+196
-164
lines changed

3 files changed

+196
-164
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
'use client';
2+
3+
import { useEffect, useState } from 'react';
4+
5+
import { StatusConnection } from '@/components/AgentSettingsForm/StatusConnection';
6+
import { Button, Icon, IconName, Text } from '@/components/UI';
7+
import { useDeleteAuthTool, useListTools, useNotify } from '@/hooks';
8+
import { getToolAuthUrl } from '@/utils';
9+
10+
type Props = {
11+
toolId: string;
12+
toolName: string;
13+
iconName: IconName;
14+
description: string;
15+
showSyncButton: boolean;
16+
};
17+
18+
export const Connection: React.FC<Props> = ({
19+
toolId,
20+
toolName,
21+
iconName,
22+
description,
23+
showSyncButton,
24+
}) => {
25+
const [init, setInit] = useState(false);
26+
const { data } = useListTools();
27+
const { mutateAsync: deleteAuthTool } = useDeleteAuthTool();
28+
const notify = useNotify();
29+
const tool = data?.find((tool) => tool.name === toolId);
30+
31+
// This is used to resolve hydration error where the server side rendered content and
32+
// the client side content don't align because the client side content depends on information
33+
// from the API that is only available at run time.
34+
useEffect(() => setInit(true), []);
35+
36+
if (!tool) return null;
37+
38+
const handleDeleteAuthTool = async () => {
39+
try {
40+
await deleteAuthTool(tool.name!);
41+
} catch {
42+
notify.error(`Failed to delete ${toolName} connection`);
43+
}
44+
};
45+
46+
const isConnected = !(tool.is_auth_required ?? false);
47+
const isAvailable = tool.is_available ?? false;
48+
const error = tool.error_message ?? '';
49+
const authUrl = getToolAuthUrl(tool.auth_url);
50+
51+
return (
52+
<article className="rounded-md border border-marble-800 p-4 dark:border-volcanic-500">
53+
<header className="mb-2 flex items-center justify-between">
54+
<div className="flex items-center gap-2">
55+
<Icon name={iconName} size="xl" />
56+
<Text className="text-volcanic-400 dark:text-mushroom-950">{toolName}</Text>
57+
</div>
58+
<StatusConnection connected={isConnected} />
59+
</header>
60+
<Text className="mb-6 text-volcanic-400 dark:text-mushroom-800">{description}</Text>
61+
{init && (
62+
<section>
63+
{!isAvailable ? (
64+
<div className="justify-items-start space-y-6">
65+
<div className="flex items-center justify-between">
66+
<p className="font-body text-p-sm uppercase text-danger-500">
67+
{error || `${toolName} connection is not available.`}
68+
</p>
69+
</div>
70+
</div>
71+
) : isConnected ? (
72+
<div className="space-y-6">
73+
{showSyncButton && (
74+
<Button label="Sync now" kind="secondary" icon="arrow-clockwise" href={authUrl} />
75+
)}
76+
<Button
77+
label="Delete connection"
78+
kind="secondary"
79+
icon="trash"
80+
theme="danger"
81+
onClick={handleDeleteAuthTool}
82+
/>
83+
</div>
84+
) : (
85+
<Button
86+
label="Authenticate"
87+
href={authUrl}
88+
kind="secondary"
89+
theme="default"
90+
icon="arrow-up-right"
91+
/>
92+
)}
93+
</section>
94+
)}
95+
</article>
96+
);
97+
};

src/interfaces/assistants_web/src/app/(main)/settings/Settings.tsx

Lines changed: 30 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import { PropsWithChildren, useState } from 'react';
44

5-
import { StatusConnection } from '@/components/AgentSettingsForm/StatusConnection';
65
import { MobileHeader } from '@/components/Global';
76
import {
87
Button,
@@ -15,8 +14,9 @@ import {
1514
Text,
1615
} from '@/components/UI';
1716
import { TOOL_GITHUB_ID, TOOL_GMAIL_ID, TOOL_SHAREPOINT_ID, TOOL_SLACK_ID } from '@/constants';
18-
import { useDeleteAuthTool, useListTools, useNotify } from '@/hooks';
19-
import { cn, getToolAuthUrl } from '@/utils';
17+
import { cn } from '@/utils';
18+
19+
import { Connection } from './Connection';
2020

2121
const tabs: { key: string; icon: IconName; label: string }[] = [
2222
{ key: 'connections', icon: 'users-three', label: 'Connections' },
@@ -73,22 +73,7 @@ const Wrapper: React.FC<PropsWithChildren> = ({ children }) => (
7373
<div className="max-w-screen-xl flex-grow overflow-y-auto">{children}</div>
7474
);
7575

76-
const Connections = () => (
77-
<Wrapper>
78-
<Text styleAs="h5" className="mb-6">
79-
Connections your assistants can access
80-
</Text>
81-
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
82-
<GoogleDriveConnection />
83-
<SlackConnection />
84-
<GmailConnection />
85-
<GithubConnection />
86-
<SharepointConnection />
87-
</div>
88-
</Wrapper>
89-
);
90-
91-
const Appearance = () => (
76+
const Appearance: React.FC = () => (
9277
<Wrapper>
9378
<Text styleAs="h5" className="mb-6">
9479
Mode
@@ -97,7 +82,7 @@ const Appearance = () => (
9782
</Wrapper>
9883
);
9984

100-
const Advanced = () => (
85+
const Advanced: React.FC = () => (
10186
<Wrapper>
10287
<Text styleAs="h5" className="mb-6">
10388
Advanced
@@ -107,7 +92,7 @@ const Advanced = () => (
10792
</Wrapper>
10893
);
10994

110-
const Profile = () => (
95+
const Profile: React.FC = () => (
11196
<Wrapper>
11297
<Text styleAs="h5" className="mb-6">
11398
User Profile
@@ -116,87 +101,23 @@ const Profile = () => (
116101
</Wrapper>
117102
);
118103

119-
const ConnectionComponent = ({
120-
toolId,
121-
toolName,
122-
iconName,
123-
description,
124-
showSyncButton,
125-
}: {
126-
toolId: string;
127-
toolName: string;
128-
iconName: IconName;
129-
description: string;
130-
showSyncButton: boolean;
131-
}) => {
132-
const { data } = useListTools();
133-
const { mutateAsync: deleteAuthTool } = useDeleteAuthTool();
134-
const notify = useNotify();
135-
const tool = data?.find((tool) => tool.name === toolId);
136-
137-
if (!tool) return null;
138-
139-
const handleDeleteAuthTool = async () => {
140-
try {
141-
await deleteAuthTool(tool.name!);
142-
} catch {
143-
notify.error(`Failed to delete ${toolName} connection`);
144-
}
145-
};
146-
147-
const isConnected = !(tool.is_auth_required ?? false);
148-
const isAvailable = tool.is_available ?? false;
149-
const error = tool.error_message ?? '';
150-
const authUrl = getToolAuthUrl(tool.auth_url);
151-
152-
return (
153-
<article className="rounded-md border border-marble-800 p-4 dark:border-volcanic-500">
154-
<header className="mb-2 flex items-center justify-between">
155-
<div className="flex items-center gap-2">
156-
<Icon name={iconName} size="xl" />
157-
<Text className="text-volcanic-400 dark:text-mushroom-950">{toolName}</Text>
158-
</div>
159-
<StatusConnection connected={isConnected} />
160-
</header>
161-
<Text className="mb-6 text-volcanic-400 dark:text-mushroom-800">{description}</Text>
162-
<section>
163-
{!isAvailable ? (
164-
<div className="justify-items-start space-y-6">
165-
<div className="flex items-center justify-between">
166-
<p className="font-body text-p-sm uppercase text-danger-500">
167-
{error || `${toolName} connection is not available.`}
168-
</p>
169-
</div>
170-
</div>
171-
) : isConnected ? (
172-
<div className="space-y-6">
173-
{showSyncButton && (
174-
<Button label="Sync now" kind="secondary" icon="arrow-clockwise" href={authUrl} />
175-
)}
176-
<Button
177-
label="Delete connection"
178-
kind="secondary"
179-
icon="trash"
180-
theme="danger"
181-
onClick={handleDeleteAuthTool}
182-
/>
183-
</div>
184-
) : (
185-
<Button
186-
label="Authenticate"
187-
href={authUrl}
188-
kind="secondary"
189-
theme="default"
190-
icon="arrow-up-right"
191-
/>
192-
)}
193-
</section>
194-
</article>
195-
);
196-
};
104+
const Connections: React.FC = () => (
105+
<Wrapper>
106+
<Text styleAs="h5" className="mb-6">
107+
Connections your assistants can access
108+
</Text>
109+
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
110+
<GoogleDriveConnection />
111+
<SlackConnection />
112+
<GmailConnection />
113+
<GithubConnection />
114+
<SharepointConnection />
115+
</div>
116+
</Wrapper>
117+
);
197118

198-
const GoogleDriveConnection = () => (
199-
<ConnectionComponent
119+
const GoogleDriveConnection: React.FC = () => (
120+
<Connection
200121
toolId="google_drive"
201122
toolName="Google Drive"
202123
iconName="google-drive"
@@ -205,8 +126,8 @@ const GoogleDriveConnection = () => (
205126
/>
206127
);
207128

208-
const SlackConnection = () => (
209-
<ConnectionComponent
129+
const SlackConnection: React.FC = () => (
130+
<Connection
210131
toolId={TOOL_SLACK_ID}
211132
toolName="Slack"
212133
iconName="slack"
@@ -215,8 +136,8 @@ const SlackConnection = () => (
215136
/>
216137
);
217138

218-
const GmailConnection = () => (
219-
<ConnectionComponent
139+
const GmailConnection: React.FC = () => (
140+
<Connection
220141
toolId={TOOL_GMAIL_ID}
221142
toolName="Gmail"
222143
iconName="gmail"
@@ -225,8 +146,8 @@ const GmailConnection = () => (
225146
/>
226147
);
227148

228-
const GithubConnection = () => (
229-
<ConnectionComponent
149+
const GithubConnection: React.FC = () => (
150+
<Connection
230151
toolId={TOOL_GITHUB_ID}
231152
toolName="Github"
232153
iconName="github"
@@ -235,8 +156,8 @@ const GithubConnection = () => (
235156
/>
236157
);
237158

238-
const SharepointConnection = () => (
239-
<ConnectionComponent
159+
const SharepointConnection: React.FC = () => (
160+
<Connection
240161
toolId={TOOL_SHAREPOINT_ID}
241162
toolName="Sharepoint"
242163
iconName="sharepoint"

0 commit comments

Comments
 (0)