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

Datagraph-search-filters #295

Merged
merged 6 commits into from
Nov 12, 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
12 changes: 11 additions & 1 deletion api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1699,7 +1699,7 @@ paths:
description: Query and search content.
tags: [datagraph]
parameters:
- $ref: "#/components/parameters/SearchQuery"
- $ref: "#/components/parameters/RequiredSearchQuery"
- $ref: "#/components/parameters/DatagraphKindQuery"
- $ref: "#/components/parameters/PaginationQuery"
responses:
Expand Down Expand Up @@ -1997,6 +1997,16 @@ components:
type: string
minLength: 0

RequiredSearchQuery:
description: Search query string.
name: q
in: query
required: true
allowEmptyValue: true
schema:
type: string
minLength: 0

DatagraphKindQuery:
description: Datagraph item kind query.
name: kind
Expand Down
9 changes: 7 additions & 2 deletions app/services/search/simplesearch/simple_searcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ func NewParallelSearcher(
) *ParallelSearcher {
return &ParallelSearcher{
searchers: map[datagraph.Kind]searcher.SingleKindSearcher{
datagraph.KindPost: &postSearcher{post_searcher},
datagraph.KindNode: &nodeSearcher{node_searcher},
datagraph.KindThread: &postSearcher{post_searcher},
datagraph.KindNode: &nodeSearcher{node_searcher},
},
}
}
Expand All @@ -53,6 +53,11 @@ func (s *ParallelSearcher) Search(ctx context.Context, q string, p pagination.Pa
searchers = lo.Values(s.searchers)
}

if len(searchers) == 0 {
results := pagination.NewPageResult(p, 0, []datagraph.Item{})
return &results, nil
}

