Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 fix: fix telemetry preference modal and default agent config error #2312

Merged
merged 7 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/app/(main)/chat/features/TelemetryNotification/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { PRIVACY_URL } from '@/const/url';
import { useServerConfigStore } from '@/store/serverConfig';
import { serverConfigSelectors } from '@/store/serverConfig/selectors';
import { useUserStore } from '@/store/user';
import { preferenceSelectors } from '@/store/user/selectors';

const useStyles = createStyles(({ css, token, isDarkMode }) => ({
container: css`
Expand Down Expand Up @@ -57,13 +58,14 @@ const TelemetryNotification = memo<{ mobile?: boolean }>(({ mobile }) => {

const { t } = useTranslation('common');
const shouldCheck = useServerConfigStore(serverConfigSelectors.enabledTelemetryChat);
const isPreferenceInit = useUserStore(preferenceSelectors.isPreferenceInit);

const [useCheckTrace, updatePreference] = useUserStore((s) => [
s.useCheckTrace,
s.updatePreference,
]);

const { data: showModal, mutate } = useCheckTrace(shouldCheck);
const { data: showModal, mutate } = useCheckTrace(shouldCheck && isPreferenceInit);

const updateTelemetry = (telemetry: boolean) => {
updatePreference({ telemetry });
Expand Down
4 changes: 1 addition & 3 deletions src/app/(main)/settings/agent/Agent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ import { memo } from 'react';

import { INBOX_SESSION_ID } from '@/const/session';
import AgentSetting from '@/features/AgentSetting';
import { useAgentStore } from '@/store/agent';
import { agentSelectors } from '@/store/agent/selectors';
import { useUserStore } from '@/store/user';
import { settingsSelectors } from '@/store/user/selectors';

const Agent = memo(() => {
const config = useAgentStore(agentSelectors.defaultAgentConfig, isEqual);
const config = useUserStore(settingsSelectors.defaultAgentConfig, isEqual);
const meta = useUserStore(settingsSelectors.defaultAgentMeta, isEqual);
const [updateAgent] = useUserStore((s) => [s.updateDefaultAgent]);

Expand Down
2 changes: 1 addition & 1 deletion src/features/ChatInput/ActionBar/Temperature.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const Temperature = memo(() => {

const [temperature, updateAgentConfig] = useAgentStore((s) => {
const config = agentSelectors.currentAgentConfig(s);
return [config.params.temperature, s.updateAgentConfig];
return [config.params?.temperature, s.updateAgentConfig];
});

return (
Expand Down
26 changes: 26 additions & 0 deletions src/services/session/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,32 @@ describe('SessionService', () => {
});
});

describe('hasSessions', () => {
it('should return false if no sessions exist', async () => {
// Setup
(SessionModel.count as Mock).mockResolvedValue(0);

// Execute
const result = await sessionService.hasSessions();

// Assert
expect(SessionModel.count).toHaveBeenCalled();
expect(result).toBe(false);
});

it('should return true if sessions exist', async () => {
// Setup
(SessionModel.count as Mock).mockResolvedValue(1);

// Execute
const result = await sessionService.hasSessions();

// Assert
expect(SessionModel.count).toHaveBeenCalled();
expect(result).toBe(true);
});
});

describe('searchSessions', () => {
it('should return sessions that match the keyword', async () => {
// Setup
Expand Down
2 changes: 1 addition & 1 deletion src/services/session/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export class ClientService implements ISessionService {
return SessionModel.count();
}
async hasSessions() {
return (await this.countSessions()) === 0;
return (await this.countSessions()) !== 0;
}

async searchSessions(keyword: string) {
Expand Down
38 changes: 38 additions & 0 deletions src/store/global/action.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { withSWR } from '~test-utils';

import { globalService } from '@/services/global';
import { useGlobalStore } from '@/store/global/index';
import { initialState } from '@/store/global/initialState';

vi.mock('zustand/traditional');

Expand Down Expand Up @@ -141,4 +142,41 @@ describe('createPreferenceSlice', () => {
expect(useGlobalStore.getState().latestVersion).toBe(latestVersion);
});
});

describe('useInitGlobalPreference', () => {
it('should init global preference if there is empty object', async () => {
vi.spyOn(
useGlobalStore.getState().preferenceStorage,
'getFromLocalStorage',
).mockReturnValueOnce({} as any);

const { result } = renderHook(() => useGlobalStore().useInitGlobalPreference(), {
wrapper: withSWR,
});

await waitFor(() => {
expect(result.current.data).toEqual({});
});

expect(useGlobalStore.getState().preference).toEqual(initialState.preference);
});

it('should update with data', async () => {
const { result } = renderHook(() => useGlobalStore());
vi.spyOn(
useGlobalStore.getState().preferenceStorage,
'getFromLocalStorage',
).mockReturnValueOnce({ inputHeight: 300 } as any);

const { result: hooks } = renderHook(() => result.current.useInitGlobalPreference(), {
wrapper: withSWR,
});

await waitFor(() => {
expect(hooks.current.data).toEqual({ inputHeight: 300 });
});

expect(result.current.preference.inputHeight).toEqual(300);
});
});
});
9 changes: 6 additions & 3 deletions src/store/global/action.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import isEqual from 'fast-deep-equal';
import { produce } from 'immer';
import { gt } from 'semver';
import useSWR, { SWRResponse } from 'swr';
Expand Down Expand Up @@ -94,9 +95,11 @@ export const globalActionSlice: StateCreator<
() => get().preferenceStorage.getFromLocalStorage(),
{
onSuccess: (preference) => {
if (preference) {
set({ preference }, false, n('initPreference'));
}
const nextPreference = merge(get().preference, preference);

if (isEqual(get().preference, nextPreference)) return;

set({ preference: nextPreference }, false, n('initPreference'));
},
},
),
Expand Down
23 changes: 22 additions & 1 deletion src/store/user/slices/preference/action.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { act, renderHook } from '@testing-library/react';
import { act, renderHook, waitFor } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { withSWR } from '~test-utils';

import { globalService } from '@/services/global';
import { useUserStore } from '@/store/user';

import { type Guide } from './initialState';
Expand Down Expand Up @@ -38,4 +40,23 @@ describe('createPreferenceSlice', () => {
expect(result.current.preference.hideSyncAlert).toEqual(true);
});
});

describe('useInitPreference', () => {
it('should return false when userId is empty', async () => {
const { result } = renderHook(() => useUserStore());

vi.spyOn(result.current.preferenceStorage, 'getFromLocalStorage').mockResolvedValueOnce(
{} as any,
);

const { result: prefernce } = renderHook(() => result.current.useInitPreference(), {
wrapper: withSWR,
});

await waitFor(() => {
expect(prefernce.current.data).toEqual({});
expect(result.current.isPreferenceInit).toBeTruthy();
});
});
});
});
4 changes: 1 addition & 3 deletions src/store/user/slices/preference/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ export const createPreferenceSlice: StateCreator<
() => get().preferenceStorage.getFromLocalStorage(),
{
onSuccess: (preference) => {
if (preference) {
set({ preference }, false, n('initPreference'));
}
set({ isPreferenceInit: true, preference }, false, n('initPreference'));
},
},
),
Expand Down
2 changes: 2 additions & 0 deletions src/store/user/slices/preference/initialState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface UserPreference {
}

export interface UserPreferenceState {
isPreferenceInit: boolean;
/**
* the user preference, which only store in local storage
*/
Expand All @@ -24,6 +25,7 @@ export interface UserPreferenceState {
}

export const initialPreferenceState: UserPreferenceState = {
isPreferenceInit: false,
preference: {
guide: {},
telemetry: null,
Expand Down
2 changes: 2 additions & 0 deletions src/store/user/slices/preference/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ const useCmdEnterToSend = (s: UserStore): boolean => s.preference.useCmdEnterToS
const userAllowTrace = (s: UserStore) => s.preference.telemetry;

const hideSyncAlert = (s: UserStore) => s.preference.hideSyncAlert;
const isPreferenceInit = (s: UserStore) => s.isPreferenceInit;

export const preferenceSelectors = {
hideSyncAlert,
isPreferenceInit,
useCmdEnterToSend,
userAllowTrace,
};
12 changes: 3 additions & 9 deletions src/store/user/slices/settings/actions/llm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,11 @@ import { act, renderHook } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';

import { userService } from '@/services/user';
import { UserStore, useUserStore } from '@/store/user';
import { UserSettingsState, initialSettingsState } from '@/store/user/slices/settings/initialState';
import {
modelConfigSelectors,
modelProviderSelectors,
settingsSelectors,
} from '@/store/user/slices/settings/selectors';
import { useUserStore } from '@/store/user';
import { GeneralModelProviderConfig } from '@/types/settings';
import { merge } from '@/utils/merge';

import { CustomModelCardDispatch, customModelCardsReducer } from '../reducers/customModelCard';
import { CustomModelCardDispatch } from '../reducers/customModelCard';
import { modelProviderSelectors, settingsSelectors } from '../selectors';

// Mock userService
vi.mock('@/services/user', () => ({
Expand Down
4 changes: 3 additions & 1 deletion src/store/user/slices/settings/selectors/settings.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DEFAULT_LANG } from '@/const/locale';
import { DEFAULT_AGENT_META } from '@/const/meta';
import { DEFAULT_AGENT, DEFAULT_TTS_CONFIG } from '@/const/settings';
import { DEFAULT_AGENT, DEFAULT_AGENT_CONFIG, DEFAULT_TTS_CONFIG } from '@/const/settings';
import { Locales } from '@/locales/resources';
import { GeneralModelProviderConfig, GlobalLLMProviderKey, GlobalSettings } from '@/types/settings';
import { isOnServerSide } from '@/utils/env';
Expand All @@ -21,6 +21,7 @@ const password = (s: UserStore) => currentSettings(s).password;
const currentTTS = (s: UserStore) => merge(DEFAULT_TTS_CONFIG, currentSettings(s).tts);

const defaultAgent = (s: UserStore) => merge(DEFAULT_AGENT, currentSettings(s).defaultAgent);
const defaultAgentConfig = (s: UserStore) => merge(DEFAULT_AGENT_CONFIG, defaultAgent(s).config);

const defaultAgentMeta = (s: UserStore) => merge(DEFAULT_AGENT_META, defaultAgent(s).meta);

Expand Down Expand Up @@ -53,6 +54,7 @@ export const settingsSelectors = {
currentTTS,
dalleConfig,
defaultAgent,
defaultAgentConfig,
defaultAgentMeta,
exportSettings,
isDalleAutoGenerating,
Expand Down
Loading