import { DefaultButton, Dropdown, IDropdownOption, IDropdownStyles, IStyleFunctionOrObject, ITextFieldStyleProps, ITextFieldStyles, Label, Stack, TextField, } from "@fluentui/react"; import { FullTextIndex, FullTextPath, FullTextPolicy } from "Contracts/DataModels"; import { CollapsibleSectionComponent } from "Explorer/Controls/CollapsiblePanel/CollapsibleSectionComponent"; import * as React from "react"; import { isFullTextSearchPreviewFeaturesEnabled } from "Utils/CapabilityUtils"; export interface FullTextPoliciesComponentProps { fullTextPolicy: FullTextPolicy; onFullTextPathChange: ( fullTextPolicy: FullTextPolicy, fullTextIndexes: FullTextIndex[], validationPassed: boolean, ) => void; discardChanges?: boolean; onChangesDiscarded?: () => void; englishOnly?: boolean; } export interface FullTextPolicyData { path: string; language: string; pathError: string; } const labelStyles = { root: { fontSize: 12, color: "var(--colorNeutralForeground1)", }, }; const textFieldStyles: IStyleFunctionOrObject = { fieldGroup: { height: 27, backgroundColor: "var(--colorNeutralBackground2)", borderColor: "var(--colorNeutralStroke1)", }, field: { fontSize: 12, padding: "0 8px", color: "var(--colorNeutralForeground1)", backgroundColor: "var(--colorNeutralBackground2)", }, root: { selectors: { input: { backgroundColor: "var(--colorNeutralBackground2)", color: "var(--colorNeutralForeground1)", }, "input:hover": { backgroundColor: "var(--colorNeutralBackground2)", borderColor: "var(--colorNeutralStroke1)", }, "input:focus": { backgroundColor: "var(--colorNeutralBackground2)", borderColor: "var(--colorBrandBackground)", }, }, }, }; const dropdownStyles: Partial = { root: { width: "40%", marginTop: "10px", selectors: { "&:hover .ms-Dropdown-title": { color: "var(--colorNeutralForeground1)", backgroundColor: "var(--colorNeutralBackground2)", borderColor: "var(--colorNeutralStroke1)", }, "&:hover span.ms-Dropdown-title": { color: "var(--colorNeutralForeground1)", }, "&:focus .ms-Dropdown-title": { color: "var(--colorNeutralForeground1)", backgroundColor: "var(--colorNeutralBackground2)", }, "&:focus span.ms-Dropdown-title": { color: "var(--colorNeutralForeground1)", }, }, }, label: { color: "var(--colorNeutralForeground1)", }, dropdown: { backgroundColor: "var(--colorNeutralBackground2)", borderColor: "var(--colorNeutralStroke1)", color: "var(--colorNeutralForeground1)", }, title: { backgroundColor: "var(--colorNeutralBackground2)", color: "var(--colorNeutralForeground1)", borderColor: "var(--colorNeutralStroke1)", selectors: { "&:hover": { backgroundColor: "var(--colorNeutralBackground2)", color: "var(--colorNeutralForeground1)", }, "&:focus": { backgroundColor: "var(--colorNeutralBackground2)", color: "var(--colorNeutralForeground1)", }, "&:hover .ms-Dropdown-titleText": { color: "var(--colorNeutralForeground1)", }, "&:focus .ms-Dropdown-titleText": { color: "var(--colorNeutralForeground1)", }, "& .ms-Dropdown-titleText": { color: "var(--colorNeutralForeground1)", }, "&.ms-Dropdown-title--hasPlaceholder": { color: "var(--colorNeutralForeground2)", }, }, }, errorMessage: { color: "var(--colorNeutralForeground1)", }, caretDown: { color: "var(--colorNeutralForeground1)", }, callout: { backgroundColor: "var(--colorNeutralBackground2)", border: "1px solid var(--colorNeutralStroke1)", }, dropdownItems: { backgroundColor: "var(--colorNeutralBackground2)", }, dropdownItem: { backgroundColor: "transparent", color: "var(--colorNeutralForeground1)", minHeight: "36px", lineHeight: "36px", selectors: { "&:hover": { backgroundColor: "rgba(255, 255, 255, 0.1)", color: "var(--colorNeutralForeground1)", }, "&:hover .ms-Dropdown-optionText": { color: "var(--colorNeutralForeground1)", }, "&:focus": { backgroundColor: "rgba(255, 255, 255, 0.1)", color: "var(--colorNeutralForeground1)", }, "&:active": { backgroundColor: "rgba(255, 255, 255, 0.15)", color: "var(--colorNeutralForeground1)", }, "& .ms-Dropdown-optionText": { color: "var(--colorNeutralForeground1)", }, }, }, dropdownItemSelected: { backgroundColor: "rgba(255, 255, 255, 0.08)", color: "var(--colorNeutralForeground1)", minHeight: "36px", lineHeight: "36px", selectors: { "&:hover": { backgroundColor: "rgba(255, 255, 255, 0.1)", color: "var(--colorNeutralForeground1)", }, "&:hover .ms-Dropdown-optionText": { color: "var(--colorNeutralForeground1)", }, "&:focus": { backgroundColor: "rgba(255, 255, 255, 0.1)", color: "var(--colorNeutralForeground1)", }, "&:active": { backgroundColor: "rgba(255, 255, 255, 0.15)", color: "var(--colorNeutralForeground1)", }, "& .ms-Dropdown-optionText": { color: "var(--colorNeutralForeground1)", }, }, }, dropdownOptionText: { color: "var(--colorNeutralForeground1)", }, dropdownItemHeader: { color: "var(--colorNeutralForeground1)", }, }; export const FullTextPoliciesComponent: React.FunctionComponent = ({ fullTextPolicy, onFullTextPathChange, discardChanges, onChangesDiscarded, englishOnly, }): JSX.Element => { const getFullTextPathError = (path: string, index?: number): string => { let error = ""; if (!path) { error = "Full text path should not be empty"; } if ( index >= 0 && fullTextPathData?.find( (fullTextPath: FullTextPolicyData, dataIndex: number) => dataIndex !== index && fullTextPath.path === path, ) ) { error = "Full text path is already defined"; } return error; }; const initializeData = (fullTextPolicy: FullTextPolicy): FullTextPolicyData[] => { if (!fullTextPolicy) { fullTextPolicy = { defaultLanguage: getFullTextLanguageOptions()[0].key as never, fullTextPaths: [] }; } return fullTextPolicy.fullTextPaths.map((fullTextPath: FullTextPath) => ({ ...fullTextPath, pathError: getFullTextPathError(fullTextPath.path), })); }; const [fullTextPathData, setFullTextPathData] = React.useState(initializeData(fullTextPolicy)); const [defaultLanguage, setDefaultLanguage] = React.useState( fullTextPolicy ? fullTextPolicy.defaultLanguage : (getFullTextLanguageOptions()[0].key as never), ); React.useEffect(() => { propagateData(); }, [fullTextPathData, defaultLanguage]); React.useEffect(() => { if (discardChanges) { setFullTextPathData(initializeData(fullTextPolicy)); setDefaultLanguage(fullTextPolicy.defaultLanguage); onChangesDiscarded(); } }, [discardChanges]); const propagateData = () => { const newFullTextPolicy: FullTextPolicy = { defaultLanguage: defaultLanguage, fullTextPaths: fullTextPathData.map((policy: FullTextPolicyData) => ({ path: policy.path, language: policy.language, })), }; const fullTextIndexes: FullTextIndex[] = fullTextPathData.map((policy) => ({ path: policy.path, })); const validationPassed = fullTextPathData.every((policy: FullTextPolicyData) => policy.pathError === ""); onFullTextPathChange(newFullTextPolicy, fullTextIndexes, validationPassed); }; const onFullTextPathValueChange = (index: number, event: React.ChangeEvent) => { const value = event.target.value.trim(); const fullTextPaths = [...fullTextPathData]; if (!fullTextPaths[index]?.path && !value.startsWith("/")) { fullTextPaths[index].path = "/" + value; } else { fullTextPaths[index].path = value; } fullTextPaths[index].pathError = getFullTextPathError(value, index); setFullTextPathData(fullTextPaths); }; const onFullTextPathPolicyChange = (index: number, option: IDropdownOption): void => { const policies = [...fullTextPathData]; policies[index].language = option.key as never; setFullTextPathData(policies); }; const onAdd = () => { setFullTextPathData([ ...fullTextPathData, { path: "", language: defaultLanguage, pathError: getFullTextPathError(""), }, ]); }; const onDelete = (index: number) => { const policies = fullTextPathData.filter((_uniqueKey, j) => index !== j); setFullTextPathData(policies); }; return ( , option: IDropdownOption) => setDefaultLanguage(option.key as never) } > {fullTextPathData && fullTextPathData.length > 0 && fullTextPathData.map((fullTextPolicy: FullTextPolicyData, index: number) => ( onDelete(index)} > ) => onFullTextPathValueChange(index, event)} value={fullTextPolicy.path || ""} errorMessage={fullTextPolicy.pathError} /> , option: IDropdownOption) => onFullTextPathPolicyChange(index, option) } > ))} Add full text path ); }; export const getFullTextLanguageOptions = (englishOnly?: boolean): IDropdownOption[] => { const multiLanguageSupportEnabled: boolean = isFullTextSearchPreviewFeaturesEnabled() && !englishOnly; const fullTextLanguageOptions: IDropdownOption[] = [ { key: "en-US", text: "English (US)", }, ...(multiLanguageSupportEnabled ? [ { key: "fr-FR", text: "French", }, { key: "de-DE", text: "German", }, { key: "es-ES", text: "Spanish", }, ] : []), ]; return fullTextLanguageOptions; };