Przeglądaj źródła

Local search for apps

unknown 3 lat temu
rodzic
commit
6ae6c58f4c

+ 1 - 1
README.md

@@ -32,7 +32,7 @@ git clone https://github.com/pawelmalak/flame
 cd flame
 
 # run only once
-npm run dev-init
+npm run dev:init
 
 # start backend and frontend development servers
 npm run dev

+ 23 - 11
client/src/components/Apps/AppGrid/AppGrid.tsx

@@ -7,6 +7,7 @@ import AppCard from '../AppCard/AppCard';
 interface ComponentProps {
   apps: App[];
   totalApps?: number;
+  searching: boolean;
 }
 
 const AppGrid = (props: ComponentProps): JSX.Element => {
@@ -16,26 +17,37 @@ const AppGrid = (props: ComponentProps): JSX.Element => {
     apps = (
       <div className={classes.AppGrid}>
         {props.apps.map((app: App): JSX.Element => {
-          return <AppCard
-            key={app.id}
-            app={app}
-          />
+          return <AppCard key={app.id} app={app} />;
         })}
       </div>
-    )
+    );
   } else {
     if (props.totalApps) {
-      apps = (
-        <p className={classes.AppsMessage}>There are no pinned applications. You can pin them from the <Link to='/applications'>/applications</Link> menu</p>
-      );
+      if (props.searching) {
+        apps = (
+          <p className={classes.AppsMessage}>
+            No apps match your search criteria
+          </p>
+        );
+      } else {
+        apps = (
+          <p className={classes.AppsMessage}>
+            There are no pinned applications. You can pin them from the{' '}
+            <Link to="/applications">/applications</Link> menu
+          </p>
+        );
+      }
     } else {
       apps = (
-        <p className={classes.AppsMessage}>You don't have any applications. You can add a new one from <Link to='/applications'>/applications</Link> menu</p>
+        <p className={classes.AppsMessage}>
+          You don't have any applications. You can add a new one from{' '}
+          <Link to="/applications">/applications</Link> menu
+        </p>
       );
     }
   }
 
   return apps;
-}
+};
 
-export default AppGrid;
+export default AppGrid;

+ 30 - 39
client/src/components/Apps/Apps.tsx

@@ -27,14 +27,11 @@ interface ComponentProps {
   getApps: Function;
   apps: App[];
   loading: boolean;
+  searching: boolean;
 }
 
 const Apps = (props: ComponentProps): JSX.Element => {
-  const {
-    getApps,
-    apps,
-    loading
-  } = props;
+  const { getApps, apps, loading, searching = false } = props;
 
   const [modalIsOpen, setModalIsOpen] = useState(false);
   const [isInEdit, setIsInEdit] = useState(false);
@@ -47,8 +44,8 @@ const Apps = (props: ComponentProps): JSX.Element => {
     orderId: 0,
     id: 0,
     createdAt: new Date(),
-    updatedAt: new Date()
-  })
+    updatedAt: new Date(),
+  });
 
   useEffect(() => {
     if (apps.length === 0) {
@@ -59,63 +56,57 @@ const Apps = (props: ComponentProps): JSX.Element => {
   const toggleModal = (): void => {
     setModalIsOpen(!modalIsOpen);
     setIsInUpdate(false);
-  }
+  };
 
   const toggleEdit = (): void => {
     setIsInEdit(!isInEdit);
     setIsInUpdate(false);
-  }
+  };
 
   const toggleUpdate = (app: App): void => {
     setAppInUpdate(app);
     setIsInUpdate(true);
     setModalIsOpen(true);
-  }
+  };
 
   return (
     <Container>
       <Modal isOpen={modalIsOpen} setIsOpen={setModalIsOpen}>
-        {!isInUpdate
-          ? <AppForm modalHandler={toggleModal} />
-          : <AppForm modalHandler={toggleModal} app={appInUpdate} />
-        }
+        {!isInUpdate ? (
+          <AppForm modalHandler={toggleModal} />
+        ) : (
+          <AppForm modalHandler={toggleModal} app={appInUpdate} />
+        )}
       </Modal>
 
       <Headline
-        title='All Applications'
-        subtitle={(<Link to='/'>Go back</Link>)}
+        title="All Applications"
+        subtitle={<Link to="/">Go back</Link>}
       />
-      
+
       <div className={classes.ActionsContainer}>
-        <ActionButton
-          name='Add'
-          icon='mdiPlusBox'
-          handler={toggleModal}
-        />
-        <ActionButton
-          name='Edit'
-          icon='mdiPencil'
-          handler={toggleEdit}
-        />
+        <ActionButton name="Add" icon="mdiPlusBox" handler={toggleModal} />
+        <ActionButton name="Edit" icon="mdiPencil" handler={toggleEdit} />
       </div>
 
       <div className={classes.Apps}>
-        {loading
-          ? <Spinner />
-          : (!isInEdit
-              ? <AppGrid apps={apps} />
-              : <AppTable updateAppHandler={toggleUpdate} />)
-        }
+        {loading ? (
+          <Spinner />
+        ) : !isInEdit ? (
+          <AppGrid apps={apps} searching />
+        ) : (
+          <AppTable updateAppHandler={toggleUpdate} />
+        )}
       </div>
     </Container>
-  )
-}
+  );
+};
 
 const mapStateToProps = (state: GlobalState) => {
   return {
     apps: state.app.apps,
-    loading: state.app.loading
-  }
-}
+    loading: state.app.loading,
+  };
+};
 
