Skip to content

Commit

Permalink
feat: multiple setting config component completed.
Browse files Browse the repository at this point in the history
add DistinctAttribute & SortableAttributes & SearchableAttributes & DisplayedAttributes components.
adjust config refetch interval.
add logic for empty config mutation to reset.
apply config tabs ghost styles.
  • Loading branch information
riccox committed Mar 11, 2023
1 parent f3b43a0 commit 99e21bc
Show file tree
Hide file tree
Showing 8 changed files with 401 additions and 10 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@mantine/hooks": "^6.0.0",
"@mantine/modals": "^6.0.0",
"@monaco-editor/react": "^4.4.6",
"@sira-ui/tailwind": "^0.8.0",
"@sira-ui/tailwind": "^0.9.0",
"@tabler/icons-react": "^2.8.0",
"@tanstack/react-query": "^4.26.1",
"@tanstack/react-query-devtools": "^4.26.1",
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 72 additions & 0 deletions src/components/Settings/config/detail/displayedAttributes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { useMutation, useQuery } from '@tanstack/react-query';
import clsx from 'clsx';
import { DisplayedAttributes as TDisplayedAttributes } from 'meilisearch';
import { FC, useEffect, useMemo } from 'react';
import { IndexSettingConfigComponentProps } from '../..';
import { ArrayInput } from './arrayInput';
import _ from 'lodash';

export const DisplayedAttributes: FC<IndexSettingConfigComponentProps> = ({
client,
className,
host,
toggleLoading,
}) => {
const query = useQuery({
queryKey: ['getDisplayedAttributes', host, client.uid],
refetchInterval: 4500,
async queryFn(ctx) {
return await client.getDisplayedAttributes();
},
});

const mutation = useMutation({
mutationKey: ['updateDisplayedAttributes', host, client.uid],
async mutationFn(variables: TDisplayedAttributes) {
console.debug('🚀 ~ file: displayedAttributes.tsx:19 ~ mutationFn ~ variables:', variables);
if (_.isEmpty(variables)) {
// empty to reset
return await client.resetDisplayedAttributes();
}
return await client.updateDisplayedAttributes(variables);
},
});

useEffect(() => {
const isLoading = query.isLoading || query.isFetching || mutation.isLoading;
toggleLoading(isLoading);
}, [mutation.isLoading, query.isFetching, query.isLoading, toggleLoading]);

return useMemo(
() => (
<div className={clsx(className)}>
<h2 className="font-semibold">Displayed Attributes</h2>
<span className="text-sm flex gap-2">
<p>
The attributes added to the displayedAttributes list appear in search results. displayedAttributes only
affects the search endpoints. It has no impact on the GET documents endpoint.
<br />
By default, the displayedAttributes array is equal to all fields in your dataset. This behavior is
represented by the value ["*"].
</p>
<a
className="link info text-info-800"
href="https://docs.meilisearch.com/learn/configuration/displayed_searchable_attributes.html#displayed-fields"
target={'_blank'}
rel="noreferrer"
>
Learn more
</a>
</span>
<ArrayInput
className="py-2"
defaultValue={query.data || []}
onMutation={(value) => {
mutation.mutate(value);
}}
/>
</div>
),
[className, mutation, query.data]
);
};
131 changes: 131 additions & 0 deletions src/components/Settings/config/detail/distinctAttribute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { useMutation, useQuery } from '@tanstack/react-query';
import clsx from 'clsx';
import { DistinctAttribute as TDistinctAttribute } from 'meilisearch';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { IndexSettingConfigComponentProps } from '../..';
import { IconAlertTriangleFilled } from '@tabler/icons-react';
import { Controller, useForm } from 'react-hook-form';
import _ from 'lodash';

