From 15719812520ffd90766b7aa413534cf9613e3580 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pawe=C5=82=20Malak?= <pawel999@icloud.com>
Date: Wed, 10 Nov 2021 16:45:30 +0100
Subject: [PATCH] Created separate settings for Docker

---
 .env                                          |   2 +-
 README.md                                     |   6 +-
 .../DockerSettings/DockerSettings.tsx         | 122 ++++++++++++++++++
 .../SearchSettings/SearchSettings.tsx         |   2 +
 client/src/components/Settings/Settings.tsx   |   6 +-
 .../UISettings.tsx}                           |  68 +---------
 .../WeatherSettings/WeatherSettings.tsx       |   2 +-
 client/src/components/Settings/settings.json  |   8 +-
 client/src/interfaces/Forms.ts                |  11 +-
 client/src/store/action-creators/config.ts    |   5 +-
 .../templateObjects/settingsTemplate.ts       |  18 ++-
 11 files changed, 167 insertions(+), 83 deletions(-)
 create mode 100644 client/src/components/Settings/DockerSettings/DockerSettings.tsx
 rename client/src/components/Settings/{OtherSettings/OtherSettings.tsx => UISettings/UISettings.tsx} (80%)

diff --git a/.env b/.env
index 6ead5e8..230ec44 100644
--- a/.env
+++ b/.env
@@ -1,5 +1,5 @@
 PORT=5005
 NODE_ENV=development
 VERSION=1.7.4
-PASSWORD=flame
+PASSWORD=flame_password
 SECRET=e02eb43d69953658c6d07311d6313f2d4467672cb881f96b29368ba1f3f4da4b
\ No newline at end of file
diff --git a/README.md b/README.md
index 2a30fa9..33e184e 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
 
 ## Description
 