-export default connect(mapStateToProps, { getApps })(Apps);
+export default connect(mapStateToProps, { getApps })(Apps);

+ 81 - 63
client/src/components/Home/Home.tsx

@@ -47,13 +47,16 @@ const Home = (props: ComponentProps): JSX.Element => {
     appsLoading,
     getCategories,
     categories,
-    categoriesLoading
+    categoriesLoading,
   } = props;
 
   const [header, setHeader] = useState({
     dateTime: dateTime(),
-    greeting: greeter()
-  })
+    greeting: greeter(),
+  });
+
+  // Local search query
+  const [localSearch, setLocalSearch] = useState<null | string>(null);
 
   // Load applications
   useEffect(() => {
@@ -78,78 +81,93 @@ const Home = (props: ComponentProps): JSX.Element => {
       interval = setInterval(() => {
         setHeader({
           dateTime: dateTime(),
-          greeting: greeter()
-        })
+          greeting: greeter(),
+        });
       }, 1000);
     }
 
     return () => clearInterval(interval);
-  }, [])
-  
+  }, []);
+
   return (
     <Container>
-      {searchConfig('hideSearch', 0) !== 1
-        ? <SearchBar />
-        : <div></div>
-      }
-
-      {searchConfig('hideHeader', 0) !== 1
-        ? (
-          <header className={classes.Header}>
-            <p>{header.dateTime}</p>
-            <Link to='/settings' className={classes.SettingsLink}>Go to Settings</Link>
-            <span className={classes.HeaderMain}>
-              <h1>{header.greeting}</h1>
-              <WeatherWidget />
-            </span>
-          </header>
-          )
-        : <div></div>
-      }
-      
-      {searchConfig('hideApps', 0) !== 1
-        ? (<Fragment>
-            <SectionHeadline title='Applications' link='/applications' />
-            {appsLoading
-              ? <Spinner />
-              : <AppGrid
-                apps={apps.filter((app: App) => app.isPinned)}
-                totalApps={apps.length}
-              />
-            }
-            <div className={classes.HomeSpace}></div>
-          </Fragment>)
-        : <div></div>
-      }
-
-      {searchConfig('hideCategories', 0) !== 1
-        ? (<Fragment>
-            <SectionHeadline title='Bookmarks' link='/bookmarks' />
-            {categoriesLoading
-              ? <Spinner />
-              : <BookmarkGrid
-                  categories={categories.filter((category: Category) => category.isPinned)}
-                  totalCategories={categories.length}
-              />
-            }
-          </Fragment>)
-        : <div></div>
-      }
-
-      <Link to='/settings' className={classes.SettingsButton}>
-        <Icon icon='mdiCog' color='var(--color-background)' />
+      {searchConfig('hideSearch', 0) !== 1 ? (
+        <SearchBar setLocalSearch={setLocalSearch} />
+      ) : (
+        <div></div>
+      )}
+
+      {searchConfig('hideHeader', 0) !== 1 ? (
+        <header className={classes.Header}>
+          <p>{header.dateTime}</p>
+          <Link to="/settings" className={classes.SettingsLink}>
+            Go to Settings
+          </Link>
+          <span className={classes.HeaderMain}>
+            <h1>{header.greeting}</h1>
+            <WeatherWidget />
+          </span>
+        </header>
+      ) : (
+        <div></div>
+      )}
+
+      {searchConfig('hideApps', 0) !== 1 ? (
+        <Fragment>
+          <SectionHeadline title="Applications" link="/applications" />
+          {appsLoading ? (
+            <Spinner />
+          ) : (
+            <AppGrid
+              apps={
+                !localSearch
+                  ? apps.filter(({ isPinned }) => isPinned)
+                  : apps.filter(({ name }) =>
+                      new RegExp(localSearch, 'i').test(name)
+                    )
+              }
+              totalApps={apps.length}
+              searching={!!localSearch}
+            />
+          )}
+          <div className={classes.HomeSpace}></div>
+        </Fragment>
+      ) : (
+        <div></div>
+      )}
+
+      {searchConfig('hideCategories', 0) !== 1 ? (
+        <Fragment>
+          <SectionHeadline title="Bookmarks" link="/bookmarks" />
+          {categoriesLoading ? (
+            <Spinner />
+          ) : (
+            <BookmarkGrid
+              categories={categories.filter(
+                (category: Category) => category.isPinned
+              )}
+              totalCategories={categories.length}
+            />
+          )}
+        </Fragment>
+      ) : (
+        <div></div>
+      )}
+
+      <Link to="/settings" className={classes.SettingsButton}>
+        <Icon icon="mdiCog" color="var(--color-background)" />
       </Link>
     </Container>
-  )
-}
+  );
+};
 
 const mapStateToProps = (state: GlobalState) => {
   return {
     appsLoading: state.app.loading,
     apps: state.app.apps,
     categoriesLoading: state.bookmark.loading,
-    categories: state.bookmark.categories
-  }
-}
+    categories: state.bookmark.categories,
+  };
+};
 
