diff --git a/README.md b/README.md index dadb428..669b7b0 100644 --- a/README.md +++ b/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 diff --git a/client/src/components/Apps/AppGrid/AppGrid.tsx b/client/src/components/Apps/AppGrid/AppGrid.tsx index cacc19c..30d5c8c 100644 --- a/client/src/components/Apps/AppGrid/AppGrid.tsx +++ b/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 = (
{props.apps.map((app: App): JSX.Element => { - return + return ; })}
- ) + ); } else { if (props.totalApps) { - apps = ( -

There are no pinned applications. You can pin them from the /applications menu

- ); + if (props.searching) { + apps = ( +

+ No apps match your search criteria +

+ ); + } else { + apps = ( +

+ There are no pinned applications. You can pin them from the{' '} + /applications menu +

+ ); + } } else { apps = ( -

You don't have any applications. You can add a new one from /applications menu

+

+ You don't have any applications. You can add a new one from{' '} + /applications menu +

); } } return apps; -} +}; -export default AppGrid; \ No newline at end of file +export default AppGrid; diff --git a/client/src/components/Apps/Apps.tsx b/client/src/components/Apps/Apps.tsx index 88c3fff..751a196 100644 --- a/client/src/components/Apps/Apps.tsx +++ b/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 ( - {!isInUpdate - ? - : - } + {!isInUpdate ? ( + + ) : ( + + )} Go back)} + title="All Applications" + subtitle={Go back} /> - +
- - + +
- {loading - ? - : (!isInEdit - ? - : ) - } + {loading ? ( + + ) : !isInEdit ? ( + + ) : ( + + )}
- ) -} + ); +}; const mapStateToProps = (state: GlobalState) => { return { apps: state.app.apps, - loading: state.app.loading - } -} + loading: state.app.loading, + }; +}; -export default connect(mapStateToProps, { getApps })(Apps); \ No newline at end of file +export default connect(mapStateToProps, { getApps })(Apps); diff --git a/client/src/components/Home/Home.tsx b/client/src/components/Home/Home.tsx index ece4a8a..12097bf 100644 --- a/client/src/components/Home/Home.tsx +++ b/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); // 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 ( - {searchConfig('hideSearch', 0) !== 1 - ? - :
- } + {searchConfig('hideSearch', 0) !== 1 ? ( + + ) : ( +
+ )} - {searchConfig('hideHeader', 0) !== 1 - ? ( -
-

{header.dateTime}

- Go to Settings - -

{header.greeting}

- -
-
- ) - :
- } - - {searchConfig('hideApps', 0) !== 1 - ? ( - - {appsLoading - ? - : app.isPinned)} - totalApps={apps.length} - /> - } -
-
) - :
- } + {searchConfig('hideHeader', 0) !== 1 ? ( +
+

{header.dateTime}

+ + Go to Settings + + +

{header.greeting}

+ +
+
+ ) : ( +
+ )} - {searchConfig('hideCategories', 0) !== 1 - ? ( - - {categoriesLoading - ? - : category.isPinned)} - totalCategories={categories.length} - /> - } - ) - :
- } + {searchConfig('hideApps', 0) !== 1 ? ( + + + {appsLoading ? ( + + ) : ( + isPinned) + : apps.filter(({ name }) => + new RegExp(localSearch, 'i').test(name) + ) + } + totalApps={apps.length} + searching={!!localSearch} + /> + )} +
+
+ ) : ( +
+ )} - - + {searchConfig('hideCategories', 0) !== 1 ? ( + + + {categoriesLoading ? ( + + ) : ( + category.isPinned + )} + totalCategories={categories.length} + /> + )} + + ) : ( +
+ )} + + +
- ) -} + ); +}; 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); \ No newline at end of file +export default connect(mapStateToProps, { getApps, getCategories })(Home); diff --git a/client/src/components/SearchBar/SearchBar.tsx b/client/src/components/SearchBar/SearchBar.tsx index 029f175..0b5f3cc 100644 --- a/client/src/components/SearchBar/SearchBar.tsx +++ b/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(document.createElement('input')); useEffect(() => { inputRef.current.focus(); - }, []) + }, []); const searchHandler = (e: KeyboardEvent) => { 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 ( searchHandler(e)} /> - ) -} + ); +}; -export default connect(null, { createNotification })(SearchBar); \ No newline at end of file +export default connect(null, { createNotification })(SearchBar); diff --git a/client/src/components/Settings/OtherSettings/OtherSettings.tsx b/client/src/components/Settings/OtherSettings/OtherSettings.tsx index 31bbd52..afaf072 100644 --- a/client/src/components/Settings/OtherSettings/OtherSettings.tsx +++ b/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 ( -
formSubmitHandler(e)}> + formSubmitHandler(e)}> {/* OTHER OPTIONS */}

Miscellaneous

- + inputChangeHandler(e)} + onChange={(e) => inputChangeHandler(e)} /> {/* BEAHVIOR OPTIONS */}

App Behavior

- - - + - + - - + - + inputChangeHandler(e, true)} + onChange={(e) => inputChangeHandler(e, true)} > - + - + - + inputChangeHandler(e, true)} + onChange={(e) => inputChangeHandler(e, true)} > -