Skip to content

Commit de173ea

Browse files
authored
Merge pull request #193 from DashHub-ai/feature/google-drive-integration
Add google drive integration
2 parents 197583b + c9b7af0 commit de173ea

27 files changed

Lines changed: 495 additions & 57 deletions

apps/chat/.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
PUBLIC_VITE_APP_ENV=dev
22
PUBLIC_VITE_API_URL=http://localhost:3000
3+
PUBLIC_VITE_GOOGLE_DRIVE_APP_ID=
4+
PUBLIC_VITE_GOOGLE_DRIVE_API_KEY=
5+
PUBLIC_VITE_GOOGLE_DRIVE_CLIENT_ID=

apps/chat/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
"@llm/commons-front": "*",
1414
"@llm/sdk": "*",
1515
"@tailwindcss/typography": "^0.5.16",
16+
"@types/gapi": "^0.0.47",
17+
"@types/google.accounts": "^0.0.15",
18+
"@types/google.picker": "^0.0.50",
1619
"@types/react-syntax-highlighter": "^15.5.3",
1720
"@types/sanitize-html": "^2.13.0",
1821
"@types/uikit": "^3.14.5",

apps/chat/src/config/config.dto.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import { AppEnvV } from '@llm/commons';
55
export const ConfigV = z.object({
66
env: AppEnvV,
77
apiUrl: z.string(),
8+
googleDrive: z.object({
9+
appId: z.string(),
10+
apiKey: z.string(),
11+
clientId: z.string(),
12+
}).optional(),
813
});
914

1015
export type ConfigT = z.infer<typeof ConfigV>;