-export default connect(mapStateToProps, { getApps, getCategories })(Home);
+export default connect(mapStateToProps, { getApps, getCategories })(Home);

+ 16 - 11
client/src/components/SearchBar/SearchBar.tsx

@@ -15,36 +15,41 @@ import { searchParser } from '../../utility';
 
 interface ComponentProps {
   createNotification: (notification: NewNotification) => void;
+  setLocalSearch: (query: string) => void;
 }
 
 const SearchBar = (props: ComponentProps): JSX.Element => {
+  const { setLocalSearch, createNotification } = props;
+
   const inputRef = useRef<HTMLInputElement>(document.createElement('input'));
 
   useEffect(() => {
     inputRef.current.focus();
-  }, [])
+  }, []);
 
   const searchHandler = (e: KeyboardEvent<HTMLInputElement>) => {
     if (e.code === 'Enter') {
-      const prefixFound = searchParser(inputRef.current.value);
+      const searchResult = searchParser(inputRef.current.value);
 
-      if (!prefixFound) {
-        props.createNotification({
+      if (!searchResult.prefix) {
+        createNotification({
           title: 'Error',
-          message: 'Prefix not found'
-        })
+          message: 'Prefix not found',
+        });
+      } else if (searchResult.isLocal) {
+        setLocalSearch(searchResult.query);
       }
     }
-  }
+  };
 
   return (
     <input
       ref={inputRef}
-      type='text'
+      type="text"
       className={classes.SearchBar}
       onKeyDown={(e) => searchHandler(e)}
     />
-  )
-}
+  );
+};
 
-export default connect(null, { createNotification })(SearchBar);
+export default connect(null, { createNotification })(SearchBar);

+ 77 - 75
client/src/components/Settings/OtherSettings/OtherSettings.tsx

@@ -6,7 +6,7 @@ import {
   createNotification,
   updateConfig,
   sortApps,
-  sortCategories
+  sortCategories,
 } from '../../../store/actions';
 
 // Typescript
@@ -14,7 +14,7 @@ import {
   GlobalState,
   NewNotification,
   Query,
-  SettingsForm
+  SettingsForm,
 } from '../../../interfaces';
 
 // UI
@@ -53,7 +53,7 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
     searchSameTab: 0,
     dockerApps: 1,
     kubernetesApps: 1,
-    unpinStoppedApps: 1
+    unpinStoppedApps: 1,
   });
 
   // Get config
@@ -73,7 +73,7 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
       searchSameTab: searchConfig('searchSameTab', 0),
       dockerApps: searchConfig('dockerApps', 0),
       kubernetesApps: searchConfig('kubernetesApps', 0),
-      unpinStoppedApps: searchConfig('unpinStoppedApps', 0)
+      unpinStoppedApps: searchConfig('unpinStoppedApps', 0),
     });
   }, [props.loading]);
 