// Earch searcher receives a smaller page size
subsearchPageSize := uint(p.Size() / len(searchers))
subsearchParams := pagination.NewPageParams(uint(p.PageOneIndexed()), subsearchPageSize)
Expand Down
6 changes: 1 addition & 5 deletions app/transports/http/bindings/datagraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ func NewDatagraph(
const datagraphSearchPageSize = 50

func (d Datagraph) DatagraphSearch(ctx context.Context, request openapi.DatagraphSearchRequestObject) (openapi.DatagraphSearchResponseObject, error) {
if request.Params.Q == nil {
return nil, fault.New("missing query")
}

pp := deserialisePageParams(request.Params.Page, datagraphSearchPageSize)

kindFilter, err := opt.MapErr(opt.NewPtr(request.Params.Kind), deserialiseDatagraphKindList)
Expand All @@ -49,7 +45,7 @@ func (d Datagraph) DatagraphSearch(ctx context.Context, request openapi.Datagrap
Kinds: kindFilter,
}

r, err := d.searcher.Search(ctx, *request.Params.Q, pp, opts)
r, err := d.searcher.Search(ctx, request.Params.Q, pp, opts)
if err != nil {
return nil, fault.Wrap(err, fctx.With(ctx))
}
Expand Down
726 changes: 363 additions & 363 deletions app/transports/http/openapi/server_gen.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion tests/semdex/semdex_weaviate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func TestSemdexWeaviate(t *testing.T) {
query := "outage"

search1, err := cl.DatagraphSearchWithResponse(ctx, &openapi.DatagraphSearchParams{
Q: &query,
Q: query,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Test coverage needed for the new search filters

The test is not verifying the new kind parameter functionality mentioned in the PR changes. Consider adding test cases that verify search results with different kind values to ensure the filter works correctly.

Here's a suggested improvement:

 search1, err := cl.DatagraphSearchWithResponse(ctx, &openapi.DatagraphSearchParams{
-				Q: query,
+				Q:    query,
+				Kind: openapi.THREAD,
 			}, e2e.WithSession(ctx, cj))

Also add a test case for searching without the kind parameter to verify backward compatibility.

Committable suggestion skipped: line range outside the PR's diff.

}, e2e.WithSession(ctx, cj))
r.NoError(err)
r.Equal(http.StatusOK, search1.StatusCode())
Expand Down
4 changes: 4 additions & 0 deletions web/panda.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { richCard } from "@/recipes/rich-card";
import { select } from "@/recipes/select";
import { table } from "@/recipes/table";
import { tagsInput } from "@/recipes/tags-input";
import { toggleGroup } from "@/recipes/toggle-group";
import { tooltip } from "@/recipes/tooltip";
import { treeView } from "@/recipes/tree-view";
import { typographyHeading } from "@/recipes/typography-heading";

Expand Down Expand Up @@ -295,6 +297,8 @@ export default defineConfig({
table: table,
tagsInput: tagsInput,
treeView: treeView,
toggleGroup: toggleGroup,
tooltip: tooltip,
},
semanticTokens,
tokens: defineTokens({
Expand Down
6 changes: 3 additions & 3 deletions web/src/api/openapi-client/datagraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ import type {
/**
* Query and search content.
*/
export const datagraphSearch = (params?: DatagraphSearchParams) => {
export const datagraphSearch = (params: DatagraphSearchParams) => {
return fetcher<DatagraphSearchOKResponse>({
url: `/datagraph`,
method: "GET",
params,
});
};

export const getDatagraphSearchKey = (params?: DatagraphSearchParams) =>
export const getDatagraphSearchKey = (params: DatagraphSearchParams) =>
[`/datagraph`, ...(params ? [params] : [])] as const;

export type DatagraphSearchQueryResult = NonNullable<
Expand All @@ -47,7 +47,7 @@ export const useDatagraphSearch = <
| NotFoundResponse
| InternalServerErrorResponse,
>(
params?: DatagraphSearchParams,
params: DatagraphSearchParams,
options?: {
swr?: SWRConfiguration<
Awaited<ReturnType<typeof datagraphSearch>>,
Expand Down
4 changes: 2 additions & 2 deletions web/src/api/openapi-schema/datagraphSearchParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ The Storyden API does not adhere to semantic versioning but instead applies a ro
*/
import type { DatagraphKindQueryParameter } from "./datagraphKindQueryParameter";
import type { PaginationQueryParameter } from "./paginationQueryParameter";
import type { SearchQueryParameter } from "./searchQueryParameter";
import type { RequiredSearchQueryParameter } from "./requiredSearchQueryParameter";

export type DatagraphSearchParams = {
/**
* Search query string.
*/
q?: SearchQueryParameter;
q: RequiredSearchQueryParameter;
/**
* Datagraph item kind query.
*/
Expand Down
1 change: 1 addition & 0 deletions web/src/api/openapi-schema/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ export * from "./replyInitialProps";
export * from "./replyList";
export * from "./replyProps";
export * from "./replyStatus";
export * from "./requiredSearchQueryParameter";
export * from "./residentKeyRequirement";
export * from "./role";
export * from "./roleCreateBody";
Expand Down
14 changes: 14 additions & 0 deletions web/src/api/openapi-schema/requiredSearchQueryParameter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Generated by orval v7.2.0 🍺
* Do not edit manually.
* storyden
* Storyden social API for building community driven platforms.
The Storyden API does not adhere to semantic versioning but instead applies a rolling strategy with deprecations and minimal breaking changes. This has been done mainly for a simpler development process and it may be changed to a more fixed versioning strategy in the future. Ultimately, the primary way Storyden tracks versions is dates, there are no set release tags currently.
* OpenAPI spec version: rolling
*/

/**
* Search query string.
*/
export type RequiredSearchQueryParameter = string;
4 changes: 2 additions & 2 deletions web/src/api/openapi-server/datagraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type datagraphSearchResponse = {
status: number;
};

export const getDatagraphSearchUrl = (params?: DatagraphSearchParams) => {
export const getDatagraphSearchUrl = (params: DatagraphSearchParams) => {
const normalizedParams = new URLSearchParams();

Object.entries(params || {}).forEach(([key, value]) => {
Expand All @@ -45,7 +45,7 @@ export const getDatagraphSearchUrl = (params?: DatagraphSearchParams) => {
};

export const datagraphSearch = async (
params?: DatagraphSearchParams,
params: DatagraphSearchParams,
options?: RequestInit,
): Promise<datagraphSearchResponse> => {
return fetcher<Promise<datagraphSearchResponse>>(
Expand Down
36 changes: 24 additions & 12 deletions web/src/app/(dashboard)/search/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
import { z } from "zod";

import { EmptyState } from "src/components/site/EmptyState";
import { SearchScreen } from "src/screens/search/SearchScreen";

import { datagraphSearch } from "@/api/openapi-server/datagraph";
import { UnreadyBanner } from "@/components/site/Unready";
import { DatagraphKindSchema } from "@/lib/datagraph/schema";

type Props = {
searchParams: Promise<Query>;
};

export const dynamic = "force-dynamic";

const QuerySchema = z.object({
q: z.string().optional(),
page: z
.string()
.transform((v) => parseInt(v, 10))
.optional(),
kind: z
.preprocess((arg: unknown) => {
if (typeof arg === "string") {
return [arg];
}

return arg;
}, z.array(DatagraphKindSchema))
.optional(),
});

type Query = z.infer<typeof QuerySchema>;
Expand All @@ -26,20 +37,21 @@ export default async function Page(props: Props) {

const params = QuerySchema.parse(searchParams);

if (!params.q) {
return (
<EmptyState>
<p>Search anything.</p>
</EmptyState>
);
}

const { data } = await datagraphSearch({ q: params.q });
const { data } = params.q
? await datagraphSearch({
q: params.q,
page: params.page?.toString(),
kind: params.kind,
})
: {
data: undefined,
};

return (
<SearchScreen
query={params.q}
page={params.page ?? 1}
initialQuery={params.q ?? ""}
initialPage={params.page ?? 1}
initialKind={params.kind ?? []}
initialResults={data}
/>
);
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/search/Search/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function Search(props: Props) {
<styled.form
display="flex"
w="full"
onSubmit={handlers.handleSearch}
// onSubmit={handlers.handleSearch}
action="/search"
>
<Input
Expand Down
33 changes: 33 additions & 0 deletions web/src/components/site/Navigation/Anchors/Search.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { SearchIcon } from "@/components/ui/icons/Search";
import { LinkButtonStyleProps } from "@/components/ui/link-button";

import { Anchor, AnchorProps, MenuItem } from "./Anchor";

export const SearchID = "search";
export const SearchRoute = "/search";
export const SearchLabel = "Search";

type Props = AnchorProps & LinkButtonStyleProps;

export function SearchAnchor(props: Props) {
return (
<Anchor
id={SearchID}
route={SearchRoute}
label={SearchLabel}
icon={<SearchIcon />}
{...props}
/>
);
}

export function SearchMenuItem() {
return (
<MenuItem
id={SearchID}
route={SearchRoute}
label={SearchLabel}
icon={<SearchIcon />}
/>
);
}
5 changes: 2 additions & 3 deletions web/src/components/site/Navigation/DesktopCommandBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import { cx } from "@/styled-system/css";
import { HStack } from "@/styled-system/jsx";
import { Floating } from "@/styled-system/patterns";

import { Search } from "../../search/Search/Search";

import styles from "./navigation.module.css";

import { SearchAnchor } from "./Anchors/Search";
import { MemberActions } from "./MemberActions";
import { SidebarToggle } from "./NavigationPane/SidebarToggle";
import { getServerSidebarState } from "./NavigationPane/server";
Expand All @@ -29,7 +28,7 @@ export async function DesktopCommandBar() {
>
<HStack className={styles["topbar-left"]}>
<SidebarToggle initialValue={initialSidebarState} />
<Search />
<SearchAnchor />
</HStack>

<HStack className={styles["topbar-middle"]} justify="space-around">
Expand Down
77 changes: 77 additions & 0 deletions web/src/components/ui/form/DatagraphKindFilterField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Portal, ToggleGroupValueChangeDetails } from "@ark-ui/react";
import { JSX } from "react";
import { Controller, ControllerProps, FieldValues } from "react-hook-form";

import * as ToggleGroup from "@/components/ui/toggle-group";
import * as Tooltip from "@/components/ui/tooltip";
import { HStack } from "@/styled-system/jsx";

type CollectionItem = {
label: string;
icon: JSX.Element;
description: string;
value: string;
};

type Props<T extends FieldValues> = Omit<ControllerProps<T>, "render"> & {
items: CollectionItem[];
};

export function DatagraphKindFilterField<T extends FieldValues>({
items,
...props
}: Props<T>) {
return (
<Controller<T>
{...props}
render={({ formState, field }) => {
function handleChangeFilter({ value }: ToggleGroupValueChangeDetails) {
field.onChange(value);
}
Comment on lines +27 to +30
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for form state

The component should handle and display form errors to provide feedback to users.

 render={({ formState, field }) => {
+  const error = formState.errors[props.name];
   function handleChangeFilter({ value }: ToggleGroupValueChangeDetails) {
     field.onChange(value);
   }
+
+  return (
+    <div>
+      {/* Existing ToggleGroup implementation */}
+      {error && (
+        <div role="alert" style={{ color: 'red', marginTop: '4px' }}>
+          {error.message}
+        </div>
+      )}
+    </div>
+  );

Committable suggestion skipped: line range outside the PR's diff.


return (
<ToggleGroup.Root
multiple
size="xs"
onValueChange={handleChangeFilter}
defaultValue={formState.defaultValues?.[props.name]}
>
{items.map((item) => (
<ToggleGroup.Item
key={item.value}
value={item.value}
aria-label={item.description}
>
<Tooltip.Root
lazyMount
openDelay={0}
positioning={{
slide: true,
shift: -48,
placement: "right-end",
}}
>
<Tooltip.Trigger asChild>
<HStack gap="1">
{item.icon} {item.label}
</HStack>
</Tooltip.Trigger>

<Portal>
<Tooltip.Positioner>
<Tooltip.Arrow>
<Tooltip.ArrowTip />
</Tooltip.Arrow>

<Tooltip.Content>{item.description}</Tooltip.Content>
</Tooltip.Positioner>
</Portal>
</Tooltip.Root>
</ToggleGroup.Item>
))}
</ToggleGroup.Root>
);
}}
/>
);
}
Loading
Loading