diff --git a/net/web/src/Admin/Admin.jsx b/net/web/src/Admin/Admin.jsx
index 885f944b..5db13ab8 100644
--- a/net/web/src/Admin/Admin.jsx
+++ b/net/web/src/Admin/Admin.jsx
@@ -44,7 +44,7 @@ export function Admin() {
return (
-
+
)
}
diff --git a/net/web/src/Admin/Dashboard/Dashboard.jsx b/net/web/src/Admin/Dashboard/Dashboard.jsx
index 0be7d44e..82829e64 100644
--- a/net/web/src/Admin/Dashboard/Dashboard.jsx
+++ b/net/web/src/Admin/Dashboard/Dashboard.jsx
@@ -1,4 +1,45 @@
-export function Dashboard() {
- return (
DASHBOARD
);
+import { DashboardWrapper, SettingsButton, AddButton, SettingsLayout } from './Dashboard.styled';
+import { Button, Modal, Input, InputNumber, Space } from 'antd';
+import { SettingOutlined, UserAddOutlined } from '@ant-design/icons';
+import { useDashboard } from './useDashboard.hook';
+
+export function Dashboard({ password, config }) {
+
+ const { state, actions } = useDashboard(password, config);
+
+ return (
+
+
+
+
+
+
+ actions.onSaveSettings()} onCancel={() => actions.setShowSettings(false)}>
+
+
+
Federated Host:
+
actions.setHost(e.target.value)}
+ value={state.host} />
+
+
+
Account Storage (GB):
+
actions.setStorage(e)}
+ placeholder="0 for unrestricted" value={state.storage} />
+
+
+
+
+
+ );
}
diff --git a/net/web/src/Admin/Dashboard/Dashboard.styled.js b/net/web/src/Admin/Dashboard/Dashboard.styled.js
new file mode 100644
index 00000000..20aab109
--- /dev/null
+++ b/net/web/src/Admin/Dashboard/Dashboard.styled.js
@@ -0,0 +1,74 @@
+import { Button, Space } from 'antd';
+import styled from 'styled-components';
+
+export const DashboardWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+
+ .container {
+ background-color: #ffffff;
+ display: flex;
+ flex-direction: column;
+ padding: 16px;
+ border-radius: 4px;
+ max-width: 500px;
+ width: 50%;
+ }
+
+ .header {
+ color: #444444;
+ display: flex;
+ flex-direction: row;
+ font-size: 20px;
+ border-bottom: 1px solid #444444;
+ }
+
+ .label {
+ padding-right: 8px;
+ padding-left: 4px;
+ display: flex;
+ align-items: center;
+ }
+
+ .settings {
+ display: flex;
+ align-items: center;
+ }
+
+ .add {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ flex-grow: 1;
+ }
+`;
+
+export const AddButton = styled(Button)`
+ color: #1890ff;
+`;
+
+export const SettingsButton = styled(Button)`
+ color: #1890ff;
+`;
+
+export const SettingsLayout = styled(Space)`
+ width: 100%;
+
+ .host {
+ white-space: nowrap;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ }
+
+ .storage {
+ white-space: nowrap;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ }
+`;
diff --git a/net/web/src/Admin/Dashboard/useDashboard.hook.js b/net/web/src/Admin/Dashboard/useDashboard.hook.js
new file mode 100644
index 00000000..06908554
--- /dev/null
+++ b/net/web/src/Admin/Dashboard/useDashboard.hook.js
@@ -0,0 +1,54 @@
+import { useState, useEffect } from 'react';
+import { setNodeConfig } from 'api/setNodeConfig';
+
+export function useDashboard(password, config) {
+
+ const [state, setState] = useState({
+ host: "",
+ storage: null,
+ showSettings: false,
+ busy: false,
+ });
+
+ const updateState = (value) => {
+ setState((s) => ({ ...s, ...value }));
+ }
+
+ useEffect(() => {
+ let storage = config.accountStorage / 1073741824;
+ if (storage > 1) {
+ storage = Math.ceil(storage);
+ }
+ updateState({ host: config.domain, storage: storage });
+ }, []);
+
+ const actions = {
+ setHost: (value) => {
+ updateState({ host: value });
+ },
+ setStorage: (value) => {
+ updateState({ storage: value });
+ },
+ setShowSettings: (value) => {
+ updateState({ showSettings: value });
+ },
+ onSaveSettings: async () => {
+ if (!state.busy) {
+ updateState({ busy: true });
+ try {
+ await setNodeConfig(password,
+ { ...state.config, domain: state.host, accountStorage: state.storage * 1073741824 });
+ updateState({ showSettings: false });
+ }
+ catch(err) {
+ console.log(err);
+ window.alert(err);
+ }
+ updateState({ busy: false });
+ }
+ },
+ };
+
+ return { state, actions };
+}
+
diff --git a/net/web/src/Login/Login.styled.js b/net/web/src/Login/Login.styled.js
index 4750fdcc..a8a02f19 100644
--- a/net/web/src/Login/Login.styled.js
+++ b/net/web/src/Login/Login.styled.js
@@ -8,7 +8,7 @@ export const LoginWrapper = styled.div`
justify-content: center;
width: 100%;
height: 100%;
-\
+
.container {
background-color: #ffffff;
display: flex;
diff --git a/net/web/src/api/setNodeConfig.js b/net/web/src/api/setNodeConfig.js
new file mode 100644
index 00000000..880f9b83
--- /dev/null
+++ b/net/web/src/api/setNodeConfig.js
@@ -0,0 +1,11 @@
+import { checkResponse, fetchWithTimeout } from './fetchUtil';
+var base64 = require('base-64');
+
+export async function setNodeConfig(password, config) {
+ let body = JSON.stringify(config);
+ let headers = new Headers()
+ headers.append('Authorization', 'Basic ' + base64.encode("admin:" + password));
+ let settings = await fetchWithTimeout(`/admin/config`, { method: 'PUT', headers, body });
+ checkResponse(settings);
+}
+