Skip to content

Commit

Permalink
Docker settings page (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
oznu authored Mar 22, 2018
1 parent 096b603 commit aaaced8
Show file tree
Hide file tree
Showing 13 changed files with 289 additions and 9 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

All notable changes to this project will be documented in this file. This project uses [Semantic Versioning](https://semver.org/).

## Next
## 3.4.0

### Notable Changes

* Added Docker Settings page where users can adjust the following:
* Toggle Homebridge Insecure / Debug Mode
* UI Theme Color
* UI Auth Mode (Form, Basic, None)
* Added the ability to set the path to the temp file using `HOMEBRIDGE_CONFIG_UI_TEMP` when running in Docker ([#62](https://github.com/oznu/homebridge-config-ui-x/issues/62))

### Bug Fixes

Expand Down
1 change: 1 addition & 0 deletions bin/standalone.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const config = {
restart: process.env.HOMEBRIDGE_CONFIG_UI_RESTART || 'killall -9 homebridge && killall -9 homebridge-config-ui-x',
theme: process.env.HOMEBRIDGE_CONFIG_UI_THEME || 'red',
auth: process.env.HOMEBRIDGE_CONFIG_UI_AUTH || 'form',
temp: process.env.HOMEBRIDGE_CONFIG_UI_TEMP || undefined,
homebridgeNpmPkg: process.env.HOMEBRIDGE_CONFIG_UI_NPM_PKG || 'homebridge',
homebridgeFork: process.env.HOMEBRIDGE_CONFIG_UI_FORK || undefined,
homebridgeInsecure: (process.env.HOMEBRIDGE_INSECURE === "1")
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "homebridge-config-ui-x",
"version": "3.3.2-1",
"version": "3.4.0",
"description": "Configuration UI plugin for Homebridge",
"license": "MIT",
"keywords": [
Expand Down Expand Up @@ -37,6 +37,7 @@
"buffer-shims": "^1.0.0",
"commander": "^2.15.0",
"cors": "^2.8.4",
"dotenv": "^5.0.1",
"express": "^4.16.3",
"fs-extra": "^5.0.0",
"jsonwebtoken": "^8.2.0",
Expand Down
62 changes: 58 additions & 4 deletions src/routes/platform-tools/docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,44 @@
import * as path from 'path';
import * as fs from 'fs-extra';
import * as child_process from 'child_process';
import * as dotenv from 'dotenv';
import { Router, Request, Response, NextFunction } from 'express';

import { hb } from '../../hb';
import { users } from '../../users';

export class DockerRouter {
public router: Router;
private startupScriptPath: string;
private dockerEnvPath: string;

private dockerEnvVariables = [
'HOMEBRIDGE_DEBUG',
'HOMEBRIDGE_INSECURE',
'HOMEBRIDGE_CONFIG_UI_THEME',
'HOMEBRIDGE_CONFIG_UI_AUTH'
];

constructor() {
this.router = Router();

this.router.get('/startup-script', users.ensureAdmin, this.getStartupScript);
this.router.post('/startup-script', users.ensureAdmin, this.saveStartupScript);
this.router.get('/startup-script', users.ensureAdmin, this.getStartupScript.bind(this));
this.router.post('/startup-script', users.ensureAdmin, this.saveStartupScript.bind(this));
this.router.get('/env', users.ensureAdmin, this.getDockerEnv.bind(this));
this.router.put('/env', users.ensureAdmin, this.saveDockerEnv.bind(this));
this.router.put('/restart-container', users.ensureAdmin, this.restartContainer);

this.dockerEnvPath = path.resolve(hb.storagePath, '.docker.env');
this.startupScriptPath = path.resolve(hb.storagePath, 'startup.sh');
}

getStartupScript(req: Request, res: Response, next: NextFunction) {
res.header({'content-type': 'text/plain'});
return res.sendFile(path.resolve(hb.storagePath, 'startup.sh'));
return res.sendFile(this.startupScriptPath);
}

saveStartupScript(req: Request, res: Response, next: NextFunction) {
return fs.writeFile(path.resolve(hb.storagePath, 'startup.sh'), req.body.script)
return fs.writeFile(this.startupScriptPath, req.body.script)
.then(() => {
hb.log('Updated startup.sh script');
return res.status(202).json({ok: true});
Expand All @@ -41,4 +56,43 @@ export class DockerRouter {
child_process.exec('killall s6-svscan');
}, 100);
}

async getDockerEnv(req: Request, res: Response, next: NextFunction) {
if (!fs.existsSync(this.dockerEnvPath)) {
return res.sendStatus(404);
}

const resp: any = {};
const file = await fs.readFile(this.dockerEnvPath);
const env = dotenv.parse(file);

this.dockerEnvVariables.forEach((key) => {
resp[key] = env[key] || process.env[key] || undefined;
if (resp[key] === '1') {
resp[key] = true;
} else if (resp[key] === '0') {
resp[key] = false;
}
});

return res.json(resp);
}

async saveDockerEnv(req: Request, res: Response, next: NextFunction) {
const resp = ['### This will overide environment variables set using the docker run command ###'];

this.dockerEnvVariables.forEach((key) => {
if (req.body[key] !== undefined) {
if (typeof (req.body[key]) === 'boolean') {
req.body[key] = req.body[key] ? '1' : '0';
}

resp.push(`${key}="${String(req.body[key])}"`);
}
});

resp.push('### This file is managed by homebridge-config-ui-x ###');
await fs.writeFile(this.dockerEnvPath, resp.join('\n') + '\n');
res.json({ok: true});
}
}
8 changes: 8 additions & 0 deletions ui/src/app/_services/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ export class ApiService {
return this.$http.put(`${this.base}/api/docker/restart-container`, {}, this.httpOptions);
}

dockerGetEnv() {
return this.$http.get(`${this.base}/api/docker/env`, this.httpOptions);
}

dockerSaveEnv(payload) {
return this.$http.put(`${this.base}/api/docker/env`, payload, this.httpOptions);
}

linuxRestartServer() {
return this.$http.put(`${this.base}/api/linux/restart-server`, {}, this.httpOptions);
}
Expand Down
3 changes: 3 additions & 0 deletions ui/src/app/_services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ export class AuthService {
}

setTheme(theme: string) {
if (this.theme) {
window.document.querySelector('body').classList.remove(`config-ui-x-${this.theme}`);
}
this.theme = theme;
window.document.querySelector('body').classList.add(`config-ui-x-${this.theme}`);
}
Expand Down
1 change: 1 addition & 0 deletions ui/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
<a class="dropdown-item waves-effect waves-light" uiSref="docker.terminal">Terminal</a>
<a class="dropdown-item waves-effect waves-light" uiSref="docker.startup-script" >Startup Script</a>
<a class="dropdown-item waves-effect waves-light" uiSref="docker.restart-container">Restart Container</a>
<a class="dropdown-item waves-effect waves-light" uiSref="docker.settings">Settings</a>
</div>
</li>

Expand Down
10 changes: 8 additions & 2 deletions ui/src/app/platform-tools/docker/docker.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { UIRouterModule, StateDeclaration } from '@uirouter/angular';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
Expand All @@ -10,6 +11,7 @@ import { SpinnerModule } from '../../spinner/spinner.module';
import { TerminalComponent } from '../terminal/terminal.component';
import { StartupScriptEditorComponent, StartupScriptEditorStates } from './startup-script-editor/startup-script-editor.component';
import { RestartContainerComponent, RestartContainerState} from './restart-container/restart-container.component';
import { SettingsComponent, SettingsState } from './settings/settings.component';

export const AbstractState: StateDeclaration = {
name: 'docker',
Expand All @@ -36,6 +38,8 @@ export const TerminalState = {
@NgModule({
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
NgbModule,
AceEditorModule,
SpinnerModule,
Expand All @@ -44,13 +48,15 @@ export const TerminalState = {
AbstractState,
StartupScriptEditorStates,
RestartContainerState,
TerminalState
TerminalState,
SettingsState
]
})
],
declarations: [
StartupScriptEditorComponent,
RestartContainerComponent
RestartContainerComponent,
SettingsComponent
]
})
export class DockerToolsModule { }
64 changes: 64 additions & 0 deletions ui/src/app/platform-tools/docker/settings/settings.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<div class="d-flex justify-content-between">
<h3 class="primary-text m-0">Settings</h3>
<div class="text-right">
<button class="btn btn-primary waves-effect m-0" *ngIf="savedSettings" uiSref="docker.restart-container">Restart Required</button>
</div>
</div>


<div class="row mt-3">
<div class="col-md-12">
<div class="alert alert-warning" role="alert">
Changing these values will override the corresponding environment variables you may have set with the docker run command.
</div>
</div>
</div>

<form novalidate [formGroup]="form">

<h5 class="primary-text">Homebridge</h5>

<ul class="list-group">
<li class="list-group-item d-flex justify-content-between align-items-center">
Homebridge Debug Mode
<div class="material-switch pull-right">
<input id="homebridgeDebugMode" formControlName="HOMEBRIDGE_DEBUG" type="checkbox" />
<label for="homebridgeDebugMode" class="badge-primary"></label>
</div>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
Homebridge Insecure Mode
<div class="material-switch pull-right">
<input id="homebridgeInsecureMode" formControlName="HOMEBRIDGE_INSECURE" type="checkbox" />
<label for="homebridgeInsecureMode" class="badge-primary"></label>
</div>
</li>
</ul>

<h5 class="primary-text mt-4">Config UI X</h5>

<ul class="list-group">
<li class="list-group-item d-flex justify-content-between align-items-center">
Config UI X Theme
<select class="custom-select custom-select-sm w-25" formControlName="HOMEBRIDGE_CONFIG_UI_THEME">
<option value="blue">Blue</option>
<option value="blue-grey">Blue-grey</option>
<option value="green">Green</option>
<option value="indigo">Indigo</option>
<option value="orange">Orange</option>
<option value="pink">Pink</option>
<option value="purple">Purple</option>
<option value="red">Red</option>
</select>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>Config UI X UI Auth Mode</div>
<select class="custom-select custom-select-sm w-25" formControlName="HOMEBRIDGE_CONFIG_UI_AUTH">
<option value="form">Form</option>
<option value="basic">Basic</option>
<option value="none">None</option>
</select>
</li>
</ul>

</form>
44 changes: 44 additions & 0 deletions ui/src/app/platform-tools/docker/settings/settings.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
.material-switch > input[type="checkbox"] {
display: none;
}

.material-switch > label {
cursor: pointer;
height: 0px;
position: relative;
width: 40px;
}

.material-switch > label::before {
background: rgb(0, 0, 0);
box-shadow: inset 0px 0px 10px rgba(0, 0, 0, 0.5);
border-radius: 8px;
content: '';
height: 16px;
margin-top: -8px;
position:absolute;
opacity: 0.3;
transition: all 0.4s ease-in-out;
width: 40px;
}
.material-switch > label::after {
background: rgb(255, 255, 255);
border-radius: 16px;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
content: '';
height: 24px;
left: -4px;
margin-top: -8px;
position: absolute;
top: -4px;
transition: all 0.3s ease-in-out;
width: 24px;
}
.material-switch > input[type="checkbox"]:checked + label::before {
background: inherit;
opacity: 0.5;
}
.material-switch > input[type="checkbox"]:checked + label::after {
background: inherit;
left: 20px;
}
Loading

0 comments on commit aaaced8

Please sign in to comment.