From 5346bee24527afecb8adee81411eb1580273b99d Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 9 Jul 2024 11:58:09 -0400 Subject: [PATCH 1/4] fix: bug where input is not flushed --- webapp/lib/use-openai-assistant.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/lib/use-openai-assistant.ts b/webapp/lib/use-openai-assistant.ts index a24c4de..98ebe70 100644 --- a/webapp/lib/use-openai-assistant.ts +++ b/webapp/lib/use-openai-assistant.ts @@ -61,6 +61,7 @@ export function useOpenAiAssistant({ assistantId = '', threadId: argsThreadId, m message: CreateMessage, ) => { try { + setInput(''); setStatus('in_progress'); let local_threadId = threadId; @@ -115,7 +116,6 @@ export function useOpenAiAssistant({ assistantId = '', threadId: argsThreadId, m }); } finally { - setInput(''); streamRef.current = null; setStatus('awaiting_message'); } From 08fe6570a64c2846617a41e897afec65990a64cf Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 9 Jul 2024 11:58:41 -0400 Subject: [PATCH 2/4] fix: removed unused privacy button --- webapp/app/_components/header.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/webapp/app/_components/header.tsx b/webapp/app/_components/header.tsx index 55889cf..e9a0e9c 100644 --- a/webapp/app/_components/header.tsx +++ b/webapp/app/_components/header.tsx @@ -1,6 +1,5 @@ import BrandLink from './brand.link'; import SettingLink from './settings.link'; -import PrivacyToggle from './privacy-toggle'; import StatusIndicator from './status-indicator'; @@ -13,7 +12,6 @@ export default function Header() {
-
From c5132c1605cd5041db48347da5de92a464e153ea Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 9 Jul 2024 13:20:46 -0400 Subject: [PATCH 3/4] feat: create new thread from home --- webapp/app/_components/assistant-thread.tsx | 2 +- webapp/app/_components/create-new-thread.tsx | 13 +- webapp/app/_components/new-thread-prompt.tsx | 26 +++ webapp/app/page.tsx | 4 +- webapp/lib/use-create-thread.ts | 31 ++- webapp/lib/use-openai-assistant.ts | 72 ++++--- webapp/lib/use-openai-assistant.ui.test.tsx | 5 +- webapp/package.json | 1 + webapp/pages/thread/[id].tsx | 5 +- webapp/pnpm-lock.yaml | 198 +++++++++++++++++++ 10 files changed, 302 insertions(+), 55 deletions(-) create mode 100644 webapp/app/_components/new-thread-prompt.tsx diff --git a/webapp/app/_components/assistant-thread.tsx b/webapp/app/_components/assistant-thread.tsx index da0a3b2..2da4839 100644 --- a/webapp/app/_components/assistant-thread.tsx +++ b/webapp/app/_components/assistant-thread.tsx @@ -8,7 +8,7 @@ import { useThreadRuns } from '@/lib/use-thread-runs'; interface Props { - threadId?: string + threadId: string } export default function AssistantThread({ threadId }: Props) { diff --git a/webapp/app/_components/create-new-thread.tsx b/webapp/app/_components/create-new-thread.tsx index 6334360..539ebf6 100644 --- a/webapp/app/_components/create-new-thread.tsx +++ b/webapp/app/_components/create-new-thread.tsx @@ -1,20 +1,13 @@ 'use client'; import { NewThread } from '@/components/new-thread'; import { useCreateThread } from '@/lib/use-create-thread'; -import { useRouter } from 'next/navigation'; -import { useCallback } from 'react'; -export function CreateNewThread() { - const router = useRouter(); - const createThread = useCreateThread(); - const onClick = useCallback(async () => { - const newThread = await createThread(); - router.push(`/thread/${newThread.id}`); - }, [createThread, router]); +export function CreateNewThread() { + const createThread = useCreateThread({ redirect: true }); return ( - + ); } diff --git a/webapp/app/_components/new-thread-prompt.tsx b/webapp/app/_components/new-thread-prompt.tsx new file mode 100644 index 0000000..8584315 --- /dev/null +++ b/webapp/app/_components/new-thread-prompt.tsx @@ -0,0 +1,26 @@ +'use client'; +import Chat from '@/components/chat'; +import { useCreateThread } from '@/lib/use-create-thread'; +import { useCurrentModel } from '@/lib/use-current-model'; +import { useState } from 'react'; + + +export default function NewThreadPrompt() { + const { data: model } = useCurrentModel(); + const [input, setInput] = useState(''); + const createThread = useCreateThread({ redirect: true }); + + return ( + setInput(event.target.value)} + onSubmit={(event) => { + event.preventDefault(); + event.stopPropagation(); + createThread(input); + }} + details={{model}} + /> + ); +} diff --git a/webapp/app/page.tsx b/webapp/app/page.tsx index d2fcf77..1da6f02 100644 --- a/webapp/app/page.tsx +++ b/webapp/app/page.tsx @@ -1,4 +1,4 @@ -import AssistantThread from './_components/assistant-thread'; +import NewThreadPrompt from './_components/new-thread-prompt'; import RecentThreads from './_components/recent-threads'; @@ -6,7 +6,7 @@ export default function Home() { return (
- +
); } diff --git a/webapp/lib/use-create-thread.ts b/webapp/lib/use-create-thread.ts index 396e301..82a193b 100644 --- a/webapp/lib/use-create-thread.ts +++ b/webapp/lib/use-create-thread.ts @@ -1,17 +1,36 @@ import { useCallback } from 'react'; +import { useRouter } from 'next/navigation'; import { useOpenaiClient } from './openai-client'; import { useListThreads } from './use-list-threads'; -import { Thread } from 'openai/resources/beta/threads/threads.mjs'; +import { Thread, ThreadCreateParams } from 'openai/resources/beta/threads/threads.mjs'; -export function useCreateThread(): () => Promise { +interface Props { + redirect?: boolean +} + +type CreateNewThread = (messageContent?: string) => Promise; +export function useCreateThread({ redirect }: Props = {}): CreateNewThread { const openai = useOpenaiClient(); + const router = useRouter(); const { revalidate } = useListThreads(); - return useCallback(async () => { - const newThread = await openai.beta.threads.create(); - revalidate(); + return useCallback(async (messageContent) => { + const messages: ThreadCreateParams.Message[] = []; + + if (messageContent) { + messages.push({ role: 'user', content: messageContent }); + } + const newThread = await openai.beta.threads.create({ + messages, + }); + + if (redirect) { + router.push(`/thread/${newThread.id}`); + } else { + revalidate(); + } return newThread; - }, [openai.beta.threads, revalidate]); + }, [openai.beta.threads, revalidate, redirect, router]); } \ No newline at end of file diff --git a/webapp/lib/use-openai-assistant.ts b/webapp/lib/use-openai-assistant.ts index 98ebe70..7ebbc52 100644 --- a/webapp/lib/use-openai-assistant.ts +++ b/webapp/lib/use-openai-assistant.ts @@ -14,14 +14,14 @@ type MessageDelta = OpenAI.Beta.Threads.Messages.MessageDelta; interface Props { assistantId?: string; - threadId?: string; + threadId: string; model?: string; temperature?: number; + initialInput?: string; } -export function useOpenAiAssistant({ assistantId = '', threadId: argsThreadId, model = 'openai:gpt-3.5-turbo', temperature }: Props = {}) { - const [messages, setMessages] = useState([ ]); - const [input, setInput] = useState(''); - const [threadId, setThreadId] = useState(argsThreadId); +export function useOpenAiAssistant({ assistantId = '', threadId, model = 'openai:gpt-3.5-turbo', temperature, initialInput }: Props) { + const [messages, setMessages] = useState([]); + const [input, setInput] = useState(initialInput ?? ''); const [status, setStatus] = useState('awaiting_message'); const [error, setError] = useState(undefined); const streamRef = useRef(null); @@ -34,12 +34,9 @@ export function useOpenAiAssistant({ assistantId = '', threadId: argsThreadId, m }, []); useEffect(() => { - setThreadId(argsThreadId); - if (!argsThreadId) return; - const fetchMessages = async () => { try { - const newMessages = await openai.beta.threads.messages.list(argsThreadId); + const newMessages = await openai.beta.threads.messages.list(threadId); setMessages(newMessages.data); } catch (e) { setUnknownError(e); @@ -47,7 +44,7 @@ export function useOpenAiAssistant({ assistantId = '', threadId: argsThreadId, m }; fetchMessages(); - }, [openai.beta.threads.messages, argsThreadId, setUnknownError]); + }, [openai.beta.threads.messages, threadId, setUnknownError]); const handleInputChange = ( event: @@ -57,34 +54,15 @@ export function useOpenAiAssistant({ assistantId = '', threadId: argsThreadId, m setInput(event.target.value); }; - const append = async ( - message: CreateMessage, - ) => { + const streamRun = useCallback(async () => { try { - setInput(''); setStatus('in_progress'); - let local_threadId = threadId; - if (!local_threadId) { - const thread = await openai.beta.threads.create(); - local_threadId = thread.id; - setThreadId(local_threadId); - } - - const created_message = await openai.beta.threads.messages.create( - local_threadId, - message - ); - setMessages(messages => [ - ...messages, - created_message, - ]); - abortControlerRef.current = new AbortController(); const signal = abortControlerRef.current.signal; await new Promise((resolve, rejects) => { - streamRef.current = openai.beta.threads.runs.stream(local_threadId, { + streamRef.current = openai.beta.threads.runs.stream(threadId, { model, assistant_id: assistantId, temperature, @@ -119,7 +97,36 @@ export function useOpenAiAssistant({ assistantId = '', threadId: argsThreadId, m streamRef.current = null; setStatus('awaiting_message'); } - }; + }, [assistantId, messages, model, openai.beta.threads.runs, setUnknownError, temperature, threadId]); + + useEffect(() => { + if (messages.at(-1)?.role === 'user') { + streamRun(); + } + }, [messages, streamRun]); + + + const append = useCallback(async ( + message?: CreateMessage, + ) => { + setInput(''); + + try { + if (message) { + const created_message = await openai.beta.threads.messages.create( + threadId, + message + ); + setMessages(messages => [ + ...messages, + created_message, + ]); + } + } catch (e) { + setUnknownError(e); + } + + }, [openai.beta.threads.messages, threadId, setUnknownError]); const abort = useCallback(() => { if (abortControlerRef.current) { @@ -128,6 +135,7 @@ export function useOpenAiAssistant({ assistantId = '', threadId: argsThreadId, m } }, []); + const submitMessage = async ( event?: React.FormEvent, ) => { diff --git a/webapp/lib/use-openai-assistant.ui.test.tsx b/webapp/lib/use-openai-assistant.ui.test.tsx index 3a91bb1..50e62d7 100644 --- a/webapp/lib/use-openai-assistant.ui.test.tsx +++ b/webapp/lib/use-openai-assistant.ui.test.tsx @@ -13,16 +13,17 @@ import { useOpenaiClient } from './openai-client'; jest.mock('./openai-client'); -describe('new-thread', () => { +describe('new-conversation', () => { const fetch = jest.fn(); const TestComponent = () => { + const threadId = 'thread_abc123'; when(useOpenaiClient).mockReturnValue(new OpenAI({ apiKey: 'abc', fetch, dangerouslyAllowBrowser: true, })); - const { status, messages, error, append } = useOpenAiAssistant(); + const { status, messages, error, append } = useOpenAiAssistant({ threadId }); return (
diff --git a/webapp/package.json b/webapp/package.json index bf5d056..ce7ff24 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -51,6 +51,7 @@ "react-dom": "^18", "react-markdown": "^9.0.1", "react-syntax-highlighter": "^15.5.0", + "react-use": "^17.5.0", "remark-gfm": "^4.0.0", "swr": "^2.2.5", "tailwind-merge": "^2.3.0", diff --git a/webapp/pages/thread/[id].tsx b/webapp/pages/thread/[id].tsx index bd763a3..d9834df 100644 --- a/webapp/pages/thread/[id].tsx +++ b/webapp/pages/thread/[id].tsx @@ -7,13 +7,14 @@ import RecentThreads from '@/app/_components/recent-threads'; export default function Page() { const router = useRouter(); - const { id } = router.query; + + const id = typeof router.query.id === 'string' ? router.query.id : undefined; return (
- { id && typeof id === 'string' && } + { id && }
); diff --git a/webapp/pnpm-lock.yaml b/webapp/pnpm-lock.yaml index 414b3d8..1e29e02 100644 --- a/webapp/pnpm-lock.yaml +++ b/webapp/pnpm-lock.yaml @@ -116,6 +116,9 @@ importers: react-syntax-highlighter: specifier: ^15.5.0 version: 15.5.0(react@18.2.0) + react-use: + specifier: ^17.5.0 + version: 17.5.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) remark-gfm: specifier: ^4.0.0 version: 4.0.0 @@ -2639,6 +2642,9 @@ packages: '@types/jest@29.5.12': resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + '@types/js-cookie@2.2.7': + resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==} + '@types/jsdom@20.0.1': resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} @@ -2943,6 +2949,9 @@ packages: '@webassemblyjs/wast-printer@1.12.1': resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} + '@xobotyi/scrollbar-width@1.9.5': + resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==} + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -3696,6 +3705,9 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} + copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + core-js-compat@3.37.1: resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} @@ -3746,6 +3758,9 @@ packages: resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} engines: {node: '>=12'} + css-in-js-utils@3.1.0: + resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==} + css-loader@6.11.0: resolution: {integrity: sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==} engines: {node: '>= 12.13.0'} @@ -3761,6 +3776,10 @@ packages: css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + css-tree@1.1.3: + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} + engines: {node: '>=8.0.0'} + css-tree@2.3.1: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} @@ -4385,6 +4404,12 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-shallow-equal@1.0.0: + resolution: {integrity: sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==} + + fastest-stable-stringify@2.0.2: + resolution: {integrity: sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==} + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -4796,6 +4821,9 @@ packages: humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + hyphenate-style-name@1.1.0: + resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -4849,6 +4877,9 @@ packages: inline-style-parser@0.2.3: resolution: {integrity: sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==} + inline-style-prefixer@7.0.1: + resolution: {integrity: sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==} + internal-ip@8.0.0: resolution: {integrity: sha512-e6c3zxr9COnnc29PIz9LffmALOt0XhIJdR7f83DyHcQksL3B40KGmU3Sr1lrHja3i7Zyqo+AbwKZ+nZiMvg/OA==} engines: {node: '>=16'} @@ -5303,6 +5334,9 @@ packages: resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} hasBin: true + js-cookie@2.2.1: + resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} + js-tiktoken@1.0.12: resolution: {integrity: sha512-L7wURW1fH9Qaext0VzaUDpFGVQgjkdE3Dgsy9/+yXyGEpBKnylTd0mU0bfbNkKDlXRb6TEsZkwuflu1B8uQbJQ==} @@ -5619,6 +5653,9 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdn-data@2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} @@ -5846,6 +5883,12 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nano-css@5.6.1: + resolution: {integrity: sha512-T2Mhc//CepkTa3X4pUhKgbEheJHYAxD0VptuqFhDbGMUWVV2m+lkNiW/Ieuj35wrfC8Zm0l7HvssQh7zcEttSw==} + peerDependencies: + react: '*' + react-dom: '*' + nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -6558,6 +6601,18 @@ packages: peerDependencies: react: '>= 0.14.0' + react-universal-interface@0.6.2: + resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==} + peerDependencies: + react: '*' + tslib: '*' + + react-use@17.5.0: + resolution: {integrity: sha512-PbfwSPMwp/hoL847rLnm/qkjg3sTRCvn6YhUZiHaUa3FA6/aNoFX79ul5Xt70O1rK+9GxSVqkY0eTwMdsR/bWg==} + peerDependencies: + react: '*' + react-dom: '*' + react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} @@ -6679,6 +6734,9 @@ packages: requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + resize-observer-polyfill@1.5.1: + resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} + resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} @@ -6735,6 +6793,9 @@ packages: ripemd160@2.0.2: resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + rtl-css-js@1.16.1: + resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -6789,6 +6850,10 @@ packages: resolution: {integrity: sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==} engines: {node: '>= 12.13.0'} + screenfull@5.2.0: + resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==} + engines: {node: '>=0.10.0'} + secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} @@ -6839,6 +6904,10 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + set-harmonic-interval@1.0.1: + resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==} + engines: {node: '>=6.9'} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} @@ -6910,6 +6979,10 @@ packages: source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map@0.5.6: + resolution: {integrity: sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==} + engines: {node: '>=0.10.0'} + source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -6944,6 +7017,9 @@ packages: peerDependencies: svelte: ^4.0.0 || ^5.0.0-next.0 + stack-generator@2.0.10: + resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==} + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -6951,6 +7027,12 @@ packages: stackframe@1.3.4: resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + stacktrace-gps@3.1.2: + resolution: {integrity: sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==} + + stacktrace-js@2.0.2: + resolution: {integrity: sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==} + statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} @@ -7076,6 +7158,9 @@ packages: babel-plugin-macros: optional: true + stylis@4.3.2: + resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==} + sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -7212,6 +7297,10 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + throttle-debounce@3.0.1: + resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==} + engines: {node: '>=10'} + through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} @@ -7244,6 +7333,9 @@ packages: tocbot@4.28.2: resolution: {integrity: sha512-/MaSa9xI6mIo84IxqqliSCtPlH0oy7sLcY9s26qPMyH/2CxtZ2vNAXYlIdEQ7kjAkCQnc0rbLygf//F5c663oQ==} + toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -7275,6 +7367,9 @@ packages: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} + ts-easing@0.2.0: + resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==} + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -10962,6 +11057,8 @@ snapshots: expect: 29.7.0 pretty-format: 29.7.0 + '@types/js-cookie@2.2.7': {} + '@types/jsdom@20.0.1': dependencies: '@types/node': 20.12.7 @@ -11376,6 +11473,8 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 + '@xobotyi/scrollbar-width@1.9.5': {} + '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} @@ -12190,6 +12289,10 @@ snapshots: cookie@0.6.0: {} + copy-to-clipboard@3.3.3: + dependencies: + toggle-selection: 1.0.6 + core-js-compat@3.37.1: dependencies: browserslist: 4.23.0 @@ -12278,6 +12381,10 @@ snapshots: dependencies: type-fest: 1.4.0 + css-in-js-utils@3.1.0: + dependencies: + hyphenate-style-name: 1.1.0 + css-loader@6.11.0(webpack@5.91.0(esbuild@0.20.2)): dependencies: icss-utils: 5.1.0(postcss@8.4.38) @@ -12299,6 +12406,11 @@ snapshots: domutils: 2.8.0 nth-check: 2.1.1 + css-tree@1.1.3: + dependencies: + mdn-data: 2.0.14 + source-map: 0.6.1 + css-tree@2.3.1: dependencies: mdn-data: 2.0.30 @@ -13152,6 +13264,10 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-shallow-equal@1.0.0: {} + + fastest-stable-stringify@2.0.2: {} + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -13634,6 +13750,8 @@ snapshots: dependencies: ms: 2.1.2 + hyphenate-style-name@1.1.0: {} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -13677,6 +13795,10 @@ snapshots: inline-style-parser@0.2.3: {} + inline-style-prefixer@7.0.1: + dependencies: + css-in-js-utils: 3.1.0 + internal-ip@8.0.0: dependencies: cidr-tools: 6.4.2 @@ -14299,6 +14421,8 @@ snapshots: jiti@1.21.0: {} + js-cookie@2.2.1: {} + js-tiktoken@1.0.12: dependencies: base64-js: 1.5.1 @@ -14736,6 +14860,8 @@ snapshots: dependencies: '@types/mdast': 4.0.4 + mdn-data@2.0.14: {} + mdn-data@2.0.30: {} media-typer@0.3.0: {} @@ -15047,6 +15173,19 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 + nano-css@5.6.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + css-tree: 1.1.3 + csstype: 3.1.3 + fastest-stable-stringify: 2.0.2 + inline-style-prefixer: 7.0.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + rtl-css-js: 1.16.1 + stacktrace-js: 2.0.2 + stylis: 4.3.2 + nanoid@3.3.6: {} nanoid@3.3.7: {} @@ -15814,6 +15953,30 @@ snapshots: react: 18.2.0 refractor: 3.6.0 + react-universal-interface@0.6.2(react@18.2.0)(tslib@2.6.3): + dependencies: + react: 18.2.0 + tslib: 2.6.3 + + react-use@17.5.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + dependencies: + '@types/js-cookie': 2.2.7 + '@xobotyi/scrollbar-width': 1.9.5 + copy-to-clipboard: 3.3.3 + fast-deep-equal: 3.1.3 + fast-shallow-equal: 1.0.0 + js-cookie: 2.2.1 + nano-css: 5.6.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-universal-interface: 0.6.2(react@18.2.0)(tslib@2.6.3) + resize-observer-polyfill: 1.5.1 + screenfull: 5.2.0 + set-harmonic-interval: 1.0.1 + throttle-debounce: 3.0.1 + ts-easing: 0.2.0 + tslib: 2.6.3 + react@18.2.0: dependencies: loose-envify: 1.4.0 @@ -16001,6 +16164,8 @@ snapshots: requires-port@1.0.0: {} + resize-observer-polyfill@1.5.1: {} + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 @@ -16055,6 +16220,10 @@ snapshots: hash-base: 3.1.0 inherits: 2.0.4 + rtl-css-js@1.16.1: + dependencies: + '@babel/runtime': 7.24.4 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -16105,6 +16274,8 @@ snapshots: ajv-formats: 2.1.1(ajv@8.16.0) ajv-keywords: 5.1.0(ajv@8.16.0) + screenfull@5.2.0: {} + secure-json-parse@2.7.0: {} semver@5.7.2: {} @@ -16170,6 +16341,8 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + set-harmonic-interval@1.0.1: {} + setimmediate@1.0.5: {} setprototypeof@1.2.0: {} @@ -16261,6 +16434,8 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 + source-map@0.5.6: {} + source-map@0.6.1: {} source-map@0.7.4: {} @@ -16290,12 +16465,27 @@ snapshots: svelte: 4.2.17 swrev: 4.0.0 + stack-generator@2.0.10: + dependencies: + stackframe: 1.3.4 + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 stackframe@1.3.4: {} + stacktrace-gps@3.1.2: + dependencies: + source-map: 0.5.6 + stackframe: 1.3.4 + + stacktrace-js@2.0.2: + dependencies: + error-stack-parser: 2.1.4 + stack-generator: 2.0.10 + stacktrace-gps: 3.1.2 + statuses@2.0.1: {} stop-iteration-iterator@1.0.0: @@ -16439,6 +16629,8 @@ snapshots: optionalDependencies: '@babel/core': 7.24.7 + stylis@4.3.2: {} + sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.5 @@ -16625,6 +16817,8 @@ snapshots: dependencies: any-promise: 1.3.0 + throttle-debounce@3.0.1: {} + through2@2.0.5: dependencies: readable-stream: 2.3.8 @@ -16652,6 +16846,8 @@ snapshots: tocbot@4.28.2: {} + toggle-selection@1.0.6: {} + toidentifier@1.0.1: {} tough-cookie@4.1.4: @@ -16677,6 +16873,8 @@ snapshots: ts-dedent@2.2.0: {} + ts-easing@0.2.0: {} + ts-interface-checker@0.1.13: {} ts-jest@29.1.5(@babel/core@7.24.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(esbuild@0.20.2)(jest@29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5)))(typescript@5.4.5): From 027091643c40fd163ae637663fb17318d350645d Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 9 Jul 2024 13:24:56 -0400 Subject: [PATCH 4/4] fix: scrollbar over threads cards --- webapp/components/threads-preview-collection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/components/threads-preview-collection.tsx b/webapp/components/threads-preview-collection.tsx index 0e95d1d..db17d51 100644 --- a/webapp/components/threads-preview-collection.tsx +++ b/webapp/components/threads-preview-collection.tsx @@ -21,7 +21,7 @@ interface Props({ error, threads, isLoading, className, children, onDelete }: Props) { return ( -
+
{children} { threads?.map((thread) => (