Add settings toggle for previous-conversation context (#66).
Unit Tests / test (pull_request) Successful in 11s
Unit Tests / test (pull_request) Successful in 11s
Wire Account Preferences to use_conversation_context via preferences API, with tooltip copy plus loading and error handling on update.
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
|
import InfoOutlined from '@mui/icons-material/InfoOutlined';
|
||||||
import {
|
import {
|
||||||
useMaterialUIController,
|
useMaterialUIController,
|
||||||
setDarkMode,
|
setDarkMode,
|
||||||
@@ -48,6 +50,16 @@ const SettingLabel = styled.span`
|
|||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
color: ${({ theme }) => theme.colors.text};
|
color: ${({ theme }) => theme.colors.text};
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const InfoIcon = styled(InfoOutlined)`
|
||||||
|
font-size: 1rem !important;
|
||||||
|
opacity: 0.7;
|
||||||
|
cursor: help;
|
||||||
|
vertical-align: middle;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ToggleSwitch = styled.label`
|
const ToggleSwitch = styled.label`
|
||||||
@@ -93,6 +105,11 @@ const Checkbox = styled.input`
|
|||||||
&:checked + ${Slider}:before {
|
&:checked + ${Slider}:before {
|
||||||
transform: translateX(26px);
|
transform: translateX(26px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled + ${Slider} {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ColorPickerContainer = styled.div`
|
const ColorPickerContainer = styled.div`
|
||||||
@@ -115,6 +132,23 @@ const ColorButton = styled.button<{ color: string; isSelected: boolean }>`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const ErrorText = styled.p`
|
||||||
|
color: #ff6b6b;
|
||||||
|
margin: 0.75rem 0 0 0;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const CONTEXT_TOOLTIP =
|
||||||
|
'This will use previous conversations to better customize the experience.';
|
||||||
|
|
||||||
|
function prefsErrorMessage(error: unknown, fallback: string): string {
|
||||||
|
const axiosError = error as {
|
||||||
|
response?: { data?: { detail?: string } };
|
||||||
|
message?: string;
|
||||||
|
};
|
||||||
|
return axiosError.response?.data?.detail || axiosError.message || fallback;
|
||||||
|
}
|
||||||
|
|
||||||
type PreferencesValues = {
|
type PreferencesValues = {
|
||||||
order: boolean;
|
order: boolean;
|
||||||
}
|
}
|
||||||
@@ -128,6 +162,10 @@ const ThemeSettingsCard = (): JSX.Element => {
|
|||||||
const themeColors = Object.keys(palettes);
|
const themeColors = Object.keys(palettes);
|
||||||
|
|
||||||
const [order, setOrder] = useState<boolean>(true);
|
const [order, setOrder] = useState<boolean>(true);
|
||||||
|
const [useConversationContext, setUseConversationContext] = useState<boolean>(false);
|
||||||
|
const [prefsLoading, setPrefsLoading] = useState<boolean>(true);
|
||||||
|
const [contextSaving, setContextSaving] = useState<boolean>(false);
|
||||||
|
const [prefsError, setPrefsError] = useState<string>('');
|
||||||
const { updatePreferences } = useContext(PreferenceContext);
|
const { updatePreferences } = useContext(PreferenceContext);
|
||||||
|
|
||||||
const handleConversationOrder = async ({ order }: PreferencesValues): Promise<void> => {
|
const handleConversationOrder = async ({ order }: PreferencesValues): Promise<void> => {
|
||||||
@@ -141,17 +179,50 @@ const ThemeSettingsCard = (): JSX.Element => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getConversationOrder() {
|
async function getConversationPreferences() {
|
||||||
|
setPrefsLoading(true);
|
||||||
|
setPrefsError('');
|
||||||
try {
|
try {
|
||||||
const { data, }: AxiosResponse<PreferencesType> = await axiosInstance.get(`/conversation_preferences`);
|
const { data }: AxiosResponse<PreferencesType> = await axiosInstance.get(
|
||||||
|
`/conversation_preferences`
|
||||||
|
);
|
||||||
setOrder(data.order);
|
setOrder(data.order);
|
||||||
|
setUseConversationContext(Boolean(data.use_conversation_context));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
setPrefsError(
|
||||||
|
prefsErrorMessage(error, 'Could not load account preferences.')
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
setPrefsLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleConversationContext = async (enabled: boolean): Promise<void> => {
|
||||||
|
const previous = useConversationContext;
|
||||||
|
setUseConversationContext(enabled);
|
||||||
|
setContextSaving(true);
|
||||||
|
setPrefsError('');
|
||||||
|
try {
|
||||||
|
const { data }: AxiosResponse<PreferencesType> = await axiosInstance.post(
|
||||||
|
'/conversation_preferences',
|
||||||
|
{ use_conversation_context: enabled }
|
||||||
|
);
|
||||||
|
setUseConversationContext(Boolean(data.use_conversation_context));
|
||||||
|
} catch (error) {
|
||||||
|
setUseConversationContext(previous);
|
||||||
|
setPrefsError(
|
||||||
|
prefsErrorMessage(
|
||||||
|
error,
|
||||||
|
'Could not update conversation context setting. Try again.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
setContextSaving(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getConversationOrder();
|
getConversationPreferences();
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleDarkMode = () => setDarkMode(dispatch, !darkMode);
|
const handleDarkMode = () => setDarkMode(dispatch, !darkMode);
|
||||||
@@ -193,6 +264,7 @@ const ThemeSettingsCard = (): JSX.Element => {
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={order}
|
checked={order}
|
||||||
|
disabled={prefsLoading}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setOrder(!order);
|
setOrder(!order);
|
||||||
handleConversationOrder({ order: !order })
|
handleConversationOrder({ order: !order })
|
||||||
@@ -202,6 +274,30 @@ const ThemeSettingsCard = (): JSX.Element => {
|
|||||||
</ToggleSwitch>
|
</ToggleSwitch>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
|
|
||||||
|
<SettingRow>
|
||||||
|
<SettingLabel>
|
||||||
|
Use previous conversations
|
||||||
|
<Tooltip title={CONTEXT_TOOLTIP}>
|
||||||
|
<span>
|
||||||
|
<InfoIcon aria-label={CONTEXT_TOOLTIP} />
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</SettingLabel>
|
||||||
|
<ToggleSwitch>
|
||||||
|
<Checkbox
|
||||||
|
type="checkbox"
|
||||||
|
checked={useConversationContext}
|
||||||
|
disabled={prefsLoading || contextSaving}
|
||||||
|
onChange={() => {
|
||||||
|
handleConversationContext(!useConversationContext);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Slider />
|
||||||
|
</ToggleSwitch>
|
||||||
|
</SettingRow>
|
||||||
|
|
||||||
|
{prefsError ? <ErrorText role="alert">{prefsError}</ErrorText> : null}
|
||||||
|
|
||||||
</GlassCard>
|
</GlassCard>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ export interface AccountType {
|
|||||||
|
|
||||||
export interface PreferencesType {
|
export interface PreferencesType {
|
||||||
order: boolean;
|
order: boolean;
|
||||||
|
use_conversation_context?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Account {
|
export class Account {
|
||||||
|
|||||||
Reference in New Issue
Block a user