Added option to set secondary search provider
This commit is contained in:
parent
2c0491a5b0
commit
16121ff547
9 changed files with 79 additions and 25 deletions
|
@ -1,5 +1,6 @@
|
||||||
### v2.3.0 (TBA)
|
### v2.3.0 (TBA)
|
||||||
- Added custom theme editor ([#246](https://github.com/pawelmalak/flame/issues/246))
|
- Added custom theme editor ([#246](https://github.com/pawelmalak/flame/issues/246))
|
||||||
|
- Added option to set secondary search provider ([#295](https://github.com/pawelmalak/flame/issues/295))
|
||||||
- Fixed bug where pressing Enter with empty search bar would redirect to search results ([#325](https://github.com/pawelmalak/flame/issues/325))
|
- Fixed bug where pressing Enter with empty search bar would redirect to search results ([#325](https://github.com/pawelmalak/flame/issues/325))
|
||||||
- Fixed bug where user could create empty app or bookmark which was causing page to go blank ([#332](https://github.com/pawelmalak/flame/issues/332))
|
- Fixed bug where user could create empty app or bookmark which was causing page to go blank ([#332](https://github.com/pawelmalak/flame/issues/332))
|
||||||
- Added new theme: Mint
|
- Added new theme: Mint
|
||||||
|
|
|
@ -64,16 +64,22 @@ export const SearchBar = (props: Props): JSX.Element => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchHandler = (e: KeyboardEvent<HTMLInputElement>) => {
|
const searchHandler = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||||
const { isLocal, search, query, isURL, sameTab, rawQuery } = searchParser(
|
const {
|
||||||
inputRef.current.value
|
isLocal,
|
||||||
);
|
encodedURL,
|
||||||
|
primarySearch,
|
||||||
|
secondarySearch,
|
||||||
|
isURL,
|
||||||
|
sameTab,
|
||||||
|
rawQuery,
|
||||||
|
} = searchParser(inputRef.current.value);
|
||||||
|
|
||||||
if (isLocal) {
|
if (isLocal) {
|
||||||
setLocalSearch(search);
|
setLocalSearch(encodedURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.code === 'Enter' || e.code === 'NumpadEnter') {
|
if (e.code === 'Enter' || e.code === 'NumpadEnter') {
|
||||||
if (!query.prefix) {
|
if (!primarySearch.prefix) {
|
||||||
// Prefix not found -> emit notification
|
// Prefix not found -> emit notification
|
||||||
createNotification({
|
createNotification({
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
|
@ -91,21 +97,20 @@ export const SearchBar = (props: Props): JSX.Element => {
|
||||||
redirectUrl(bookmarkSearchResult[0].bookmarks[0].url, sameTab);
|
redirectUrl(bookmarkSearchResult[0].bookmarks[0].url, sameTab);
|
||||||
} else {
|
} else {
|
||||||
// no local results -> search the internet with the default search provider if query is not empty
|
// no local results -> search the internet with the default search provider if query is not empty
|
||||||
|
|
||||||
if (!/^ *$/.test(rawQuery)) {
|
if (!/^ *$/.test(rawQuery)) {
|
||||||
let template = query.template;
|
let template = primarySearch.template;
|
||||||
|
|
||||||
if (query.prefix === 'l') {
|
if (primarySearch.prefix === 'l') {
|
||||||
template = 'https://duckduckgo.com/?q=';
|
template = secondarySearch.template;
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = `${template}${search}`;
|
const url = `${template}${encodedURL}`;
|
||||||
redirectUrl(url, sameTab);
|
redirectUrl(url, sameTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Valid query -> redirect to search results
|
// Valid query -> redirect to search results
|
||||||
const url = `${query.template}${search}`;
|
const url = `${primarySearch.template}${encodedURL}`;
|
||||||
redirectUrl(url, sameTab);
|
redirectUrl(url, sameTab);
|
||||||
}
|
}
|
||||||
} else if (e.code === 'Escape') {
|
} else if (e.code === 'Escape') {
|
||||||
|
|
|
@ -167,7 +167,7 @@ export const GeneralSettings = (): JSX.Element => {
|
||||||
{/* === SEARCH OPTIONS === */}
|
{/* === SEARCH OPTIONS === */}
|
||||||
<SettingsHeadline text="Search" />
|
<SettingsHeadline text="Search" />
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<label htmlFor="defaultSearchProvider">Default search provider</label>
|
<label htmlFor="defaultSearchProvider">Primary search provider</label>
|
||||||
<select
|
<select
|
||||||
id="defaultSearchProvider"
|
id="defaultSearchProvider"
|
||||||
name="defaultSearchProvider"
|
name="defaultSearchProvider"
|
||||||
|
@ -186,6 +186,34 @@ export const GeneralSettings = (): JSX.Element => {
|
||||||
</select>
|
</select>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
|
|
||||||
|
{formData.defaultSearchProvider === 'l' && (
|
||||||
|
<InputGroup>
|
||||||
|
<label htmlFor="secondarySearchProvider">
|
||||||
|
Secondary search provider
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="secondarySearchProvider"
|
||||||
|
name="secondarySearchProvider"
|
||||||
|
value={formData.secondarySearchProvider}
|
||||||
|
onChange={(e) => inputChangeHandler(e)}
|
||||||
|
>
|
||||||
|
{[...queries, ...customQueries].map((query: Query, idx) => {
|
||||||
|
const isCustom = idx >= queries.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<option key={idx} value={query.prefix}>
|
||||||
|
{isCustom && '+'} {query.name}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
<span>
|
||||||
|
Will be used when "Local search" is primary search provider and
|
||||||
|
there are not any local results
|
||||||
|
</span>
|
||||||
|
</InputGroup>
|
||||||
|
)}
|
||||||
|
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<label htmlFor="searchSameTab">
|
<label htmlFor="searchSameTab">
|
||||||
Open search results in the same tab
|
Open search results in the same tab
|
||||||
|
|
|
@ -17,6 +17,7 @@ export interface Config {
|
||||||
hideCategories: boolean;
|
hideCategories: boolean;
|
||||||
hideSearch: boolean;
|
hideSearch: boolean;
|
||||||
defaultSearchProvider: string;
|
defaultSearchProvider: string;
|
||||||
|
secondarySearchProvider: string;
|
||||||
dockerApps: boolean;
|
dockerApps: boolean;
|
||||||
dockerHost: string;
|
dockerHost: string;
|
||||||
kubernetesApps: boolean;
|
kubernetesApps: boolean;
|
||||||
|
|
|
@ -10,6 +10,7 @@ export interface WeatherForm {
|
||||||
|
|
||||||
export interface GeneralForm {
|
export interface GeneralForm {
|
||||||
defaultSearchProvider: string;
|
defaultSearchProvider: string;
|
||||||
|
secondarySearchProvider: string;
|
||||||
searchSameTab: boolean;
|
searchSameTab: boolean;
|
||||||
pinAppsByDefault: boolean;
|
pinAppsByDefault: boolean;
|
||||||
pinCategoriesByDefault: boolean;
|
pinCategoriesByDefault: boolean;
|
||||||
|
|
|
@ -4,7 +4,8 @@ export interface SearchResult {
|
||||||
isLocal: boolean;
|
isLocal: boolean;
|
||||||
isURL: boolean;
|
isURL: boolean;
|
||||||
sameTab: boolean;
|
sameTab: boolean;
|
||||||
search: string;
|
encodedURL: string;
|
||||||
query: Query;
|
primarySearch: Query;
|
||||||
|
secondarySearch: Query;
|
||||||
rawQuery: string;
|
rawQuery: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { queries } from './searchQueries.json';
|
import { queries } from './searchQueries.json';
|
||||||
import { Query, SearchResult } from '../interfaces';
|
import { SearchResult } from '../interfaces';
|
||||||
import { store } from '../store/store';
|
import { store } from '../store/store';
|
||||||
import { isUrlOrIp } from '.';
|
import { isUrlOrIp } from '.';
|
||||||
|
|
||||||
|
@ -8,8 +8,13 @@ export const searchParser = (searchQuery: string): SearchResult => {
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
isURL: false,
|
isURL: false,
|
||||||
sameTab: false,
|
sameTab: false,
|
||||||
search: '',
|
encodedURL: '',
|
||||||
query: {
|
primarySearch: {
|
||||||
|
name: '',
|
||||||
|
prefix: '',
|
||||||
|
template: '',
|
||||||
|
},
|
||||||
|
secondarySearch: {
|
||||||
name: '',
|
name: '',
|
||||||
prefix: '',
|
prefix: '',
|
||||||
template: '',
|
template: '',
|
||||||
|
@ -25,20 +30,26 @@ export const searchParser = (searchQuery: string): SearchResult => {
|
||||||
// Match prefix and query
|
// Match prefix and query
|
||||||
const splitQuery = searchQuery.match(/^\/([a-z]+)[ ](.+)$/i);
|
const splitQuery = searchQuery.match(/^\/([a-z]+)[ ](.+)$/i);
|
||||||
|
|
||||||
|
// Extract prefix
|
||||||
const prefix = splitQuery ? splitQuery[1] : config.defaultSearchProvider;
|
const prefix = splitQuery ? splitQuery[1] : config.defaultSearchProvider;
|
||||||
|
|
||||||
const search = splitQuery
|
// Encode url
|
||||||
|
const encodedURL = splitQuery
|
||||||
? encodeURIComponent(splitQuery[2])
|
? encodeURIComponent(splitQuery[2])
|
||||||
: encodeURIComponent(searchQuery);
|
: encodeURIComponent(searchQuery);
|
||||||
|
|
||||||
const query = [...queries, ...customQueries].find(
|
// Find primary search engine template
|
||||||
(q: Query) => q.prefix === prefix
|
const findProvider = (prefix: string) => {
|
||||||
);
|
return [...queries, ...customQueries].find((q) => q.prefix === prefix);
|
||||||
|
};
|
||||||
|
|
||||||
// If search provider was found
|
const primarySearch = findProvider(prefix);
|
||||||
if (query) {
|
const secondarySearch = findProvider(config.secondarySearchProvider);
|
||||||
result.query = query;
|
|
||||||
result.search = search;
|
// If search providers were found
|
||||||
|
if (primarySearch) {
|
||||||
|
result.primarySearch = primarySearch;
|
||||||
|
result.encodedURL = encodedURL;
|
||||||
|
|
||||||
if (prefix === 'l') {
|
if (prefix === 'l') {
|
||||||
result.isLocal = true;
|
result.isLocal = true;
|
||||||
|
@ -46,6 +57,10 @@ export const searchParser = (searchQuery: string): SearchResult => {
|
||||||
result.sameTab = config.searchSameTab;
|
result.sameTab = config.searchSameTab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (secondarySearch) {
|
||||||
|
result.secondarySearch = secondarySearch;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ export const configTemplate: Config = {
|
||||||
hideCategories: false,
|
hideCategories: false,
|
||||||
hideSearch: false,
|
hideSearch: false,
|
||||||
defaultSearchProvider: 'l',
|
defaultSearchProvider: 'l',
|
||||||
|
secondarySearchProvider: 'd',
|
||||||
dockerApps: false,
|
dockerApps: false,
|
||||||
dockerHost: 'localhost',
|
dockerHost: 'localhost',
|
||||||
kubernetesApps: false,
|
kubernetesApps: false,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"hideCategories": false,
|
"hideCategories": false,
|
||||||
"hideSearch": false,
|
"hideSearch": false,
|
||||||
"defaultSearchProvider": "l",
|
"defaultSearchProvider": "l",
|
||||||
|
"secondarySearchProvider": "d",
|
||||||
"dockerApps": false,
|
"dockerApps": false,
|
||||||
"dockerHost": "localhost",
|
"dockerHost": "localhost",
|
||||||
"kubernetesApps": false,
|
"kubernetesApps": false,
|
||||||
|
|
Loading…
Reference in a new issue