{"version":3,"sources":["datatypes/Pages.ts","datatypes/Common.ts","datatypes/Libraries.ts","datatypes/RequirementsSearch.ts","datatypes/Answers.ts","components/RequirementsSearchFilter.tsx","components/RequirementsSearch.tsx","datatypes/AnswerTypes.ts","../node_modules/babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/toConsumableArray.js","../node_modules/babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js","../node_modules/babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/iterableToArray.js","../node_modules/babel-preset-react-app/node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js","datatypes/SearchResultSorting.ts","components/DebugMode.ts","components/FulltextResultItem.tsx","components/FulltextResults.tsx","components/SectionTypeAlert.tsx","components/AnswerContent.tsx","components/RequirementsSearchResultsEmptyPageSection.tsx","components/RequirementsSearchResultsPageSection.tsx","components/RequirementsSearchKeywordResultsGroup.tsx","components/RequirementsSearchKeywordResults.tsx","pagetypes/RequirementsSearchPage.tsx","hooks/usePrevious.ts"],"names":["buildPageUrl","pageId","sanitizeId","getPage","id","locale","url","fetchServerUrl","then","response","json","page","navbarIcon","iconId","iconStringToIdConversions","transformIconLocatorStringId","catch","reason","console","log","link","faLink","question","faQuestion","industry","faIndustry","faClipboardCheck","getSectionNameForContentType","contentType","key","toLowerCase","i18n","exists","t","getTooltipForContentType","toString","getPageTitleForContentType","getContentTypeSectionIndex","getIconForContentType","iconType","IconType","FontAwesome","faTasks","faInfoCircle","faFileAlt","faBook","replace","getLibraryFilterNames","libraries","length","map","l","lib","filtersDict","LibraryFilter","libraryName","filter","join","getLibraryFilters","filters","getLibrarySortOrder","sortOrder","getLibraryFiltersDictionary","allLibrariesUnchecked","toLibraryFilterList","items","result","forEach","i","LibraryFilterGroup","selected","concat","children","c","push","libraryId","libraryNameKey","isDefault","parentGroup","this","setSelected","groupId","groupNameKey","f","suggestionsRunning","getSearchSuggestions","searchString","maxCount","a","trim","preparedSearchString","encodeURIComponent","suggestions","error","getRequirementsSearchResults","preparedLibrariesString","getStatsKey","err","results","fulltextResults","selectedLibraries","buildRequirementsSearchUrl","groupPageResults","groups","distinct","r","pages","p","reverseSortByMember","grp","summaryContentTypes","groupSummary","group","groupedCounts","ct","count","otherResults","sum","getAnswerTypePriority","answerType","getAnswer","keyword","filename","RadioButton","props","isChecked","onToggle","isEnabled","buttonGroup","className","type","value","disabled","radioGroup","checked","onChange","Checkbox","Filter","useTranslation","FilterGroup","groupName","RequirementsSearchFilter","useState","isOpen","setIsOpen","onBoxCollapseToggle","e","preventDefault","onFilterToggle","target","filterIds","setLibraries","title","onClick","icon","faMinusSquare","faPlusSquare","href","Collapse","SearchBoxStyle","noSuggestionsBox","element","noData","style","fontSize","textTransform","React","cloneElement","IsReportableSearchBox","onSubmit","suggest","ContentMarkdown","source","InputGroup","InputGroupAddon","addonType","InputGroupText","name","data","placeholder","popupSettings","height","listNoDataRender","Button","color","UncontrolledTooltip","BasicSearchBox","onClose","RequirementsSearch","language","setSearchString","lastPostedSearchString","setLastPostedSearchString","setSuggestions","autocompleteSuggest","setAutocompleteSuggest","wasLoaded","setWasLoaded","useEffect","autoFocus","document","querySelector","focus","runSearch","useCallback","str","history","nativeEvent","state","focusedItem","onLibraryChange","wasChanged","suggestion","userInput","sug","isBusy","Loading","boxStyle","is_reportable","getAnswerTypeContent","answerTypeCode","answerTypeContent","answerTypes","alertTitle","badgeTitle","description","yes","code","faCheckCircle","alertClassName","badgeClassName","no","faBan","optional","maybe","faQuestionCircle","info","_toConsumableArray","arr","Array","isArray","arrayLikeToArray","iter","Symbol","iterator","Object","from","unsupportedIterableToArray","TypeError","COMPARE_HIGHEST","sortByKeyword","sortByMember","getFirstAlphabeticalTerm","searchTerms","answer","matchingLibraries","Math","max","x","sortByLibrary","sortByAnswerType","keywords","canonical","isDebugMode","wnd","window","buildHighlightUrl","ScoreDebug","location","parseQueryString","search","score","FulltextResultContent","ContentLink","inline","highlightedTitle","highlightedContentMarkdown","FulltextOnlyHeader","hasAnswerOrPageResults","FulltextResultItems","FulltextSection","htmlId","CollapsibleSection","sectionKey","linkClassName","rowClassName","defaultCollapsed","rememberCollapsedState","sectionIcon","faBinoculars","headerTitle","tooltip","FulltextResults","SectionTypeAlert","alertTypeLower","alertType","config","role","AnswerContent","lastAnswerId","setLastAnswerId","setAnswer","sectionType","relationshipText","contentMarkdown","RequirementsSearchResultsEmptyPageSection","libraryIds","contentTypePlural","libraryIdString","Item","content","RequirementsSearchResultsPageSection","item","LibrariesList","SearchTermLink","searchTerm","prefixComma","Fragment","prepareUriString","SearchTermLinks","distinctSearchTerms","flat","Header","Answer","EmptyPageGroups","PageGroups","isOnlyAnswerGroup","indexOf","RequirementsSearchKeywordResultsGroup","showHeader","answerGrouping","RequirementsSearchKeywordResults","sortFunc","sortFuncParam","setSortFuncParam","groupedResults","HelpTooltip","placement","evt","RequirementsSearchResultGroupTableGroup","isExpanded","sanitizeHtmlId","getUniqueAnswerGroupId","NoResults","getUniqueGroupId","globalExpandedState","getGlobalExpandedState","setIsExpanded","event","setGlobalExpandedState","getCollapseIcon","colSpan","isFirst","capitalizeFirstWord","getLibrariesOrUndefined","defaultValue","undefined","getStringOrUndefined","requirementsSearchPageReducer","update","triggerUpdate","triggerUrlChange","RequirementsSearchPage","useReducer","pageModel","pageDispatch","setPageTitle","useDDHPageContext","faSearch","pathname","searchStringFromUrl","match","params","getUrlSearchTerm","_searchString","_libraries","previousLocale","ref","useRef","current","usePrevious","Results"],"mappings":"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","file":"static/js/4.d5732086.chunk.js","sourcesContent":["import { sanitizeId } from \"./Common\";\r\nimport { i18n } from \"../ddh-translations\";\r\nimport { fetchServerUrl } from \"../util\";\r\nimport { IconLocator, IconType } from \"../components/IconRenderer\";\r\nimport {\r\n faTasks,\r\n faInfoCircle,\r\n faBook,\r\n faFileAlt,\r\n faLink,\r\n faQuestion,\r\n faIndustry,\r\n faClipboardCheck,\r\n} from \"@fortawesome/free-solid-svg-icons\";\r\nimport { IconProp } from \"@fortawesome/fontawesome-svg-core\";\r\n\r\nexport function buildPageUrl(pageId: string): string {\r\n return `/page/${sanitizeId(pageId)}`;\r\n}\r\n\r\n/**\r\n * Defines the header data and content for a page in the system.\r\n */\r\nexport interface DDHPage {\r\n /** The unique content ID used to retrieve this page. */\r\n id: string;\r\n\r\n /** The title of the page. Should be displayed at the top of the page and in link text to this page. */\r\n title: string;\r\n\r\n /** The type of page. Used to style and group links to this page. */\r\n contentType: string;\r\n\r\n navbarText?: string | undefined;\r\n\r\n navbarIcon?: IconLocator | undefined;\r\n\r\n /** The content of the page in markdown. */\r\n contentMarkdown: string;\r\n\r\n keywords: string[];\r\n\r\n libraries: string[] | null;\r\n\r\n collapseSectionsByDefault: boolean;\r\n}\r\n\r\n/**\r\n * Retrieves the complete contents of the page by doing a GET request to the API and returning the\r\n * resulting JSON. Returns a promise that resolves when the request is complete.\r\n * @param id The unique page content ID to retrieve.\r\n */\r\nexport function getPage(id: string, locale: string): Promise<DDHPage | null> {\r\n var url = `/api/page/${sanitizeId(id)}?locale=${locale}`;\r\n return fetchServerUrl(url)\r\n .then((response) => response.json())\r\n .then((page) => transformIconLocatorStringId(page))\r\n .catch((reason) => {\r\n console.log(`Error retrieving page ${url}`);\r\n console.log(reason);\r\n return null;\r\n });\r\n}\r\n\r\nconst iconStringToIdConversions: { [id: string]: IconProp } = {\r\n link: faLink,\r\n question: faQuestion,\r\n industry: faIndustry,\r\n \"clipboard-check\": faClipboardCheck,\r\n};\r\n\r\nfunction transformIconLocatorStringId(page: DDHPage | null) {\r\n if (\r\n page &&\r\n page.navbarIcon &&\r\n typeof page.navbarIcon.iconId === \"string\" &&\r\n iconStringToIdConversions[page.navbarIcon.iconId]\r\n ) {\r\n page.navbarIcon.iconId =\r\n iconStringToIdConversions[page.navbarIcon.iconId];\r\n }\r\n return page;\r\n}\r\n\r\n/**\r\n * Converts a page content type ID into a friendly name to show the user.\r\n * @param contentType The ID of the content type.\r\n */\r\nexport function getSectionNameForContentType(contentType: string): string {\r\n const key = `ContentTypeSectionName_${contentType.toLowerCase()}`;\r\n if (i18n.exists(key)) {\r\n return i18n.t(key);\r\n } else {\r\n return i18n.t(`ContentTypeSectionName_(default)`);\r\n }\r\n}\r\n\r\nexport function getTooltipForContentType(contentType: string): string | null {\r\n const key = `ContentTypeTooltip_${contentType.toLowerCase()}`;\r\n if (i18n.exists(key)) {\r\n return i18n.t(key).toString();\r\n } else {\r\n return null;\r\n }\r\n}\r\n\r\nexport function getPageTitleForContentType(contentType: string): string {\r\n const key = `ContentTypePageTitle_${contentType.toLowerCase()}`;\r\n if (i18n.exists(key)) {\r\n return i18n.t(key);\r\n } else {\r\n return i18n.t(`ContentTypePageTitle_(default)`);\r\n }\r\n}\r\n\r\n/** Defines the order in which contentTypes should be displayed in results. Higher weights are displayed first. */\r\nexport function getContentTypeSectionIndex(contentType: string): number {\r\n switch (contentType.toLowerCase()) {\r\n case \"requirement\":\r\n return 1000;\r\n case \"citation\":\r\n return 999;\r\n case \"document\":\r\n return 998;\r\n default:\r\n return 0;\r\n }\r\n}\r\n\r\nexport function getIconForContentType(contentType: string) {\r\n switch (contentType) {\r\n case \"requirement\":\r\n return {\r\n iconType: IconType.FontAwesome,\r\n iconId: faTasks,\r\n };\r\n case \"guidance\":\r\n return {\r\n iconType: IconType.FontAwesome,\r\n iconId: faInfoCircle,\r\n };\r\n case \"document\":\r\n return {\r\n iconType: IconType.FontAwesome,\r\n iconId: faFileAlt,\r\n };\r\n case \"glossary\":\r\n return {\r\n iconType: IconType.FontAwesome,\r\n iconId: faBook,\r\n };\r\n default:\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Strips all characters other than a-z, A-Z, 0-9, and dashes (-) from a string.\r\n * @param id The ID to be sanitized.\r\n */\r\nexport function sanitizeId(id: string) {\r\n return id.replace(/[^a-zA-Z0-9-]/g, \"-\");\r\n}\r\n","import { TFunction } from \"i18next\";\r\n\r\n/**\r\n * Defines an item in the library filters list; either a container group of library filters, or a single library filter.\r\n */\r\nexport interface LibraryFilterItem {\r\n id: string;\r\n selected: boolean;\r\n sortOrder: number;\r\n setSelected: (selected: boolean) => void;\r\n}\r\n\r\n/**\r\n * Returns the full display names (separated by commas) for a list of library IDs.\r\n * @param libraries A list of library filter IDs.\r\n */\r\nexport function getLibraryFilterNames(\r\n libraries: string[] | null,\r\n t: TFunction\r\n) {\r\n if (libraries === null || libraries.length === 0) {\r\n return null;\r\n }\r\n\r\n return libraries\r\n .map((l) => {\r\n var lib = filtersDict[l];\r\n if (lib && lib instanceof LibraryFilter) {\r\n return lib.libraryName(t);\r\n }\r\n return null;\r\n })\r\n .filter((l) => l)\r\n .join(\", \");\r\n}\r\n\r\n/**\r\n * Returns all library filter IDs in the system.\r\n */\r\nexport function getLibraryFilterIDs() {\r\n return Object.keys(filtersDict);\r\n}\r\n\r\n/**\r\n * Returns all library filter objects in the system, as a tree.\r\n */\r\nexport function getLibraryFilters() {\r\n return filters;\r\n}\r\n\r\nexport function getLibrarySortOrder(id: string): number {\r\n return (filtersDict[id] && filtersDict[id].sortOrder) || 0;\r\n}\r\n\r\n/**\r\n * Returns a flattened dictionary of all library filter objects in the system, which\r\n * can be used to convert a library filter ID into a library filter object.\r\n */\r\nexport function getLibraryFiltersDictionary() {\r\n return filtersDict;\r\n}\r\n\r\nexport function allLibrariesUnchecked() {\r\n return toLibraryFilterList(filters).length === 0;\r\n}\r\n\r\n/**\r\n * Returns a list of the IDs of all checked LibraryFilter objects in the given set of LibraryFilterItems.\r\n * @param items A list of library filter objects representing both filters and container groups\r\n */\r\nexport function toLibraryFilterList(items: LibraryFilterItem[]): string[] {\r\n var result: string[] = [];\r\n\r\n items.forEach((i) => {\r\n if (i instanceof LibraryFilterGroup) {\r\n if (i.selected) {\r\n result = result.concat(\r\n i.children.filter((c) => c.selected).map((c) => c.id)\r\n );\r\n }\r\n } else if (i instanceof LibraryFilter) {\r\n if (i.selected) {\r\n result.push(i.id);\r\n }\r\n }\r\n });\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Represents a single library filter in the system.\r\n *\r\n * If contained in a LibraryFilterGroup, it is mutually exclusive with other items in the group.\r\n */\r\nexport class LibraryFilter implements LibraryFilterItem {\r\n /**\r\n * The library filter ID. Used to keep track of which library filters are selected\r\n * by the user and tagged to specific pages and answers.\r\n */\r\n id: string;\r\n // libraryName: string;\r\n libraryNameKey: string;\r\n selected: boolean;\r\n sortOrder: number;\r\n parentGroup: LibraryFilterGroup | null;\r\n\r\n constructor(\r\n libraryId: string,\r\n libraryNameKey: string,\r\n sortOrder: number,\r\n isDefault: boolean\r\n ) {\r\n this.id = libraryId;\r\n this.libraryNameKey = libraryNameKey;\r\n this.selected = isDefault;\r\n this.parentGroup = null;\r\n this.sortOrder = sortOrder;\r\n }\r\n\r\n libraryName(t: TFunction) {\r\n return t(this.libraryNameKey);\r\n }\r\n\r\n setSelected(selected: boolean) {\r\n this.selected = selected;\r\n\r\n if (selected && this.parentGroup) {\r\n this.parentGroup.children\r\n .filter((c) => c.id !== this.id)\r\n .forEach((c) => c.setSelected(false));\r\n }\r\n }\r\n}\r\n\r\nexport class LibraryFilterGroup implements LibraryFilterItem {\r\n id: string;\r\n // groupName: string;\r\n groupNameKey: string;\r\n selected: boolean;\r\n sortOrder: number;\r\n children: LibraryFilter[];\r\n\r\n constructor(\r\n groupId: string,\r\n groupNameKey: string,\r\n isDefault: boolean,\r\n children: LibraryFilter[]\r\n ) {\r\n this.id = groupId;\r\n this.groupNameKey = groupNameKey;\r\n this.selected = isDefault;\r\n this.children = children;\r\n this.sortOrder = 0;\r\n\r\n this.children.forEach((c) => (c.parentGroup = this));\r\n }\r\n\r\n groupName(t: TFunction) {\r\n return t(this.groupNameKey);\r\n }\r\n\r\n setSelected(selected: boolean) {\r\n this.selected = selected;\r\n }\r\n}\r\n\r\nvar filters: LibraryFilterItem[] = [\r\n new LibraryFilterGroup(\"csa-group\", \"CSAFull\", true, [\r\n new LibraryFilter(\"csa\", \"CSAOnly\", 30, true),\r\n new LibraryFilter(\"msqp\", \"CSAWithMSQP\", 20, false),\r\n ]),\r\n new LibraryFilter(\"ap\", \"AdditionalProtocol\", 10, true),\r\n];\r\n\r\nvar filtersDict: { [id: string]: LibraryFilterItem } = {};\r\nfilters.forEach((f) => {\r\n filtersDict[f.id] = f;\r\n if (f instanceof LibraryFilterGroup) {\r\n f.children.forEach((c) => (filtersDict[c.id] = c));\r\n }\r\n});\r\n","import { TFunction } from \"i18next\";\r\nimport {\r\n distinct,\r\n fetchServerUrl,\r\n getStatsKey,\r\n reverseSortByMember,\r\n sum,\r\n} from \"../util\";\r\nimport { getContentTypeSectionIndex } from \"./Pages\";\r\n\r\nconst minSuggestionLength: number = 3;\r\nvar suggestionsRunning: boolean = false;\r\nexport async function getSearchSuggestions(\r\n searchString: string | null,\r\n locale: string,\r\n maxCount: number\r\n): Promise<string[]> {\r\n if (\r\n !searchString ||\r\n searchString.trim().length < minSuggestionLength ||\r\n suggestionsRunning\r\n )\r\n return [\"\"];\r\n\r\n var preparedSearchString = encodeURIComponent(searchString);\r\n suggestionsRunning = true;\r\n\r\n try {\r\n var response = await fetchServerUrl(\r\n `/api/suggestions/${preparedSearchString}?maxCount=${encodeURIComponent(\r\n maxCount\r\n )}&locale=${locale}`\r\n );\r\n suggestionsRunning = false;\r\n var json = await response.json();\r\n return json.suggestions;\r\n } catch (err) {\r\n console.error(err);\r\n return [\"\"];\r\n }\r\n}\r\n\r\nexport interface DDHRequirementsSearchResult {\r\n results: DDHAnswerGrouping[];\r\n fulltextResults: DDHFulltextResult[];\r\n selectedLibraries: string[] | null;\r\n}\r\n\r\nexport interface DDHFulltextResult {\r\n id: string;\r\n objectType: string;\r\n url: string | null;\r\n score: number;\r\n contentType: string;\r\n highlightedTitle: string;\r\n highlightedContentMarkdown: string;\r\n}\r\n\r\nexport interface DDHAnswerGrouping {\r\n answer: DDHAnswerSearchResult | null;\r\n searchTerms: DDHKeywordGrouping[];\r\n matchingLibraries: string[] | null;\r\n pages: DDHPageSearchResult[];\r\n}\r\n\r\nexport interface DDHPageSearchResult {\r\n id: string;\r\n searchTerms: DDHKeywordGrouping[];\r\n libraries: string[] | null;\r\n counts: number;\r\n title: string;\r\n contentType: string;\r\n}\r\n\r\nexport interface DDHPageResultsGrouping {\r\n contentType: string;\r\n pages: DDHPageSearchResult[];\r\n}\r\n\r\nexport interface DDHKeywordGrouping {\r\n canonical: string;\r\n searchTerms: string[];\r\n}\r\n\r\n/**\r\n * Defines a mapping between a search keyword and a colloquial answer, as returned from a search.\r\n */\r\nexport interface DDHAnswerSearchResult {\r\n id: string;\r\n answerType: string;\r\n searchTerms: DDHKeywordGrouping[];\r\n libraries: string[] | null;\r\n relationshipText: string;\r\n contentMarkdown: string;\r\n}\r\n\r\n/**\r\n * Returns results for a requirements search.\r\n * @param searchString The search string input by the user.\r\n */\r\nexport function getRequirementsSearchResults(\r\n searchString: string,\r\n locale: string,\r\n libraries: string[] | null\r\n): Promise<DDHRequirementsSearchResult> {\r\n if (libraries && libraries.length === 0) libraries = null;\r\n\r\n console.log(\r\n `Running requirements search for ${searchString} in libraries ${\r\n (libraries && libraries.join(\", \")) || \"(null)\"\r\n }`\r\n );\r\n\r\n var preparedSearchString = encodeURIComponent(searchString);\r\n var preparedLibrariesString = libraries\r\n ? `libraries=${libraries.map((l) => encodeURIComponent(l)).join(\",\")}&`\r\n : \"\";\r\n\r\n return fetchServerUrl(\r\n `/api/search/${preparedSearchString}?${preparedLibrariesString}statsKey=${encodeURIComponent(\r\n getStatsKey()\r\n )}&locale=${locale}`\r\n )\r\n .then((response: any) => response.json())\r\n .catch((err) => {\r\n console.error(err);\r\n return {\r\n results: [],\r\n fulltextResults: [],\r\n selectedLibraries: null,\r\n };\r\n });\r\n}\r\n\r\nexport function buildRequirementsSearchUrl(\r\n searchString: string | null\r\n): string {\r\n return `/requirements-search/${\r\n searchString == null ? \"\" : encodeURIComponent(searchString)\r\n }`;\r\n}\r\n\r\nexport function groupPageResults(results: DDHPageSearchResult[]) {\r\n var groups: DDHPageResultsGrouping[] = distinct(\r\n results.map((r) => r.contentType)\r\n ).map((contentType) => {\r\n var pages = results.filter((p) => p.contentType === contentType);\r\n return {\r\n contentType: contentType,\r\n pages: pages,\r\n };\r\n });\r\n\r\n reverseSortByMember(groups, (grp: DDHPageResultsGrouping) =>\r\n getContentTypeSectionIndex(grp.contentType)\r\n );\r\n return groups;\r\n}\r\n\r\nconst summaryContentTypes = [\"requirement\", \"guidance\", \"glossary\", \"document\"];\r\nexport function groupSummary(t: TFunction, group: DDHAnswerGrouping): string[] {\r\n var results: string[] = [];\r\n\r\n const groupedCounts = summaryContentTypes.map(\r\n (ct) => group.pages.filter((p) => p.contentType === ct).length\r\n );\r\n\r\n for (var i = 0; i < groupedCounts.length; i++) {\r\n const count = groupedCounts[i];\r\n if (count > 0) {\r\n results.push(\r\n `${count} ${t(\r\n `SearchResultSummary_${summaryContentTypes[i]}${\r\n count === 1 ? \"\" : \"s\"\r\n }`\r\n )}`\r\n );\r\n }\r\n }\r\n\r\n const otherResults = group.pages.length - sum(groupedCounts);\r\n if (otherResults > 0) {\r\n results.push(\r\n `${otherResults} ${t(\r\n `SearchResultSummary_(${\r\n group.pages.length === otherResults ? \"keyword\" : \"other\"\r\n }${otherResults === 1 ? \"\" : \"s\"})`\r\n )}`\r\n );\r\n }\r\n\r\n if (results.length === 0) {\r\n results.push(t(\"SearchResultSummary_(none)\"));\r\n }\r\n\r\n return results;\r\n}\r\n","import { fetchServerUrl } from \"../util\";\r\nimport { sanitizeId } from \"./Common\";\r\n\r\n/**\r\n * Defines the full metadata and content associated with colloquial answer.\r\n */\r\nexport interface DDHAnswerContent {\r\n /** The colloquial answer's unique ID, used to retrieve it in the system. */\r\n id: string;\r\n\r\n /**\r\n * The primary search term that this answer is associated with.\r\n */\r\n primarySearchTerm: string;\r\n\r\n /**\r\n * A description of the answer. Used only when displaying the answer in full-text search results.\r\n */\r\n description: string;\r\n\r\n /**\r\n * The type of answer: \"yes,\" \"no,\" \"maybe,\" or empty.\r\n */\r\n answerType: string | null;\r\n\r\n /**\r\n * The libraries this answer is associated with. If null, this answer matches any library filter.\r\n */\r\n libraries: string[] | null;\r\n\r\n /** The content that will be shown as part of this answer, in markdown. */\r\n contentMarkdown: string;\r\n\r\n /**\r\n * The search term that triggered this answer.\r\n */\r\n searchTerm: string | null;\r\n}\r\n\r\nexport function getAnswerTypePriority(answerType: string | null) {\r\n if (!answerType) return -1;\r\n\r\n switch (answerType.toLowerCase()) {\r\n case \"yes\":\r\n return 30;\r\n case \"maybe\":\r\n return 20;\r\n case \"no\":\r\n return 10;\r\n default:\r\n return 0;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the full answer object from the web server.\r\n *\r\n * Currently, the full answer object is stored as a JSON file: /data/answer/answerId.json\r\n * @param id The colloquial answer ID.\r\n * @param keyword The user's actual keyword that triggered this colloquial answer.\r\n */\r\nexport function getAnswer(\r\n id: string,\r\n locale: string,\r\n keyword: string | null\r\n): Promise<DDHAnswerContent | null> {\r\n var filename = `/api/answer/${sanitizeId(id)}?locale=${locale}`;\r\n return fetchServerUrl(filename)\r\n .then((response) => response.json())\r\n .catch((reason) => {\r\n console.log(`Error retrieving answer ${filename}`);\r\n console.log(reason);\r\n return null;\r\n });\r\n}\r\n","import React, { useState } from \"react\";\r\nimport {\r\n getLibraryFilters,\r\n LibraryFilter,\r\n getLibraryFiltersDictionary,\r\n toLibraryFilterList,\r\n LibraryFilterGroup,\r\n allLibrariesUnchecked,\r\n} from \"../datatypes/Libraries\";\r\nimport { Collapse } from \"reactstrap\";\r\nimport { faPlusSquare, faMinusSquare } from \"@fortawesome/free-solid-svg-icons\";\r\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\r\nimport { useTranslation } from \"react-i18next\";\r\n\r\ninterface RequirementsSearchFilterProps {\r\n setLibraries: (libraries: string[] | null) => void;\r\n}\r\n\r\nfunction RadioButton(props: {\r\n libraryId: string;\r\n libraryName: string;\r\n isChecked: boolean;\r\n onToggle: any;\r\n isEnabled: boolean;\r\n buttonGroup: string;\r\n}) {\r\n const {\r\n libraryId,\r\n libraryName,\r\n isChecked,\r\n onToggle,\r\n isEnabled,\r\n buttonGroup,\r\n } = props;\r\n\r\n return (\r\n <div className=\"form-check\" key={libraryId}>\r\n <label className=\"form-check-label\">\r\n <input\r\n type=\"radio\"\r\n className=\"form-check-input\"\r\n value={libraryId}\r\n disabled={!isEnabled}\r\n radioGroup={buttonGroup}\r\n checked={isChecked}\r\n onChange={onToggle}\r\n />{\" \"}\r\n {libraryName}\r\n </label>\r\n </div>\r\n );\r\n}\r\n\r\nfunction Checkbox(props: {\r\n libraryId: string;\r\n libraryName: string;\r\n isChecked: boolean;\r\n onToggle: any;\r\n}) {\r\n const { libraryId, libraryName, isChecked, onToggle } = props;\r\n\r\n return (\r\n <div className=\"form-check\" key={libraryId}>\r\n <label className=\"form-check-label\">\r\n <input\r\n type=\"checkbox\"\r\n className=\"form-check-input\"\r\n value={libraryId}\r\n checked={isChecked}\r\n onChange={onToggle}\r\n />{\" \"}\r\n {libraryName}\r\n </label>\r\n </div>\r\n );\r\n}\r\n\r\nfunction Filter(props: { filter: LibraryFilter; onToggle: any }) {\r\n const { filter, onToggle } = props;\r\n const { t } = useTranslation();\r\n return (\r\n <Checkbox\r\n libraryId={filter.id}\r\n libraryName={filter.libraryName(t)}\r\n isChecked={filter.selected}\r\n onToggle={onToggle}\r\n />\r\n );\r\n}\r\n\r\nfunction FilterGroup(props: { grp: LibraryFilterGroup; onToggle: any }) {\r\n const { grp, onToggle } = props;\r\n const { t } = useTranslation();\r\n\r\n return (\r\n <div key={grp.id}>\r\n <Checkbox\r\n libraryId={grp.id}\r\n libraryName={grp.groupName(t)}\r\n isChecked={grp.selected}\r\n onToggle={onToggle}\r\n />\r\n <div className=\"pl-4\">\r\n {grp.children.map((c) => (\r\n <RadioButton\r\n key={c.libraryName(t)}\r\n libraryId={c.id}\r\n libraryName={c.libraryName(t)}\r\n isChecked={c.selected}\r\n onToggle={onToggle}\r\n isEnabled={grp.selected}\r\n buttonGroup={grp.id}\r\n />\r\n ))}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nconst filters = getLibraryFilters();\r\nconst filtersDict = getLibraryFiltersDictionary();\r\n\r\nexport default function RequirementsSearchFilter(\r\n props: RequirementsSearchFilterProps\r\n) {\r\n const { t } = useTranslation();\r\n const [isOpen, setIsOpen] = useState<boolean>(true);\r\n\r\n const onBoxCollapseToggle = function (e: any) {\r\n setIsOpen(!isOpen);\r\n e.preventDefault();\r\n return false;\r\n };\r\n\r\n const onFilterToggle = function (e: any) {\r\n var id = e.target.value;\r\n if (filtersDict[id]) {\r\n filtersDict[id].setSelected(e.target.checked);\r\n // Don't deselect the last checkbox\r\n if (allLibrariesUnchecked()) filtersDict[id].setSelected(true);\r\n }\r\n\r\n var filterIds = toLibraryFilterList(filters);\r\n props.setLibraries(filterIds.length > 0 ? filterIds : null);\r\n };\r\n\r\n return (\r\n <div className=\"card filter-box mb-2\">\r\n <div className=\"card-header bg-secondary\">\r\n <button\r\n className=\"btn btn-link m-0 p-0 mr-2\"\r\n title={isOpen ? t(\"CollapseFilters\") : t(\"ExpandFilters\")}\r\n onClick={onBoxCollapseToggle}\r\n >\r\n <FontAwesomeIcon\r\n title={\r\n isOpen ? t(\"CollapseFilters\") : t(\"ExpandFilters\")\r\n }\r\n icon={isOpen ? faMinusSquare : faPlusSquare}\r\n />\r\n </button>\r\n <a\r\n href=\"#\"\r\n title={isOpen ? \"Collapse Filters\" : \"Expand Filters\"}\r\n onClick={onBoxCollapseToggle}\r\n >\r\n {t(\"SearchFilterTitle\")}\r\n </a>\r\n </div>\r\n <Collapse isOpen={isOpen} className=\"form-group p-2 mb-0 card-body\">\r\n <small className=\"font-italic mt-2 mb-2\">\r\n {t(\"SearchFilterOneMustBeSelected\")}\r\n </small>\r\n {filters.map((f) => {\r\n if (f instanceof LibraryFilterGroup) {\r\n return (\r\n <FilterGroup\r\n key={f.groupName(t)}\r\n grp={f}\r\n onToggle={onFilterToggle}\r\n />\r\n );\r\n } else if (f instanceof LibraryFilter) {\r\n return (\r\n <Filter\r\n key={f.libraryName(t)}\r\n filter={f}\r\n onToggle={onFilterToggle}\r\n />\r\n );\r\n } else {\r\n return null;\r\n }\r\n })}\r\n </Collapse>\r\n </div>\r\n );\r\n}\r\n","import { AutoComplete } from \"@progress/kendo-react-dropdowns\";\r\nimport React, { useCallback, useEffect, useState } from \"react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport {\r\n Button,\r\n InputGroup,\r\n InputGroupAddon,\r\n InputGroupText,\r\n UncontrolledTooltip,\r\n} from \"reactstrap\";\r\nimport {\r\n buildRequirementsSearchUrl,\r\n getSearchSuggestions,\r\n} from \"../datatypes/RequirementsSearch\";\r\nimport ContentMarkdown from \"./ContentMarkdown\";\r\nimport Loading from \"./Loading\";\r\nimport RequirementsSearchFilter from \"./RequirementsSearchFilter\";\r\nimport { i18n } from \"../ddh-translations\";\r\n\r\ninterface RequirementsSearchProps {\r\n searchString: string;\r\n history: any;\r\n boxStyle?: SearchBoxStyle | null | undefined;\r\n setLibraries?:\r\n | ((searchString: string, libraries: string[] | null) => void)\r\n | undefined;\r\n autoFocus: boolean;\r\n isBusy: boolean;\r\n}\r\n\r\nexport enum SearchBoxStyle {\r\n basic,\r\n is_reportable,\r\n}\r\n\r\nfunction noSuggestionsBox(element: React.ReactElement<HTMLDivElement>) {\r\n const noData = (\r\n <h3 style={{ fontSize: \"1em\", textTransform: \"none\" }}>\r\n {i18n.t(\"NoSuggestions\")}\r\n </h3>\r\n );\r\n\r\n return React.cloneElement(element, { ...element.props }, noData);\r\n}\r\n\r\nfunction IsReportableSearchBox(props: {\r\n searchString: string;\r\n onSubmit: any;\r\n onChange: any;\r\n suggest: string;\r\n suggestions: string[];\r\n}) {\r\n const { searchString, onSubmit, onChange, suggest, suggestions } = props;\r\n const { t } = useTranslation();\r\n\r\n return (\r\n <form onSubmit={onSubmit}>\r\n <ContentMarkdown source={t(\"RequirementsSearchIntroText\")} />\r\n <div\r\n id=\"requirements-search\"\r\n className=\"d-flex flex-wrap search-controls\"\r\n >\r\n <div>\r\n <InputGroup className=\"mb-3\">\r\n <InputGroupAddon addonType=\"prepend\">\r\n <InputGroupText className=\"font-weight-bold\">\r\n {t(\"IsReportablePrefix\")}\r\n </InputGroupText>\r\n </InputGroupAddon>\r\n <AutoComplete\r\n name=\"requirements-search-input\"\r\n className=\"search-box\"\r\n data={suggestions}\r\n placeholder={t(\"SearchPlaceholder\")}\r\n value={searchString}\r\n onChange={onChange}\r\n suggest={suggest}\r\n aria-label=\"Search\"\r\n popupSettings={{ height: \"300px\" }}\r\n listNoDataRender={noSuggestionsBox}\r\n />\r\n <InputGroupAddon addonType=\"append\">\r\n <InputGroupText className=\"font-weight-bold\">\r\n {t(\"IsReportableSuffix\")}\r\n </InputGroupText>\r\n </InputGroupAddon>\r\n </InputGroup>\r\n </div>\r\n <div className=\"pl-2 pr-2\">\r\n <Button color=\"primary\" id=\"requirements-search-button\">\r\n {t(\"SearchButton\")}\r\n </Button>\r\n </div>\r\n </div>\r\n {searchString ? (\r\n <UncontrolledTooltip target=\"requirements-search\">\r\n {t(\"SearchFor\")} \"{searchString}\"\r\n </UncontrolledTooltip>\r\n ) : (\r\n <></>\r\n )}\r\n </form>\r\n );\r\n}\r\n\r\nfunction BasicSearchBox(props: {\r\n searchString: string;\r\n onSubmit: any;\r\n onChange: any;\r\n onClose: any;\r\n suggest: string;\r\n suggestions: string[];\r\n setLibraries: ((libraries: string[] | null) => void) | null;\r\n}) {\r\n const {\r\n searchString,\r\n onSubmit,\r\n onChange,\r\n onClose,\r\n suggest,\r\n suggestions,\r\n setLibraries,\r\n } = props;\r\n\r\n const { t } = useTranslation();\r\n\r\n return (\r\n <form onSubmit={onSubmit}>\r\n <ContentMarkdown source={t(\"RequirementsSearchIntroText\")} />\r\n <div\r\n id=\"requirements-search\"\r\n className=\"d-flex flex-wrap search-controls\"\r\n >\r\n <div className=\"flex-shrink-1 align-baseline\">\r\n <AutoComplete\r\n name=\"requirements-search-input\"\r\n className=\"search-box\"\r\n data={suggestions}\r\n placeholder={t(\"SearchPlaceholder\")}\r\n value={searchString}\r\n onChange={onChange}\r\n onClose={onClose}\r\n suggest={suggest}\r\n aria-label=\"Search\"\r\n popupSettings={{ height: \"300px\" }}\r\n listNoDataRender={noSuggestionsBox}\r\n />\r\n </div>\r\n <div className=\"pl-2 align-baseline\">\r\n <button\r\n className=\"btn btn-primary\"\r\n id=\"requirements-search-button\"\r\n >\r\n {t(\"SearchButton\")}\r\n </button>\r\n </div>\r\n </div>\r\n {searchString ? (\r\n <UncontrolledTooltip target=\"requirements-search\">\r\n {t(\"SearchFor\")} \"{searchString}\"\r\n </UncontrolledTooltip>\r\n ) : (\r\n <></>\r\n )}\r\n {setLibraries ? (\r\n <RequirementsSearchFilter setLibraries={setLibraries} />\r\n ) : (\r\n <></>\r\n )}\r\n </form>\r\n );\r\n}\r\n\r\nexport default function RequirementsSearch(props: RequirementsSearchProps) {\r\n const {\r\n i18n: { language: locale },\r\n } = useTranslation();\r\n const [searchString, setSearchString] = useState<string>(\r\n props.searchString\r\n );\r\n const [lastPostedSearchString, setLastPostedSearchString] =\r\n useState<string>(props.searchString);\r\n\r\n const [suggestions, setSuggestions] = useState<string[]>([]);\r\n const [autocompleteSuggest, setAutocompleteSuggest] = useState<string>(\"\");\r\n\r\n // Auto focus the search box\r\n const [wasLoaded, setWasLoaded] = useState<boolean>(false);\r\n useEffect(() => {\r\n if (!wasLoaded) {\r\n setWasLoaded(true);\r\n if (props.autoFocus) {\r\n (\r\n document.querySelector(\r\n \".search-box input\"\r\n ) as HTMLInputElement\r\n )?.focus();\r\n }\r\n }\r\n }, [wasLoaded, props.autoFocus]);\r\n\r\n useEffect(() => {\r\n // Keeps track of changes to searchString pushed down from the parent page\r\n // This allows us to change the text in the search box when navigating with back/foward in browser\r\n if (props.searchString !== lastPostedSearchString) {\r\n setLastPostedSearchString(props.searchString);\r\n setSearchString(props.searchString);\r\n }\r\n }, [lastPostedSearchString, props.searchString]);\r\n\r\n const runSearch = useCallback(\r\n (str: string) => {\r\n console.log(`RequirementsSearch component got search \"${str}\"`);\r\n props.history.push(buildRequirementsSearchUrl(str));\r\n },\r\n [props.history]\r\n );\r\n\r\n // On form submit, change the URL\r\n const onSubmit = useCallback(\r\n (e: any) => {\r\n e.preventDefault();\r\n runSearch(searchString);\r\n },\r\n [runSearch, searchString]\r\n );\r\n\r\n // On autocomplete close, trigger search depending on how it occurred\r\n const onClose = useCallback(\r\n (e: any) => {\r\n if (\r\n e.nativeEvent &&\r\n e.nativeEvent.key &&\r\n e.nativeEvent.key === \"Enter\"\r\n ) {\r\n if (\r\n e.target &&\r\n e.target.state &&\r\n e.target.state.focusedItem &&\r\n e.target.state.focusedItem !== \"\" &&\r\n e.target.state.focusedItem !== searchString\r\n ) {\r\n runSearch(e.target.state.focusedItem);\r\n } else {\r\n onSubmit(e.nativeEvent);\r\n }\r\n return;\r\n }\r\n },\r\n [onSubmit, runSearch, searchString]\r\n );\r\n\r\n // On library change, also trigger search update\r\n const onLibraryChange = useCallback(\r\n (libraries: string[] | null) => {\r\n if (props.setLibraries) props.setLibraries(searchString, libraries);\r\n },\r\n [props, searchString]\r\n );\r\n\r\n // On text box change, update the current search string\r\n const onChange = useCallback(\r\n (e: any) => {\r\n var wasChanged = e.target.value !== searchString;\r\n setSearchString(e.target.value);\r\n\r\n if (\r\n e.nativeEvent &&\r\n e.nativeEvent.key &&\r\n e.nativeEvent.key === \"Enter\"\r\n ) {\r\n return;\r\n }\r\n\r\n setAutocompleteSuggest(e.suggestion ? e.suggestion.value : \"\");\r\n if (\r\n wasChanged &&\r\n e.target.value !== null &&\r\n e.target.value.trim() !== \"\"\r\n ) {\r\n getSearchSuggestions(\r\n e.suggestion ? e.suggestion.userInput : \"\",\r\n locale,\r\n 20\r\n ).then((sug) => setSuggestions(sug));\r\n }\r\n },\r\n [locale, searchString]\r\n );\r\n\r\n if (props.isBusy) {\r\n return <Loading />;\r\n }\r\n\r\n switch (props.boxStyle) {\r\n case SearchBoxStyle.is_reportable:\r\n return (\r\n <IsReportableSearchBox\r\n searchString={searchString}\r\n onSubmit={onSubmit}\r\n onChange={onChange}\r\n suggest={autocompleteSuggest}\r\n suggestions={suggestions}\r\n />\r\n );\r\n\r\n default:\r\n return (\r\n <BasicSearchBox\r\n searchString={searchString}\r\n onSubmit={onSubmit}\r\n onChange={onChange}\r\n onClose={onClose}\r\n suggest={autocompleteSuggest}\r\n suggestions={suggestions}\r\n setLibraries={onLibraryChange}\r\n />\r\n );\r\n }\r\n}\r\n","import { IconLocator, IconType } from \"../components/IconRenderer\";\r\nimport {\r\n faCheckCircle,\r\n faQuestionCircle,\r\n} from \"@fortawesome/free-regular-svg-icons\";\r\nimport { faBan, faInfoCircle } from \"@fortawesome/free-solid-svg-icons\";\r\nimport { TFunction } from \"i18next\";\r\n\r\nexport interface AnswerTypeContent {\r\n code: string;\r\n alertTitle: string;\r\n badgeTitle: string;\r\n description: string;\r\n icon: IconLocator;\r\n alertClassName: string;\r\n badgeClassName: string;\r\n}\r\n\r\nexport function getAnswerTypeContent(answerTypeCode: string, t: TFunction) {\r\n let answerTypeContent = answerTypes[answerTypeCode] || null;\r\n if (answerTypeContent) {\r\n answerTypeContent = {\r\n ...answerTypeContent,\r\n alertTitle: t(answerTypeContent.alertTitle),\r\n badgeTitle: t(answerTypeContent.badgeTitle),\r\n description: t(answerTypeContent.description),\r\n };\r\n }\r\n return answerTypeContent;\r\n}\r\n\r\nconst answerTypes: { [id: string]: AnswerTypeContent } = {\r\n yes: {\r\n code: \"yes\",\r\n alertTitle: \"answerTypes.yes.alertTitle\",\r\n badgeTitle: \"answerTypes.yes.badgeTitle\",\r\n description: \"answerTypes.yes.description\",\r\n icon: {\r\n iconType: IconType.FontAwesome,\r\n iconId: faCheckCircle,\r\n },\r\n alertClassName: \"alert-success\",\r\n badgeClassName: \"badge-success\",\r\n },\r\n no: {\r\n code: \"no\",\r\n alertTitle: \"answerTypes.no.alertTitle\",\r\n badgeTitle: \"answerTypes.no.badgeTitle\",\r\n description: \"answerTypes.no.description\",\r\n icon: {\r\n iconType: IconType.FontAwesome,\r\n iconId: faBan,\r\n },\r\n alertClassName: \"alert-danger\",\r\n badgeClassName: \"badge-danger\",\r\n },\r\n optional: {\r\n code: \"optional\",\r\n alertTitle: \"answerTypes.optional.alertTitle\",\r\n badgeTitle: \"answerTypes.optional.badgeTitle\",\r\n description: \"answerTypes.optional.description\",\r\n icon: {\r\n iconType: IconType.FontAwesome,\r\n iconId: faBan,\r\n },\r\n alertClassName: \"alert-warning\",\r\n badgeClassName: \"badge-warning\",\r\n },\r\n maybe: {\r\n code: \"maybe\",\r\n alertTitle: \"answerTypes.maybe.alertTitle\",\r\n badgeTitle: \"answerTypes.maybe.badgeTitle\",\r\n description: \"answerTypes.maybe.description\",\r\n icon: {\r\n iconType: IconType.FontAwesome,\r\n iconId: faQuestionCircle,\r\n },\r\n alertClassName: \"alert-warning\",\r\n badgeClassName: \"badge-warning\",\r\n },\r\n \"maybe-related\": {\r\n code: \"maybe-related\",\r\n alertTitle: \"answerTypes.maybe-related.alertTitle\",\r\n badgeTitle: \"answerTypes.maybe-related.badgeTitle\",\r\n description: \"answerTypes.maybe-related.description\",\r\n icon: {\r\n iconType: IconType.FontAwesome,\r\n iconId: faQuestionCircle,\r\n },\r\n alertClassName: \"alert-warning\",\r\n badgeClassName: \"badge-warning\",\r\n },\r\n info: {\r\n code: \"info\",\r\n alertTitle: \"answerTypes.info.alertTitle\",\r\n badgeTitle: \"answerTypes.info.badgeTitle\",\r\n description: \"answerTypes.info.description\",\r\n icon: {\r\n iconType: IconType.FontAwesome,\r\n iconId: faInfoCircle,\r\n },\r\n alertClassName: \"alert-info\",\r\n badgeClassName: \"badge-info\",\r\n },\r\n};\r\n","import arrayWithoutHoles from \"@babel/runtime/helpers/esm/arrayWithoutHoles\";\nimport iterableToArray from \"@babel/runtime/helpers/esm/iterableToArray\";\nimport unsupportedIterableToArray from \"@babel/runtime/helpers/esm/unsupportedIterableToArray\";\nimport nonIterableSpread from \"@babel/runtime/helpers/esm/nonIterableSpread\";\nexport default function _toConsumableArray(arr) {\n return arrayWithoutHoles(arr) || iterableToArray(arr) || unsupportedIterableToArray(arr) || nonIterableSpread();\n}","import arrayLikeToArray from \"@babel/runtime/helpers/esm/arrayLikeToArray\";\nexport default function _arrayWithoutHoles(arr) {\n if (Array.isArray(arr)) return arrayLikeToArray(arr);\n}","export default function _iterableToArray(iter) {\n if (typeof Symbol !== \"undefined\" && Symbol.iterator in Object(iter)) return Array.from(iter);\n}","export default function _nonIterableSpread() {\n throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}","import { getLibrarySortOrder } from \"./Libraries\";\r\nimport { getAnswerTypePriority } from \"./Answers\";\r\nimport { sortByMember, reverseSortByMember } from \"../util\";\r\nimport { DDHAnswerGrouping, DDHKeywordGrouping } from \"./RequirementsSearch\";\r\n\r\n//const COMPARE_LOWEST = -99999;\r\nconst COMPARE_HIGHEST = 99999;\r\n\r\nexport function sortByParameter(\r\n groups: DDHAnswerGrouping[],\r\n sortFunc: SortFunctionParameter | null\r\n): DDHAnswerGrouping[] {\r\n return ((sortFunc && sortFunc.sortFunc) || sortByAnswerType)(groups);\r\n}\r\n\r\nexport interface SortFunctionParameter {\r\n sortFunc: ((groups: DDHAnswerGrouping[]) => DDHAnswerGrouping[]) | null;\r\n}\r\n\r\nexport function sortByKeyword(groups: DDHAnswerGrouping[]) {\r\n return sortByMember(groups, (grp) => [\r\n getFirstAlphabeticalTerm(grp.searchTerms),\r\n getAnswerTypePriority(grp.answer ? grp.answer.answerType : null),\r\n (grp.matchingLibraries &&\r\n Math.max(\r\n ...grp.matchingLibraries.map((x) => getLibrarySortOrder(x))\r\n )) ||\r\n COMPARE_HIGHEST,\r\n ]);\r\n}\r\n\r\nexport function sortByLibrary(groups: DDHAnswerGrouping[]) {\r\n return reverseSortByMember(groups, (grp) => [\r\n (grp.matchingLibraries &&\r\n Math.max(\r\n ...grp.matchingLibraries.map((x) => getLibrarySortOrder(x))\r\n )) ||\r\n COMPARE_HIGHEST,\r\n getAnswerTypePriority(grp.answer ? grp.answer.answerType : null),\r\n ]);\r\n}\r\n\r\nexport function sortByAnswerType(\r\n groups: DDHAnswerGrouping[]\r\n): DDHAnswerGrouping[] {\r\n return reverseSortByMember(groups, (grp) => [\r\n getAnswerTypePriority(grp.answer ? grp.answer.answerType : null),\r\n (grp.matchingLibraries &&\r\n Math.max(\r\n ...grp.matchingLibraries.map((x) => getLibrarySortOrder(x))\r\n )) ||\r\n COMPARE_HIGHEST,\r\n ]);\r\n}\r\n\r\nfunction getFirstAlphabeticalTerm(searchTerms: DDHKeywordGrouping[]) {\r\n var keywords = searchTerms.map((x) => x.canonical);\r\n keywords = sortByMember(keywords, (x) => x);\r\n return keywords;\r\n}\r\n","import { parseQueryString } from \"../util\";\r\n\r\nvar isDebugMode = false;\r\n\r\nconst wnd: any = window;\r\nconst debugKey = \"__DEBUG__\";\r\n\r\n/**\r\n * Returns true if \"debug\" mode is on, which allows components to behave differently.\r\n *\r\n * To turn on debug mode, set __DEBUG__ = true in the JavaScript console, or add a \"debug\" query string parameter.\r\n */\r\nexport function getDebugMode(): boolean {\r\n if (!isDebugMode) {\r\n if (\r\n wnd[debugKey] ||\r\n (wnd &&\r\n wnd.location &&\r\n parseQueryString(wnd.location.search)[\"debug\"])\r\n )\r\n isDebugMode = true;\r\n }\r\n\r\n return isDebugMode;\r\n}\r\n","import React from \"react\";\r\n\r\nimport {\r\n getPageTitleForContentType,\r\n getIconForContentType,\r\n} from \"../datatypes/Pages\";\r\nimport { getDebugMode } from \"./DebugMode\";\r\n\r\nimport ContentMarkdown from \"./ContentMarkdown\";\r\nimport { RenderIcon } from \"./IconRenderer\";\r\nimport { ContentLink } from \"./ContentLink\";\r\nimport { DDHFulltextResult } from \"../datatypes/RequirementsSearch\";\r\n\r\nexport interface FulltextResultContentProps {\r\n result: DDHFulltextResult;\r\n searchString: string;\r\n}\r\n\r\n/**\r\n * Adds the \"searchTerm\" parameter to the returned URL, which allows highlighting on content pages.\r\n * @param url\r\n * @param searchString\r\n */\r\nfunction buildHighlightUrl(url: string | null, searchString: string) {\r\n if (url === null) return \"#\";\r\n return `${url}?searchTerm=${encodeURIComponent(searchString)}`;\r\n}\r\n\r\n/**\r\n * Renders the score returned by the fulltext engine if debug mode is on.\r\n * @param result\r\n */\r\nfunction ScoreDebug({ result }: { result: DDHFulltextResult }) {\r\n if (!getDebugMode()) {\r\n return null;\r\n }\r\n return <span className=\"debug\">(score: {result.score})</span>;\r\n}\r\n\r\nexport default function FulltextResultContent(\r\n props: FulltextResultContentProps\r\n) {\r\n const { result, searchString } = props;\r\n const icon = getIconForContentType(result.contentType);\r\n\r\n return (\r\n <li className=\"fulltext-result\">\r\n <ContentLink\r\n href={buildHighlightUrl(result.url, searchString)}\r\n className=\"fulltext-header\"\r\n >\r\n {icon ? (\r\n <>\r\n <RenderIcon\r\n iconType={icon.iconType}\r\n iconId={icon.iconId}\r\n />\r\n \r\n </>\r\n ) : null}\r\n {getPageTitleForContentType(result.contentType)}\r\n : \r\n <ContentMarkdown\r\n inline={true}\r\n source={result.highlightedTitle}\r\n />\r\n </ContentLink>\r\n <ScoreDebug result={result} />\r\n <ContentMarkdown source={result.highlightedContentMarkdown} />\r\n </li>\r\n );\r\n}\r\n","import { faBinoculars } from \"@fortawesome/free-solid-svg-icons\";\r\nimport React from \"react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { sanitizeId } from \"../datatypes/Common\";\r\nimport { getTooltipForContentType } from \"../datatypes/Pages\";\r\nimport { DDHFulltextResult } from \"../datatypes/RequirementsSearch\";\r\nimport CollapsibleSection from \"./CollapsibleSection\";\r\nimport ContentMarkdown from \"./ContentMarkdown\";\r\nimport FulltextResultItem from \"./FulltextResultItem\";\r\nimport { IconType } from \"./IconRenderer\";\r\n\r\ninterface FulltextResultsProps {\r\n fulltextResults: DDHFulltextResult[];\r\n searchString: string;\r\n /**\r\n * Should be set to true if answer or page results were included; false if only full-text results were included.\r\n *\r\n * If false, expands full-text results by default.\r\n */\r\n hasAnswerOrPageResults: boolean;\r\n}\r\n\r\n/**\r\n * Renders additional descriptive text if only fulltext results were returned.\r\n * @param t\r\n * @param hasAnswerOrPageResults\r\n */\r\nfunction FulltextOnlyHeader(props: { hasAnswerOrPageResults: boolean }) {\r\n const { hasAnswerOrPageResults } = props;\r\n const { t } = useTranslation();\r\n\r\n if (!hasAnswerOrPageResults) {\r\n return (\r\n <ContentMarkdown source={t(\"FulltextSearchResultsOnlyHeader\")} />\r\n );\r\n } else {\r\n return <></>;\r\n }\r\n}\r\n\r\nfunction FulltextResultItems(props: {\r\n searchString: string;\r\n results: DDHFulltextResult[];\r\n}) {\r\n const { searchString, results } = props;\r\n console.log(`Rendering fulltext result items`);\r\n\r\n return (\r\n <ul>\r\n {results.map((r) => (\r\n <FulltextResultItem\r\n key={r.id}\r\n searchString={searchString}\r\n result={r}\r\n />\r\n ))}\r\n </ul>\r\n );\r\n}\r\n\r\nfunction FulltextSection(props: {\r\n searchString: string;\r\n isOpen: boolean;\r\n results: DDHFulltextResult[];\r\n}) {\r\n const { t } = useTranslation();\r\n const { searchString, isOpen, results } = props;\r\n\r\n var htmlId = `fulltext-${sanitizeId(searchString)}`;\r\n return (\r\n <div className=\"search-result-block\">\r\n <CollapsibleSection\r\n key={htmlId}\r\n sectionKey={htmlId}\r\n linkClassName=\"h2\"\r\n rowClassName=\"section-header\"\r\n defaultCollapsed={!isOpen}\r\n rememberCollapsedState={false}\r\n sectionIcon={{\r\n iconType: IconType.FontAwesome,\r\n iconId: faBinoculars,\r\n }}\r\n headerTitle={`${t(\r\n \"FulltextSearchResults\"\r\n )} '${searchString}' (${results.length})`}\r\n tooltip={getTooltipForContentType(\"fulltext\")}\r\n >\r\n <FulltextResultItems\r\n searchString={searchString}\r\n results={results}\r\n />\r\n </CollapsibleSection>\r\n </div>\r\n );\r\n}\r\n\r\n// TODO: If we always collapse results, remove hasAnswerOrPageResults logic\r\n\r\nexport function FulltextResults(props: FulltextResultsProps) {\r\n if (props.fulltextResults.length === 0) return <></>;\r\n\r\n return (\r\n <>\r\n <FulltextOnlyHeader\r\n hasAnswerOrPageResults={props.hasAnswerOrPageResults}\r\n />\r\n <FulltextSection\r\n searchString={props.searchString}\r\n isOpen={!props.hasAnswerOrPageResults}\r\n results={props.fulltextResults}\r\n />\r\n </>\r\n );\r\n}\r\n","import React from \"react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { getAnswerTypeContent } from \"../datatypes/AnswerTypes\";\r\nimport { RenderIcon } from \"./IconRenderer\";\r\n\r\ninterface SectionTypeAlertProps {\r\n alertType: string | null;\r\n sectionType: string;\r\n}\r\n\r\nexport default function SectionTypeAlert(props: SectionTypeAlertProps) {\r\n const { t } = useTranslation();\r\n var alertTypeLower = props.alertType ? props.alertType.toLowerCase() : null;\r\n\r\n var config = alertTypeLower\r\n ? getAnswerTypeContent(alertTypeLower, t)\r\n : null;\r\n if (config) {\r\n return (\r\n <div className={`alert ${config.alertClassName}`} role=\"alert\">\r\n <span className=\"section-icon\">\r\n <RenderIcon\r\n iconType={config.icon.iconType}\r\n iconId={config.icon.iconId}\r\n />\r\n </span>\r\n <strong>{config.alertTitle}</strong>: {config.description}\r\n </div>\r\n );\r\n } else {\r\n return <></>;\r\n }\r\n}\r\n","import React, { useState } from \"react\";\r\nimport SectionTypeAlert from \"./SectionTypeAlert\";\r\nimport ContentMarkdown from \"./ContentMarkdown\";\r\nimport { DDHAnswerSearchResult } from \"../datatypes/RequirementsSearch\";\r\n\r\nexport interface AnswerContentProps {\r\n answer: DDHAnswerSearchResult;\r\n}\r\n\r\n/**\r\n * Show the content of an answer object, including:\r\n * - The answer type formatted as an alert\r\n * - The content of all relationships that match this answer\r\n * - The main content of the answer\r\n * @param props\r\n */\r\nexport function AnswerContent(props: AnswerContentProps) {\r\n const [lastAnswerId, setLastAnswerId] = useState<string | null>(null);\r\n const [answer, setAnswer] = useState<DDHAnswerSearchResult | null>(null);\r\n\r\n if (lastAnswerId !== props.answer.id) {\r\n setLastAnswerId(props.answer.id);\r\n setAnswer(props.answer);\r\n }\r\n\r\n if (!answer) return <></>;\r\n\r\n return (\r\n <>\r\n <SectionTypeAlert\r\n alertType={answer.answerType || \"\"}\r\n sectionType=\"answer\"\r\n />\r\n {answer.relationshipText ? (\r\n <ContentMarkdown\r\n source={answer.relationshipText}\r\n className=\"search-result-block\"\r\n />\r\n ) : (\r\n <></>\r\n )}\r\n <ContentMarkdown\r\n source={answer.contentMarkdown}\r\n className=\"search-result-block\"\r\n />\r\n </>\r\n );\r\n}\r\n","import React from \"react\";\r\nimport {\r\n getIconForContentType,\r\n getSectionNameForContentType,\r\n getTooltipForContentType,\r\n} from \"../datatypes/Pages\";\r\nimport CollapsibleSection from \"./CollapsibleSection\";\r\nimport { useTranslation } from \"react-i18next\";\r\n\r\nexport interface RequirementsSearchResultsEmptyPageSectionProps {\r\n searchString: string;\r\n contentType: string;\r\n contentTypePlural: string;\r\n libraryIds: string[] | null;\r\n}\r\n\r\nexport function RequirementsSearchResultsEmptyPageSection(\r\n props: RequirementsSearchResultsEmptyPageSectionProps\r\n) {\r\n const { searchString, contentType, libraryIds, contentTypePlural } = props;\r\n const { t } = useTranslation();\r\n const libraryIdString = (libraryIds && libraryIds.join(\"-\")) || \"all\";\r\n\r\n return (\r\n <CollapsibleSection\r\n key={`req-search-section-${contentType}`}\r\n sectionKey={`req-search-section-${contentType}-${searchString}-${libraryIdString}`}\r\n sectionIcon={getIconForContentType(contentType)}\r\n headerTitle={`${getSectionNameForContentType(contentType)} (0)`}\r\n defaultCollapsed={false}\r\n tooltip={getTooltipForContentType(contentType)}\r\n rowClassName=\"section-header\"\r\n >\r\n <ul>\r\n {t(\"No\")} {contentTypePlural} {t(\"foundForThisKeyword\")}\r\n </ul>\r\n </CollapsibleSection>\r\n );\r\n}\r\n","import React from \"react\";\r\nimport {\r\n getSectionNameForContentType,\r\n getTooltipForContentType,\r\n buildPageUrl,\r\n getIconForContentType,\r\n} from \"../datatypes/Pages\";\r\nimport CollapsibleSection from \"./CollapsibleSection\";\r\nimport { ContentLink } from \"./ContentLink\";\r\nimport { DDHPageSearchResult } from \"../datatypes/RequirementsSearch\";\r\n\r\nexport interface RequirementsSearchResultsPageSectionProps {\r\n searchString: string;\r\n contentType: string;\r\n items: DDHPageSearchResult[];\r\n libraryIds: string[] | null;\r\n isOpen: boolean;\r\n}\r\n\r\nfunction Item(props: { content: DDHPageSearchResult }) {\r\n const { content } = props;\r\n\r\n return (\r\n <li>\r\n <ContentLink\r\n href={buildPageUrl(content.id)}\r\n className=\"requirements-link\"\r\n >\r\n {content.title}\r\n </ContentLink>\r\n </li>\r\n );\r\n}\r\n\r\nexport function RequirementsSearchResultsPageSection(\r\n props: RequirementsSearchResultsPageSectionProps\r\n) {\r\n const { searchString, contentType, items, isOpen, libraryIds } = props;\r\n const libraryIdString = (libraryIds && libraryIds.join(\"-\")) || \"all\";\r\n\r\n return (\r\n <CollapsibleSection\r\n key={`req-search-section-${contentType}`}\r\n sectionKey={`req-search-section-${contentType}-${searchString}-${libraryIdString}`}\r\n sectionIcon={getIconForContentType(contentType)}\r\n headerTitle={`${getSectionNameForContentType(contentType)} (${\r\n items.length\r\n })`}\r\n defaultCollapsed={!isOpen}\r\n tooltip={getTooltipForContentType(contentType)}\r\n rowClassName=\"section-header\"\r\n >\r\n <ul>\r\n {items.map((item) => (\r\n <Item key={item.id} content={item} />\r\n ))}\r\n </ul>\r\n </CollapsibleSection>\r\n );\r\n}\r\n","import React from \"react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { getLibraryFilterNames } from \"../datatypes/Libraries\";\r\nimport {\r\n buildRequirementsSearchUrl,\r\n DDHAnswerGrouping,\r\n DDHAnswerSearchResult,\r\n DDHPageResultsGrouping,\r\n DDHPageSearchResult,\r\n groupPageResults,\r\n} from \"../datatypes/RequirementsSearch\";\r\nimport { distinct, prepareUriString } from \"../util\";\r\nimport { AnswerContent } from \"./AnswerContent\";\r\nimport { RequirementsSearchResultsEmptyPageSection } from \"./RequirementsSearchResultsEmptyPageSection\";\r\nimport { RequirementsSearchResultsPageSection } from \"./RequirementsSearchResultsPageSection\";\r\n\r\ninterface RequirementsSearchKeywordResultsGroupProps {\r\n answerGrouping: DDHAnswerGrouping;\r\n isOnlyAnswerGroup: boolean;\r\n searchString: string;\r\n showHeader?: boolean | undefined;\r\n}\r\n\r\nfunction LibrariesList(props: { grp: DDHAnswerGrouping }) {\r\n const { grp } = props;\r\n const { t } = useTranslation();\r\n\r\n var matchingLibraries = getLibraryFilterNames(grp.matchingLibraries, t);\r\n if (matchingLibraries === null) {\r\n return null;\r\n } else {\r\n return (\r\n <>\r\n {t(\"KeywordSearchResultsWithin\")} {matchingLibraries}\r\n </>\r\n );\r\n }\r\n}\r\n\r\nfunction SearchTermLink(props: { searchTerm: string; prefixComma: boolean }) {\r\n const { searchTerm, prefixComma } = props;\r\n return (\r\n <React.Fragment key={prepareUriString(searchTerm)}>\r\n {prefixComma ? \", \" : \"\"}\"\r\n <a href={buildRequirementsSearchUrl(searchTerm)}>{searchTerm}</a>\"\r\n </React.Fragment>\r\n );\r\n}\r\n\r\nfunction SearchTermLinks(props: { grp: DDHAnswerGrouping }) {\r\n const { grp } = props;\r\n const distinctSearchTerms = distinct(\r\n grp.searchTerms.map((a) => a.searchTerms).flat()\r\n );\r\n return (\r\n <>\r\n {distinctSearchTerms.map((keyword, i) => (\r\n <SearchTermLink searchTerm={keyword} prefixComma={i !== 0} />\r\n ))}\r\n </>\r\n );\r\n}\r\n\r\nfunction Header(props: { grp: DDHAnswerGrouping }) {\r\n const { grp } = props;\r\n const { t } = useTranslation();\r\n\r\n return (\r\n <h2 className=\"search-results-group-header\">\r\n {t(\"KeywordSearchResultsFor\")}\r\n <SearchTermLinks grp={grp} /> <LibrariesList grp={grp} />\r\n </h2>\r\n );\r\n}\r\n\r\nfunction Answer(props: {\r\n answer: DDHAnswerSearchResult | null;\r\n searchTerm: string;\r\n}) {\r\n const { answer } = props;\r\n\r\n if (answer === null) {\r\n return <></>;\r\n } else {\r\n return <AnswerContent answer={answer} />;\r\n }\r\n}\r\n\r\nfunction EmptyPageGroups(props: {\r\n searchString: string;\r\n pages: DDHPageSearchResult[];\r\n libraryIds: string[] | null;\r\n}) {\r\n const { searchString, pages, libraryIds } = props;\r\n const { t } = useTranslation();\r\n\r\n if (pages.filter((p) => p.contentType === \"requirement\").length === 0) {\r\n return (\r\n <RequirementsSearchResultsEmptyPageSection\r\n searchString={searchString}\r\n contentType={t(\"requirement\")}\r\n contentTypePlural={t(\"requirements\")}\r\n libraryIds={libraryIds}\r\n />\r\n );\r\n }\r\n return <></>;\r\n}\r\n\r\nfunction PageGroups(props: {\r\n searchString: string;\r\n groups: DDHPageResultsGrouping[];\r\n libraryIds: string[] | null;\r\n isOnlyAnswerGroup: boolean;\r\n}) {\r\n const { searchString, groups, libraryIds, isOnlyAnswerGroup } = props;\r\n\r\n return (\r\n <>\r\n {groups.map((grp) => (\r\n <RequirementsSearchResultsPageSection\r\n key={grp.contentType}\r\n searchString={searchString}\r\n contentType={grp.contentType}\r\n libraryIds={libraryIds}\r\n items={grp.pages}\r\n isOpen={isOnlyAnswerGroup && groups.indexOf(grp) === 0}\r\n />\r\n ))}\r\n </>\r\n );\r\n}\r\n\r\nexport function RequirementsSearchKeywordResultsGroup(\r\n props: RequirementsSearchKeywordResultsGroupProps\r\n) {\r\n return (\r\n <>\r\n {props.showHeader && <Header grp={props.answerGrouping} />}\r\n <div className=\"search-results-group\">\r\n <Answer\r\n answer={props.answerGrouping.answer}\r\n searchTerm={\r\n props.answerGrouping.searchTerms[0].searchTerms[0]\r\n }\r\n />\r\n <EmptyPageGroups\r\n searchString={props.searchString}\r\n pages={props.answerGrouping.pages}\r\n libraryIds={props.answerGrouping.matchingLibraries}\r\n />\r\n <PageGroups\r\n searchString={props.searchString}\r\n groups={groupPageResults(props.answerGrouping.pages)}\r\n libraryIds={props.answerGrouping.matchingLibraries}\r\n isOnlyAnswerGroup={props.isOnlyAnswerGroup}\r\n />\r\n </div>\r\n </>\r\n );\r\n}\r\n","import React, { useState } from \"react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { getAnswerTypeContent } from \"../datatypes/AnswerTypes\";\r\nimport {\r\n getGlobalExpandedState,\r\n setGlobalExpandedState,\r\n} from \"../datatypes/CollapsedState\";\r\nimport { getLibraryFilterNames } from \"../datatypes/Libraries\";\r\nimport {\r\n buildRequirementsSearchUrl,\r\n DDHAnswerGrouping,\r\n DDHRequirementsSearchResult,\r\n groupSummary,\r\n} from \"../datatypes/RequirementsSearch\";\r\nimport {\r\n sortByAnswerType,\r\n sortByKeyword,\r\n sortByLibrary,\r\n sortByParameter,\r\n SortFunctionParameter,\r\n} from \"../datatypes/SearchResultSorting\";\r\nimport { getCollapseIcon } from \"../ddh-styles\";\r\nimport {\r\n capitalizeFirstWord,\r\n distinct,\r\n prepareUriString,\r\n sanitizeHtmlId,\r\n} from \"../util\";\r\nimport ContentMarkdown from \"./ContentMarkdown\";\r\nimport { FulltextResults } from \"./FulltextResults\";\r\nimport HelpTooltip from \"./HelpTooltip\";\r\nimport { RenderIcon } from \"./IconRenderer\";\r\nimport { RequirementsSearchKeywordResultsGroup } from \"./RequirementsSearchKeywordResultsGroup\";\r\n\r\nexport interface RequirementsSearchKeywordResultsProps {\r\n searchString: string;\r\n result: DDHRequirementsSearchResult;\r\n}\r\n\r\nexport function RequirementsSearchKeywordResults(\r\n props: RequirementsSearchKeywordResultsProps\r\n) {\r\n const { searchString, result } = props;\r\n const [sortFuncParam, setSortFuncParam] =\r\n useState<SortFunctionParameter | null>(null);\r\n const { t } = useTranslation();\r\n\r\n const sortByKeywordClick = (\r\n evt: React.MouseEvent<HTMLAnchorElement, MouseEvent>\r\n ) => {\r\n setSortFuncParam({\r\n sortFunc: sortByKeyword,\r\n });\r\n evt.preventDefault();\r\n };\r\n\r\n const sortByLibraryClick = (\r\n evt: React.MouseEvent<HTMLAnchorElement, MouseEvent>\r\n ) => {\r\n setSortFuncParam({\r\n sortFunc: sortByLibrary,\r\n });\r\n evt.preventDefault();\r\n };\r\n\r\n const sortByAnswerTypeClick = (\r\n evt: React.MouseEvent<HTMLAnchorElement, MouseEvent>\r\n ) => {\r\n setSortFuncParam({\r\n sortFunc: sortByAnswerType,\r\n });\r\n evt.preventDefault();\r\n };\r\n\r\n var groupedResults = sortByParameter(result.results, sortFuncParam);\r\n\r\n if (groupedResults.length > 0 || result.fulltextResults.length > 0) {\r\n return (\r\n <>\r\n <hr />\r\n {groupedResults.length > 0 ? (\r\n <>\r\n <div className=\"section-header row\">\r\n <div className=\"col-item\">\r\n <span className=\"h2\">\r\n {t(\"KeywordSearchResults\")}\r\n </span>\r\n <HelpTooltip\r\n id=\"KeywordSearchResultsHeader\"\r\n tooltip={t(\"KeywordSearchResults_Tooltip\")}\r\n placement=\"right\"\r\n />\r\n </div>\r\n </div>\r\n <table className=\"table srtg-table\">\r\n <thead className=\"thead-light\">\r\n <tr>\r\n <th title=\"Expand/collapse icon\"> </th>\r\n <th>\r\n <a\r\n href=\"#\"\r\n onClick={sortByKeywordClick}\r\n >\r\n {t(\"Keywords\")}\r\n </a>\r\n </th>\r\n <th>\r\n <a\r\n href=\"#\"\r\n onClick={sortByLibraryClick}\r\n >\r\n {t(\"Agreement\")}\r\n </a>\r\n </th>\r\n <th>\r\n <a\r\n href=\"#\"\r\n onClick={sortByAnswerTypeClick}\r\n >\r\n {t(\"Result\")}\r\n </a>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {groupedResults.map((grp) => (\r\n <RequirementsSearchResultGroupTableGroup\r\n key={`group-${getUniqueAnswerGroupId(\r\n grp\r\n )}`}\r\n searchString={searchString}\r\n group={grp}\r\n isExpanded={groupedResults.length === 1}\r\n />\r\n ))}\r\n </tbody>\r\n </table>\r\n </>\r\n ) : (\r\n <ContentMarkdown\r\n source={t(\"FulltextSearchResultsOnlyHeader\")}\r\n />\r\n )}\r\n <FulltextResults\r\n searchString={searchString}\r\n hasAnswerOrPageResults={true}\r\n fulltextResults={result.fulltextResults}\r\n />\r\n </>\r\n );\r\n } else {\r\n return <NoResults />;\r\n }\r\n}\r\n\r\ninterface RequirementsSearchResultGroupTableGroupProps {\r\n group: DDHAnswerGrouping;\r\n searchString: string;\r\n isExpanded: boolean;\r\n}\r\n\r\nexport function getUniqueAnswerGroupId(group: DDHAnswerGrouping) {\r\n return `${sanitizeHtmlId(group.answer?.id || \"noanswer\")}-${sanitizeHtmlId(\r\n (group.matchingLibraries && group.matchingLibraries.join(\"-\")) || \"all\"\r\n )}-${sanitizeHtmlId(\r\n group.searchTerms &&\r\n group.searchTerms.map((x) => x.searchTerms).join(\"-\")\r\n )}`;\r\n}\r\n\r\nfunction getUniqueGroupId(\r\n grp: DDHAnswerGrouping,\r\n searchString: string\r\n): string | null {\r\n return `${grp.answer?.id || \"noAnswer\"}-${grp.searchTerms\r\n .map((x) => x.canonical)\r\n .join(\",\")}-${\r\n (grp.matchingLibraries && grp.matchingLibraries.join(\",\")) || \"(all)\"\r\n }-${searchString}`;\r\n}\r\n\r\nfunction RequirementsSearchResultGroupTableGroup(\r\n props: RequirementsSearchResultGroupTableGroupProps\r\n) {\r\n const { group, searchString } = props;\r\n const groupId = getUniqueGroupId(group, searchString);\r\n const globalExpandedState = getGlobalExpandedState(groupId);\r\n\r\n const [isExpanded, setIsExpanded] = useState<boolean>(\r\n globalExpandedState !== null ? globalExpandedState : props.isExpanded\r\n );\r\n\r\n const { t } = useTranslation();\r\n\r\n const clickExpand = (\r\n event: React.MouseEvent<HTMLAnchorElement, MouseEvent>\r\n ) => {\r\n setGlobalExpandedState(groupId, !isExpanded);\r\n setIsExpanded(!isExpanded);\r\n event.preventDefault();\r\n };\r\n\r\n const answerType =\r\n group.answer && group.answer.answerType\r\n ? getAnswerTypeContent(group.answer.answerType, t)\r\n : null;\r\n\r\n return (\r\n <>\r\n <tr className=\"table-light srtg-group-header\">\r\n <td>\r\n <a\r\n href=\"#\"\r\n onClick={clickExpand}\r\n title={\r\n isExpanded\r\n ? t(\"SearchResultsGroup_Collapse\")\r\n : t(\"SearchResultsGroup_Expand\")\r\n }\r\n >\r\n {getCollapseIcon(isExpanded)}\r\n </a>\r\n </td>\r\n <td>\r\n <SearchTermLinks grp={group} />\r\n </td>\r\n <td>\r\n <LibrariesList grp={group} />\r\n </td>\r\n <td>\r\n {answerType && answerType.badgeClassName ? (\r\n <div>\r\n <div\r\n className={`badge ${answerType.badgeClassName}`}\r\n >\r\n <RenderIcon\r\n iconType={answerType.icon.iconType}\r\n iconId={answerType.icon.iconId}\r\n />\r\n </div>\r\n \r\n <strong>{answerType.badgeTitle}</strong>\r\n </div>\r\n ) : null}\r\n {groupSummary(t, group).join(\"; \")}\r\n </td>\r\n </tr>\r\n {isExpanded ? (\r\n <tr>\r\n <td colSpan={4}>\r\n <RequirementsSearchKeywordResultsGroup\r\n searchString={searchString}\r\n answerGrouping={group}\r\n isOnlyAnswerGroup={true}\r\n showHeader={false}\r\n />\r\n </td>\r\n </tr>\r\n ) : null}\r\n </>\r\n );\r\n}\r\n\r\nfunction NoResults() {\r\n const { t } = useTranslation();\r\n\r\n return (\r\n <div id=\"search-results\">\r\n <ContentMarkdown source={t(\"RequirementsSearchNoResults\")} />\r\n </div>\r\n );\r\n}\r\n\r\nfunction SearchTermLink(props: { searchTerm: string; isFirst: boolean }) {\r\n const { t } = useTranslation();\r\n const { searchTerm, isFirst } = props;\r\n\r\n return (\r\n <React.Fragment key={prepareUriString(searchTerm)}>\r\n {!isFirst ? \", \" : \"\"}\r\n <a\r\n href={buildRequirementsSearchUrl(searchTerm)}\r\n title={t(\"SearchResultsGroup_SearchFor\").replace(\r\n /\\{keyword\\}/g,\r\n searchTerm\r\n )}\r\n >\r\n {isFirst ? capitalizeFirstWord(searchTerm) : searchTerm}\r\n </a>\r\n </React.Fragment>\r\n );\r\n}\r\n\r\nfunction SearchTermLinks(props: { grp: DDHAnswerGrouping }) {\r\n const { grp } = props;\r\n\r\n const distinctSearchTerms = distinct(\r\n grp.searchTerms.map((a) => a.searchTerms).flat()\r\n );\r\n\r\n return (\r\n <>\r\n {distinctSearchTerms.map((keyword, i) => (\r\n <SearchTermLink\r\n key={keyword}\r\n searchTerm={keyword}\r\n isFirst={i === 0}\r\n />\r\n ))}\r\n </>\r\n );\r\n}\r\n\r\nfunction LibrariesList(props: { grp: DDHAnswerGrouping }) {\r\n const { t } = useTranslation();\r\n const { grp } = props;\r\n\r\n var matchingLibraries = getLibraryFilterNames(grp.matchingLibraries, t);\r\n if (matchingLibraries === null) {\r\n return <>{t(\"SearchFilter_All\")}</>;\r\n } else {\r\n return <>{matchingLibraries}</>;\r\n }\r\n}\r\n","import { faSearch } from \"@fortawesome/free-solid-svg-icons\";\r\nimport React, { useCallback, useEffect, useReducer } from \"react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { useDDHPageContext } from \"../components/DDHPageContext\";\r\nimport { IconType } from \"../components/IconRenderer\";\r\nimport RequirementsSearch from \"../components/RequirementsSearch\";\r\nimport { RequirementsSearchKeywordResults } from \"../components/RequirementsSearchKeywordResults\";\r\nimport { getLibraryFilters, toLibraryFilterList } from \"../datatypes/Libraries\";\r\nimport {\r\n buildRequirementsSearchUrl,\r\n DDHRequirementsSearchResult,\r\n getRequirementsSearchResults,\r\n} from \"../datatypes/RequirementsSearch\";\r\nimport { prepareUriString } from \"../util\";\r\nimport { usePrevious } from \"../hooks/usePrevious\";\r\n\r\ninterface RequirementsSearchPageState {\r\n isBusy: boolean;\r\n searchString: string;\r\n result: DDHRequirementsSearchResult | null;\r\n libraries: string[] | null;\r\n triggerUpdate: boolean;\r\n triggerUrlChange: string | null;\r\n}\r\n\r\ninterface RequirementsSearchPageUpdate {\r\n type: \"updateTriggered\" | \"resultSet\" | \"runSearch\" | \"changeParams\";\r\n searchString?: string | undefined;\r\n result?: DDHRequirementsSearchResult | null | undefined;\r\n libraries?: string[] | null | undefined;\r\n triggerUrlChange?: string | null | undefined;\r\n}\r\n\r\nfunction getLibrariesOrUndefined(\r\n value: string[] | null | undefined,\r\n defaultValue: string[] | null\r\n): string[] | null {\r\n if (value === undefined) return defaultValue;\r\n return value;\r\n}\r\n\r\nfunction getStringOrUndefined(\r\n value: string | null | undefined,\r\n defaultValue: string | null\r\n): string | null {\r\n if (value === undefined) return defaultValue;\r\n return value;\r\n}\r\n\r\nfunction requirementsSearchPageReducer(\r\n state: RequirementsSearchPageState,\r\n update: RequirementsSearchPageUpdate\r\n): RequirementsSearchPageState {\r\n // If we triggered an update, update busy state and clear trigger update flag\r\n if (update.type === \"updateTriggered\") {\r\n return {\r\n isBusy: true,\r\n searchString: state.searchString,\r\n result: state.result,\r\n libraries: state.libraries,\r\n triggerUpdate: false,\r\n triggerUrlChange: null,\r\n };\r\n }\r\n\r\n // If the result changes, update the state and complete the update\r\n // We can also update the searchString (e.g., if we're setting a null result for a blank search string)\r\n if (update.type === \"resultSet\") {\r\n return {\r\n isBusy: false,\r\n searchString:\r\n getStringOrUndefined(update.searchString, state.searchString) ||\r\n \"\",\r\n result: update.result || null,\r\n libraries: state.libraries,\r\n triggerUpdate: false,\r\n triggerUrlChange: null,\r\n };\r\n }\r\n\r\n // If the parameters change, trigger an update (unless we're in the middle of an update).\r\n // This might be occuring in stages (because a URL is being updated), so\r\n // only set triggerUpdate if specified.\r\n if (!state.isBusy && update.type === \"runSearch\") {\r\n return {\r\n isBusy: false,\r\n searchString:\r\n getStringOrUndefined(update.searchString, state.searchString) ||\r\n \"\",\r\n result: state.result,\r\n libraries: getLibrariesOrUndefined(\r\n update.libraries,\r\n state.libraries\r\n ),\r\n triggerUpdate: true,\r\n triggerUrlChange: null,\r\n };\r\n }\r\n\r\n if (update.type === \"changeParams\" || update.type === \"runSearch\") {\r\n return {\r\n isBusy: false,\r\n searchString:\r\n getStringOrUndefined(update.searchString, state.searchString) ||\r\n \"\",\r\n result: state.result,\r\n libraries: getLibrariesOrUndefined(\r\n update.libraries,\r\n state.libraries\r\n ),\r\n triggerUpdate: true,\r\n triggerUrlChange: update.triggerUrlChange || null,\r\n };\r\n }\r\n\r\n return state;\r\n}\r\n\r\nexport default function RequirementsSearchPage(props: any) {\r\n const {\r\n t,\r\n i18n: { language: locale },\r\n } = useTranslation();\r\n\r\n const [pageModel, pageDispatch] = useReducer(\r\n requirementsSearchPageReducer,\r\n {\r\n isBusy: false,\r\n searchString: \"\",\r\n result: null,\r\n libraries: toLibraryFilterList(getLibraryFilters()),\r\n triggerUpdate: false,\r\n triggerUrlChange: null,\r\n }\r\n );\r\n\r\n const { setPageTitle } = useDDHPageContext();\r\n\r\n // Set title\r\n useEffect(() => {\r\n setPageTitle(t(\"RequirementsSearch\"), t(\"RequirementsSearch\"), {\r\n iconType: IconType.FontAwesome,\r\n iconId: faSearch,\r\n });\r\n }, [setPageTitle, t]);\r\n\r\n // Force a URL change if one is queued up\r\n useEffect(() => {\r\n if (\r\n pageModel.triggerUrlChange &&\r\n pageModel.triggerUrlChange !== props.history.location.pathname\r\n ) {\r\n props.history.push(pageModel.triggerUrlChange);\r\n }\r\n }, [pageModel.triggerUrlChange, props.history]);\r\n\r\n // Get search phrase from URL\r\n const getUrlSearchTerm = useCallback(() => {\r\n if (!props.match.params || !props.match.params[0]) return \"\";\r\n return prepareUriString(props.match.params[0]);\r\n }, [props.match.params]);\r\n\r\n var searchStringFromUrl: string = getUrlSearchTerm() || \"\";\r\n\r\n // Trigger a search string change\r\n useEffect(() => {\r\n if (searchStringFromUrl !== pageModel.searchString) {\r\n if (searchStringFromUrl === \"\") {\r\n pageDispatch({\r\n type: \"resultSet\",\r\n result: null,\r\n searchString: \"\",\r\n });\r\n } else {\r\n pageDispatch({\r\n type: \"runSearch\",\r\n searchString: searchStringFromUrl,\r\n triggerUrlChange: null,\r\n });\r\n }\r\n }\r\n }, [pageModel.searchString, searchStringFromUrl]);\r\n\r\n // Get library filter change\r\n const onLibraryChange = useCallback(\r\n (_searchString: string, _libraries: string[] | null) => {\r\n // If library changes, trigger an update\r\n // If search string also changed, update library but queue up a URL change\r\n if (pageModel.libraries !== _libraries) {\r\n pageDispatch({\r\n type:\r\n pageModel.searchString === _searchString\r\n ? \"runSearch\"\r\n : \"changeParams\",\r\n libraries: _libraries,\r\n searchString: _searchString,\r\n triggerUrlChange: buildRequirementsSearchUrl(_searchString),\r\n });\r\n }\r\n },\r\n [pageModel.libraries, pageModel.searchString]\r\n );\r\n\r\n // Trigger search result\r\n useEffect(() => {\r\n if (pageModel.triggerUpdate) {\r\n pageDispatch({ type: \"updateTriggered\" });\r\n getRequirementsSearchResults(\r\n pageModel.searchString,\r\n locale,\r\n pageModel.libraries\r\n ).then((r) => {\r\n pageDispatch({ type: \"resultSet\", result: r || null });\r\n });\r\n }\r\n }, [\r\n locale,\r\n pageModel.libraries,\r\n pageModel.searchString,\r\n pageModel.triggerUpdate,\r\n ]);\r\n\r\n const previousLocale = usePrevious(locale);\r\n\r\n useEffect(() => {\r\n if (previousLocale !== undefined && previousLocale !== locale) {\r\n console.log(`Locale updated. Trigger re-search.`);\r\n pageDispatch({ type: \"runSearch\" });\r\n }\r\n }, [locale, previousLocale]);\r\n\r\n return (\r\n <div id=\"content\">\r\n <RequirementsSearch\r\n autoFocus={true}\r\n searchString={pageModel.searchString}\r\n history={props.history}\r\n setLibraries={onLibraryChange}\r\n isBusy={pageModel.isBusy}\r\n />\r\n <Results\r\n searchString={pageModel.searchString}\r\n result={pageModel.result}\r\n />\r\n </div>\r\n );\r\n}\r\n\r\nexport interface ResultsProps {\r\n searchString: string;\r\n result: DDHRequirementsSearchResult | null;\r\n}\r\n\r\nexport function Results(props: ResultsProps) {\r\n const { searchString, result } = props;\r\n\r\n if (result === null) {\r\n return null;\r\n }\r\n\r\n return (\r\n <RequirementsSearchKeywordResults\r\n searchString={searchString}\r\n result={result}\r\n />\r\n );\r\n}\r\n","import { useRef, useEffect } from \"react\";\r\n\r\nexport function usePrevious<T>(value: T) {\r\n // The ref object is a generic container whose current property is mutable ...\r\n // ... and can hold any value, similar to an instance property on a class\r\n const ref = useRef<T>();\r\n\r\n // Store current value in ref\r\n useEffect(() => {\r\n ref.current = value;\r\n }, [value]); // Only re-run if value changes\r\n\r\n // Return previous value (happens before update in useEffect above)\r\n return ref.current;\r\n}\r\n"],"sourceRoot":""}