Added search index functionality

refs https://github.com/TryGhost/Team/issues/1665
refs 402e54987e/packages/ease/assets/js/main.js (L16-L127)

- This is a React adaptation of the referenced sodo-search functionality
- The module exposes two methods: init and search. Init requires an API URL parameter and an API key; search requires a text value and returns matching search results
This commit is contained in:
Naz 2022-07-05 10:09:10 +02:00
parent 55e3bf3885
commit f6838e2113
4 changed files with 101 additions and 0 deletions

View File

@ -8,6 +8,7 @@
"@testing-library/jest-dom": "5.16.2",
"@testing-library/react": "12.1.2",
"@testing-library/user-event": "14.0.0",
"elasticlunr": "0.9.5",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-scripts": "4.0.3"
@ -59,6 +60,7 @@
"copy-webpack-plugin": "6.4.1",
"eslint-plugin-ghost": "2.12.0",
"minimist": "1.2.5",
"nock": "13.2.8",
"ora": "5.4.1",
"rewire": "6.0.0",
"serve-handler": "6.1.3",

View File

@ -2,8 +2,25 @@ import React from 'react';
import './App.css';
import AppContext from './AppContext';
import PopupModal from './components/PopupModal';
import {init as initSearchIndex} from './search-index.js';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
apiUrl: props.apiUrl,
apiKey: props.apiKey
};
}
componentDidMount() {
initSearchIndex({
apiUrl: this.state.apiUrl,
apiKey: this.state.apiKey
});
}
render() {
return (
<AppContext.Provider value={{

View File

@ -0,0 +1,57 @@
import elasticlunr from 'elasticlunr';
let index;
export const init = async function ({apiUrl, apiKey}) {
// remove default stop words to search of *any* word
elasticlunr.clearStopWords();
const url = `${apiUrl}/posts/?key=${apiKey}&limit=all&fields=id,title,excerpt,url,updated_at,visibility&order=updated_at%20desc&formats=plaintext`;
const indexDump = JSON.parse(localStorage.getItem('ease_search_index'));
localStorage.removeItem('ease_index');
localStorage.removeItem('ease_last');
function update(data) {
data.posts.forEach(function (post) {
index.addDoc(post);
});
localStorage.setItem('ease_search_index', JSON.stringify(index));
localStorage.setItem('ease_search_last', data.posts[0].updated_at);
}
if (
!indexDump
) {
return fetch(url)
.then(response => response.json())
.then((data) => {
if (data.posts.length > 0) {
index = elasticlunr(function () {
this.addField('title');
this.addField('plaintext');
this.setRef('id');
});
update(data);
}
});
} else {
index = elasticlunr.Index.load(indexDump);
return fetch(`${url}&filter=updated_at:>'${localStorage.getItem('ease_search_last').replace(/\..*/, '').replace(/T/, ' ')}'`
)
.then(response => response.json())
.then((data) => {
if (data.posts.length > 0) {
update(data);
}
});
}
};
export const search = function (value) {
return index.search(value, {expand: true});
};

View File

@ -4385,6 +4385,11 @@ ejs@^3.1.5:
dependencies:
jake "^10.8.5"
elasticlunr@0.9.5:
version "0.9.5"
resolved "https://registry.yarnpkg.com/elasticlunr/-/elasticlunr-0.9.5.tgz#65541bb309dddd0cf94f2d1c8861b2be651bb0d5"
integrity sha512-5YM9LFQgVYfuLNEoqMqVWIBuF2UNCA+xu/jz1TyryLN/wmBcQSb+GNAwvLKvEpGESwgGN8XA1nbLAt6rKlyHYQ==
electron-to-chromium@^1.3.564, electron-to-chromium@^1.4.172:
version "1.4.177"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.177.tgz#b6a4436eb788ca732556cd69f384b8a3c82118c5"
@ -7133,6 +7138,11 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
json-stringify-safe@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==
json5@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
@ -7849,6 +7859,16 @@ no-case@^3.0.4:
lower-case "^2.0.2"
tslib "^2.0.3"
nock@13.2.8:
version "13.2.8"
resolved "https://registry.yarnpkg.com/nock/-/nock-13.2.8.tgz#e2043ccaa8e285508274575e090a7fe1e46b90f1"
integrity sha512-JT42FrXfQRpfyL4cnbBEJdf4nmBpVP0yoCcSBr+xkT8Q1y3pgtaCKHGAAOIFcEJ3O3t0QbVAmid0S0f2bj3Wpg==
dependencies:
debug "^4.1.0"
json-stringify-safe "^5.0.1"
lodash "^4.17.21"
propagate "^2.0.0"
node-forge@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
@ -9296,6 +9316,11 @@ prop-types@^15.8.1:
object-assign "^4.1.1"
react-is "^16.13.1"
propagate@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45"
integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==
proxy-addr@~2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"