diff --git a/ui/src/pages/Applications.js b/ui/src/pages/Applications.js
deleted file mode 100644
index 393bafd..0000000
--- a/ui/src/pages/Applications.js
+++ /dev/null
@@ -1,184 +0,0 @@
-import React, {Component} from 'react';
-import Grid from 'material-ui/Grid';
-import Table, {TableBody, TableCell, TableHead, TableRow} from 'material-ui/Table';
-import Paper from 'material-ui/Paper';
-import Button from 'material-ui/Button';
-import IconButton from 'material-ui/IconButton';
-import Dialog, {DialogActions, DialogContent, DialogContentText, DialogTitle} from 'material-ui/Dialog';
-import TextField from 'material-ui/TextField';
-import Tooltip from 'material-ui/Tooltip';
-import AppStore from '../stores/AppStore';
-import ToggleVisibility from '../component/ToggleVisibility';
-import ConfirmDialog from '../component/ConfirmDialog';
-import * as AppAction from '../actions/AppAction';
-import DefaultPage from '../component/DefaultPage';
-import PropTypes from 'prop-types';
-import Delete from 'material-ui-icons/Delete';
-import Avatar from 'material-ui/Avatar';
-import Edit from 'material-ui-icons/Edit';
-
-class Applications extends Component {
- constructor() {
- super();
- this.uploadId = -1;
- this.state = {apps: [], createDialog: false, deleteId: -1};
- }
-
- componentWillMount() {
- AppStore.on('change', this.updateApps);
- this.updateApps();
- }
-
- componentWillUnmount() {
- AppStore.removeListener('change', this.updateApps);
- }
-
- updateApps = () => this.setState({...this.state, apps: AppStore.get()});
-
- uploadImage = (id) => {
- this.uploadId = id;
- this.upload.click();
- };
- onUploadImage = (e) => {
- const file = e.target.files[0];
- if (!file) {
- return;
- }
- if (['image/png', 'image/jpeg', 'image/gif'].indexOf(file['type']) !== -1) {
- AppAction.uploadImage(this.uploadId, file);
- } else {
- alert('Uploaded file must be of type png, jpeg or gif.');
- }
- };
-
- showCreateDialog = () => this.setState({...this.state, createDialog: true});
- hideCreateDialog = () => this.setState({...this.state, createDialog: false});
-
- showCloseDialog = (deleteId) => this.setState({...this.state, deleteId});
- hideCloseDialog = () => this.setState({...this.state, deleteId: -1});
-
- render() {
- const {apps, createDialog, deleteId} = this.state;
- return (
-
-
-
-
-
-
-
- Name
- Token
- Description
-
-
-
-
- {apps.map((app) => {
- return (
- this.uploadImage(app.id)}
- fDelete={() => this.showCloseDialog(app.id)}/>
- );
- })}
-
-
- this.upload = upload} type="file" style={{display: 'none'}}
- onChange={this.onUploadImage}/>
-
-
- {createDialog && }
- {deleteId !== -1 && AppAction.deleteApp(deleteId)}
- />}
-
- );
- }
-}
-
-class Row extends Component {
- static propTypes = {
- name: PropTypes.string.isRequired,
- value: PropTypes.string.isRequired,
- description: PropTypes.string.isRequired,
- fDelete: PropTypes.func.isRequired,
- fUpload: PropTypes.func.isRequired,
- image: PropTypes.string.isRequired,
- };
-
- render() {
- const {name, value, description, fDelete, fUpload, image} = this.props;
- return (
-
-
-
-
- {name}
-
-
-
- {description}
-
-
-
-
- );
- }
-}
-
-class AddDialog extends Component {
- static propTypes = {
- fClose: PropTypes.func.isRequired,
- fOnSubmit: PropTypes.func.isRequired,
- };
-
- constructor() {
- super();
- this.state = {name: '', description: ''};
- }
-
- handleChange(propertyName, event) {
- const state = this.state;
- state[propertyName] = event.target.value;
- this.setState(state);
- }
-
- render() {
- const {fClose, fOnSubmit} = this.props;
- const {name, description} = this.state;
- const submitEnabled = this.state.name.length !== 0;
- const submitAndClose = () => {
- fOnSubmit(name, description);
- fClose();
- };
- return (
-
- );
- }
-}
-
-export default Applications;
diff --git a/ui/src/pages/Applications.tsx b/ui/src/pages/Applications.tsx
new file mode 100644
index 0000000..632c7f5
--- /dev/null
+++ b/ui/src/pages/Applications.tsx
@@ -0,0 +1,131 @@
+import Delete from 'material-ui-icons/Delete';
+import Edit from 'material-ui-icons/Edit';
+import Avatar from 'material-ui/Avatar';
+import Grid from 'material-ui/Grid';
+import IconButton from 'material-ui/IconButton';
+import Paper from 'material-ui/Paper';
+import Table, {TableBody, TableCell, TableHead, TableRow} from 'material-ui/Table';
+import React, {ChangeEvent, Component, SFC} from 'react';
+import * as AppAction from '../actions/AppAction';
+import ConfirmDialog from '../component/ConfirmDialog';
+import DefaultPage from '../component/DefaultPage';
+import ToggleVisibility from '../component/ToggleVisibility';
+import AppStore from '../stores/AppStore';
+import AddApplicationDialog from './dialog/AddApplicationDialog';
+
+interface IState {
+ apps: IApplication[]
+ createDialog: boolean
+ deleteId: number
+}
+
+class Applications extends Component<{}, IState> {
+ public state = {apps: [], createDialog: false, deleteId: -1};
+ private uploadId: number = -1;
+ private upload: HTMLInputElement | null = null;
+
+ public componentWillMount() {
+ AppStore.on('change', this.updateApps);
+ this.updateApps();
+ }
+
+ public componentWillUnmount() {
+ AppStore.removeListener('change', this.updateApps);
+ }
+
+ public render() {
+ const {apps, createDialog, deleteId} = this.state;
+ return (
+
+
+
+
+
+
+
+ Name
+ Token
+ Description
+
+
+
+
+ {apps.map((app: IApplication) => {
+ return (
+ this.uploadImage(app.id)}
+ fDelete={() => this.showCloseDialog(app.id)}/>
+ );
+ })}
+
+
+ this.upload = upload} type="file" style={{display: 'none'}}
+ onChange={this.onUploadImage}/>
+
+
+ {createDialog && }
+ {deleteId !== -1 && AppAction.deleteApp(deleteId)}
+ />}
+
+ );
+ }
+
+ private updateApps = () => this.setState({...this.state, apps: AppStore.get()});
+ private uploadImage = (id: number) => {
+ this.uploadId = id;
+ if (this.upload) {
+ this.upload.click();
+ }
+ };
+
+ private onUploadImage = (e: ChangeEvent) => {
+ const file = e.target.files && e.target.files[0];
+ if (!file) {
+ return;
+ }
+ if (['image/png', 'image/jpeg', 'image/gif'].indexOf(file.type) !== -1) {
+ AppAction.uploadImage(this.uploadId, file);
+ } else {
+ alert('Uploaded file must be of type png, jpeg or gif.');
+ }
+ };
+ private showCreateDialog = () => this.setState({...this.state, createDialog: true});
+
+ private hideCreateDialog = () => this.setState({...this.state, createDialog: false});
+ private showCloseDialog = (deleteId: number) => this.setState({...this.state, deleteId});
+
+ private hideCloseDialog = () => this.setState({...this.state, deleteId: -1});
+}
+
+interface IRowProps {
+ name: string
+ value: string
+ description: string
+ fUpload: VoidFunction
+ image: string
+ fDelete: VoidFunction
+}
+
+const Row: SFC = ({name, value, description, fDelete, fUpload, image}) => (
+
+
+
+
+ {name}
+
+
+
+ {description}
+
+
+
+
+);
+
+export default Applications;
diff --git a/ui/src/pages/dialog/AddApplicationDialog.tsx b/ui/src/pages/dialog/AddApplicationDialog.tsx
new file mode 100644
index 0000000..7abddea
--- /dev/null
+++ b/ui/src/pages/dialog/AddApplicationDialog.tsx
@@ -0,0 +1,57 @@
+import Button from 'material-ui/Button';
+import Dialog, {DialogActions, DialogContent, DialogContentText, DialogTitle} from 'material-ui/Dialog';
+import TextField from 'material-ui/TextField';
+import Tooltip from 'material-ui/Tooltip';
+import React, {Component} from 'react';
+
+interface IProps {
+ fClose: VoidFunction
+ fOnSubmit: (name: string, description: string) => void
+}
+
+interface IState {
+ name: string
+ description: string
+}
+
+export default class AddDialog extends Component {
+ public state = {name: '', description: ''};
+
+ public render() {
+ const {fClose, fOnSubmit} = this.props;
+ const {name, description} = this.state;
+ const submitEnabled = this.state.name.length !== 0;
+ const submitAndClose = () => {
+ fOnSubmit(name, description);
+ fClose();
+ };
+ return (
+
+ );
+ }
+
+ private handleChange(propertyName: string, event: React.ChangeEvent) {
+ const state = this.state;
+ state[propertyName] = event.target.value;
+ this.setState(state);
+ }
+}
\ No newline at end of file