diff --git a/src/components/Form/CodeEditor/CodeEditor.tsx b/src/components/Form/CodeEditor/CodeEditor.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..e0ad33d42c6ab8305d69c99c2e39fd112dd55867
--- /dev/null
+++ b/src/components/Form/CodeEditor/CodeEditor.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { highlight, languages } from 'prismjs';
+import { useController } from 'react-hook-form';
+import Editor from 'react-simple-code-editor';
+
+/* eslint-disable react/react-in-jsx-scope */
+export const CodeEditor = ({ control, name, required }: CodeEditorProps) => {
+  const {
+    field,
+    // fieldState: { invalid, isTouched, isDirty },
+    // formState: { touchedFields, dirtyFields },
+  } = useController({
+    name,
+    control,
+    rules: { required },
+    defaultValue: '',
+  });
+
+  return (
+    <>
+      <Editor
+        value={field.value}
+        onValueChange={field.onChange}
+        highlight={(value) => highlight(value, languages.js, 'yaml')}
+        preClassName="font-mono whitespace-normal font-light"
+        textareaClassName="font-mono overflow-auto font-light"
+        className="font-mono text-sm font-light"
+      />
+    </>
+  );
+};
+
+type CodeEditorProps = {
+  control: any;
+  name: string;
+  required?: boolean;
+};
diff --git a/src/components/Form/CodeEditor/index.ts b/src/components/Form/CodeEditor/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9f6648589e9fda8625b1ae948da0337d71bb8efa
--- /dev/null
+++ b/src/components/Form/CodeEditor/index.ts
@@ -0,0 +1 @@
+export { CodeEditor } from './CodeEditor';
diff --git a/src/components/Form/index.ts b/src/components/Form/index.ts
index 1fc764c889bf826e01b8169210b45fe9f51429cb..5276586281294c676e305d9e61c3f560a0574392 100644
--- a/src/components/Form/index.ts
+++ b/src/components/Form/index.ts
@@ -1,3 +1,4 @@
 export { Input } from './Input';
 export { Select } from './Select';
 export { Switch } from './Switch';
+export { CodeEditor } from './CodeEditor';
diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx
index 157b72896aea57e98df4683667a6346fa7dcbe1c..95f22567a3a0760f239c38ab0f8a03b6f1e8840c 100644
--- a/src/components/Table/Table.tsx
+++ b/src/components/Table/Table.tsx
@@ -166,7 +166,7 @@ export const Table = <T extends Record<string, unknown>>({
                       />
                     </svg>
                   </div>
-                  <p className="text-sm text-primary-600 mt-2">Loading users</p>
+                  <p className="text-sm text-primary-600 mt-2">Loading...</p>
                 </div>
               </td>
             </tr>
diff --git a/src/components/UserModal/consts.ts b/src/components/UserModal/consts.ts
index 7304a419c1f98dd2c6ebced01760f86fda475b81..3d36fc70744ef1f460f8484cabab9df95be2eee9 100644
--- a/src/components/UserModal/consts.ts
+++ b/src/components/UserModal/consts.ts
@@ -5,21 +5,25 @@ export const appAccessList = [
     name: 'wekan',
     image: '/assets/wekan.svg',
     label: 'Wekan',
+    defaultSubdomain: 'wekan.{domain}',
   },
   {
     name: 'wordpress',
     image: '/assets/wordpress.svg',
     label: 'Wordpress',
+    defaultSubdomain: 'www.{domain}',
   },
   {
     name: 'nextcloud',
     image: '/assets/nextcloud.svg',
     label: 'Nextcloud',
+    defaultSubdomain: 'files.{domain}',
   },
   {
     name: 'zulip',
     image: '/assets/zulip.svg',
     label: 'Zulip',
+    defaultSubdomain: 'zulip.{domain}',
   },
 ];
 
diff --git a/src/modules/apps/Apps.tsx b/src/modules/apps/Apps.tsx
index 74039a0f38cced7b3e0a7cc92aa5b465ad1c6cda..945146ab22b137330da67347a43642702c9161e3 100644
--- a/src/modules/apps/Apps.tsx
+++ b/src/modules/apps/Apps.tsx
@@ -2,6 +2,7 @@
 import React, { useState, useCallback, useMemo, useEffect } from 'react';
 import { useNavigate } from 'react-router';
 import { SearchIcon } from '@heroicons/react/solid';
+import { showToast, ToastType } from 'src/common/util/show-toast';
 import _, { debounce } from 'lodash';
 import { Table } from 'src/components';
 import { appAccessList } from 'src/components/UserModal/consts';
@@ -61,7 +62,16 @@ export const Apps: React.FC = () => {
         return (
           <div className="flex items-center">
             <div className={`flex-shrink-0 h-4 w-4 rounded-full bg-${getConstForStatus(status, 'colorClass')}`} />
-            <div className={`ml-2 text-sm text-${getConstForStatus(status, 'colorClass')}`}>{status}</div>
+            {status === AppStatus.Installing ? (
+              <div
+                className={`ml-2 cursor-pointer text-sm text-${getConstForStatus(status, 'colorClass')}`}
+                onClick={() => showToast('Installing an app can take up to 10 minutes.', ToastType.Success)}
+              >
+                {status}
+              </div>
+            ) : (
+              <div className={`ml-2 text-sm text-${getConstForStatus(status, 'colorClass')}`}>{status}</div>
+            )}
           </div>
         );
       },
@@ -147,7 +157,9 @@ export const Apps: React.FC = () => {
         </div>
       </div>
 
-      <AppInstallModal appSlug={appSlug} onClose={() => setInstallModalOpen(false)} open={installModalOpen} />
+      {installModalOpen && (
+        <AppInstallModal appSlug={appSlug} onClose={() => setInstallModalOpen(false)} open={installModalOpen} />
+      )}
     </div>
   );
 };
