Browse Source

More improvements

update-deps
Alex Mikhalev 7 years ago
parent
commit
8c94246f33
  1. 15
      app/script/components/App.tsx
  2. 19
      app/script/components/DeviceView.tsx
  3. 55
      app/script/components/MessagesView.tsx
  4. 26
      app/script/components/ProgramTable.tsx
  5. 27
      app/script/components/SectionTable.tsx
  6. 16
      app/script/index.tsx
  7. 3
      app/script/ui.ts
  8. 4
      app/script/utils.ts
  9. 27
      app/style/app.css
  10. 1
      package.json
  11. 7
      tslint.json
  12. 12
      yarn.lock

15
app/script/components/App.tsx

@ -1,22 +1,25 @@ @@ -1,22 +1,25 @@
import "app/style/app.css";
import "font-awesome/css/font-awesome.css";
import { observer } from "mobx-react";
import DevTools from "mobx-react-devtools";
import * as React from "react";
import "semantic-ui-css/semantic.css";
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";
@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 <Item.Group divided>
return (
<Item.Group divided>
<MessagesView uiStore={this.props.uiStore} />
<DeviceView device={this.props.device} />
<DevTools />
</Item.Group>;
</Item.Group>
);
}
}

19
app/script/components/DeviceView.tsx

@ -7,19 +7,22 @@ import { ProgramTable, RunSectionForm, SectionRunnerView, SectionTable } from ". @@ -7,19 +7,22 @@ import { ProgramTable, RunSectionForm, SectionRunnerView, SectionTable } from ".
import { SprinklersDevice } from "../sprinklers";
import FontAwesome = require("react-fontawesome");
const ConnectionState = ({ connected }: { connected: boolean }) =>
<span className={classNames({
const ConnectionState = ({ connected }: { connected: boolean }) => {
const classes = classNames({
"device--connectionState": true,
"device--connectionState-connected": connected,
"device--connectionState-disconnected": !connected,
})}>
<FontAwesome name={connected ? "plug" : "chain-broken"} />
&nbsp;
});
return (
<span className={classes}>
<FontAwesome name={connected ? "plug" : "chain-broken"} />&nbsp;
{connected ? "Connected" : "Disconnected"}
</span>;
</span>
);
};
@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 @@ -31,7 +34,7 @@ export default class DeviceView extends React.PureComponent<{ device: Sprinklers
<ConnectionState connected={connected} />
</Header>
<Item.Meta>
Raspberry Pi Grinklers Instance
</Item.Meta>
<SectionRunnerView sectionRunner={sectionRunner} />
<SectionTable sections={sections} />

55
app/script/components/MessagesView.tsx

@ -1,30 +1,47 @@ @@ -1,30 +1,47 @@
import { observer } from "mobx-react";
import * as React from "react";
import {CSSTransitionGroup} from "react-transition-group";
import {Message} from "semantic-ui-react";
import { Message, MessageList, TransitionGroup } from "semantic-ui-react";
import { Message as UiMessage, UiStore } from "../ui";
@observer
export default class MessagesView extends React.PureComponent<{ uiStore: UiStore }, {}> {
class MessageView extends React.Component<{
uiStore: UiStore,
message: UiMessage,
index: number,
}> {
render() {
return <div className="messages">
<CSSTransitionGroup transitionName="message" transitionAppear={true} transitionAppearTimeout={500}
transitionEnterTimeout={500} transitionLeaveTimeout={500}>
{this.props.uiStore.messages.map(this.renderMessage)}
</CSSTransitionGroup>
</div>;
const { id, header, content, type } = this.props.message;
return (
<Message
header={header}
content={content}
success={type === UiMessage.Type.Success}
info={type === UiMessage.Type.Info}
warning={type === UiMessage.Type.Warning}
error={type === UiMessage.Type.Error}
onDismiss={this.dismiss}
/>
);
}
private renderMessage = (message: UiMessage, index: number) => {
const {header, content, type} = message;
return <Message key={message.id} className="message"
header={header} content={content}
success={type === UiMessage.Type.Success}
info={type === UiMessage.Type.Info} warning={type === UiMessage.Type.Warning}
error={type === UiMessage.Type.Error} onDismiss={() => 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) => (
<MessageView key={message.id} uiStore={this.props.uiStore} message={message} index={index} />
));
return (
<div className="messages" >
<TransitionGroup animation="scale" duration={200}>
{messages}
</TransitionGroup>
</div>
);
}
}

26
app/script/components/ProgramTable.tsx

@ -4,7 +4,7 @@ import {Table} from "semantic-ui-react"; @@ -4,7 +4,7 @@ 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 (
<div>{JSON.stringify(this.props.schedule)}</div>
@ -13,35 +13,39 @@ export class ScheduleView extends React.PureComponent<{ schedule: 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 sequenceItems = sequence.map((item, index) => (
<li key={index}>Section {item.section + 1 + ""} for&nbsp;
{item.duration.minutes}M {item.duration.seconds}S</li>
));
return [(
<Table.Row key={i}>
<Table.Cell className="program--number">{"" + (i + 1)}</Table.Cell>
<Table.Cell className="program--name">{name}</Table.Cell>
<Table.Cell className="program--running">{running ? "Running" : "Not running"}</Table.Cell>
<Table.Cell className="program--enabled">{enabled ? "Enabled" : "Not enabled"}</Table.Cell>
</Table.Row>
,
), (
<Table.Row key={i + .5}>
<Table.Cell className="program--sequence" colSpan="4">
<ul>
{sequence.map((item) =>
(<li>Section {item.section + 1 + ""} for&nbsp;
{item.duration.minutes}M {item.duration.seconds}S</li>))}
{sequenceItems}
</ul>
<ScheduleView schedule={schedule} />
</Table.Cell>
</Table.Row>
,
];
)];
}
render() {
const programRows = Array.prototype.concat.apply([],
this.props.programs.map(ProgramTable.renderRows));
return (
<Table celled>
<Table.Header>
@ -56,9 +60,7 @@ export default class ProgramTable extends React.PureComponent<{ programs: Progra @@ -56,9 +60,7 @@ export default class ProgramTable extends React.PureComponent<{ programs: Progra
</Table.Row>
</Table.Header>
<Table.Body>
{
Array.prototype.concat.apply([], this.props.programs.map(ProgramTable.renderRows))
}
{programRows}
</Table.Body>
</Table>
);

27
app/script/components/SectionTable.tsx

@ -9,30 +9,33 @@ import FontAwesome = require("react-fontawesome"); @@ -9,30 +9,33 @@ 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;
return (
<Table.Row key={index}>
<Table.Cell className="section--number">{"" + (index + 1)}</Table.Cell>
<Table.Cell className="section--name">{name}</Table.Cell>
<Table.Cell className={classNames({
const sectionStateClass = classNames({
"section--state": true,
"section--state-true": state,
"section--state-false": !state,
})}>{state ?
});
const sectionState = state ?
(<span><FontAwesome name="tint" /> Irrigating</span>)
: "Not irrigating"}
</Table.Cell>
: "Not irrigating";
return (
<Table.Row key={index}>
<Table.Cell className="section--number">{"" + (index + 1)}</Table.Cell>
<Table.Cell className="section--name">{name}</Table.Cell>
<Table.Cell className={sectionStateClass}>{sectionState}</Table.Cell>
</Table.Row>
);
}
render() {
return (<Table celled striped>
const rows = this.props.sections.map(SectionTable.renderRow);
return (
<Table celled striped>
<Table.Header>
<Table.Row>
<Table.HeaderCell colSpan="3">Sections</Table.HeaderCell>
@ -44,9 +47,7 @@ export default class SectionTable extends React.PureComponent<{ sections: Sectio @@ -44,9 +47,7 @@ export default class SectionTable extends React.PureComponent<{ sections: Sectio
</Table.Row>
</Table.Header>
<Table.Body>
{
this.props.sections.map(SectionTable.renderRow)
}
{rows}
</Table.Body>
</Table>
);

16
app/script/index.tsx

@ -14,15 +14,19 @@ uiStore.addMessage(new Message("asdf", "boo!", Message.Type.Error)); @@ -14,15 +14,19 @@ uiStore.addMessage(new Message("asdf", "boo!", Message.Type.Error));
const rootElem = document.getElementById("app");
ReactDOM.render(<AppContainer>
<App device={device} uiStore={uiStore} />
</AppContainer>, rootElem);
const doRender = (Component: typeof App) => {
ReactDOM.render((
<AppContainer>
<Component device={device} uiStore={uiStore} />
</AppContainer>
), rootElem);
};
doRender(App);
if (module.hot) {
module.hot.accept("./components/App", () => {
const NextApp = require<any>("./components/App").default as typeof App;
ReactDOM.render(<AppContainer>
<NextApp device={device} uiStore={uiStore} />
</AppContainer>, rootElem);
doRender(NextApp);
});
}

3
app/script/ui.ts

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
import {observable} from "mobx";
import { getRandomId } from "./utils";
export class Message {
id: string;
@ -7,7 +8,7 @@ export class Message { @@ -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;

4
app/script/utils.ts

@ -7,3 +7,7 @@ export function checkedIndexOf<T>(o: T | number, arr: T[], type: string = "objec @@ -7,3 +7,7 @@ export function checkedIndexOf<T>(o: T | number, arr: T[], type: string = "objec
}
return idx;
}
export function getRandomId() {
return Math.floor(Math.random() * 1000000000);
}

27
app/style/app.css

@ -47,30 +47,3 @@ @@ -47,30 +47,3 @@
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;
}

1
package.json

@ -58,6 +58,7 @@ @@ -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"

7
tslint.json

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
{
"defaultSeverity": "error",
"defaultSeverity": "warning",
"extends": [
"tslint:latest"
"tslint:latest", "tslint-react"
],
"jsRules": {},
"rules": {
@ -33,7 +33,8 @@ @@ -33,7 +33,8 @@
"no-submodule-imports": false,
"no-unused-variable": [
true
]
],
"jsx-boolean-value": [ true, "never" ]
},
"rulesDirectory": []
}

12
yarn.lock

@ -4248,6 +4248,12 @@ tslib@^1.7.1: @@ -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: @@ -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"

Loading…
Cancel
Save