export const DistinctAttribute: FC<IndexSettingConfigComponentProps> = ({ client, className, host, toggleLoading }) => {
const query = useQuery({
queryKey: ['getDistinctAttribute', host, client.uid],
refetchInterval: 4500,
async queryFn(ctx) {
return await client.getDistinctAttribute();
},
});

const mutation = useMutation({
mutationKey: ['updateDistinctAttribute', host, client.uid],
async mutationFn(variables: TDistinctAttribute) {
console.debug('🚀 ~ file: distinctAttributes.tsx:19 ~ mutationFn ~ variables:', variables);
if (_.isEmpty(variables)) {
// empty to reset
return await client.resetDistinctAttribute();
}
return await client.updateDistinctAttribute(variables);
},
});

useEffect(() => {
const isLoading = query.isLoading || query.isFetching || mutation.isLoading;
toggleLoading(isLoading);
}, [mutation.isLoading, query.isFetching, query.isLoading, toggleLoading]);

const [isEditing, setIsEditing] = useState<boolean>(false);
const form = useForm({ defaultValues: { input: '' } });

const onCompleteInput = useCallback(() => {
// close input
setIsEditing(false);
form.reset();
}, [form]);

const startEdit = useCallback(() => {
form.setValue('input', query.data || '');
setIsEditing(true);
}, [form, query.data]);

const onSubmit = form.handleSubmit(async ({ input }) => {
mutation.mutate(input);
onCompleteInput();
});

return useMemo(
() => (
<div className={clsx(className)}>
<h2 className="font-semibold">Distinct Attribute</h2>
<span className="text-sm flex gap-2">
<p>The distinct attribute is a field whose value will always be unique in the returned documents.</p>
<a
className="link info text-info-800"
href="https://docs.meilisearch.com/learn/configuration/distinct.html"
target={'_blank'}
rel="noreferrer"
>
Learn more
</a>
</span>
<span className="prompt warn sm">
<span className="icon">
<IconAlertTriangleFilled />
</span>
<p className="content">
Updating distinct attributes will re-index all documents in the index, which can take some time. We
recommend updating your index settings first and then adding documents as this reduces RAM consumption.
</p>
</span>

<form className={clsx('flex flex-col gap-2')}>
<Controller
name="input"
control={form.control}
render={({ field: { value, onChange } }) => (
<span
className="tooltip secondary bottom"
data-tooltip="leave empty to reset the distinct attribute of an index to its default value."
>
<input
className="input outline primary"
disabled={!isEditing}
{...{ value: (isEditing ? value : query.data) || '', onChange }}
/>
</span>
)}
/>
<div className="flex gap-2 items-center">
<button
className={clsx(isEditing && 'hidden', 'flex-1 btn outline sm info')}
onClick={(e) => {
e.preventDefault();
startEdit();
}}
>
Edit
</button>
<button
className={clsx(!isEditing && 'hidden', 'flex-1 btn outline sm success')}
onClick={(e) => {
e.preventDefault();
onSubmit();
}}
>
Save
</button>
<button
className={clsx(!isEditing && 'hidden', 'flex-1 btn outline sm bw')}
onClick={(e) => {
e.preventDefault();
onCompleteInput();
}}
>
Cancel
</button>
</div>
</form>
</div>
),
[className, form.control, isEditing, onCompleteInput, onSubmit, query.data, startEdit]
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FC, useEffect, useMemo } from 'react';
import { IndexSettingConfigComponentProps } from '../..';
import { ArrayInput } from './arrayInput';
import { IconAlertTriangleFilled } from '@tabler/icons-react';
import _ from 'lodash';

export const FilterableAttributes: FC<IndexSettingConfigComponentProps> = ({
client,
Expand All @@ -14,7 +15,7 @@ export const FilterableAttributes: FC<IndexSettingConfigComponentProps> = ({
}) => {
const query = useQuery({
queryKey: ['getFilterableAttributes', host, client.uid],
refetchInterval: 3000,
refetchInterval: 4500,
async queryFn(ctx) {
return await client.getFilterableAttributes();
},
Expand All @@ -24,6 +25,10 @@ export const FilterableAttributes: FC<IndexSettingConfigComponentProps> = ({
mutationKey: ['updateFilterableAttributes', host, client.uid],
async mutationFn(variables: TFilterableAttributes) {
console.debug('🚀 ~ file: filterableAttributes.tsx:19 ~ mutationFn ~ variables:', variables);
if (_.isEmpty(variables)) {
// empty to reset
return await client.resetFilterableAttributes();
}
return await client.updateFilterableAttributes(variables);
},
});
Expand All @@ -42,6 +47,8 @@ export const FilterableAttributes: FC<IndexSettingConfigComponentProps> = ({
<a
className="link info text-info-800"
href="https://docs.meilisearch.com/learn/advanced/filtering_and_faceted_search.html"
target={'_blank'}
rel="noreferrer"
>
Learn more
</a>
Expand Down
81 changes: 81 additions & 0 deletions src/components/Settings/config/detail/searchableAttributes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useMutation, useQuery } from '@tanstack/react-query';
import clsx from 'clsx';
import { SearchableAttributes as TSearchableAttributes } from 'meilisearch';
import { FC, useEffect, useMemo } from 'react';
import { IndexSettingConfigComponentProps } from '../..';
import { ArrayInput } from './arrayInput';
import { IconAlertTriangleFilled } from '@tabler/icons-react';
import _ from 'lodash';

export const SearchableAttributes: FC<IndexSettingConfigComponentProps> = ({
client,
className,
host,
toggleLoading,
}) => {
const query = useQuery({
queryKey: ['getSearchableAttributes', host, client.uid],
refetchInterval: 4500,
async queryFn(ctx) {
return await client.getSearchableAttributes();
},
});

const mutation = useMutation({
mutationKey: ['updateSearchableAttributes', host, client.uid],
async mutationFn(variables: TSearchableAttributes) {
console.debug('🚀 ~ file: searchableAttributes.tsx:19 ~ mutationFn ~ variables:', variables);
if (_.isEmpty(variables)) {
// empty to reset
return await client.resetSearchableAttributes();
}
return await client.updateSearchableAttributes(variables);
},
});

useEffect(() => {
const isLoading = query.isLoading || query.isFetching || mutation.isLoading;
toggleLoading(isLoading);
}, [mutation.isLoading, query.isFetching, query.isLoading, toggleLoading]);

return useMemo(
() => (
<div className={clsx(className)}>
<h2 className="font-semibold">Searchable Attributes</h2>
<span className="text-sm flex gap-2">
<p>
The values associated with attributes in the searchableAttributes list are searched for matching query
words. The order of the list also determines the attribute ranking order. <br /> By default, the
searchableAttributes array is equal to all fields in your dataset. This behavior is represented by the value
["*"].
</p>
<a
className="link info text-info-800"
href="https://docs.meilisearch.com/learn/configuration/displayed_searchable_attributes.html#searchable-fields"
target={'_blank'}
rel="noreferrer"
>
Learn more
</a>
</span>
<span className="prompt warn sm">
<span className="icon">
<IconAlertTriangleFilled />
</span>
<p className="content">
Updating searchable attributes will re-index all documents in the index, which can take some time. We
recommend updating your index settings first and then adding documents as this reduces RAM consumption.
</p>
</span>
<ArrayInput
className="py-2"
defaultValue={query.data || []}
onMutation={(value) => {
mutation.mutate(value);
}}
/>
</div>
),
[className, mutation, query.data]
);
};
Loading

0 comments on commit 99e21bc

Please sign in to comment.