@@ -105,115 +105,117 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
 
     setFormData({
       ...formData,
-      [e.target.name]: value
+      [e.target.name]: value,
     });
   };
 
   return (
-    <form onSubmit={e => formSubmitHandler(e)}>
+    <form onSubmit={(e) => formSubmitHandler(e)}>
       {/* OTHER OPTIONS */}
       <h2 className={classes.SettingsSection}>Miscellaneous</h2>
       <InputGroup>
-        <label htmlFor='customTitle'>Custom page title</label>
+        <label htmlFor="customTitle">Custom page title</label>
         <input
-          type='text'
-          id='customTitle'
-          name='customTitle'
-          placeholder='Flame'
+          type="text"
+          id="customTitle"
+          name="customTitle"
+          placeholder="Flame"
           value={formData.customTitle}
-          onChange={e => inputChangeHandler(e)}
+          onChange={(e) => inputChangeHandler(e)}
         />
       </InputGroup>
 
       {/* BEAHVIOR OPTIONS */}
       <h2 className={classes.SettingsSection}>App Behavior</h2>
       <InputGroup>
-        <label htmlFor='pinAppsByDefault'>
+        <label htmlFor="pinAppsByDefault">
           Pin new applications by default
         </label>
         <select
-          id='pinAppsByDefault'
-          name='pinAppsByDefault'
+          id="pinAppsByDefault"
+          name="pinAppsByDefault"
           value={formData.pinAppsByDefault}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
         </select>
       </InputGroup>
       <InputGroup>
-        <label htmlFor='pinCategoriesByDefault'>
+        <label htmlFor="pinCategoriesByDefault">
           Pin new categories by default
         </label>
         <select
-          id='pinCategoriesByDefault'
-          name='pinCategoriesByDefault'
+          id="pinCategoriesByDefault"
+          name="pinCategoriesByDefault"
           value={formData.pinCategoriesByDefault}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
         </select>
       </InputGroup>
       <InputGroup>
-        <label htmlFor='useOrdering'>Sorting type</label>
+        <label htmlFor="useOrdering">Sorting type</label>
         <select
-          id='useOrdering'
-          name='useOrdering'
+          id="useOrdering"
+          name="useOrdering"
           value={formData.useOrdering}
-          onChange={e => inputChangeHandler(e)}
+          onChange={(e) => inputChangeHandler(e)}
         >
-          <option value='createdAt'>By creation date</option>
-          <option value='name'>Alphabetical order</option>
-          <option value='orderId'>Custom order</option>
+          <option value="createdAt">By creation date</option>
+          <option value="name">Alphabetical order</option>
+          <option value="orderId">Custom order</option>
         </select>
       </InputGroup>
       <InputGroup>
-        <label htmlFor='defaultSearchProvider'>Default Search Provider</label>
+        <label htmlFor="defaultSearchProvider">Default Search Provider</label>
         <select
-          id='defaultSearchProvider'
-          name='defaultSearchProvider'
+          id="defaultSearchProvider"
+          name="defaultSearchProvider"
           value={formData.defaultSearchProvider}
-          onChange={e => inputChangeHandler(e)}
+          onChange={(e) => inputChangeHandler(e)}
         >
-          {queries.map((query: Query) => (
-            <option value={query.prefix}>{query.name}</option>
+          {queries.map((query: Query, idx) => (
+            <option key={idx} value={query.prefix}>
+              {query.name}
+            </option>
           ))}
         </select>
       </InputGroup>
       <InputGroup>
-        <label htmlFor='searchSameTab'>
+        <label htmlFor="searchSameTab">
           Open search results in the same tab
         </label>
         <select
-          id='searchSameTab'
-          name='searchSameTab'
+          id="searchSameTab"
+          name="searchSameTab"
           value={formData.searchSameTab}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
         </select>
       </InputGroup>
       <InputGroup>
-        <label htmlFor='appsSameTab'>Open applications in the same tab</label>
+        <label htmlFor="appsSameTab">Open applications in the same tab</label>
         <select
-          id='appsSameTab'
-          name='appsSameTab'
+          id="appsSameTab"
+          name="appsSameTab"
           value={formData.appsSameTab}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
         </select>
       </InputGroup>
       <InputGroup>
-        <label htmlFor='bookmarksSameTab'>Open bookmarks in the same tab</label>
+        <label htmlFor="bookmarksSameTab">Open bookmarks in the same tab</label>
         <select
-          id='bookmarksSameTab'
-          name='bookmarksSameTab'
+          id="bookmarksSameTab"
+          name="bookmarksSameTab"
           value={formData.bookmarksSameTab}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
@@ -223,48 +225,48 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
       {/* MODULES OPTIONS */}
       <h2 className={classes.SettingsSection}>Modules</h2>
       <InputGroup>
-        <label htmlFor='hideSearch'>Hide search bar</label>
+        <label htmlFor="hideSearch">Hide search bar</label>
         <select
-          id='hideSearch'
-          name='hideSearch'
+          id="hideSearch"
+          name="hideSearch"
           value={formData.hideSearch}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
         </select>
       </InputGroup>
       <InputGroup>
-        <label htmlFor='hideHeader'>Hide greeting and date</label>
+        <label htmlFor="hideHeader">Hide greeting and date</label>
         <select
-          id='hideHeader'
-          name='hideHeader'
+          id="hideHeader"
+          name="hideHeader"
           value={formData.hideHeader}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
         </select>
       </InputGroup>
       <InputGroup>
-        <label htmlFor='hideApps'>Hide applications</label>
+        <label htmlFor="hideApps">Hide applications</label>
         <select
-          id='hideApps'
-          name='hideApps'
+          id="hideApps"
+          name="hideApps"
           value={formData.hideApps}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
         </select>
       </InputGroup>
       <InputGroup>
-        <label htmlFor='hideCategories'>Hide categories</label>
+        <label htmlFor="hideCategories">Hide categories</label>
         <select
-          id='hideCategories'
-          name='hideCategories'
+          id="hideCategories"
+          name="hideCategories"
           value={formData.hideCategories}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
@@ -274,26 +276,26 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
       {/* DOCKER SETTINGS */}
       <h2 className={classes.SettingsSection}>Docker</h2>
       <InputGroup>
-        <label htmlFor='dockerApps'>Use Docker API</label>
+        <label htmlFor="dockerApps">Use Docker API</label>
         <select
-          id='dockerApps'
-          name='dockerApps'
+          id="dockerApps"
+          name="dockerApps"
           value={formData.dockerApps}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
         </select>
       </InputGroup>
       <InputGroup>
-        <label htmlFor='unpinStoppedApps'>
+        <label htmlFor="unpinStoppedApps">
           Unpin stopped containers / other apps
         </label>
         <select
-          id='unpinStoppedApps'
-          name='unpinStoppedApps'
+          id="unpinStoppedApps"
+          name="unpinStoppedApps"
           value={formData.unpinStoppedApps}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
@@ -303,12 +305,12 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
       {/* KUBERNETES SETTINGS */}
       <h2 className={classes.SettingsSection}>Kubernetes</h2>
       <InputGroup>
-        <label htmlFor='kubernetesApps'>Use Kubernetes Ingress API</label>
+        <label htmlFor="kubernetesApps">Use Kubernetes Ingress API</label>
         <select
-          id='kubernetesApps'
-          name='kubernetesApps'
+          id="kubernetesApps"
+          name="kubernetesApps"
           value={formData.kubernetesApps}
-          onChange={e => inputChangeHandler(e, true)}
+          onChange={(e) => inputChangeHandler(e, true)}
         >
           <option value={1}>True</option>
           <option value={0}>False</option>
@@ -321,7 +323,7 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
 
 const mapStateToProps = (state: GlobalState) => {
   return {
-    loading: state.config.loading
+    loading: state.config.loading,
   };
 };
 
@@ -329,7 +331,7 @@ const actions = {
   createNotification,
   updateConfig,
   sortApps,
-  sortCategories
+  sortCategories,
 };
 
 export default connect(mapStateToProps, actions)(OtherSettings);

+ 5 - 0
client/src/interfaces/SearchResult.ts

@@ -0,0 +1,5 @@
+export interface SearchResult {
+  isLocal: boolean;
+  prefix: null | string;
+  query: string;
+}

+ 2 - 1
client/src/interfaces/index.ts

@@ -8,4 +8,5 @@ export * from './Category';
 export * from './Notification';
 export * from './Config';
 export * from './Forms';
-export * from './Query';
+export * from './Query';
+export * from './SearchResult';

+ 30 - 11
client/src/utility/searchParser.ts

@@ -1,26 +1,45 @@
 import { queries } from './searchQueries.json';
-import { Query } from '../interfaces';
+import { Query, SearchResult } from '../interfaces';
 
 import { searchConfig } from '.';
 
-export const searchParser = (searchQuery: string): boolean => {
+export const searchParser = (searchQuery: string): SearchResult => {
+  const result: SearchResult = {
+    isLocal: false,
+    prefix: null,
+    query: '',
+  };
+
   const splitQuery = searchQuery.match(/^\/([a-z]+)[ ](.+)$/i);
-  const prefix = splitQuery ? splitQuery[1] : searchConfig('defaultSearchProvider', 'd');
-  const search = splitQuery ? encodeURIComponent(splitQuery[2]) : encodeURIComponent(searchQuery);
+
+  const prefix = splitQuery
+    ? splitQuery[1]
+    : searchConfig('defaultSearchProvider', 'l');
+
+  const search = splitQuery
+    ? encodeURIComponent(splitQuery[2])
+    : encodeURIComponent(searchQuery);
 
   const query = queries.find((q: Query) => q.prefix === prefix);
 
   if (query) {
-    const sameTab = searchConfig('searchSameTab', false);
+    result.prefix = query.prefix;
+    result.query = search;
 
-    if (sameTab) {
-      document.location.replace(`${query.template}${search}`);
+    if (prefix === 'l') {
+      result.isLocal = true;
     } else {
-      window.open(`${query.template}${search}`);
+      const sameTab = searchConfig('searchSameTab', false);
+
+      if (sameTab) {
+        document.location.replace(`${query.template}${search}`);
+      } else {
+        window.open(`${query.template}${search}`);
+      }
     }
 
-    return true;
+    return result;
   }
 
-  return false;
-}
+  return result;
+};

+ 5 - 0
client/src/utility/searchQueries.json

@@ -25,6 +25,11 @@
       "prefix": "im",
       "template": "https://www.imdb.com/find?q="
     },
+    {
+      "name": "Local search",
+      "prefix": "l",
+      "template": "#"
+    },
     {
       "name": "Reddit",
       "prefix": "r",

Plik diff jest za duży
+ 1 - 4510
package-lock.json


+ 7 - 7
package.json

@@ -5,13 +5,13 @@
   "main": "index.js",
   "scripts": {
     "start": "node server.js",
-    "init-server": "echo Instaling server dependencies && npm install && mkdir public && touch public/flame.css",
-    "init-client": "cd client && echo Instaling client dependencies && npm install",
-    "dev-init": "npm run init-server && npm run init-client",
-    "dev-server": "nodemon server.js",
-    "dev-client": "npm start --prefix client",
-    "dev": "concurrently \"npm run dev-server\" \"npm run dev-client\"",
-    "skaffold": "concurrently \"npm run init-client\" \"npm run dev-server\""
+    "init:server": "echo Instaling server dependencies && npm install && mkdir public && touch public/flame.css",
+    "init:client": "cd client && echo Instaling client dependencies && npm install",
+    "dev:init": "npm run init:server && npm run init:client",
+    "dev:server": "nodemon server.js",
+    "dev:client": "npm start --prefix client",
+    "dev": "concurrently \"npm run dev:server\" \"npm run dev:client\"",
+    "skaffold": "concurrently \"npm run init:client\" \"npm run dev:server\""
   },
   "author": "",
   "license": "ISC",

+ 10 - 10
utils/initConfig.js

@@ -9,27 +9,27 @@ const initConfig = async () => {
   const configPairs = await Config.findAll({
     where: {
       key: {
-        [Op.or]: config.map(pair => pair.key)
-      }
-    }
-  })
+        [Op.or]: config.map((pair) => pair.key),
+      },
+    },
+  });
 
   // Get key from each pair
   const configKeys = configPairs.map((pair) => pair.key);
 
   // Create missing pairs
-  config.forEach(async ({ key, value}) => {
+  config.forEach(async ({ key, value }) => {
     if (!configKeys.includes(key)) {
       await Config.create({
         key,
         value,
-        valueType: typeof value
-      })
+        valueType: typeof value,
+      });
     }
-  })
+  });
 
   logger.log('Initial config created');
   return;
-}
+};
 
-module.exports = initConfig;
+module.exports = initConfig;

+ 1 - 1
utils/initialConfig.json

@@ -62,7 +62,7 @@
     },
     {
       "key": "defaultSearchProvider",
-      "value": "d"
+      "value": "l"
     },
     {
       "key": "dockerApps",

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików