@databiosphere/findable-ui 49.1.0 → 49.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +14 -0
- package/lib/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.d.ts +2 -3
- package/lib/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.js +3 -4
- package/lib/views/ResearchView/assistant/assistant.js +3 -5
- package/lib/views/ResearchView/assistant/components/Form/form.d.ts +1 -2
- package/lib/views/ResearchView/assistant/components/Form/form.js +5 -18
- package/lib/views/ResearchView/assistant/components/Form/types.d.ts +1 -2
- package/lib/views/ResearchView/assistant/components/Form/utils.d.ts +1 -1
- package/lib/views/ResearchView/assistant/components/Messages/hooks/UseScroll/hook.d.ts +2 -1
- package/lib/views/ResearchView/assistant/components/Messages/hooks/UseScroll/hook.js +5 -2
- package/lib/views/ResearchView/assistant/components/ToggleButtonGroup/toggleButtonGroup.d.ts +2 -3
- package/lib/views/ResearchView/assistant/components/ToggleButtonGroup/toggleButtonGroup.js +3 -4
- package/lib/views/ResearchView/assistant/stories/assistant.stories.js +1 -1
- package/lib/views/ResearchView/state/provider.d.ts +4 -1
- package/lib/views/ResearchView/state/provider.js +5 -2
- package/lib/views/ResearchView/state/query/context.d.ts +5 -0
- package/lib/views/ResearchView/state/query/context.js +7 -0
- package/lib/views/ResearchView/state/query/hooks/UseQuery/hook.d.ts +6 -0
- package/lib/views/ResearchView/state/query/hooks/UseQuery/hook.js +9 -0
- package/lib/views/ResearchView/state/query/hooks/UseSubmit/hook.d.ts +7 -0
- package/lib/views/ResearchView/state/query/hooks/UseSubmit/hook.js +46 -0
- package/lib/views/ResearchView/state/query/provider.d.ts +13 -0
- package/lib/views/ResearchView/state/query/provider.js +15 -0
- package/lib/views/ResearchView/{query → state/query}/types.d.ts +5 -12
- package/package.json +1 -1
- package/src/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.tsx +8 -4
- package/src/views/ResearchView/assistant/assistant.tsx +3 -5
- package/src/views/ResearchView/assistant/components/Form/form.tsx +4 -19
- package/src/views/ResearchView/assistant/components/Form/types.ts +0 -2
- package/src/views/ResearchView/assistant/components/Form/utils.ts +1 -1
- package/src/views/ResearchView/assistant/components/Messages/hooks/UseScroll/hook.ts +5 -2
- package/src/views/ResearchView/assistant/components/ToggleButtonGroup/toggleButtonGroup.tsx +8 -4
- package/src/views/ResearchView/assistant/stories/assistant.stories.tsx +1 -1
- package/src/views/ResearchView/state/provider.tsx +8 -1
- package/src/views/ResearchView/state/query/context.ts +9 -0
- package/src/views/ResearchView/state/query/hooks/UseQuery/hook.ts +11 -0
- package/src/views/ResearchView/state/query/hooks/UseSubmit/hook.ts +66 -0
- package/src/views/ResearchView/state/query/provider.tsx +27 -0
- package/src/views/ResearchView/{query → state/query}/types.ts +9 -15
- package/tests/research.queryProvider.test.ts +321 -0
- package/lib/views/ResearchView/adapter/useAdapter.d.ts +0 -6
- package/lib/views/ResearchView/adapter/useAdapter.js +0 -15
- package/lib/views/ResearchView/query/useQuery.d.ts +0 -7
- package/lib/views/ResearchView/query/useQuery.js +0 -44
- package/src/views/ResearchView/adapter/useAdapter.ts +0 -19
- package/src/views/ResearchView/query/useQuery.ts +0 -60
- package/tests/research.useQuery.test.ts +0 -165
- /package/lib/views/ResearchView/{query → state/query}/types.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [49.2.0](https://github.com/DataBiosphere/findable-ui/compare/v49.1.0...v49.2.0) (2026-03-02)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add href to selected toggle buttons for navigation ([#805](https://github.com/DataBiosphere/findable-ui/issues/805)) ([7bacb28](https://github.com/DataBiosphere/findable-ui/commit/7bacb280d4075bb2f403d076e14ee58d26905045))
|
|
9
|
+
* lift query submission into queryprovider ([#803](https://github.com/DataBiosphere/findable-ui/issues/803)) ([466780e](https://github.com/DataBiosphere/findable-ui/commit/466780e12c3218bea29b82cd9759d24334573d91))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* use instant scroll on mount and smooth scroll on subsequent updates ([#806](https://github.com/DataBiosphere/findable-ui/issues/806)) ([30777a7](https://github.com/DataBiosphere/findable-ui/commit/30777a7338f28726959b757ffad8577890c56db0))
|
|
15
|
+
* use instant scroll on mount for messages panel ([#807](https://github.com/DataBiosphere/findable-ui/issues/807)) ([30777a7](https://github.com/DataBiosphere/findable-ui/commit/30777a7338f28726959b757ffad8577890c56db0))
|
|
16
|
+
|
|
3
17
|
## [49.1.0](https://github.com/DataBiosphere/findable-ui/compare/v49.0.0...v49.1.0) (2026-02-28)
|
|
4
18
|
|
|
5
19
|
|
package/lib/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { JSX } from "react";
|
|
2
2
|
/**
|
|
3
|
-
* ToggleButtonGroup component for navigating
|
|
4
|
-
*
|
|
5
|
-
* @returns ToggleButtonGroup JSX element.
|
|
3
|
+
* ToggleButtonGroup component for navigating between ExploreView and ResearchView.
|
|
4
|
+
* @returns ToggleButtonGroup JSX element, or null if routes are not configured.
|
|
6
5
|
*/
|
|
7
6
|
export declare const ToggleButtonGroup: () => JSX.Element | null;
|
package/lib/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.js
CHANGED
|
@@ -6,13 +6,12 @@ import { useAiRoutes } from "../../../../../../hooks/ai/useAiRoutes/hook";
|
|
|
6
6
|
import { StyledToggleButtonGroup } from "./toggleButtonGroup.styles";
|
|
7
7
|
import { Beta } from "../../../../../../components/common/Chip/components/Beta/beta";
|
|
8
8
|
/**
|
|
9
|
-
* ToggleButtonGroup component for navigating
|
|
10
|
-
*
|
|
11
|
-
* @returns ToggleButtonGroup JSX element.
|
|
9
|
+
* ToggleButtonGroup component for navigating between ExploreView and ResearchView.
|
|
10
|
+
* @returns ToggleButtonGroup JSX element, or null if routes are not configured.
|
|
12
11
|
*/
|
|
13
12
|
export const ToggleButtonGroup = () => {
|
|
14
13
|
const { routes } = useAiRoutes() || {};
|
|
15
14
|
if (!routes)
|
|
16
15
|
return null;
|
|
17
|
-
return (_jsx(StyledBox, { children: _jsxs(StyledToggleButtonGroup, { exclusive: true, children: [_jsxs(ToggleButton, { component: Link, href: routes.research, value: "research", children: ["Research ", _jsx(Beta, {})] }), _jsx(ToggleButton, { selected: true, value: "search", children: "Search" })] }) }));
|
|
16
|
+
return (_jsx(StyledBox, { children: _jsxs(StyledToggleButtonGroup, { exclusive: true, children: [_jsxs(ToggleButton, { component: Link, href: routes.research, value: "research", children: ["Research ", _jsx(Beta, {})] }), _jsx(ToggleButton, { component: Link, href: routes.search, selected: true, value: "search", children: "Search" })] }) }));
|
|
18
17
|
};
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useChatState } from "../state/hooks/UseChatState/hook";
|
|
3
3
|
import { Form } from "./components/Form/form";
|
|
4
4
|
import { Input } from "./components/Input/input";
|
|
5
|
-
import { Messages } from "./components/Messages/messages";
|
|
6
5
|
import { getPlaceholder } from "./components/Input/utils";
|
|
6
|
+
import { Messages } from "./components/Messages/messages";
|
|
7
7
|
import { Drawer } from "./components/Drawer/drawer";
|
|
8
|
-
import { useChatState } from "../state/hooks/UseChatState/hook";
|
|
9
8
|
import { ToggleButtonGroup } from "./components/ToggleButtonGroup/toggleButtonGroup";
|
|
10
9
|
/**
|
|
11
10
|
* Renders the research assistant drawer.
|
|
12
11
|
* @returns The assistant drawer.
|
|
13
12
|
*/
|
|
14
13
|
export const Assistant = () => {
|
|
15
|
-
const { actions } = useAdapter();
|
|
16
14
|
const { state } = useChatState();
|
|
17
|
-
return (_jsxs(Drawer, { children: [_jsx(ToggleButtonGroup, {}), _jsxs(Form, {
|
|
15
|
+
return (_jsxs(Drawer, { children: [_jsx(ToggleButtonGroup, {}), _jsxs(Form, { status: state.status, children: [_jsx(Messages, { state: state }), _jsx(Input, { disabled: state.status.loading, placeholder: getPlaceholder(state) })] })] }));
|
|
18
16
|
};
|
|
@@ -3,10 +3,9 @@ import { FormProps } from "./types";
|
|
|
3
3
|
/**
|
|
4
4
|
* Renders the research form.
|
|
5
5
|
* @param props - Component props.
|
|
6
|
-
* @param props.actions - Form actions.
|
|
7
6
|
* @param props.children - Form children.
|
|
8
7
|
* @param props.className - Class name for styling.
|
|
9
8
|
* @param props.status - Form status.
|
|
10
9
|
* @returns The research form container element.
|
|
11
10
|
*/
|
|
12
|
-
export declare const Form: ({
|
|
11
|
+
export declare const Form: ({ children, className, status, }: FormProps) => JSX.Element;
|
|
@@ -1,39 +1,26 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { TEST_IDS } from "../../../../../tests/testIds";
|
|
3
|
-
import {
|
|
3
|
+
import { useQuery } from "../../../state/query/hooks/UseQuery/hook";
|
|
4
4
|
import { FIELD_NAME } from "./constants";
|
|
5
|
-
import { getPayload } from "./utils";
|
|
6
5
|
import { StyledForm } from "./form.styles";
|
|
6
|
+
import { getPayload } from "./utils";
|
|
7
7
|
/**
|
|
8
8
|
* Renders the research form.
|
|
9
9
|
* @param props - Component props.
|
|
10
|
-
* @param props.actions - Form actions.
|
|
11
10
|
* @param props.children - Form children.
|
|
12
11
|
* @param props.className - Class name for styling.
|
|
13
12
|
* @param props.status - Form status.
|
|
14
13
|
* @returns The research form container element.
|
|
15
14
|
*/
|
|
16
|
-
export const Form = ({
|
|
17
|
-
const
|
|
15
|
+
export const Form = ({ children, className, status, }) => {
|
|
16
|
+
const { onSubmit } = useQuery();
|
|
18
17
|
return (_jsx(StyledForm, { className: className, "data-testid": TEST_IDS.RESEARCH_FORM, onSubmit: async (e) => {
|
|
19
|
-
await
|
|
20
|
-
onError: (error) => {
|
|
21
|
-
dispatch.onSetError(error.message);
|
|
22
|
-
},
|
|
23
|
-
onMutate: (form, query) => {
|
|
24
|
-
dispatch.onSetQuery(query);
|
|
25
|
-
dispatch.onSetStatus(true);
|
|
26
|
-
form.reset();
|
|
27
|
-
},
|
|
18
|
+
await onSubmit(e, getPayload(e), {
|
|
28
19
|
onSettled: (form) => {
|
|
29
|
-
dispatch.onSetStatus(false);
|
|
30
20
|
const input = form.elements.namedItem(FIELD_NAME.AI_PROMPT);
|
|
31
21
|
if (input instanceof HTMLElement)
|
|
32
22
|
input.focus();
|
|
33
23
|
},
|
|
34
|
-
onSuccess: (data) => {
|
|
35
|
-
dispatch.onSetMessage(data);
|
|
36
|
-
},
|
|
37
24
|
status,
|
|
38
25
|
});
|
|
39
26
|
}, children: children }));
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { UseQuery } from "../../../query/types";
|
|
2
1
|
import { BaseComponentProps, ChildrenProps } from "../../../../../components/types";
|
|
3
2
|
import { ChatState } from "../../../state/types";
|
|
4
|
-
export type FormProps = BaseComponentProps & ChildrenProps & Pick<
|
|
3
|
+
export type FormProps = BaseComponentProps & ChildrenProps & Pick<ChatState, "status">;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DependencyList, RefObject } from "react";
|
|
2
2
|
/**
|
|
3
|
-
* Provides a ref that
|
|
3
|
+
* Provides a ref that scrolls to the bottom when dependencies change.
|
|
4
|
+
* Uses instant scroll on mount and smooth scroll on subsequent updates.
|
|
4
5
|
* @param deps - Dependency list that triggers scroll on change.
|
|
5
6
|
* @returns A ref to attach to the scrollable container.
|
|
6
7
|
*/
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { useEffect, useRef } from "react";
|
|
2
2
|
/**
|
|
3
|
-
* Provides a ref that
|
|
3
|
+
* Provides a ref that scrolls to the bottom when dependencies change.
|
|
4
|
+
* Uses instant scroll on mount and smooth scroll on subsequent updates.
|
|
4
5
|
* @param deps - Dependency list that triggers scroll on change.
|
|
5
6
|
* @returns A ref to attach to the scrollable container.
|
|
6
7
|
*/
|
|
7
8
|
export function useScroll(deps) {
|
|
9
|
+
const behaviorRef = useRef("instant");
|
|
8
10
|
const ref = useRef(null);
|
|
9
11
|
useEffect(() => {
|
|
10
12
|
ref.current?.scrollTo({
|
|
11
|
-
behavior:
|
|
13
|
+
behavior: behaviorRef.current,
|
|
12
14
|
top: ref.current.scrollHeight,
|
|
13
15
|
});
|
|
16
|
+
behaviorRef.current = "smooth";
|
|
14
17
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- deps are passed in as an argument
|
|
15
18
|
}, deps);
|
|
16
19
|
return ref;
|
package/lib/views/ResearchView/assistant/components/ToggleButtonGroup/toggleButtonGroup.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { JSX } from "react";
|
|
2
2
|
/**
|
|
3
|
-
* ToggleButtonGroup component for navigating
|
|
4
|
-
*
|
|
5
|
-
* @returns ToggleButtonGroup JSX element.
|
|
3
|
+
* ToggleButtonGroup component for navigating between ResearchView and ExploreView.
|
|
4
|
+
* @returns ToggleButtonGroup JSX element, or null if routes are not configured.
|
|
6
5
|
*/
|
|
7
6
|
export declare const ToggleButtonGroup: () => JSX.Element | null;
|
|
@@ -5,13 +5,12 @@ import Link from "next/link";
|
|
|
5
5
|
import { useAiRoutes } from "../../../../../hooks/ai/useAiRoutes/hook";
|
|
6
6
|
import { Beta } from "../../../../../components/common/Chip/components/Beta/beta";
|
|
7
7
|
/**
|
|
8
|
-
* ToggleButtonGroup component for navigating
|
|
9
|
-
*
|
|
10
|
-
* @returns ToggleButtonGroup JSX element.
|
|
8
|
+
* ToggleButtonGroup component for navigating between ResearchView and ExploreView.
|
|
9
|
+
* @returns ToggleButtonGroup JSX element, or null if routes are not configured.
|
|
11
10
|
*/
|
|
12
11
|
export const ToggleButtonGroup = () => {
|
|
13
12
|
const { routes } = useAiRoutes() || {};
|
|
14
13
|
if (!routes)
|
|
15
14
|
return null;
|
|
16
|
-
return (_jsx(StyledBox, { children: _jsxs(StyledToggleButtonGroup, { exclusive: true, children: [_jsxs(ToggleButton, { selected: true, value: "research", children: ["Research ", _jsx(Beta, {})] }), _jsx(ToggleButton, { component: Link, href: routes.search, value: "search", children: "Search" })] }) }));
|
|
15
|
+
return (_jsx(StyledBox, { children: _jsxs(StyledToggleButtonGroup, { exclusive: true, children: [_jsxs(ToggleButton, { component: Link, href: routes.research, selected: true, value: "research", children: ["Research ", _jsx(Beta, {})] }), _jsx(ToggleButton, { component: Link, href: routes.search, value: "search", children: "Search" })] }) }));
|
|
17
16
|
};
|
|
@@ -8,7 +8,7 @@ import { ConfigProvider } from "../../../../providers/config";
|
|
|
8
8
|
const meta = {
|
|
9
9
|
component: Assistant,
|
|
10
10
|
decorators: [
|
|
11
|
-
(Story) => (_jsx(ConfigProvider, { config: INITIAL_CONFIG, children: _jsx(ChatProvider, { initialArgs: INITIAL_ARGS, children: _jsx(Box, { sx: {
|
|
11
|
+
(Story) => (_jsx(ConfigProvider, { config: INITIAL_CONFIG, children: _jsx(ChatProvider, { initialArgs: INITIAL_ARGS, url: "https://api.example.com", children: _jsx(Box, { sx: {
|
|
12
12
|
backgroundColor: PALETTE.COMMON_WHITE,
|
|
13
13
|
display: "flex",
|
|
14
14
|
flexDirection: "column",
|
|
@@ -3,14 +3,17 @@ import { InitialArgs } from "./initializer/types";
|
|
|
3
3
|
/**
|
|
4
4
|
* Provider for Chat state.
|
|
5
5
|
* Manages chat state such as query and response data.
|
|
6
|
+
* Nests QueryProvider to own the fetch lifecycle for query submission.
|
|
6
7
|
*
|
|
7
8
|
* @param props - Props.
|
|
8
9
|
* @param props.children - Children.
|
|
9
10
|
* @param props.initialArgs - Initial arguments.
|
|
11
|
+
* @param props.url - URL for the query endpoint.
|
|
10
12
|
*
|
|
11
13
|
* @returns A context provider wrapping the given children.
|
|
12
14
|
*/
|
|
13
|
-
export declare function ChatProvider({ children, initialArgs, }: {
|
|
15
|
+
export declare function ChatProvider({ children, initialArgs, url, }: {
|
|
14
16
|
children: ReactNode;
|
|
15
17
|
initialArgs?: InitialArgs;
|
|
18
|
+
url: string;
|
|
16
19
|
}): JSX.Element;
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { ChatContext } from "./context";
|
|
3
3
|
import { useChatReducer } from "./hooks/UseChatReducer/hook";
|
|
4
|
+
import { QueryProvider } from "./query/provider";
|
|
4
5
|
/**
|
|
5
6
|
* Provider for Chat state.
|
|
6
7
|
* Manages chat state such as query and response data.
|
|
8
|
+
* Nests QueryProvider to own the fetch lifecycle for query submission.
|
|
7
9
|
*
|
|
8
10
|
* @param props - Props.
|
|
9
11
|
* @param props.children - Children.
|
|
10
12
|
* @param props.initialArgs - Initial arguments.
|
|
13
|
+
* @param props.url - URL for the query endpoint.
|
|
11
14
|
*
|
|
12
15
|
* @returns A context provider wrapping the given children.
|
|
13
16
|
*/
|
|
14
|
-
export function ChatProvider({ children, initialArgs, }) {
|
|
17
|
+
export function ChatProvider({ children, initialArgs, url, }) {
|
|
15
18
|
const reducer = useChatReducer(initialArgs);
|
|
16
|
-
return (_jsx(ChatContext.Provider, { value: reducer, children: children }));
|
|
19
|
+
return (_jsx(ChatContext.Provider, { value: reducer, children: _jsx(QueryProvider, { url: url, children: children }) }));
|
|
17
20
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { QueryContext } from "../../context";
|
|
3
|
+
/**
|
|
4
|
+
* Hook to access query submission from the QueryProvider.
|
|
5
|
+
* @returns Query context value with onSubmit.
|
|
6
|
+
*/
|
|
7
|
+
export const useQuery = () => {
|
|
8
|
+
return useContext(QueryContext);
|
|
9
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { QueryContextValue } from "../../types";
|
|
2
|
+
/**
|
|
3
|
+
* Hook that manages query submission and abort lifecycle.
|
|
4
|
+
* @param url - The API URL to send queries to.
|
|
5
|
+
* @returns Object containing the onSubmit handler.
|
|
6
|
+
*/
|
|
7
|
+
export declare const useSubmit: (url: string) => Pick<QueryContextValue, "onSubmit">;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useCallback, useRef } from "react";
|
|
2
|
+
import { fetchResponse } from "../../../../query/fetch";
|
|
3
|
+
import { useChatDispatch } from "../../../hooks/UseChatDispatch/hook";
|
|
4
|
+
/**
|
|
5
|
+
* Hook that manages query submission and abort lifecycle.
|
|
6
|
+
* @param url - The API URL to send queries to.
|
|
7
|
+
* @returns Object containing the onSubmit handler.
|
|
8
|
+
*/
|
|
9
|
+
export const useSubmit = (url) => {
|
|
10
|
+
const abortRef = useRef(null);
|
|
11
|
+
const dispatch = useChatDispatch();
|
|
12
|
+
const onSubmit = useCallback(async (e, payload, options) => {
|
|
13
|
+
e.preventDefault();
|
|
14
|
+
if (options.status.loading)
|
|
15
|
+
return;
|
|
16
|
+
const { query } = payload;
|
|
17
|
+
if (!query)
|
|
18
|
+
return;
|
|
19
|
+
const form = e.currentTarget;
|
|
20
|
+
// Dispatch query and loading state.
|
|
21
|
+
dispatch.onSetQuery(query);
|
|
22
|
+
dispatch.onSetStatus(true);
|
|
23
|
+
form.reset();
|
|
24
|
+
options.onMutate?.(form, query);
|
|
25
|
+
// Abort any in-flight request.
|
|
26
|
+
abortRef.current?.abort();
|
|
27
|
+
const controller = new AbortController();
|
|
28
|
+
abortRef.current = controller;
|
|
29
|
+
await fetchResponse(url, query, {
|
|
30
|
+
controller,
|
|
31
|
+
onError: (error) => {
|
|
32
|
+
dispatch.onSetError(error.message);
|
|
33
|
+
options.onError?.(error);
|
|
34
|
+
},
|
|
35
|
+
onSettled: () => {
|
|
36
|
+
dispatch.onSetStatus(false);
|
|
37
|
+
options.onSettled?.(form);
|
|
38
|
+
},
|
|
39
|
+
onSuccess: (data) => {
|
|
40
|
+
dispatch.onSetMessage(data);
|
|
41
|
+
options.onSuccess?.(data);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}, [dispatch, url]);
|
|
45
|
+
return { onSubmit };
|
|
46
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { JSX, ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Provider that owns the fetch lifecycle for query submission.
|
|
4
|
+
* Persists across page navigation so in-flight requests are not aborted.
|
|
5
|
+
* @param props - Props.
|
|
6
|
+
* @param props.children - Children.
|
|
7
|
+
* @param props.url - URL for the query endpoint.
|
|
8
|
+
* @returns A context provider wrapping the given children.
|
|
9
|
+
*/
|
|
10
|
+
export declare function QueryProvider({ children, url, }: {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
url: string;
|
|
13
|
+
}): JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { QueryContext } from "./context";
|
|
3
|
+
import { useSubmit } from "./hooks/UseSubmit/hook";
|
|
4
|
+
/**
|
|
5
|
+
* Provider that owns the fetch lifecycle for query submission.
|
|
6
|
+
* Persists across page navigation so in-flight requests are not aborted.
|
|
7
|
+
* @param props - Props.
|
|
8
|
+
* @param props.children - Children.
|
|
9
|
+
* @param props.url - URL for the query endpoint.
|
|
10
|
+
* @returns A context provider wrapping the given children.
|
|
11
|
+
*/
|
|
12
|
+
export function QueryProvider({ children, url, }) {
|
|
13
|
+
const { onSubmit } = useSubmit(url);
|
|
14
|
+
return (_jsx(QueryContext.Provider, { value: { onSubmit }, children: children }));
|
|
15
|
+
}
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { FormEvent } from "react";
|
|
2
|
-
|
|
3
|
-
* Actions returned by the useQuery hook.
|
|
4
|
-
*/
|
|
5
|
-
export interface Actions {
|
|
6
|
-
onSubmit: (e: FormEvent<HTMLFormElement>, payload: OnSubmitPayload, options?: OnSubmitOptions) => Promise<void>;
|
|
7
|
-
}
|
|
2
|
+
import { Status } from "../types";
|
|
8
3
|
/**
|
|
9
4
|
* Options for the onSubmit action.
|
|
10
5
|
*/
|
|
@@ -13,9 +8,7 @@ export interface OnSubmitOptions {
|
|
|
13
8
|
onMutate?: (form: HTMLFormElement, query: string) => void;
|
|
14
9
|
onSettled?: (form: HTMLFormElement) => void;
|
|
15
10
|
onSuccess?: (data: unknown) => void;
|
|
16
|
-
status
|
|
17
|
-
loading: boolean;
|
|
18
|
-
};
|
|
11
|
+
status: Status;
|
|
19
12
|
}
|
|
20
13
|
/**
|
|
21
14
|
* Payload for the onSubmit action.
|
|
@@ -24,8 +17,8 @@ export interface OnSubmitPayload {
|
|
|
24
17
|
query: string;
|
|
25
18
|
}
|
|
26
19
|
/**
|
|
27
|
-
*
|
|
20
|
+
* Context value for the QueryProvider.
|
|
28
21
|
*/
|
|
29
|
-
export interface
|
|
30
|
-
|
|
22
|
+
export interface QueryContextValue {
|
|
23
|
+
onSubmit: (e: FormEvent<HTMLFormElement>, payload: OnSubmitPayload, options: OnSubmitOptions) => Promise<void>;
|
|
31
24
|
}
|
package/package.json
CHANGED
package/src/views/ExploreView/entityList/filters/components/ToggleButtonGroup/toggleButtonGroup.tsx
CHANGED
|
@@ -7,9 +7,8 @@ import { StyledToggleButtonGroup } from "./toggleButtonGroup.styles";
|
|
|
7
7
|
import { Beta } from "../../../../../../components/common/Chip/components/Beta/beta";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* ToggleButtonGroup component for navigating
|
|
11
|
-
*
|
|
12
|
-
* @returns ToggleButtonGroup JSX element.
|
|
10
|
+
* ToggleButtonGroup component for navigating between ExploreView and ResearchView.
|
|
11
|
+
* @returns ToggleButtonGroup JSX element, or null if routes are not configured.
|
|
13
12
|
*/
|
|
14
13
|
export const ToggleButtonGroup = (): JSX.Element | null => {
|
|
15
14
|
const { routes } = useAiRoutes() || {};
|
|
@@ -22,7 +21,12 @@ export const ToggleButtonGroup = (): JSX.Element | null => {
|
|
|
22
21
|
<ToggleButton component={Link} href={routes.research} value="research">
|
|
23
22
|
Research <Beta />
|
|
24
23
|
</ToggleButton>
|
|
25
|
-
<ToggleButton
|
|
24
|
+
<ToggleButton
|
|
25
|
+
component={Link}
|
|
26
|
+
href={routes.search}
|
|
27
|
+
selected
|
|
28
|
+
value="search"
|
|
29
|
+
>
|
|
26
30
|
Search
|
|
27
31
|
</ToggleButton>
|
|
28
32
|
</StyledToggleButtonGroup>
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { JSX } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { useChatState } from "../state/hooks/UseChatState/hook";
|
|
3
3
|
import { Form } from "./components/Form/form";
|
|
4
4
|
import { Input } from "./components/Input/input";
|
|
5
|
-
import { Messages } from "./components/Messages/messages";
|
|
6
5
|
import { getPlaceholder } from "./components/Input/utils";
|
|
6
|
+
import { Messages } from "./components/Messages/messages";
|
|
7
7
|
import { Drawer } from "./components/Drawer/drawer";
|
|
8
|
-
import { useChatState } from "../state/hooks/UseChatState/hook";
|
|
9
8
|
import { ToggleButtonGroup } from "./components/ToggleButtonGroup/toggleButtonGroup";
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -13,12 +12,11 @@ import { ToggleButtonGroup } from "./components/ToggleButtonGroup/toggleButtonGr
|
|
|
13
12
|
* @returns The assistant drawer.
|
|
14
13
|
*/
|
|
15
14
|
export const Assistant = (): JSX.Element => {
|
|
16
|
-
const { actions } = useAdapter();
|
|
17
15
|
const { state } = useChatState();
|
|
18
16
|
return (
|
|
19
17
|
<Drawer>
|
|
20
18
|
<ToggleButtonGroup />
|
|
21
|
-
<Form
|
|
19
|
+
<Form status={state.status}>
|
|
22
20
|
<Messages state={state} />
|
|
23
21
|
<Input
|
|
24
22
|
disabled={state.status.loading}
|
|
@@ -1,50 +1,35 @@
|
|
|
1
1
|
import { JSX } from "react";
|
|
2
2
|
import { TEST_IDS } from "../../../../../tests/testIds";
|
|
3
|
-
import {
|
|
4
|
-
import { MessageResponse } from "../../../state/types";
|
|
3
|
+
import { useQuery } from "../../../state/query/hooks/UseQuery/hook";
|
|
5
4
|
import { FIELD_NAME } from "./constants";
|
|
5
|
+
import { StyledForm } from "./form.styles";
|
|
6
6
|
import { FormProps } from "./types";
|
|
7
7
|
import { getPayload } from "./utils";
|
|
8
|
-
import { StyledForm } from "./form.styles";
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Renders the research form.
|
|
12
11
|
* @param props - Component props.
|
|
13
|
-
* @param props.actions - Form actions.
|
|
14
12
|
* @param props.children - Form children.
|
|
15
13
|
* @param props.className - Class name for styling.
|
|
16
14
|
* @param props.status - Form status.
|
|
17
15
|
* @returns The research form container element.
|
|
18
16
|
*/
|
|
19
17
|
export const Form = ({
|
|
20
|
-
actions,
|
|
21
18
|
children,
|
|
22
19
|
className,
|
|
23
20
|
status,
|
|
24
21
|
}: FormProps): JSX.Element => {
|
|
25
|
-
const
|
|
22
|
+
const { onSubmit } = useQuery();
|
|
26
23
|
return (
|
|
27
24
|
<StyledForm
|
|
28
25
|
className={className}
|
|
29
26
|
data-testid={TEST_IDS.RESEARCH_FORM}
|
|
30
27
|
onSubmit={async (e) => {
|
|
31
|
-
await
|
|
32
|
-
onError: (error) => {
|
|
33
|
-
dispatch.onSetError(error.message);
|
|
34
|
-
},
|
|
35
|
-
onMutate: (form, query) => {
|
|
36
|
-
dispatch.onSetQuery(query);
|
|
37
|
-
dispatch.onSetStatus(true);
|
|
38
|
-
form.reset();
|
|
39
|
-
},
|
|
28
|
+
await onSubmit(e, getPayload(e), {
|
|
40
29
|
onSettled: (form) => {
|
|
41
|
-
dispatch.onSetStatus(false);
|
|
42
30
|
const input = form.elements.namedItem(FIELD_NAME.AI_PROMPT);
|
|
43
31
|
if (input instanceof HTMLElement) input.focus();
|
|
44
32
|
},
|
|
45
|
-
onSuccess: (data) => {
|
|
46
|
-
dispatch.onSetMessage(data as MessageResponse);
|
|
47
|
-
},
|
|
48
33
|
status,
|
|
49
34
|
});
|
|
50
35
|
}}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { UseQuery } from "../../../query/types";
|
|
2
1
|
import {
|
|
3
2
|
BaseComponentProps,
|
|
4
3
|
ChildrenProps,
|
|
@@ -7,5 +6,4 @@ import { ChatState } from "../../../state/types";
|
|
|
7
6
|
|
|
8
7
|
export type FormProps = BaseComponentProps &
|
|
9
8
|
ChildrenProps &
|
|
10
|
-
Pick<UseQuery, "actions"> &
|
|
11
9
|
Pick<ChatState, "status">;
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { DependencyList, RefObject, useEffect, useRef } from "react";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Provides a ref that
|
|
4
|
+
* Provides a ref that scrolls to the bottom when dependencies change.
|
|
5
|
+
* Uses instant scroll on mount and smooth scroll on subsequent updates.
|
|
5
6
|
* @param deps - Dependency list that triggers scroll on change.
|
|
6
7
|
* @returns A ref to attach to the scrollable container.
|
|
7
8
|
*/
|
|
8
9
|
export function useScroll(
|
|
9
10
|
deps: DependencyList,
|
|
10
11
|
): RefObject<HTMLDivElement | null> {
|
|
12
|
+
const behaviorRef = useRef<ScrollBehavior>("instant");
|
|
11
13
|
const ref = useRef<HTMLDivElement>(null);
|
|
12
14
|
|
|
13
15
|
useEffect(() => {
|
|
14
16
|
ref.current?.scrollTo({
|
|
15
|
-
behavior:
|
|
17
|
+
behavior: behaviorRef.current,
|
|
16
18
|
top: ref.current.scrollHeight,
|
|
17
19
|
});
|
|
20
|
+
behaviorRef.current = "smooth";
|
|
18
21
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- deps are passed in as an argument
|
|
19
22
|
}, deps);
|
|
20
23
|
|
|
@@ -6,9 +6,8 @@ import { useAiRoutes } from "../../../../../hooks/ai/useAiRoutes/hook";
|
|
|
6
6
|
import { Beta } from "../../../../../components/common/Chip/components/Beta/beta";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* ToggleButtonGroup component for navigating
|
|
10
|
-
*
|
|
11
|
-
* @returns ToggleButtonGroup JSX element.
|
|
9
|
+
* ToggleButtonGroup component for navigating between ResearchView and ExploreView.
|
|
10
|
+
* @returns ToggleButtonGroup JSX element, or null if routes are not configured.
|
|
12
11
|
*/
|
|
13
12
|
export const ToggleButtonGroup = (): JSX.Element | null => {
|
|
14
13
|
const { routes } = useAiRoutes() || {};
|
|
@@ -18,7 +17,12 @@ export const ToggleButtonGroup = (): JSX.Element | null => {
|
|
|
18
17
|
return (
|
|
19
18
|
<StyledBox>
|
|
20
19
|
<StyledToggleButtonGroup exclusive>
|
|
21
|
-
<ToggleButton
|
|
20
|
+
<ToggleButton
|
|
21
|
+
component={Link}
|
|
22
|
+
href={routes.research}
|
|
23
|
+
selected
|
|
24
|
+
value="research"
|
|
25
|
+
>
|
|
22
26
|
Research <Beta />
|
|
23
27
|
</ToggleButton>
|
|
24
28
|
<ToggleButton component={Link} href={routes.search} value="search">
|
|
@@ -12,7 +12,7 @@ const meta: Meta<typeof Assistant> = {
|
|
|
12
12
|
decorators: [
|
|
13
13
|
(Story): JSX.Element => (
|
|
14
14
|
<ConfigProvider config={INITIAL_CONFIG}>
|
|
15
|
-
<ChatProvider initialArgs={INITIAL_ARGS}>
|
|
15
|
+
<ChatProvider initialArgs={INITIAL_ARGS} url="https://api.example.com">
|
|
16
16
|
<Box
|
|
17
17
|
sx={{
|
|
18
18
|
backgroundColor: PALETTE.COMMON_WHITE,
|