Browse Source

More awesome work on stuff

update-deps
Alex Mikhalev 7 years ago
parent
commit
f9ae6fac6f
  1. 4
      app/components/DeviceView.tsx
  2. 4
      app/components/MessageTest.tsx
  3. 4
      app/components/MessagesView.tsx
  4. 5
      app/index.tsx
  5. 18
      app/state/index.ts
  6. 8
      app/state/inject.tsx
  7. 46
      app/state/web.ts
  8. 16
      common/sprinklers/SprinklersDevice.ts
  9. 21
      common/sprinklers/json/index.ts
  10. 8
      server/index.ts

4
app/components/DeviceView.tsx

@ -4,7 +4,7 @@ import * as React from "react";
import FontAwesome = require("react-fontawesome"); import FontAwesome = require("react-fontawesome");
import { Header, Item } from "semantic-ui-react"; import { Header, Item } from "semantic-ui-react";
import { injectState, State } from "@app/state"; import { injectState, MqttApiState } from "@app/state";
import { SprinklersDevice } from "@common/sprinklers"; import { SprinklersDevice } from "@common/sprinklers";
import { ProgramTable, RunSectionForm, SectionRunnerView, SectionTable } from "."; import { ProgramTable, RunSectionForm, SectionRunnerView, SectionTable } from ".";
@ -24,7 +24,7 @@ const ConnectionState = ({ connected }: { connected: boolean }) => {
interface DeviceViewProps { interface DeviceViewProps {
deviceId: string; deviceId: string;
state: State; state: MqttApiState;
} }
class DeviceView extends React.Component<DeviceViewProps> { class DeviceView extends React.Component<DeviceViewProps> {

4
app/components/MessageTest.tsx

@ -1,10 +1,10 @@
import * as React from "react"; import * as React from "react";
import { Button, Segment } from "semantic-ui-react"; import { Button, Segment } from "semantic-ui-react";
import { injectState, State } from "@app/state"; import { injectState, MqttApiState } from "@app/state";
import { getRandomId } from "@common/utils"; import { getRandomId } from "@common/utils";
class MessageTest extends React.Component<{ state: State }> { class MessageTest extends React.Component<{ state: MqttApiState }> {
render() { render() {
return ( return (
<Segment> <Segment>

4
app/components/MessagesView.tsx

@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import { Message, MessageProps, TransitionGroup } from "semantic-ui-react"; import { Message, MessageProps, TransitionGroup } from "semantic-ui-react";
import { injectState, State, UiMessage, UiStore } from "@app/state/"; import { injectState, MqttApiState, UiMessage, UiStore } from "@app/state/";
@observer @observer
class MessageView extends React.Component<{ class MessageView extends React.Component<{
@ -33,7 +33,7 @@ class MessageView extends React.Component<{
} }
} }
class MessagesView extends React.Component<{ state: State }> { class MessagesView extends React.Component<{ state: MqttApiState }> {
render() { render() {
const { uiStore } = this.props.state; const { uiStore } = this.props.state;
const messages = uiStore.messages.map((message) => ( const messages = uiStore.messages.map((message) => (

5
app/index.tsx

@ -3,12 +3,13 @@ import * as ReactDOM from "react-dom";
import { AppContainer } from "react-hot-loader"; import { AppContainer } from "react-hot-loader";
import App from "@app/components/App"; import App from "@app/components/App";
import { ProvideState, State } from "@app/state"; import { ProvideState, MqttApiState, WebApiState } from "@app/state";
import log, { setLogger } from "@common/logger"; import log, { setLogger } from "@common/logger";
setLogger(log.child({ name: "sprinklers3/app" })); setLogger(log.child({ name: "sprinklers3/app" }));
const state = new State(); // const state = new MqttApiState();
const state = new WebApiState();
state.start(); state.start();
const rootElem = document.getElementById("app"); const rootElem = document.getElementById("app");

18
app/state/index.ts

@ -1,17 +1,13 @@
import { ISprinklersApi } from "@common/sprinklers"; import { ISprinklersApi } from "@common/sprinklers";
import { MqttApiClient } from "@common/sprinklers/mqtt"; import { MqttApiClient } from "@common/sprinklers/mqtt";
import { WebApiClient } from "./web";
import { UiMessage, UiStore } from "./ui"; import { UiMessage, UiStore } from "./ui";
export { UiMessage, UiStore }; export { UiMessage, UiStore };
export * from "./inject"; export * from "./inject";
export interface IState { export abstract class StateBase {
sprinklersApi: ISprinklersApi; abstract readonly sprinklersApi: ISprinklersApi;
uiStore: UiStore;
}
export class State implements IState {
sprinklersApi: ISprinklersApi = new MqttApiClient(`ws://${location.hostname}:1884`);
uiStore = new UiStore(); uiStore = new UiStore();
constructor() { constructor() {
@ -23,6 +19,14 @@ export class State implements IState {
} }
} }
export class MqttApiState extends StateBase {
sprinklersApi = new MqttApiClient(`ws://${location.hostname}:1884`);
}
export class WebApiState extends StateBase {
sprinklersApi = new WebApiClient();
}
// const state = new State(); // const state = new State();
// export default state; // export default state;

8
app/state/inject.tsx

@ -1,10 +1,10 @@
import * as PropTypes from "prop-types"; import * as PropTypes from "prop-types";
import * as React from "react"; import * as React from "react";
import { State } from "@app/state"; import { StateBase } from "@app/state";
interface IProvidedStateContext { interface IProvidedStateContext {
providedState: State; providedState: StateBase;
} }
const providedStateContextTypes: PropTypes.ValidationMap<any> = { const providedStateContextTypes: PropTypes.ValidationMap<any> = {
@ -12,7 +12,7 @@ const providedStateContextTypes: PropTypes.ValidationMap<any> = {
}; };
export class ProvideState extends React.Component<{ export class ProvideState extends React.Component<{
state: State, state: StateBase,
}> implements React.ChildContextProvider<IProvidedStateContext> { }> implements React.ChildContextProvider<IProvidedStateContext> {
static childContextTypes = providedStateContextTypes; static childContextTypes = providedStateContextTypes;
@ -30,7 +30,7 @@ export class ProvideState extends React.Component<{
type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T]; type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T];
type Omit<T, K extends keyof T> = {[P in Diff<keyof T, K>]: T[P]}; type Omit<T, K extends keyof T> = {[P in Diff<keyof T, K>]: T[P]};
export function injectState<P extends { "state": State }>(Component: React.ComponentType<P>) { export function injectState<P extends { "state": StateBase }>(Component: React.ComponentType<P>) {
return class extends React.Component<Omit<P, "state">> { return class extends React.Component<Omit<P, "state">> {
static contextTypes = providedStateContextTypes; static contextTypes = providedStateContextTypes;
context: IProvidedStateContext; context: IProvidedStateContext;

46
app/state/web.ts

@ -0,0 +1,46 @@
import { update } from "serializr";
import * as s from "@common/sprinklers";
import * as schema from "@common/sprinklers/json";
export class WebSprinklersDevice extends s.SprinklersDevice {
get id() {
return "grinklers";
}
async runSection(section: number | s.Section, duration: s.Duration): Promise<{}> {
return {};
}
async runProgram(program: number | s.Program): Promise<{}> {
return {};
}
async cancelSectionRunById(id: number): Promise<{}> {
return {};
}
async pauseSectionRunner(): Promise<{}> {
return {};
}
async unpauseSectionRunner(): Promise<{}> {
return {};
}
}
export class WebApiClient implements s.ISprinklersApi {
start() {
// NOT IMPLEMENTED
}
getDevice(name: string): s.SprinklersDevice {
const device = new WebSprinklersDevice();
fetch("/api/grinklers")
.then((res) => res.json())
.then((json) => {
update(schema.sprinklersDeviceSchema, device, json);
})
.catch((e) => alert(e));
return device;
}
removeDevice(name: string) {
// NOT IMPLEMENTED
}
}

16
common/sprinklers/SprinklersDevice.ts

@ -10,6 +10,10 @@ export abstract class SprinklersDevice {
@observable programs: Program[] = []; @observable programs: Program[] = [];
@observable sectionRunner: SectionRunner; @observable sectionRunner: SectionRunner;
constructor() {
this.sectionRunner = new (this.sectionRunnerConstructor)(this);
}
abstract get id(): string; abstract get id(): string;
abstract runSection(section: number | Section, duration: Duration): Promise<{}>; abstract runSection(section: number | Section, duration: Duration): Promise<{}>;
abstract runProgram(program: number | Program): Promise<{}>; abstract runProgram(program: number | Program): Promise<{}>;
@ -17,9 +21,15 @@ export abstract class SprinklersDevice {
abstract pauseSectionRunner(): Promise<{}>; abstract pauseSectionRunner(): Promise<{}>;
abstract unpauseSectionRunner(): Promise<{}>; abstract unpauseSectionRunner(): Promise<{}>;
abstract get sectionConstructor(): typeof Section; get sectionConstructor(): typeof Section {
abstract get sectionRunnerConstructor(): typeof SectionRunner; return Section;
abstract get programConstructor(): typeof Program; }
get sectionRunnerConstructor(): typeof SectionRunner {
return SectionRunner;
}
get programConstructor(): typeof Program {
return Program;
}
toString(): string { toString(): string {
return `SprinklersDevice{id="${this.id}", connected=${this.connected}, ` + return `SprinklersDevice{id="${this.id}", connected=${this.connected}, ` +

21
common/sprinklers/json/index.ts

@ -8,15 +8,28 @@ import * as s from "..";
export const durationSchema: PropSchema = { export const durationSchema: PropSchema = {
serializer: (duration: s.Duration | null) => serializer: (duration: s.Duration | null) =>
duration != null ? duration.toSeconds() : null, duration != null ? duration.toSeconds() : null,
deserializer: (json: any) => deserializer: (json: any, done) => {
typeof json === "number" ? s.Duration.fromSeconds(json) : null, if (typeof json === "number") {
done(null, s.Duration.fromSeconds(json));
} else {
done(new Error(`Duration expects a number, not ${json}`), undefined);
}
},
}; };
export const dateSchema: PropSchema = { export const dateSchema: PropSchema = {
serializer: (jsDate: Date | null) => jsDate != null ? serializer: (jsDate: Date | null) => jsDate != null ?
jsDate.toISOString() : null, jsDate.toISOString() : null,
deserializer: (json: any) => typeof json === "string" ? deserializer: (json: any, done) => {
new Date(json) : null, if (json === null) {
done(null, null);
}
try {
done(null, new Date(json));
} catch (e) {
done(e, undefined);
}
},
}; };
export const dateOfYearSchema: ModelSchema<s.DateOfYear> = { export const dateOfYearSchema: ModelSchema<s.DateOfYear> = {

8
server/index.ts

@ -13,13 +13,17 @@ const mqttClient = new mqtt.MqttApiClient("mqtt://localhost:1883");
mqttClient.start(); mqttClient.start();
import { sprinklersDeviceSchema } from "@common/sprinklers/json"; import { sprinklersDeviceSchema } from "@common/sprinklers/json";
import { autorun } from "mobx"; import { autorunAsync } from "mobx";
import { serialize } from "serializr"; import { serialize } from "serializr";
const device = mqttClient.getDevice("grinklers"); const device = mqttClient.getDevice("grinklers");
autorunAsync(() => {
const j = serialize(sprinklersDeviceSchema, device);
log.info({ device: j });
}, 0);
app.get("/api/grinklers", (req, res) => { app.get("/api/grinklers", (req, res) => {
const j = serialize(sprinklersDeviceSchema, device); const j = serialize(sprinklersDeviceSchema, device);
log.trace(j);
res.send(j); res.send(j);
}); });

Loading…
Cancel
Save