apps/chat/src/config/try-read-env-or-panic.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,24 @@ export function tryReadEnvOrPanic() {
1414
const {
1515
PUBLIC_VITE_APP_ENV,
1616
PUBLIC_VITE_API_URL,
17+
PUBLIC_VITE_GOOGLE_DRIVE_APP_ID,
18+
PUBLIC_VITE_GOOGLE_DRIVE_API_KEY,
19+
PUBLIC_VITE_GOOGLE_DRIVE_CLIENT_ID,
1720
} = import.meta.env ?? {};
1821

1922
const config: UnparsedEnvObject<ConfigT> = {
2023
env: PUBLIC_VITE_APP_ENV,
2124
apiUrl: PUBLIC_VITE_API_URL,
25+
26+
...PUBLIC_VITE_GOOGLE_DRIVE_API_KEY
27+
&& PUBLIC_VITE_GOOGLE_DRIVE_API_KEY
28+
&& PUBLIC_VITE_GOOGLE_DRIVE_CLIENT_ID && {
29+
googleDrive: {
30+
appId: PUBLIC_VITE_GOOGLE_DRIVE_APP_ID,
31+
apiKey: PUBLIC_VITE_GOOGLE_DRIVE_API_KEY,
32+
clientId: PUBLIC_VITE_GOOGLE_DRIVE_CLIENT_ID,
33+
},
34+
},
2235
};
2336

2437
return pipe(

apps/chat/src/i18n/packs/i18n-lang-en.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,12 +512,16 @@ export const I18N_PACK_EN = {
512512
send: 'Send',
513513
cancel: 'Cancel',
514514
submitOnEnter: 'Submit on Enter',
515-
attachFile: 'Attach file',
516515
refresh: 'Refresh response',
517516
reply: 'Reply to this message',
518517
addApp: 'Add app',
519518
pin: 'Pin',
520519
unpin: 'Unpin',
520+
files: {
521+
attachFile: 'Attach file',
522+
attachLocalFile: 'Attach file from your computer',
523+
attachGoogleDriveFile: 'Attach file from Google Drive',
524+
},
521525
},
522526
placeholders: {
523527
enterMessage: 'Enter your message...',

apps/chat/src/i18n/packs/i18n-lang-pl.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,6 @@ export const I18N_PACK_PL: I18nLangPack = {
510510
send: 'Wyślij',
511511
cancel: 'Anuluj',
512512
submitOnEnter: 'Wyślij po naciśnięciu Enter',
513-
attachFile: 'Załącz plik',
514513
refresh: 'Odśwież odpowiedź',
515514
reply: 'Odpowiedz na tę wiadomość',
516515
expand: {
@@ -520,6 +519,11 @@ export const I18N_PACK_PL: I18nLangPack = {
520519
addApp: 'Dodaj aplikację',
521520
pin: 'Przypnij',
522521
unpin: 'Odepnij',
522+
files: {
523+
attachFile: 'Załącz plik',
524+
attachLocalFile: 'Załącz plik ze swojego komputera',
525+
attachGoogleDriveFile: 'Załącz plik z Google Drive',
526+
},
523527
},
524528
placeholders: {
525529
enterMessage: 'Wpisz wiadomość...',
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import clsx from 'clsx';
2+
import { PaperclipIcon } from 'lucide-react';
3+
4+
import { useI18n } from '~/i18n';
5+
6+
type Props = {
7+
disabled?: boolean;
8+
};
9+
10+
export function AttachFileButton({ disabled }: Props) {
11+
const t = useI18n().pack.chat.actions.files;
12+
13+
return (
14+
<button
15+
type="button"
16+
title={t.attachFile}
17+
className={clsx(
18+
'hover:bg-gray-100 p-2 rounded-lg',
19+
'text-gray-500 hover:text-gray-700',
20+
'transition-colors duration-200',
21+
disabled && 'opacity-50 cursor-not-allowed',
22+
)}
23+
disabled={disabled}
24+
>
25+
<PaperclipIcon size={20} />
26+
</button>
27+
);
28+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { controlled } from '@under-control/forms';
2+
import clsx from 'clsx';
3+
import { pipe } from 'fp-ts/lib/function';
4+
import { UploadIcon } from 'lucide-react';
5+
6+
import { tapTaskOption } from '@llm/commons';
7+
import { useConfig } from '~/config';
8+
import { useI18n } from '~/i18n';
9+
import { useGoogleDriveFilePicker } from '~/modules/google-drive';
10+
import { GoogleDriveSVG } from '~/ui';
11+
12+
import { selectChatFile } from '../select-chat-file';
13+
import { AttachFileButton } from './attach-file-button';
14+
15+
type Props = {
16+
disabled?: boolean;
17+
};
18+
19+
export const AttachFileDropdown = controlled<File[], Props>(({ disabled, control: { value, setValue } }) => {
20+
const config = useConfig();
21+
const t = useI18n().pack.chat.actions.files;
22+
23+
const [selectGoogleDriveFile, attachGoogleFileStatus] = useGoogleDriveFilePicker();
24+
25+
const onAttachGoogleDriveFile = async () => {
26+
const files = await selectGoogleDriveFile();
27+
28+
setValue({
29+
value: [...(value ?? []), ...files ?? []],
30+
});
31+
};
32+
33+
const onAttachLocalFile = pipe(
34+
selectChatFile,
35+
tapTaskOption((file: File) => {
36+
setValue({
37+
value: [...(value ?? []), file],
38+
});
39+
}),
40+
);
41+
42+
return (
43+
<>
44+
<AttachFileButton disabled={disabled} />
45+
46+
<div className="uk-drop uk-dropdown" uk-dropdown="mode: click">
47+
<ul className="uk-dropdown-nav uk-nav">
48+
<li>
49+
<a
50+
className="justify-between uk-drop-close"
51+
type="button"
52+
href="#"
53+
onClick={(e) => {
54+
e.preventDefault();
55+
void onAttachLocalFile();
56+
}}
57+
>
58+
<span className="flex items-center gap-2">
59+
<UploadIcon size={16} />
60+
{t.attachLocalFile}
61+
</span>
62+
</a>
63+
</li>
64+
65+
{config.googleDrive && (
66+
<li>
67+
<a
68+
className={clsx(
69+
'justify-between uk-drop-close',
70+
attachGoogleFileStatus.isLoading && 'opacity-50 cursor-not-allowed pointer-events-none',
71+
)}
72+
type="button"
73+
href="#"
74+
onClick={(e) => {
75+
e.preventDefault();
76+
void onAttachGoogleDriveFile();
77+
}}
78+
>
79+
<span className="flex items-center gap-2">
80+
<GoogleDriveSVG width={16} height={16} />
81+
{t.attachGoogleDriveFile}
82+
</span>
83+
</a>
84+
</li>
85+
)}
86+
</ul>
87+
</div>
88+
</>
89+
);
90+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './attach-file-button';
2+
export * from './attach-file-dropdown';
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
export * from './file-card';
2-
export * from './files-cards-controlled-list';
3-
export * from './files-cards-list';
1+
export * from './attach-file';
2+
export * from './list';
43
export * from './select-chat-file';
54
export * from './use-chat-file-drop';

0 commit comments

Comments
 (0)