diff --git a/src/modules/apps/components/AppInstallModal/AppInstallModal.tsx b/src/modules/apps/components/AppInstallModal/AppInstallModal.tsx
index e69937ede9c7f6133f4e4c2a07415ca07ccdf199..4a2b925df9314c6269489f50f32ea5f8c942e227 100644
--- a/src/modules/apps/components/AppInstallModal/AppInstallModal.tsx
+++ b/src/modules/apps/components/AppInstallModal/AppInstallModal.tsx
@@ -1,36 +1,22 @@
 import React, { useEffect, useState } from 'react';
-import Editor from 'react-simple-code-editor';
-import { highlight, languages } from 'prismjs';
+import { useForm } from 'react-hook-form';
 import _ from 'lodash';
-import { useApps } from 'src/services/apps';
+import { AppForm, useApps } from 'src/services/apps';
 import { Modal, Tabs } from 'src/components';
+import { CodeEditor, Input } from 'src/components/Form';
+import { appAccessList } from 'src/components/UserModal/consts';
 import { AppInstallModalProps } from './types';
-
-const initialCode = `luck: except
-natural: still
-near: though
-search:
-  - feature
-  - - 1980732354.689713
-    - hour
-    - butter:
-        ordinary: 995901949.8974948
-        teeth: true
-        whole:
-          - -952367353
-          - - talk: -1773961379
-              temperature: false
-              oxygen: true
-              laugh:
-                flag:
-                  in: 2144751662
-                  hospital: -1544066384.1973226
-                  law: congress
-                  great: stomach`;
+import { initialAppForm, initialCode } from './consts';
 
 export const AppInstallModal = ({ open, onClose, appSlug }: AppInstallModalProps) => {
-  const [code, setCode] = useState(initialCode);
-  const { app, appLoading, loadApp } = useApps();
+  const [appName, setAppName] = useState('');
+  const { app, appLoading, installApp, loadApp, clearSelectedApp } = useApps();
+
+  const { control, reset, handleSubmit } = useForm<AppForm>({
+    defaultValues: initialAppForm,
+  });
+
+  const getDefaultSubdomain = () => _.get(_.find(appAccessList, ['name', appSlug]), 'defaultSubdomain', '');
 
   useEffect(() => {
     if (appSlug) {
@@ -39,9 +25,31 @@ export const AppInstallModal = ({ open, onClose, appSlug }: AppInstallModalProps
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [appSlug, open]);
 
+  useEffect(() => {
+    if (!_.isEmpty(app)) {
+      setAppName(app.name);
+      reset({ subdomain: getDefaultSubdomain(), configuration: initialCode });
+    }
+
+    return () => {
+      reset({ subdomain: getDefaultSubdomain(), configuration: initialCode });
+    };
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [app, reset, open]);
+
+  const handleClose = () => {
+    clearSelectedApp();
+    reset();
+    onClose();
+  };
+
   const handleSave = async () => {
-    _.noop();
-    // todo: implement
+    try {
+      await handleSubmit((data) => installApp(data))();
+    } catch (e: any) {
+      // Continue
+    }
+    handleClose();
   };
 
   const handleKeyPress = (e: any) => {
@@ -54,7 +62,7 @@ export const AppInstallModal = ({ open, onClose, appSlug }: AppInstallModalProps
     return (
       <div className="mt-6 grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-6">
         <div className="sm:col-span-3">
-          <input name="subdomain" placeholder="Subdomain" onKeyPress={handleKeyPress} required={false} />
+          <Input control={control} name="subdomain" label="Subdomain" onKeyPress={handleKeyPress} required={false} />
         </div>
       </div>
     );
@@ -65,40 +73,10 @@ export const AppInstallModal = ({ open, onClose, appSlug }: AppInstallModalProps
       <div>
         <div className="bg-gray-100 overflow-hidden rounded-lg">
           <div className="px-4 h-16 sm:px-6 bg-gray-200 flex items-center">
-            <span className="text-gray-600 text-lg leading-6 font-medium">Current Configuration</span>
+            <span className="text-gray-600 text-lg leading-6 font-medium">App Configuration</span>
           </div>
           <div className="px-4 py-5 sm:p-6 overflow-x-auto">
-            <Editor
-              value={code}
-              onValueChange={(value) => setCode(value)}
-              highlight={(value) => highlight(value, languages.js, 'yaml')}
-              preClassName="font-mono whitespace-normal font-light"
-              textareaClassName="font-mono overflow-auto font-light"
-              className="font-mono text-sm font-light"
-            />
-            <pre className="font-mono text-sm font-light">
-              {`luck: except
-natural: still
-near: though
-search:
-  - feature
-  - - 1980732354.689713
-    - hour
-    - butter:
-        ordinary: 995901949.8974948
-        teeth: true
-        whole:
-          - -952367353
-          - - talk: -1773961379
-              temperature: false
-              oxygen: true
-              laugh:
-                flag:
-                  in: 2144751662
-                  hospital: -1544066384.1973226
-                  law: congress
-                  great: stomach`}
-            </pre>
+            <CodeEditor control={control} name="configuration" />
           </div>
         </div>
       </div>
@@ -110,10 +88,6 @@ search:
     { name: 'Advanced Configuration', component: renderConfiguration() },
   ];
 
-  const handleClose = () => {
-    onClose();
-  };
-
   return (
     <>
       <Modal onClose={handleClose} open={open} onSave={handleSave} isLoading={appLoading} useCancelButton>
@@ -121,7 +95,7 @@ search:
           <div className="space-y-10 divide-y divide-gray-200">
             <div>
               <div>
-                <h3 className="text-lg leading-6 font-medium text-gray-900">Install app {_.get(app, 'name')}</h3>
+                <h3 className="text-lg leading-6 font-medium text-gray-900">Install app {appName}</h3>
               </div>
 
               <div className="px-4 py-5 sm:p-6">
diff --git a/src/modules/apps/components/AppInstallModal/consts.ts b/src/modules/apps/components/AppInstallModal/consts.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ee4b0b4682866a8763eb8dd5cfec1e8694824692
--- /dev/null
+++ b/src/modules/apps/components/AppInstallModal/consts.ts
@@ -0,0 +1,28 @@
+import { AppForm } from 'src/services/apps';
+
+export const initialCode = `luck: except
+natural: still
+near: though
+search:
+  - feature
+  - - 1980732354.689713
+    - hour
+    - butter:
+        ordinary: 995901949.8974948
+        teeth: true
+        whole:
+          - -952367353
+          - - talk: -1773961379
+              temperature: false
+              oxygen: true
+              laugh:
+                flag:
+                  in: 2144751662
+                  hospital: -1544066384.1973226
+                  law: congress
+                  great: stomach`;
+
+export const initialAppForm = {
+  subdomain: '',
+  configuration: initialCode,
+} as AppForm;
diff --git a/src/services/apps/hooks/use-apps.ts b/src/services/apps/hooks/use-apps.ts
index 135fb045217c541d65c184638b49de1d800186c2..9137f36d0cd3dc3a99ac3a2c6d7a26ae65049d59 100644
--- a/src/services/apps/hooks/use-apps.ts
+++ b/src/services/apps/hooks/use-apps.ts
@@ -1,5 +1,5 @@
 import { useDispatch, useSelector } from 'react-redux';
-import { fetchApps, fetchAppBySlug, updateAppBySlug, installAppBySlug } from '../redux';
+import { fetchApps, fetchAppBySlug, updateAppBySlug, installAppBySlug, clearCurrentApp } from '../redux';
 import { getCurrentApp, getAppLoading, getAppsLoading, getApps } from '../redux/selectors';
 
 export function useApps() {
@@ -25,6 +25,10 @@ export function useApps() {
     return dispatch(installAppBySlug(data));
   }
 
+  function clearSelectedApp() {
+    return dispatch(clearCurrentApp());
+  }
+
   return {
     apps,
     app,
@@ -34,5 +38,6 @@ export function useApps() {
     appLoading,
     appTableLoading,
     installApp,
+    clearSelectedApp,
   };
 }
diff --git a/src/services/apps/redux/actions.ts b/src/services/apps/redux/actions.ts
index 69c00ec3e550968bbdf3bd77d7b186d9abbdfaf0..47c365f2864cbfb510f781ae80c8973f64481dba 100644
--- a/src/services/apps/redux/actions.ts
+++ b/src/services/apps/redux/actions.ts
@@ -8,6 +8,7 @@ export enum AppActionTypes {
   FETCH_APP = 'apps/fetch_app',
   UPDATE_APP = 'apps/update_app',
   INSTALL_APP = 'apps/install_app',
+  CLEAR_APP = 'apps/clear_app',
   SET_APP_LOADING = 'apps/app_loading',
   SET_APPS_LOADING = 'apps/apps_loading',
 }
@@ -97,7 +98,7 @@ export const installAppBySlug = (app: any) => async (dispatch: Dispatch<any>) =>
   try {
     const { data } = await performApiCall({
       path: `/apps/${app.slug}/install`,
-      method: 'POST',
+      method: 'PATCH',
       body: transformInstallAppRequest(app),
     });
 
@@ -117,3 +118,10 @@ export const installAppBySlug = (app: any) => async (dispatch: Dispatch<any>) =>
 
   dispatch(setAppLoading(false));
 };
+
+export const clearCurrentApp = () => (dispatch: Dispatch<any>) => {
+  dispatch({
+    type: AppActionTypes.CLEAR_APP,
+    payload: {},
+  });
+};
diff --git a/src/services/apps/redux/reducers.ts b/src/services/apps/redux/reducers.ts
index 0258928d44d5cb88903974dd2067192e25189912..c978377777caba46f3e5528d1841c4c374011259 100644
--- a/src/services/apps/redux/reducers.ts
+++ b/src/services/apps/redux/reducers.ts
@@ -31,6 +31,11 @@ const appsReducer = (state: any = initialUsersState, action: any) => {
         ...state,
         currentApp: action.payload,
       };
+    case AppActionTypes.CLEAR_APP:
+      return {
+        ...state,
+        currentApp: {},
+      };
     default:
       return state;
   }
diff --git a/src/services/apps/transformations.ts b/src/services/apps/transformations.ts
index fd41caab382cf8c860addb29b5195fb2c3726181..0d66b28da62cabb628ce275d592569e52efd66e4 100644
--- a/src/services/apps/transformations.ts
+++ b/src/services/apps/transformations.ts
@@ -1,4 +1,4 @@
-import { App, AppStatus, FormApp } from './types';
+import { App, AppStatus, AppForm } from './types';
 
 const transformAppStatus = (status: string) => {
   switch (status) {
@@ -24,14 +24,15 @@ export const transformApp = (response: any): App => {
   };
 };
 
-export const transformAppRequest = (data: FormApp) => {
+export const transformAppRequest = (data: AppForm) => {
   return {
     automatic_updates: data.automaticUpdates,
   };
 };
 
-export const transformInstallAppRequest = (data: FormApp) => {
+export const transformInstallAppRequest = (data: AppForm) => {
   return {
     subdomain: data.subdomain,
+    configuration: data.configuration,
   };
 };
diff --git a/src/services/apps/types.ts b/src/services/apps/types.ts
index d93e1ca135a15d0bbc5eaade13b0944d89b8c53a..76a418f4374d9f5d086fd1c247cc365aef7f7eb3 100644
--- a/src/services/apps/types.ts
+++ b/src/services/apps/types.ts
@@ -7,7 +7,7 @@ export interface App {
   automaticUpdates: boolean;
 }
 
-export interface FormApp extends App {
+export interface AppForm extends App {
   configuration: string;
 }