-Flame is self-hosted startpage for your server. Its design is inspired (heavily) by [SUI](https://github.com/jeroenpardon/sui). Flame is very easy to setup and use. With built-in editors it allows you to setup your very own application hub in no time - no file editing necessary.
+Flame is self-hosted startpage for your server. Its design is inspired (heavily) by [SUI](https://github.com/jeroenpardon/sui). Flame is very easy to setup and use. With built-in editors, it allows you to setup your very own application hub in no time - no file editing necessary.
 
 ## Technology
 
@@ -151,7 +151,7 @@ labels:
 # - flame.icon=custom to make changes in app. ie: custom icon upload
 ```
 
-> "Use Docker API" option must be enabled for this to work. You can find it in Settings > Other > Docker section
+> "Use Docker API" option must be enabled for this to work. You can find it in Settings > Docker
 
 You can also set up different apps in the same label adding `;` between each one.
 
@@ -199,7 +199,7 @@ metadata:
   - flame.pawelmalak/icon=icon-name # optional, default is "kubernetes"
 ```
 
-> "Use Kubernetes Ingress API" option must be enabled for this to work. You can find it in Settings > Other > Kubernetes section
+> "Use Kubernetes Ingress API" option must be enabled for this to work. You can find it in Settings > Docker
 
 ### Import HTML Bookmarks (Experimental)
 
diff --git a/client/src/components/Settings/DockerSettings/DockerSettings.tsx b/client/src/components/Settings/DockerSettings/DockerSettings.tsx
new file mode 100644
index 0000000..54410d8
--- /dev/null
+++ b/client/src/components/Settings/DockerSettings/DockerSettings.tsx
@@ -0,0 +1,122 @@
+import { useState, useEffect, ChangeEvent, FormEvent } from 'react';
+
+// Redux
+import { useDispatch, useSelector } from 'react-redux';
+import { State } from '../../../store/reducers';
+import { bindActionCreators } from 'redux';
+import { actionCreators } from '../../../store';
+
+// Typescript
+import { DockerSettingsForm } from '../../../interfaces';
+
+// UI
+import { InputGroup, Button, SettingsHeadline } from '../../UI';
+
+// Utils
+import { inputHandler, dockerSettingsTemplate } from '../../../utility';
+
+export const DockerSettings = (): JSX.Element => {
+  const { loading, config } = useSelector((state: State) => state.config);
+
+  const dispatch = useDispatch();
+  const { updateConfig } = bindActionCreators(actionCreators, dispatch);
+
+  // Initial state
+  const [formData, setFormData] = useState<DockerSettingsForm>(
+    dockerSettingsTemplate
+  );
+
+  // Get config
+  useEffect(() => {
+    setFormData({
+      ...config,
+    });
+  }, [loading]);
+
+  // Form handler
+  const formSubmitHandler = async (e: FormEvent) => {
+    e.preventDefault();
+
+    // Save settings
+    await updateConfig(formData);
+  };
+
+  // Input handler
+  const inputChangeHandler = (
+    e: ChangeEvent<HTMLInputElement | HTMLSelectElement>,
+    options?: { isNumber?: boolean; isBool?: boolean }
+  ) => {
+    inputHandler<DockerSettingsForm>({
+      e,
+      options,
+      setStateHandler: setFormData,
+      state: formData,
+    });
+  };
+
+  return (
+    <form onSubmit={(e) => formSubmitHandler(e)}>
+      <SettingsHeadline text="Docker" />
+      {/* CUSTOM DOCKER SOCKET HOST */}
+      <InputGroup>
+        <label htmlFor="dockerHost">Docker Host</label>
+        <input
+          type="text"
+          id="dockerHost"
+          name="dockerHost"
+          placeholder="dockerHost:port"
+          value={formData.dockerHost}
+          onChange={(e) => inputChangeHandler(e)}
+        />
+      </InputGroup>
+
+      {/* USE DOCKER API */}
+      <InputGroup>
+        <label htmlFor="dockerApps">Use Docker API</label>
+        <select
+          id="dockerApps"
+          name="dockerApps"
+          value={formData.dockerApps ? 1 : 0}
+          onChange={(e) => inputChangeHandler(e, { isBool: true })}
+        >
+          <option value={1}>True</option>
+          <option value={0}>False</option>
+        </select>
+      </InputGroup>
+
+      {/* UNPIN DOCKER APPS */}
+      <InputGroup>
+        <label htmlFor="unpinStoppedApps">
+          Unpin stopped containers / other apps
+        </label>
+        <select
+          id="unpinStoppedApps"
+          name="unpinStoppedApps"
+          value={formData.unpinStoppedApps ? 1 : 0}
+          onChange={(e) => inputChangeHandler(e, { isBool: true })}
+        >
+          <option value={1}>True</option>
+          <option value={0}>False</option>
+        </select>
+      </InputGroup>
+
+      {/* KUBERNETES SETTINGS */}
+      <SettingsHeadline text="Kubernetes" />
+      {/* USE KUBERNETES */}
+      <InputGroup>
+        <label htmlFor="kubernetesApps">Use Kubernetes Ingress API</label>
+        <select
+          id="kubernetesApps"
+          name="kubernetesApps"
+          value={formData.kubernetesApps ? 1 : 0}
+          onChange={(e) => inputChangeHandler(e, { isBool: true })}
+        >
+          <option value={1}>True</option>
+          <option value={0}>False</option>
+        </select>
+      </InputGroup>
+
+      <Button>Save changes</Button>
+    </form>
+  );
+};
diff --git a/client/src/components/Settings/SearchSettings/SearchSettings.tsx b/client/src/components/Settings/SearchSettings/SearchSettings.tsx
index 2717b43..1a931df 100644
--- a/client/src/components/Settings/SearchSettings/SearchSettings.tsx
+++ b/client/src/components/Settings/SearchSettings/SearchSettings.tsx
@@ -16,6 +16,8 @@ import { inputHandler, searchSettingsTemplate } from '../../../utility';
 
 // Data
 import { queries } from '../../../utility/searchQueries.json';
+
+// Redux
 import { State } from '../../../store/reducers';
 import { bindActionCreators } from 'redux';
 import { actionCreators } from '../../../store';
diff --git a/client/src/components/Settings/Settings.tsx b/client/src/components/Settings/Settings.tsx
index 0c53693..d506b4e 100644
--- a/client/src/components/Settings/Settings.tsx
+++ b/client/src/components/Settings/Settings.tsx
@@ -9,10 +9,11 @@ import classes from './Settings.module.css';
 // Components
 import { Themer } from '../Themer/Themer';
 import { WeatherSettings } from './WeatherSettings/WeatherSettings';
-import { OtherSettings } from './OtherSettings/OtherSettings';
+import { UISettings } from './UISettings/UISettings';
 import { AppDetails } from './AppDetails/AppDetails';
 import { StyleSettings } from './StyleSettings/StyleSettings';
 import { SearchSettings } from './SearchSettings/SearchSettings';
+import { DockerSettings } from './DockerSettings/DockerSettings';
 
 // UI
 import { Container, Headline } from '../UI';
@@ -46,7 +47,8 @@ export const Settings = (): JSX.Element => {
             <Route exact path="/settings" component={Themer} />
             <Route path="/settings/weather" component={WeatherSettings} />
             <Route path="/settings/search" component={SearchSettings} />
-            <Route path="/settings/other" component={OtherSettings} />
+            <Route path="/settings/interface" component={UISettings} />
+            <Route path="/settings/docker" component={DockerSettings} />
             <Route path="/settings/css" component={StyleSettings} />
             <Route path="/settings/app" component={AppDetails} />
           </Switch>
diff --git a/client/src/components/Settings/OtherSettings/OtherSettings.tsx b/client/src/components/Settings/UISettings/UISettings.tsx
similarity index 80%
rename from client/src/components/Settings/OtherSettings/OtherSettings.tsx
rename to client/src/components/Settings/UISettings/UISettings.tsx
index 85b9f06..78d8b14 100644
--- a/client/src/components/Settings/OtherSettings/OtherSettings.tsx
+++ b/client/src/components/Settings/UISettings/UISettings.tsx
@@ -2,6 +2,9 @@ import { useState, useEffect, ChangeEvent, FormEvent } from 'react';
 
 // Redux
 import { useDispatch, useSelector } from 'react-redux';
+import { State } from '../../../store/reducers';
+import { bindActionCreators } from 'redux';
+import { actionCreators } from '../../../store';
 
 // Typescript
 import { OtherSettingsForm } from '../../../interfaces';
@@ -11,11 +14,8 @@ import { InputGroup, Button, SettingsHeadline } from '../../UI';
 
 // Utils
 import { otherSettingsTemplate, inputHandler } from '../../../utility';
-import { State } from '../../../store/reducers';
-import { bindActionCreators } from 'redux';
-import { actionCreators } from '../../../store';
 
-export const OtherSettings = (): JSX.Element => {
+export const UISettings = (): JSX.Element => {
   const { loading, config } = useSelector((state: State) => state.config);
 
   const dispatch = useDispatch();
@@ -277,66 +277,6 @@ export const OtherSettings = (): JSX.Element => {
         </select>
       </InputGroup>
 
-      {/* DOCKER SETTINGS */}
-      <SettingsHeadline text="Docker" />
-      {/* CUSTOM DOCKER SOCKET HOST */}
-      <InputGroup>
-        <label htmlFor="dockerHost">Docker Host</label>
-        <input
-          type="text"
-          id="dockerHost"
-          name="dockerHost"
-          placeholder="dockerHost:port"
-          value={formData.dockerHost}
-          onChange={(e) => inputChangeHandler(e)}
-        />
-      </InputGroup>
-
-      {/* USE DOCKER API */}
-      <InputGroup>
-        <label htmlFor="dockerApps">Use Docker API</label>
-        <select
-          id="dockerApps"
-          name="dockerApps"
-          value={formData.dockerApps ? 1 : 0}
-          onChange={(e) => inputChangeHandler(e, { isBool: true })}
-        >
-          <option value={1}>True</option>
-          <option value={0}>False</option>
-        </select>
-      </InputGroup>
-
-      {/* UNPIN DOCKER APPS */}
-      <InputGroup>
-        <label htmlFor="unpinStoppedApps">
-          Unpin stopped containers / other apps
-        </label>
-        <select
-          id="unpinStoppedApps"
-          name="unpinStoppedApps"
-          value={formData.unpinStoppedApps ? 1 : 0}
-          onChange={(e) => inputChangeHandler(e, { isBool: true })}
-        >
-          <option value={1}>True</option>
-          <option value={0}>False</option>
-        </select>
-      </InputGroup>
-
-      {/* KUBERNETES SETTINGS */}
-      <SettingsHeadline text="Kubernetes" />
-      {/* USE KUBERNETES */}
-      <InputGroup>
-        <label htmlFor="kubernetesApps">Use Kubernetes Ingress API</label>
-        <select
-          id="kubernetesApps"
-          name="kubernetesApps"
-          value={formData.kubernetesApps ? 1 : 0}
-          onChange={(e) => inputChangeHandler(e, { isBool: true })}
-        >
-          <option value={1}>True</option>
-          <option value={0}>False</option>
-        </select>
-      </InputGroup>
       <Button>Save changes</Button>
     </form>
   );
diff --git a/client/src/components/Settings/WeatherSettings/WeatherSettings.tsx b/client/src/components/Settings/WeatherSettings/WeatherSettings.tsx
index d4af837..c587517 100644
--- a/client/src/components/Settings/WeatherSettings/WeatherSettings.tsx
+++ b/client/src/components/Settings/WeatherSettings/WeatherSettings.tsx
@@ -5,6 +5,7 @@ import axios from 'axios';
 import { useDispatch, useSelector } from 'react-redux';
 import { bindActionCreators } from 'redux';
 import { actionCreators } from '../../../store';
+import { State } from '../../../store/reducers';
 
 // Typescript
 import { ApiResponse, Weather, WeatherForm } from '../../../interfaces';
@@ -14,7 +15,6 @@ import { InputGroup, Button } from '../../UI';
 
 // Utils
 import { inputHandler, weatherSettingsTemplate } from '../../../utility';
-import { State } from '../../../store/reducers';
 
 export const WeatherSettings = (): JSX.Element => {
   const { loading, config } = useSelector((state: State) => state.config);
diff --git a/client/src/components/Settings/settings.json b/client/src/components/Settings/settings.json
index 3cc24e9..5c3acc1 100644
--- a/client/src/components/Settings/settings.json
+++ b/client/src/components/Settings/settings.json
@@ -13,8 +13,12 @@
       "dest": "/settings/search"
     },
     {
-      "name": "Other",
-      "dest": "/settings/other"
+      "name": "Interface",
+      "dest": "/settings/interface"
+    },
+    {
+      "name": "Docker",
+      "dest": "/settings/docker"
     },
     {
       "name": "CSS",
diff --git a/client/src/interfaces/Forms.ts b/client/src/interfaces/Forms.ts
index 66f4136..7272f21 100644
--- a/client/src/interfaces/Forms.ts
+++ b/client/src/interfaces/Forms.ts
@@ -22,13 +22,16 @@ export interface OtherSettingsForm {
   useOrdering: string;
   appsSameTab: boolean;
   bookmarksSameTab: boolean;
-  dockerApps: boolean;
-  dockerHost: string;
-  kubernetesApps: boolean;
-  unpinStoppedApps: boolean;
   useAmericanDate: boolean;
   greetingsSchema: string;
   daySchema: string;
   monthSchema: string;
   showTime: boolean;
 }
+
+export interface DockerSettingsForm {
+  dockerApps: boolean;
+  dockerHost: string;
+  kubernetesApps: boolean;
+  unpinStoppedApps: boolean;
+}
diff --git a/client/src/store/action-creators/config.ts b/client/src/store/action-creators/config.ts
index 7522ec8..d81a2a2 100644
--- a/client/src/store/action-creators/config.ts
+++ b/client/src/store/action-creators/config.ts
@@ -11,6 +11,7 @@ import axios from 'axios';
 import {
   ApiResponse,
   Config,
+  DockerSettingsForm,
   OtherSettingsForm,
   Query,
   SearchForm,
@@ -49,7 +50,9 @@ export const getConfig = () => async (dispatch: Dispatch<GetConfigAction>) => {
 };
 
 export const updateConfig =
-  (formData: WeatherForm | OtherSettingsForm | SearchForm) =>
+  (
+    formData: WeatherForm | OtherSettingsForm | SearchForm | DockerSettingsForm
+  ) =>
   async (dispatch: Dispatch<UpdateConfigAction>) => {
     try {
       const res = await axios.put<ApiResponse<Config>>('/api/config', formData);
diff --git a/client/src/utility/templateObjects/settingsTemplate.ts b/client/src/utility/templateObjects/settingsTemplate.ts
index 981ffba..f175318 100644
--- a/client/src/utility/templateObjects/settingsTemplate.ts
+++ b/client/src/utility/templateObjects/settingsTemplate.ts
@@ -1,4 +1,9 @@
-import { OtherSettingsForm, SearchForm, WeatherForm } from '../../interfaces';
+import {
+  DockerSettingsForm,
+  OtherSettingsForm,
+  SearchForm,
+  WeatherForm,
+} from '../../interfaces';
 
 export const otherSettingsTemplate: OtherSettingsForm = {
   customTitle: document.title,
@@ -10,10 +15,6 @@ export const otherSettingsTemplate: OtherSettingsForm = {
   useOrdering: 'createdAt',
   appsSameTab: false,
   bookmarksSameTab: false,
-  dockerApps: true,
-  dockerHost: 'localhost',
-  kubernetesApps: true,
-  unpinStoppedApps: true,
   useAmericanDate: false,
   greetingsSchema: 'Good evening!;Good afternoon!;Good morning!;Good night!',
   daySchema: 'Sunday;Monday;Tuesday;Wednesday;Thursday;Friday;Saturday',
@@ -35,3 +36,10 @@ export const searchSettingsTemplate: SearchForm = {
   defaultSearchProvider: 'l',
   disableAutofocus: false,
 };
+
+export const dockerSettingsTemplate: DockerSettingsForm = {
+  dockerApps: true,
+  dockerHost: 'localhost',
+  kubernetesApps: true,
+  unpinStoppedApps: true,
+};