mirror of
https://github.com/hexastack/hexabot
synced 2024-12-02 00:54:56 +00:00
Merge pull request #369 from Hexastack/feat/nlp-select-pattern-v2
feat: new nlp pattern input
This commit is contained in:
commit
4422b07bee
@ -456,7 +456,8 @@
|
|||||||
"is_rtl": "RTL",
|
"is_rtl": "RTL",
|
||||||
"original_text": "Original Text",
|
"original_text": "Original Text",
|
||||||
"inputs": "Inputs",
|
"inputs": "Inputs",
|
||||||
"outputs": "Outputs"
|
"outputs": "Outputs",
|
||||||
|
"any": "- Any -"
|
||||||
},
|
},
|
||||||
"placeholder": {
|
"placeholder": {
|
||||||
"your_username": "Your username",
|
"your_username": "Your username",
|
||||||
|
@ -456,8 +456,9 @@
|
|||||||
"is_default": "Par Défaut",
|
"is_default": "Par Défaut",
|
||||||
"is_rtl": "RTL",
|
"is_rtl": "RTL",
|
||||||
"original_text": "Texte par défaut",
|
"original_text": "Texte par défaut",
|
||||||
"inputs": "Port d'entré",
|
"inputs": "Ports d'entrée",
|
||||||
"outputs": "Port de sorti"
|
"outputs": "Ports de sortie",
|
||||||
|
"any": "- Toutes -"
|
||||||
},
|
},
|
||||||
"placeholder": {
|
"placeholder": {
|
||||||
"your_username": "Votre nom d'utilisateur",
|
"your_username": "Votre nom d'utilisateur",
|
||||||
|
319
frontend/src/app-components/inputs/NlpPatternSelect.tsx
Normal file
319
frontend/src/app-components/inputs/NlpPatternSelect.tsx
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 Hexastack. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
|
||||||
|
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
|
||||||
|
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Cancel } from "@mui/icons-material";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Chip,
|
||||||
|
CircularProgress,
|
||||||
|
IconButton,
|
||||||
|
InputAdornment,
|
||||||
|
Skeleton,
|
||||||
|
Typography,
|
||||||
|
useTheme,
|
||||||
|
} from "@mui/material";
|
||||||
|
import Autocomplete from "@mui/material/Autocomplete";
|
||||||
|
import { forwardRef, SyntheticEvent, useRef } from "react";
|
||||||
|
|
||||||
|
import { Input } from "@/app-components/inputs/Input";
|
||||||
|
import { useFind } from "@/hooks/crud/useFind";
|
||||||
|
import { useGetFromCache } from "@/hooks/crud/useGet";
|
||||||
|
import { useSearch } from "@/hooks/useSearch";
|
||||||
|
import { useTranslate } from "@/hooks/useTranslate";
|
||||||
|
import { EntityType, Format } from "@/services/types";
|
||||||
|
import { NlpPattern } from "@/types/block.types";
|
||||||
|
import { INlpEntity } from "@/types/nlp-entity.types";
|
||||||
|
import { INlpValue } from "@/types/nlp-value.types";
|
||||||
|
|
||||||
|
type NlpPatternSelectProps = {
|
||||||
|
patterns: NlpPattern[];
|
||||||
|
onChange: (patterns: NlpPattern[]) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const NlpPatternSelect = (
|
||||||
|
{ patterns, onChange }: NlpPatternSelectProps,
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
|
const inputRef = useRef(null);
|
||||||
|
const theme = useTheme();
|
||||||
|
const { t } = useTranslate();
|
||||||
|
const { searchPayload } = useSearch<INlpEntity>({
|
||||||
|
$iLike: ["name"],
|
||||||
|
});
|
||||||
|
const { data: options, isLoading } = useFind(
|
||||||
|
{ entity: EntityType.NLP_ENTITY, format: Format.FULL },
|
||||||
|
{ hasCount: false, params: searchPayload },
|
||||||
|
);
|
||||||
|
const getNlpValueFromCache = useGetFromCache(EntityType.NLP_VALUE);
|
||||||
|
const handleNlpEntityChange = (
|
||||||
|
_event: SyntheticEvent<Element, Event>,
|
||||||
|
entities: INlpEntity[],
|
||||||
|
): void => {
|
||||||
|
const intersection = patterns.filter(({ entity: entityName }) =>
|
||||||
|
entities.find(({ name }) => name === entityName),
|
||||||
|
);
|
||||||
|
const additions = entities.filter(
|
||||||
|
({ name }) =>
|
||||||
|
!patterns.find(({ entity: entityName }) => name === entityName),
|
||||||
|
);
|
||||||
|
const newSelection = [
|
||||||
|
...intersection,
|
||||||
|
...additions.map(
|
||||||
|
({ name }) =>
|
||||||
|
({
|
||||||
|
entity: name,
|
||||||
|
match: "entity",
|
||||||
|
value: name,
|
||||||
|
} as NlpPattern),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
onChange(newSelection);
|
||||||
|
};
|
||||||
|
const handleNlpValueChange = (
|
||||||
|
{ id, name }: Pick<INlpEntity, "id" | "name">,
|
||||||
|
valueId: string,
|
||||||
|
): void => {
|
||||||
|
const newSelection = patterns.slice(0);
|
||||||
|
const update = newSelection.find(({ entity: e }) => e === name);
|
||||||
|
|
||||||
|
if (!update) {
|
||||||
|
throw new Error("Unable to find nlp entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueId === id) {
|
||||||
|
update.match = "entity";
|
||||||
|
update.value = name;
|
||||||
|
} else {
|
||||||
|
const value = getNlpValueFromCache(valueId);
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
throw new Error("Unable to find nlp value in cache");
|
||||||
|
}
|
||||||
|
update.match = "value";
|
||||||
|
update.value = value.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange(newSelection);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!options.length) {
|
||||||
|
return (
|
||||||
|
<Skeleton animation="wave" variant="rounded" width="100%" height={56} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultValue =
|
||||||
|
options.filter(({ name }) =>
|
||||||
|
patterns.find(({ entity: entityName }) => entityName === name),
|
||||||
|
) || {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Autocomplete
|
||||||
|
ref={ref}
|
||||||
|
size="medium"
|
||||||
|
disabled={options.length === 0}
|
||||||
|
value={defaultValue}
|
||||||
|
multiple={true}
|
||||||
|
options={options}
|
||||||
|
onChange={handleNlpEntityChange}
|
||||||
|
renderOption={(props, { name, doc }, { selected }) => (
|
||||||
|
<Box
|
||||||
|
component="li"
|
||||||
|
{...props}
|
||||||
|
p={2}
|
||||||
|
display="flex"
|
||||||
|
flexDirection="column"
|
||||||
|
style={{
|
||||||
|
alignItems: "start",
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: selected
|
||||||
|
? theme.palette.action.selected
|
||||||
|
: "inherit",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.action.hover,
|
||||||
|
},
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="body1" fontWeight="bold">
|
||||||
|
{name}
|
||||||
|
</Typography>
|
||||||
|
{doc && (
|
||||||
|
<Typography variant="body2" color="textSecondary">
|
||||||
|
{doc}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
getOptionLabel={({ name }) => name}
|
||||||
|
isOptionEqualToValue={(option, value) => option.id === value.id}
|
||||||
|
freeSolo={false}
|
||||||
|
loading={isLoading}
|
||||||
|
renderTags={(entities, getTagProps) => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
gap: 0.5,
|
||||||
|
mx: "0.5rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{entities.map(({ id, name, values }, index) => {
|
||||||
|
const { key, onDelete } = getTagProps({ index });
|
||||||
|
const nlpValues = values.map((vId) =>
|
||||||
|
getNlpValueFromCache(vId),
|
||||||
|
) as INlpValue[];
|
||||||
|
const selectedValue = patterns.find(
|
||||||
|
(e) => e.entity === name,
|
||||||
|
)?.value;
|
||||||
|
const { id: selectedId = id } =
|
||||||
|
nlpValues.find(({ value }) => value === selectedValue) || {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Autocomplete
|
||||||
|
size="small"
|
||||||
|
value={selectedId}
|
||||||
|
options={[id].concat(values)}
|
||||||
|
multiple={false}
|
||||||
|
key={key}
|
||||||
|
getOptionLabel={(option) => {
|
||||||
|
const nlpValueCache = getNlpValueFromCache(option);
|
||||||
|
|
||||||
|
if (nlpValueCache) {
|
||||||
|
return nlpValueCache?.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option === id) {
|
||||||
|
return t("label.any");
|
||||||
|
}
|
||||||
|
|
||||||
|
return option;
|
||||||
|
}}
|
||||||
|
freeSolo={false}
|
||||||
|
disableClearable
|
||||||
|
popupIcon={false}
|
||||||
|
onChange={(e, valueId) =>
|
||||||
|
handleNlpValueChange({ id, name }, valueId)
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
minWidth: 50,
|
||||||
|
".MuiAutocomplete-input": {
|
||||||
|
minWidth: "100px !important",
|
||||||
|
},
|
||||||
|
"& .MuiOutlinedInput-root": {
|
||||||
|
paddingRight: "2rem !important",
|
||||||
|
"&.MuiInputBase-sizeSmall": {
|
||||||
|
padding: "0 6px 0 0 !important",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
renderInput={(props) => (
|
||||||
|
<Input
|
||||||
|
{...props}
|
||||||
|
InputProps={{
|
||||||
|
...props.InputProps,
|
||||||
|
readOnly: true,
|
||||||
|
sx: {
|
||||||
|
padding: 0,
|
||||||
|
overflow: "hidden",
|
||||||
|
cursor: "pointer",
|
||||||
|
fontSize: "14px",
|
||||||
|
},
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<Chip
|
||||||
|
sx={{
|
||||||
|
p: "0 0.3rem",
|
||||||
|
border: "none",
|
||||||
|
borderRadius: 0,
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
label={name}
|
||||||
|
variant="role"
|
||||||
|
/>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
{isLoading ? (
|
||||||
|
<CircularProgress color="inherit" size={20} />
|
||||||
|
) : (
|
||||||
|
<IconButton
|
||||||
|
sx={{ p: 0, pr: "2px" }}
|
||||||
|
onClick={(e) => {
|
||||||
|
onDelete(e);
|
||||||
|
|
||||||
|
onChange(
|
||||||
|
patterns.filter((p) => p.entity !== name),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
edge="end"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<Cancel
|
||||||
|
sx={{
|
||||||
|
fontSize: "16px",
|
||||||
|
transition: ".05s",
|
||||||
|
"&:hover": {
|
||||||
|
color: theme.palette.grey[700],
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
htmlColor={theme.palette.grey[500]}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
renderInput={(props) => (
|
||||||
|
<Input
|
||||||
|
{...props}
|
||||||
|
sx={{
|
||||||
|
"& .MuiOutlinedInput-root": {
|
||||||
|
paddingRight: "6px !important",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
size="small"
|
||||||
|
label={t("label.nlp")}
|
||||||
|
InputProps={{
|
||||||
|
...props.InputProps,
|
||||||
|
inputRef,
|
||||||
|
onClick: (event) => {
|
||||||
|
if (event.target !== inputRef.current) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
endAdornment: isLoading ? (
|
||||||
|
<CircularProgress color="inherit" size={20} />
|
||||||
|
) : null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
NlpPatternSelect.displayName = "NlpPatternSelect";
|
||||||
|
|
||||||
|
export default forwardRef(NlpPatternSelect) as (
|
||||||
|
props: NlpPatternSelectProps & {
|
||||||
|
ref?: React.ForwardedRef<HTMLDivElement>;
|
||||||
|
},
|
||||||
|
) => ReturnType<typeof NlpPatternSelect>;
|
@ -35,7 +35,7 @@ import { useTranslate } from "@/hooks/useTranslate";
|
|||||||
import { EntityType } from "@/services/types";
|
import { EntityType } from "@/services/types";
|
||||||
import { OutgoingMessageFormat } from "@/types/message.types";
|
import { OutgoingMessageFormat } from "@/types/message.types";
|
||||||
|
|
||||||
import { IBlockAttributes, IBlock } from "../../types/block.types";
|
import { IBlock, IBlockAttributes } from "../../types/block.types";
|
||||||
|
|
||||||
import BlockFormProvider from "./form/BlockFormProvider";
|
import BlockFormProvider from "./form/BlockFormProvider";
|
||||||
import { MessageForm } from "./form/MessageForm";
|
import { MessageForm } from "./form/MessageForm";
|
||||||
@ -69,24 +69,31 @@ const BlockDialog: FC<BlockDialogProps> = ({
|
|||||||
toast.success(t("message.success_save"));
|
toast.success(t("message.success_save"));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const methods = useForm<IBlockAttributes>({
|
const DEFAULT_VALUES = {
|
||||||
defaultValues: {
|
name: block?.name || "",
|
||||||
name: block?.name || "",
|
patterns: block?.patterns || [],
|
||||||
patterns: block?.patterns || [],
|
trigger_labels: block?.trigger_labels || [],
|
||||||
trigger_labels: block?.trigger_labels || [],
|
trigger_channels: block?.trigger_channels || [],
|
||||||
trigger_channels: block?.trigger_channels || [],
|
options: block?.options || {
|
||||||
options: block?.options || {
|
typing: 0,
|
||||||
typing: 0,
|
content: {
|
||||||
content: {
|
display: OutgoingMessageFormat.list,
|
||||||
display: OutgoingMessageFormat.list,
|
top_element_style: "compact",
|
||||||
top_element_style: "compact",
|
limit: 2,
|
||||||
limit: 2,
|
},
|
||||||
},
|
assignTo: block?.options?.assignTo,
|
||||||
assignTo: block?.options?.assignTo,
|
fallback: block?.options?.fallback || {
|
||||||
|
active: true,
|
||||||
|
message: [],
|
||||||
|
max_attempts: 1,
|
||||||
},
|
},
|
||||||
assign_labels: block?.assign_labels || [],
|
|
||||||
message: block?.message || [""],
|
|
||||||
},
|
},
|
||||||
|
assign_labels: block?.assign_labels || [],
|
||||||
|
message: block?.message || [""],
|
||||||
|
capture_vars: block?.capture_vars || [],
|
||||||
|
} as IBlockAttributes;
|
||||||
|
const methods = useForm<IBlockAttributes>({
|
||||||
|
defaultValues: DEFAULT_VALUES,
|
||||||
});
|
});
|
||||||
const {
|
const {
|
||||||
reset,
|
reset,
|
||||||
@ -114,10 +121,8 @@ const BlockDialog: FC<BlockDialogProps> = ({
|
|||||||
}, [open, reset]);
|
}, [open, reset]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (block) {
|
if (block && open) {
|
||||||
reset({
|
reset(DEFAULT_VALUES);
|
||||||
name: block.name,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,14 @@
|
|||||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Box, Grid, MenuItem, TextFieldProps, Typography } from "@mui/material";
|
import { Grid, MenuItem, TextFieldProps } from "@mui/material";
|
||||||
import { FC, useEffect, useState } from "react";
|
import { FC, useEffect, useState } from "react";
|
||||||
import { RegisterOptions, useFormContext } from "react-hook-form";
|
import { RegisterOptions, useFormContext } from "react-hook-form";
|
||||||
|
|
||||||
import AutoCompleteEntitySelect from "@/app-components/inputs/AutoCompleteEntitySelect";
|
import AutoCompleteEntitySelect from "@/app-components/inputs/AutoCompleteEntitySelect";
|
||||||
import { Input } from "@/app-components/inputs/Input";
|
import { Input } from "@/app-components/inputs/Input";
|
||||||
|
import NlpPatternSelect from "@/app-components/inputs/NlpPatternSelect";
|
||||||
import { RegexInput } from "@/app-components/inputs/RegexInput";
|
import { RegexInput } from "@/app-components/inputs/RegexInput";
|
||||||
import { useGetFromCache } from "@/hooks/crud/useGet";
|
|
||||||
import { useTranslate } from "@/hooks/useTranslate";
|
import { useTranslate } from "@/hooks/useTranslate";
|
||||||
import { EntityType, Format } from "@/services/types";
|
import { EntityType, Format } from "@/services/types";
|
||||||
import {
|
import {
|
||||||
@ -25,8 +25,6 @@ import {
|
|||||||
PayloadPattern,
|
PayloadPattern,
|
||||||
} from "@/types/block.types";
|
} from "@/types/block.types";
|
||||||
import { IMenuItem } from "@/types/menu.types";
|
import { IMenuItem } from "@/types/menu.types";
|
||||||
import { INlpEntity } from "@/types/nlp-entity.types";
|
|
||||||
import { INlpValue } from "@/types/nlp-value.types";
|
|
||||||
|
|
||||||
import { ContentPostbackInput } from "./ContentPostbackInput";
|
import { ContentPostbackInput } from "./ContentPostbackInput";
|
||||||
import { PostbackInput } from "./PostbackInput";
|
import { PostbackInput } from "./PostbackInput";
|
||||||
@ -71,7 +69,7 @@ const PatternInput: FC<PatternInputProps> = ({
|
|||||||
register,
|
register,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useFormContext<IBlockAttributes>();
|
} = useFormContext<IBlockAttributes>();
|
||||||
const getNlpEntityFromCache = useGetFromCache(EntityType.NLP_ENTITY);
|
// const getNlpEntityFromCache = useGetFromCache(EntityType.NLP_ENTITY);
|
||||||
const [pattern, setPattern] = useState<Pattern>(value);
|
const [pattern, setPattern] = useState<Pattern>(value);
|
||||||
const [patternType, setPatternType] = useState<PatternType>(getType(value));
|
const [patternType, setPatternType] = useState<PatternType>(getType(value));
|
||||||
const types = [
|
const types = [
|
||||||
@ -147,83 +145,12 @@ const PatternInput: FC<PatternInputProps> = ({
|
|||||||
</Input>
|
</Input>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={9}>
|
<Grid item xs={9}>
|
||||||
{patternType === "nlp" ? (
|
{patternType === "nlp" && (
|
||||||
<AutoCompleteEntitySelect<INlpValue, "value">
|
<NlpPatternSelect
|
||||||
value={(pattern as NlpPattern[]).map((v) =>
|
patterns={pattern as NlpPattern[]}
|
||||||
"value" in v && v.value ? v.value : v.entity,
|
onChange={setPattern}
|
||||||
)}
|
|
||||||
searchFields={["value", "label"]}
|
|
||||||
entity={EntityType.NLP_VALUE}
|
|
||||||
format={Format.FULL}
|
|
||||||
idKey="value"
|
|
||||||
labelKey="value"
|
|
||||||
label={t("label.nlp")}
|
|
||||||
multiple={true}
|
|
||||||
onChange={(_e, data) => {
|
|
||||||
setPattern(
|
|
||||||
data.map((d) => {
|
|
||||||
const entity = getNlpEntityFromCache(d.entity) as INlpEntity;
|
|
||||||
|
|
||||||
return d.value === "any"
|
|
||||||
? {
|
|
||||||
match: "entity",
|
|
||||||
entity: entity.name,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
match: "value",
|
|
||||||
entity: entity.name,
|
|
||||||
value: d.value,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
getOptionLabel={(option) => {
|
|
||||||
const entity = getNlpEntityFromCache(option.entity) as INlpEntity;
|
|
||||||
|
|
||||||
return `${entity.name}=${option.value}`;
|
|
||||||
}}
|
|
||||||
groupBy={(option) => {
|
|
||||||
const entity = getNlpEntityFromCache(option.entity) as INlpEntity;
|
|
||||||
|
|
||||||
return entity.name;
|
|
||||||
}}
|
|
||||||
renderGroup={(params) => (
|
|
||||||
<li key={params.key}>
|
|
||||||
<Typography
|
|
||||||
component="h4"
|
|
||||||
p={2}
|
|
||||||
fontWeight={700}
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
{params.group}
|
|
||||||
</Typography>
|
|
||||||
<Box>{params.children}</Box>
|
|
||||||
</li>
|
|
||||||
)}
|
|
||||||
preprocess={(options) => {
|
|
||||||
return options.reduce((acc, curr) => {
|
|
||||||
const entity = getNlpEntityFromCache(curr.entity) as INlpEntity;
|
|
||||||
|
|
||||||
if (entity.lookups.includes("keywords")) {
|
|
||||||
const exists = acc.find(
|
|
||||||
({ value, id }) => value === "any" && id === entity.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!exists) {
|
|
||||||
acc.push({
|
|
||||||
entity: entity.id,
|
|
||||||
id: entity.id,
|
|
||||||
value: "any",
|
|
||||||
} as INlpValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
acc.push(curr);
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, [] as INlpValue[]);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
)}
|
||||||
{patternType === "menu" ? (
|
{patternType === "menu" ? (
|
||||||
<AutoCompleteEntitySelect<IMenuItem, "title", false>
|
<AutoCompleteEntitySelect<IMenuItem, "title", false>
|
||||||
value={pattern ? (pattern as PayloadPattern).value : null}
|
value={pattern ? (pattern as PayloadPattern).value : null}
|
||||||
|
@ -69,16 +69,11 @@ export interface PayloadPattern {
|
|||||||
type?: PayloadType;
|
type?: PayloadType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NlpPattern =
|
export type NlpPattern = {
|
||||||
| {
|
entity: string;
|
||||||
entity: string;
|
match: "value" | "entity";
|
||||||
match: "entity";
|
value: string;
|
||||||
}
|
};
|
||||||
| {
|
|
||||||
entity: string;
|
|
||||||
match: "value";
|
|
||||||
value: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Pattern = null | string | PayloadPattern | NlpPattern[];
|
export type Pattern = null | string | PayloadPattern | NlpPattern[];
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user