Skip to content
This repository was archived by the owner on Jan 2, 2025. It is now read-only.

Commit 4d1db52

Browse files
FE changes to answer tooling (#542)
* Minor fe fixes (#536) * fix page container height on homepage * update some text colors * fix files accordion * refetch repo once it is synced to fix empty tab when reopening bloop and repo is still being synced * refetch repo only on repo page * make repositories context and analytics context shared between tabs * update chat head for different themes * update chat colors for light theme * Minor UI fixes (#541) * update padding on results page to fix chat overlapping pagination * change icon in search input on loading steps * revert preserving tabs on restart * support more url formats for adding public repos * explaining code starts a new conversation * navigate to repo root only if user is on results page * typescript fixes
1 parent 966d70c commit 4d1db52

File tree

28 files changed

+984
-143
lines changed

28 files changed

+984
-143
lines changed

client/src/App.tsx

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import './index.css';
44
import 'highlight.js/styles/vs2015.css';
55
import Tab from './Tab';
66
import { TabsContext } from './context/tabsContext';
7-
import { UITabType } from './types/general';
7+
import { RepoType, UITabType } from './types/general';
88
import {
99
getJsonFromStorage,
1010
getPlainFromStorage,
@@ -13,9 +13,11 @@ import {
1313
savePlainToStorage,
1414
TABS_KEY,
1515
} from './services/storage';
16-
import { initApi } from './services/api';
16+
import { getRepos, initApi } from './services/api';
1717
import { useComponentWillMount } from './hooks/useComponentWillMount';
1818
import { RepoSource } from './types';
19+
import { RepositoriesContext } from './context/repositoriesContext';
20+
import { AnalyticsContextProvider } from './context/providers/AnalyticsContextProvider';
1921

2022
type Props = {
2123
deviceContextValue: DeviceContextType;
@@ -24,19 +26,16 @@ type Props = {
2426
function App({ deviceContextValue }: Props) {
2527
useComponentWillMount(() => initApi(deviceContextValue.apiUrl));
2628

27-
const [tabs, setTabs] = useState<UITabType[]>(
28-
getJsonFromStorage(TABS_KEY) || [
29-
{
30-
key: 'initial',
31-
name: 'Home',
32-
repoName: '',
33-
source: RepoSource.LOCAL,
34-
},
35-
],
36-
);
37-
const [activeTab, setActiveTab] = useState(
38-
getPlainFromStorage(LAST_ACTIVE_TAB_KEY) || 'initial',
39-
);
29+
const [tabs, setTabs] = useState<UITabType[]>([
30+
{
31+
key: 'initial',
32+
name: 'Home',
33+
repoName: '',
34+
source: RepoSource.LOCAL,
35+
},
36+
]);
37+
const [activeTab, setActiveTab] = useState('initial');
38+
const [repositories, setRepositories] = useState<RepoType[] | undefined>();
4039

4140
const handleAddTab = useCallback(
4241
(repoRef: string, repoName: string, name: string, source: RepoSource) => {
@@ -100,17 +99,51 @@ function App({ deviceContextValue }: Props) {
10099
[tabs, activeTab, handleAddTab, handleRemoveTab],
101100
);
102101

102+
const fetchRepos = useCallback(() => {
103+
getRepos().then((data) => {
104+
const list = data?.list?.sort((a, b) => (a.name < b.name ? -1 : 1)) || [];
105+
setRepositories(list);
106+
});
107+
}, []);
108+
109+
useEffect(() => {
110+
fetchRepos();
111+
const intervalId = setInterval(fetchRepos, 5000);
112+
return () => {
113+
clearInterval(intervalId);
114+
};
115+
}, []);
116+
117+
const reposContextValue = useMemo(
118+
() => ({
119+
repositories,
120+
setRepositories,
121+
localSyncError: false,
122+
githubSyncError: false,
123+
fetchRepos,
124+
}),
125+
[repositories],
126+
);
127+
103128
return (
104-
<TabsContext.Provider value={contextValue}>
105-
{tabs.map((t) => (
106-
<Tab
107-
key={t.key}
108-
deviceContextValue={deviceContextValue}
109-
isActive={t.key === activeTab}
110-
tab={t}
111-
/>
112-
))}
113-
</TabsContext.Provider>
129+
<AnalyticsContextProvider
130+
forceAnalytics={deviceContextValue.forceAnalytics}
131+
isSelfServe={deviceContextValue.isSelfServe}
132+
envConfig={deviceContextValue.envConfig}
133+
>
134+
<RepositoriesContext.Provider value={reposContextValue}>
135+
<TabsContext.Provider value={contextValue}>
136+
{tabs.map((t) => (
137+
<Tab
138+
key={t.key}
139+
deviceContextValue={deviceContextValue}
140+
isActive={t.key === activeTab}
141+
tab={t}
142+
/>
143+
))}
144+
</TabsContext.Provider>
145+
</RepositoriesContext.Provider>
146+
</AnalyticsContextProvider>
114147
);
115148
}
116149

client/src/Tab.tsx

Lines changed: 16 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
import React, { useMemo, useState } from 'react';
21
import { BrowserRouter, Route, Routes } from 'react-router-dom';
32
import Settings from './components/Settings';
4-
import { RepoType, UITabType } from './types/general';
3+
import { UITabType } from './types/general';
54
import { DeviceContextType } from './context/deviceContext';
6-
import { RepositoriesContext } from './context/repositoriesContext';
75
import './index.css';
8-
import { AnalyticsContextProvider } from './context/providers/AnalyticsContextProvider';
96
import ReportBugModal from './components/ReportBugModal';
107
import { UIContextProvider } from './context/providers/UiContextProvider';
118
import { DeviceContextProvider } from './context/providers/DeviceContextProvider';
@@ -21,47 +18,24 @@ type Props = {
2118
};
2219

2320
function Tab({ deviceContextValue, isActive, tab }: Props) {
24-
const [repositories, setRepositories] = useState<RepoType[] | undefined>();
25-
26-
const reposContextValue = useMemo(
27-
() => ({
28-
repositories,
29-
setRepositories,
30-
localSyncError: false,
31-
githubSyncError: false,
32-
}),
33-
[repositories],
34-
);
35-
3621
return (
3722
<div className={`${isActive ? '' : 'hidden'} `}>
3823
<BrowserRouter>
39-
<AnalyticsContextProvider
40-
forceAnalytics={deviceContextValue.forceAnalytics}
41-
isSelfServe={deviceContextValue.isSelfServe}
42-
envConfig={deviceContextValue.envConfig}
43-
>
44-
<DeviceContextProvider deviceContextValue={deviceContextValue}>
45-
<UIContextProvider tab={tab}>
46-
<AppNavigationProvider>
47-
<SearchContextProvider tab={tab}>
48-
<RepositoriesContext.Provider value={reposContextValue}>
49-
<ChatContextProvider>
50-
<Routes>
51-
<Route
52-
path="*"
53-
element={<ContentContainer tab={tab} />}
54-
/>
55-
</Routes>
56-
<Settings />
57-
<ReportBugModal />
58-
</ChatContextProvider>
59-
</RepositoriesContext.Provider>
60-
</SearchContextProvider>
61-
</AppNavigationProvider>
62-
</UIContextProvider>
63-
</DeviceContextProvider>
64-
</AnalyticsContextProvider>
24+
<DeviceContextProvider deviceContextValue={deviceContextValue}>
25+
<UIContextProvider tab={tab}>
26+
<AppNavigationProvider>
27+
<SearchContextProvider tab={tab}>
28+
<ChatContextProvider>
29+
<Routes>
30+
<Route path="*" element={<ContentContainer tab={tab} />} />
31+
</Routes>
32+
<Settings />
33+
<ReportBugModal />
34+
</ChatContextProvider>
35+
</SearchContextProvider>
36+
</AppNavigationProvider>
37+
</UIContextProvider>
38+
</DeviceContextProvider>
6539
</BrowserRouter>
6640
</div>
6741
);

client/src/components/Accordion/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState } from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import { AnimatePresence, motion } from 'framer-motion';
33
import { ChevronDownFilled, ChevronUpFilled } from '../../icons';
44
import { ACCORDION_CHILDREN_ANIMATION } from '../../consts/animations';
@@ -25,6 +25,9 @@ const Accordion = ({
2525
defaultExpanded = true,
2626
}: Props) => {
2727
const [expanded, setExpanded] = useState(defaultExpanded);
28+
useEffect(() => {
29+
setExpanded(defaultExpanded);
30+
}, [defaultExpanded]);
2831
return (
2932
<div
3033
className={`rounded border hover:border-bg-border ${

client/src/components/Breadcrumbs/BreadcrumbSection.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ type Props = {
1313

1414
const typeMap = {
1515
link: {
16-
default: 'text-label-muted hover:text-bg-main active:text-bg-main',
17-
isLast: 'text-label-base',
16+
default: 'text-label-base hover:text-bg-main active:text-bg-main',
17+
isLast: 'text-label-title',
1818
},
1919
button: {
2020
default:

client/src/components/Chat/AllCoversations/index.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ const AllConversations = ({
7070
isLoading: false,
7171
type: ChatMessageType.Answer,
7272
loadingSteps: m.search_steps?.map(
73-
(s: { type: string; content: string }) => s.content,
73+
(s: { type: string; content: string }) => ({
74+
...s,
75+
displayText: s.content,
76+
}),
7477
),
7578
text: m.conclusion,
7679
results: m.results,
@@ -89,7 +92,7 @@ const AllConversations = ({
8992
isHistoryOpen ? 'mr-0' : '-mr-97'
9093
} transition-all duration-300 ease-out-slow`}
9194
>
92-
<div className="p-4 bg-chat-bg-sub border-b border-chat-bg-divider flex items-center gap-2 text-label-title">
95+
<div className="p-4 bg-chat-bg-base/35 border-b border-chat-bg-border flex items-center gap-2 text-label-title">
9396
{!!openItem && (
9497
<ChipButton variant="filled" onClick={() => setOpenItem(null)}>
9598
<ArrowLeft sizeClassName="w-4 h-4" />
@@ -106,12 +109,16 @@ const AllConversations = ({
106109
Create new
107110
</ChipButton>
108111
)}
109-
<ChipButton variant="filled" onClick={() => setHistoryOpen(false)}>
112+
<ChipButton
113+
variant="filled"
114+
colorScheme="base"
115+
onClick={() => setHistoryOpen(false)}
116+
>
110117
<CloseSign sizeClassName="w-3.5 h-3.5" />
111118
</ChipButton>
112119
</div>
113120
{!openItem && (
114-
<div className="flex flex-col gap-1 py-4 overflow-auto flex-1 pb-12 bg-chat-bg-sub">
121+
<div className="flex flex-col gap-1 py-4 overflow-auto flex-1 pb-12">
115122
{conversations.map((c) => (
116123
<ConversationListItem
117124
key={c.thread_id}

client/src/components/Chat/ChipButton.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,23 @@ import { PropsWithChildren } from 'react';
33
type Props = {
44
variant?: 'filled' | 'outlined';
55
onClick?: () => void;
6+
colorScheme?: 'chat' | 'base';
67
};
78

89
const ChipButton = ({
910
children,
1011
variant,
1112
onClick,
13+
colorScheme = 'chat',
1214
}: PropsWithChildren<Props>) => {
1315
return (
1416
<button
15-
className={`flex items-center justify-center gap-1 py-1 px-3 rounded-full text-label-title ${
16-
variant === 'filled' ? 'bg-chat-bg-sub' : 'border border-chat-bg-border'
17+
className={`flex items-center justify-center gap-1 py-1 px-3 h-7 rounded-full text-label-title ${
18+
variant === 'filled'
19+
? colorScheme === 'chat'
20+
? 'bg-chat-bg-sub'
21+
: 'bg-bg-sub'
22+
: 'border border-chat-bg-border'
1723
} caption`}
1824
onClick={onClick}
1925
>

client/src/components/Chat/Conversation.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const Conversation = ({
5757
)}
5858
<p className="caption text-label-base flex-1">
5959
{m.isLoading
60-
? m.loadingSteps[m.loadingSteps.length - 1]
60+
? m.loadingSteps[m.loadingSteps.length - 1].displayText
6161
: 'Answer Ready'}
6262
</p>
6363
{!m.isLoading && !!m.results?.length ? (

client/src/components/Chat/InputLoader.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useEffect, useRef, useState } from 'react';
2+
import { ChatLoadingStep } from '../../types/general';
23

3-
const InputLoader = ({ loadingSteps }: { loadingSteps: string[] }) => {
4+
const InputLoader = ({ loadingSteps }: { loadingSteps: ChatLoadingStep[] }) => {
45
const [state, setState] = useState(-1);
56
const steps = useRef(loadingSteps);
67

client/src/components/Chat/NLInput.tsx

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,20 @@ import React, {
22
ChangeEvent,
33
useCallback,
44
useEffect,
5+
useMemo,
56
useRef,
67
useState,
78
} from 'react';
8-
import { FeatherSelected, QuillIcon, SendIcon } from '../../icons';
9+
import {
10+
FeatherSelected,
11+
MagnifyTool,
12+
PointClick,
13+
QuillIcon,
14+
SendIcon,
15+
} from '../../icons';
916
import ClearButton from '../ClearButton';
1017
import Tooltip from '../Tooltip';
18+
import { ChatLoadingStep } from '../../types/general';
1119
import InputLoader from './InputLoader';
1220

1321
type Props = {
@@ -18,7 +26,7 @@ type Props = {
1826
onStop?: () => void;
1927
onChange?: (e: ChangeEvent<HTMLTextAreaElement>) => void;
2028
onSubmit?: () => void;
21-
loadingSteps?: string[];
29+
loadingSteps?: ChatLoadingStep[];
2230
selectedLines?: [number, number] | null;
2331
setSelectedLines?: (l: [number, number] | null) => void;
2432
};
@@ -66,6 +74,12 @@ const NLInput = ({
6674
[isComposing, onSubmit],
6775
);
6876

77+
const shouldShowLoader = useMemo(
78+
() =>
79+
isStoppable && loadingSteps?.length && placeholder !== defaultPlaceholder,
80+
[isStoppable, loadingSteps?.length, placeholder],
81+
);
82+
6983
return (
7084
<div
7185
className={`w-full flex items-start gap-2 rounded-lg
@@ -76,14 +90,20 @@ const NLInput = ({
7690
: 'bg-chat-bg-base hover:text-label-title hover:border-chat-bg-border-hover'
7791
} transition-all ease-out duration-150 flex-grow-0 relative`}
7892
>
79-
{isStoppable &&
80-
loadingSteps?.length &&
81-
placeholder !== defaultPlaceholder && (
82-
<InputLoader loadingSteps={loadingSteps} />
93+
{shouldShowLoader && <InputLoader loadingSteps={loadingSteps!} />}
94+
<div className="pt-4.5">
95+
{shouldShowLoader ? (
96+
loadingSteps?.[loadingSteps?.length - 1]?.type === 'PROC' ? (
97+
<PointClick />
98+
) : (
99+
<MagnifyTool />
100+
)
101+
) : selectedLines ? (
102+
<FeatherSelected />
103+
) : (
104+
<QuillIcon />
83105
)}
84-
<span className="py-4">
85-
{selectedLines ? <FeatherSelected /> : <QuillIcon />}
86-
</span>
106+
</div>
87107
<textarea
88108
className={`w-full py-4 bg-transparent rounded-lg outline-none focus:outline-0 resize-none
89109
placeholder:text-current placeholder:truncate placeholder:max-w-[19.5rem] flex-grow-0`}

0 commit comments

Comments
 (0)