diff --git a/app/script/components/App.tsx b/app/script/components/App.tsx index 75b70d6..4cf5524 100644 --- a/app/script/components/App.tsx +++ b/app/script/components/App.tsx @@ -1,22 +1,25 @@ -import "app/style/app.css"; -import "font-awesome/css/font-awesome.css"; -import {observer} from "mobx-react"; +import { observer } from "mobx-react"; import DevTools from "mobx-react-devtools"; import * as React from "react"; +import { Item } from "semantic-ui-react"; +import { DeviceView, MessagesView } from "."; +import { SprinklersDevice } from "../sprinklers"; +import { UiStore } from "../ui"; + +import "app/style/app.css"; +import "font-awesome/css/font-awesome.css"; import "semantic-ui-css/semantic.css"; -import {Item} from "semantic-ui-react"; -import {DeviceView, MessagesView} from "."; -import {SprinklersDevice} from "../sprinklers"; -import {UiStore} from "../ui"; @observer -export default class App extends React.PureComponent<{ device: SprinklersDevice, uiStore: UiStore }, any> { +export default class App extends React.Component<{ device: SprinklersDevice, uiStore: UiStore }> { render() { - return - - - - ; + return ( + + + + + + ); } } diff --git a/app/script/components/DeviceView.tsx b/app/script/components/DeviceView.tsx index 2671709..cf6caa6 100644 --- a/app/script/components/DeviceView.tsx +++ b/app/script/components/DeviceView.tsx @@ -7,19 +7,22 @@ import { ProgramTable, RunSectionForm, SectionRunnerView, SectionTable } from ". import { SprinklersDevice } from "../sprinklers"; import FontAwesome = require("react-fontawesome"); -const ConnectionState = ({ connected }: { connected: boolean }) => - { + const classes = classNames({ "device--connectionState": true, "device--connectionState-connected": connected, "device--connectionState-disconnected": !connected, - })}> - -   - {connected ? "Connected" : "Disconnected"} - ; + }); + return ( + +   + {connected ? "Connected" : "Disconnected"} + + ); +}; @observer -export default class DeviceView extends React.PureComponent<{ device: SprinklersDevice }, {}> { +export default class DeviceView extends React.Component<{ device: SprinklersDevice }> { render() { const { id, connected, sections, programs, sectionRunner } = this.props.device; return ( @@ -31,7 +34,7 @@ export default class DeviceView extends React.PureComponent<{ device: Sprinklers - + Raspberry Pi Grinklers Instance diff --git a/app/script/components/MessagesView.tsx b/app/script/components/MessagesView.tsx index 3cd0c56..84e2c4f 100644 --- a/app/script/components/MessagesView.tsx +++ b/app/script/components/MessagesView.tsx @@ -1,30 +1,47 @@ -import {observer} from "mobx-react"; +import { observer } from "mobx-react"; import * as React from "react"; -import {CSSTransitionGroup} from "react-transition-group"; -import {Message} from "semantic-ui-react"; -import {Message as UiMessage, UiStore} from "../ui"; +import { Message, MessageList, TransitionGroup } from "semantic-ui-react"; +import { Message as UiMessage, UiStore } from "../ui"; + +class MessageView extends React.Component<{ + uiStore: UiStore, + message: UiMessage, + index: number, +}> { -@observer -export default class MessagesView extends React.PureComponent<{ uiStore: UiStore }, {}> { render() { - return
- - {this.props.uiStore.messages.map(this.renderMessage)} - -
; + const { id, header, content, type } = this.props.message; + return ( + + ); } - private renderMessage = (message: UiMessage, index: number) => { - const {header, content, type} = message; - return this.dismiss(index)}/>; + private dismiss = () => { + const { uiStore, index } = this.props; + uiStore.messages.splice(index, 1); } +} - private dismiss(index: number) { - this.props.uiStore.messages.splice(index, 1); +@observer +export default class MessagesView extends React.Component<{ uiStore: UiStore }> { + render() { + const messages = this.props.uiStore.messages.map((message, index) => ( + + )); + return ( +
+ + {messages} + +
+ ); } } diff --git a/app/script/components/ProgramTable.tsx b/app/script/components/ProgramTable.tsx index 2f867d9..604f507 100644 --- a/app/script/components/ProgramTable.tsx +++ b/app/script/components/ProgramTable.tsx @@ -1,10 +1,10 @@ -import {observer} from "mobx-react"; +import { observer } from "mobx-react"; import * as React from "react"; -import {Table} from "semantic-ui-react"; -import {Program, Schedule} from "../sprinklers"; +import { Table } from "semantic-ui-react"; +import { Program, Schedule } from "../sprinklers"; @observer -export class ScheduleView extends React.PureComponent<{ schedule: Schedule }, {}> { +export class ScheduleView extends React.Component<{ schedule: Schedule }> { render() { return (
{JSON.stringify(this.props.schedule)}
@@ -13,35 +13,39 @@ export class ScheduleView extends React.PureComponent<{ schedule: Schedule }, {} } @observer -export default class ProgramTable extends React.PureComponent<{ programs: Program[] }, {}> { +export default class ProgramTable extends React.Component<{ programs: Program[] }> { private static renderRows(program: Program, i: number): JSX.Element[] | null { if (!program) { return null; } - const {name, running, enabled, schedule, sequence} = program; - return [ + const { name, running, enabled, schedule, sequence } = program; + const sequenceItems = sequence.map((item, index) => ( +
  • Section {item.section + 1 + ""} for  + {item.duration.minutes}M {item.duration.seconds}S
  • + )); + return [( {"" + (i + 1)} {name} {running ? "Running" : "Not running"} {enabled ? "Enabled" : "Not enabled"} - , + ), (
      - {sequence.map((item) => - (
    • Section {item.section + 1 + ""} for  - {item.duration.minutes}M {item.duration.seconds}S
    • ))} + {sequenceItems}
    - +
    - , - ]; + )]; } render() { + const programRows = Array.prototype.concat.apply([], + this.props.programs.map(ProgramTable.renderRows)); + return ( @@ -56,9 +60,7 @@ export default class ProgramTable extends React.PureComponent<{ programs: Progra - { - Array.prototype.concat.apply([], this.props.programs.map(ProgramTable.renderRows)) - } + {programRows}
    ); diff --git a/app/script/components/SectionTable.tsx b/app/script/components/SectionTable.tsx index 37ccefa..1c6a00a 100644 --- a/app/script/components/SectionTable.tsx +++ b/app/script/components/SectionTable.tsx @@ -1,38 +1,41 @@ import * as classNames from "classnames"; -import {observer} from "mobx-react"; +import { observer } from "mobx-react"; import * as React from "react"; -import {Table} from "semantic-ui-react"; +import { Table } from "semantic-ui-react"; -import {Section} from "../sprinklers"; +import { Section } from "../sprinklers"; import FontAwesome = require("react-fontawesome"); /* tslint:disable:object-literal-sort-keys */ @observer -export default class SectionTable extends React.PureComponent<{ sections: Section[] }, {}> { +export default class SectionTable extends React.Component<{ sections: Section[] }> { private static renderRow(section: Section, index: number) { if (!section) { return null; } - const {name, state} = section; + const { name, state } = section; + const sectionStateClass = classNames({ + "section--state": true, + "section--state-true": state, + "section--state-false": !state, + }); + const sectionState = state ? + ( Irrigating) + : "Not irrigating"; return ( {"" + (index + 1)} {name} - {state ? - ( Irrigating) - : "Not irrigating"} - + {sectionState} ); } render() { - return ( + const rows = this.props.sections.map(SectionTable.renderRow); + return ( +
    Sections @@ -44,9 +47,7 @@ export default class SectionTable extends React.PureComponent<{ sections: Sectio - { - this.props.sections.map(SectionTable.renderRow) - } + {rows}
    ); diff --git a/app/script/index.tsx b/app/script/index.tsx index e8607c5..9317fbb 100644 --- a/app/script/index.tsx +++ b/app/script/index.tsx @@ -14,15 +14,19 @@ uiStore.addMessage(new Message("asdf", "boo!", Message.Type.Error)); const rootElem = document.getElementById("app"); -ReactDOM.render( - -, rootElem); +const doRender = (Component: typeof App) => { + ReactDOM.render(( + + + + ), rootElem); +}; + +doRender(App); if (module.hot) { module.hot.accept("./components/App", () => { const NextApp = require("./components/App").default as typeof App; - ReactDOM.render( - - , rootElem); + doRender(NextApp); }); } diff --git a/app/script/ui.ts b/app/script/ui.ts index ae92de0..33ec45e 100644 --- a/app/script/ui.ts +++ b/app/script/ui.ts @@ -1,4 +1,5 @@ import {observable} from "mobx"; +import { getRandomId } from "./utils"; export class Message { id: string; @@ -7,7 +8,7 @@ export class Message { type: Message.Type = Message.Type.Default; constructor(header: string, content: string = "", type: Message.Type = Message.Type.Default) { - this.id = "" + Math.floor(Math.random() * 1000000000); + this.id = "" + getRandomId(); this.header = header; this.content = content; this.type = type; diff --git a/app/script/utils.ts b/app/script/utils.ts index 6435fa8..5bbeb65 100644 --- a/app/script/utils.ts +++ b/app/script/utils.ts @@ -7,3 +7,7 @@ export function checkedIndexOf(o: T | number, arr: T[], type: string = "objec } return idx; } + +export function getRandomId() { + return Math.floor(Math.random() * 1000000000); +} diff --git a/app/style/app.css b/app/style/app.css index 0686b64..fafee8b 100644 --- a/app/style/app.css +++ b/app/style/app.css @@ -46,31 +46,4 @@ left: 12px; right: 12px; z-index: 1000; -} - -.message-enter, -.message-appear { - opacity: 0.01; -} - -.message-enter.message-enter-active, -.message-appear.message-appear-active { - opacity: 1; - transition: all 500ms ease-in; -} - -.message-leave { - /*opacity: 1;*/ - transform-origin: top; - overflow-y: hidden; -} - -.message-leave.message-leave-active { - /*opacity: 0.01;*/ - transform: scaleY(0.01); - /*height: 0;*/ - margin-top: 0; - padding-top: 0; - padding-bottom: 0; - transition: all 500ms ease-in; } \ No newline at end of file diff --git a/package.json b/package.json index cd833bb..feb9fa8 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "style-loader": "^0.18.1", "ts-loader": "^2.1.0", "tslint": "^5.4.2", + "tslint-react": "^3.2.0", "typescript": "^2.3.4", "webpack": "^3.0.0", "webpack-dev-server": "^2.4.4" diff --git a/tslint.json b/tslint.json index 1c0575b..389bdbf 100644 --- a/tslint.json +++ b/tslint.json @@ -1,7 +1,7 @@ { - "defaultSeverity": "error", + "defaultSeverity": "warning", "extends": [ - "tslint:latest" + "tslint:latest", "tslint-react" ], "jsRules": {}, "rules": { @@ -33,7 +33,8 @@ "no-submodule-imports": false, "no-unused-variable": [ true - ] + ], + "jsx-boolean-value": [ true, "never" ] }, "rulesDirectory": [] } diff --git a/yarn.lock b/yarn.lock index 0333983..5d7eabb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4248,6 +4248,12 @@ tslib@^1.7.1: version "1.7.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec" +tslint-react@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/tslint-react/-/tslint-react-3.2.0.tgz#851fb505201c63d0343c51726e6364f7e9ad2e99" + dependencies: + tsutils "^2.8.0" + tslint@^5.4.2: version "5.7.0" resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.7.0.tgz#c25e0d0c92fa1201c2bc30e844e08e682b4f3552" @@ -4263,6 +4269,12 @@ tslint@^5.4.2: tslib "^1.7.1" tsutils "^2.8.1" +tsutils@^2.8.0: + version "2.8.2" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.8.2.tgz#2c1486ba431260845b0ac6f902afd9d708a8ea6a" + dependencies: + tslib "^1.7.1" + tsutils@^2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.8.1.tgz#3771404e7ca9f0bedf5d919a47a4b1890a68efff"